【腾讯云HAI域探密】- HAI为NPL保驾护航

近些年,随着机器学习技术的蓬勃发展,以GPU为代表的一系列专用芯片以优越的高性能计算能力和愈发低廉的成本,在机器学习领域得到广泛认可和青睐。GPU等专用芯片以较低的成本提供海量算力,已经成为机器学习和AI人工智能领域的核心利器,在人工智能时代发挥着越来越重要的作用。

在这里插入图片描述

今天给大家推荐和介绍的“高性能应用服务HAI”,是一款大幅降低GPU云服务器使用门槛,多角度优化产品使用体验,开箱即用。拥有澎湃算力,即开即用。以应用为中心,匹配GPU云算力资源,助力中小企业及开发者快速部署LLM、AI作画、数据科学等高性能应用。

在这里插入图片描述
探讨一下如何利用“高性能应用服务HAI”进行业务场景赋能,已经是很多公司目前需要面临的问题。本文分享一下“高性能应用服务HAI”在医疗NLP体系中的实践过程,希望能通过“高性能应用服务HAI”的方案对公司的业务进行将本增效。

在这里插入图片描述


一、为什么在AI的领域需要使用GPU呢?

在这些领域中,GPU 可以加速训练模型、处理海量数据等计算密集型任务,显著提高了计算效率和速度。因此,GPU 已成为现代计算机的重要组成部分,被广泛应用于各种领域。

1. GPU 和 CPU 的主要区别体现在以下几个方面:

在这里插入图片描述

2. GPU 的工作原理:

在这里插入图片描述


二、“高性能应用服务HAI”能够带来什么?

1. 什么是HAI呢?

高性能应用服务(Hyper Application Inventor,HAI)是一款面向 Al、科学计算的GPU 应用服务产品,提供即插即用的澎湃算力与常见环境。助力中小企业及开发者快速部署LLM、AI作画、数据科学等高性能应用,原生集成配套的开发工具与组件,大幅提高应用层的开发生产效率。
在这里插入图片描述

2. 平时在使用AIGC应用的痛点:

在这里插入图片描述

3. 高性能应用服务HAI可以让我们干什么?

通过“高性能应用服务HAI”的StableDiffusion模型可以进行AI绘画,是一种利用深度学习算法进行创作的绘图方式,被广泛应用于游戏、数字媒体、电影、广告设计、动画等领域,可以让设计师加快绘图相关的工作,从“人工”GC逐渐的转向AIGC人工智生产内容。

在这里插入图片描述

4. “高性能应用服务HAI”降本增效的结果:

在这里插入图片描述

5. “高性能应用服务HAI”全面的AI应用托管服务:

“高性能应用服务HAI”是根据应用匹配推选GPU算力资源,实现最高性价比,是面向开发者和企业的AI工程化平台,提供了覆盖数据提供、模型开发、模型训练、模型部署的全流程服务。

在这里插入图片描述

同时,打通必备云服务组件,大幅简化云服务配置流程,为机器学习开发的每个步骤加速创新,包括:

  • 分钟级自动构建LLM、AI作画等应用环境,适合模型开发、模型训练、模型部署
  • 提供多种预装模型环境,包含如StableDiffusion、ChatGLM等热门模型
  • 提供开发者友好的图形界面,支持JupyterLab、WebUI等多种算力连接方,AI研究调试超低门槛。
  • 学术加速为企业提供训练加速和推理加速的能力,提高AI训练和推理的速度、易用性和稳定性,极大提升AI计算的效率。

在这里插入图片描述

“高性能应用服务HAI”基于软硬件一体优化技术,超大规模分布式深度学习任务运行,具备高性能、高效率、高利用率等核心优势,实现AI开发及应用过程的降本增效。


三、对比GPU云服务器,高性能应用服务HAI解决的业务痛点问题:

1. 总结优势与劣势:

在这里插入图片描述

四、“高性能应用服务HAI”的应用场景有哪些?

在这里插入图片描述


五、基于ChatGLM2-6B实现智能客服系统:

通过官方提供的第二个实验手册:未来对话:HAI创作个人专属的知识宇宙,我们可以在3-5分钟就可以初始化一个“高性能应用服务HAI”的ChatGLM2-6B智能AI对话应用。

“高性能应用服务HAI”相对传统的GPU云服务自建AI应用,是属于更为上层的应用,屏蔽了很多的繁琐的工作量,如环境搭建、选型、系统运维维护。

在这里插入图片描述

1. 简单的试用“高性能应用服务HAI”中ChatGLM2-6B的AI对话功能:

通过打开控制台,点击“Gradio WebUI”,输入我们需要的答案就可以查询相关医疗相关的知识。

在这里插入图片描述

在同时访问的时候,和不同地址访问的时候,也是不会互相影响,相当于“单独的个体”,可以让不同的部门进行使用,不致于产会“串行”、“阻塞”的问题。

在这里插入图片描述

上面我们可以很容易就上线了一个AI对话的应用,可以提供了业务不同的部门进行使用,比如商务团队的需要写医疗相关专业术语标书、运营团队需要写相关活动的文案、医疗咨询师需要查询一些专业病理知识,使用默认的web页面不太方便,且没有受到权限控制,可以用以下API接口的形式接入到我们的自己业务平台中。

2. 基于“高性能应用服务HAI”的ChatGLM2-6B以API接口提供web服务:

根据官方的手册中提到,脚本中有一个api.py的文件,使用它就可以提供API的服务,不过,出现了报错:

torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to allocate 108.00 MiB. GPU 0 has a total capacty of 14.58 GiB of which 43.38 MiB is free. Process 10594 has 11.76 GiB memory in use. Process 12441 has 2.78 GiB memory in use. Of the allocated memory 2.68 GiB is allocated by PyTorch, and 1.85 MiB is reserved by PyTorch but unallocated. If reserved but unallocated memory is large try setting max_split_size_mb to avoid fragmentation.  See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

在这里插入图片描述

由于资源不足导致无法启动,通过以下的命令进行关闭不需要的额外资源:

apt-get update && apt-get install sudo
sudo apt-get update  
sudo apt-get install psmisc
sudo fuser -k 6889/tcp #执行这条命令将关闭 HAI提供的 chatglm2_gradio webui功能

在控制台中开通8000端的网络安全规则。

在这里插入图片描述

再能过postman进行访问IP + 端口(8000)端口,也可以修改其它的端口,需要修改脚本/root/ChatGLM2-6B/api.py。

if __name__ == '__main__':
    tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm2-6b", revision="v1.0", trust_remote_code=True)
    model = AutoModel.from_pretrained("THUDM/chatglm2-6b", revision="v1.0", trust_remote_code=True).cuda()
    # 多显卡支持,使用下面三行代替上面两行,将num_gpus改为你实际的显卡数量
    # model_path = "THUDM/chatglm2-6b"
    # tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
    # model = load_model_on_gpus(model_path, num_gpus=2)
    model.eval()
uvicorn.run(app, host='0.0.0.0', port=8000, workers=1)

在这里插入图片描述

此时,我们就可以启动一个web API形式的服务,提供post接口,这样,其它的业务平台,可以通过接口访问的方式来调用。

在这里插入图片描述

3. 小程序中提供AI分析助手:

在小程序的代码中,请求基于“高性能应用服务HAI”的ChatGLM2-6B以API接口提供web服务,可以有效的进行权限的控制,防止外部人员使用。

<template>
	<view>
		<u-sticky>
			<u-notice-bar direction="row" text="" url="/pages/user/myQuestion"
				linkType="navigateTo" mode="link" speed="60" bgColor="#e7f9f3" color="#1acc89">
			</u-notice-bar>
		</u-sticky>
		<view style="width: 94%;margin: 30rpx auto;" v-if="skeletonLoading">
			<u-skeleton rows="5" :loading="skeletonLoading"></u-skeleton>
		</view>
		<view class="container" v-if="!skeletonLoading">
			<view class="pre-form">
				<u-transition :show="true" mode="fade-left">
					<view class="option-item">
						<view class="option-content">
							<view class="sd-model-item sd-model-item-after" @click="sencePopupOpen()">
								<view class="sd-item">
									<view style="border-radius: 6px;">
										<u--image :src="chatSenceSelected.icon_full_path" radius="6" width="100rpx"
											height="100rpx" :lazyLoad="false"
											:customStyle="{'background-color': '#fff!important'}">
										</u--image>
									</view>
									<view class="sd-item-context">
										<view class="sd-item-title sd-item-title-weight">
											{
    
    {
    
    chatSenceSelected.role}}
										</view>
										<view class="sd-item-tips">
											{
    
    {
    
    chatSenceSelected.explain}}
										</view>
									</view>
								</view>
							</view>
						</view>
					</view>
					<view class="option-item">
						<view class="title layout">
							<view class="title-item">内容需求</view>
							<view class="tips-item" @click="resetExample">试试范文</view>
						</view>
						<view class="option-content">
							<view class="sd-model-item-context">
								<u--textarea v-model="chatParams.prompt"
									:placeholder="chatSenceSelected.placeholder || '请输入内容需求'" count maxlength='500'
									border="bottom" height="240" :customStyle="{'padding':'0'}" confirmType="done">
								</u--textarea>
							</view>
						</view>
					</view>
					<u--form labelPosition="left" :labelStyle="{'font-weight':'600'}">
						<u-form-item label="字数要求" labelWidth="auto" v-if="chatSenceSelected.max_output">
							<template slot="right">
								<u-number-box v-model="chatParams.words" :step="100" integer inputWidth="50" :min="50"
									:max="chatSenceSelected.max_output">
								</u-number-box>
							</template>
						</u-form-item>
					</u--form>
				</u-transition>
			</view>
		</view>
		<u-popup :show="sencePopup" mode="left" @close="senceClose" :closeable="true" :safeAreaInsetBottom="false">
			<scroll-view :scroll-top="scrollTop" scroll-y="true" :style="{height:`${systemInfo.windowHeight}px`}"
				@scroll="sencePopupScroll">
				<view class="popup-box" style="margin: 80rpx 30rpx 30rpx 30rpx;">
					<view class="option-item popup-list" v-for="(sence,senceIndex) in chatSence" :key="senceIndex">
						<view class="option-item-title">{
    
    {
    
    sence.case_title}}</view>
						<view class="option-content option-content-flex">
							<view class="sd-model-item sd-model-item-margin" v-for="(item,index) in sence.child"
								:key="index" @click="setChatSence(senceIndex,index)"
								:class="chatSenceSelected.id == item.id ? 'sd-model-item-selected':''">
								<view class="sd-item">
									<view class="sd-item-context" style="margin: 0;">
										<view class="sd-item-title sd-item-font">{
    
    {
    
    item.role}}</view>
									</view>
								</view>
							</view>
						</view>
					</view>
				</view>
			</scroll-view>
		</u-popup>
		<!-- 功能按钮区域 -->
		<view class="tool">
			<u-grid :border="false" col="4">
				<u-grid-item @click="goAppStore">
					<u-icon :name="assetUrl + 'apps.png'" size="48rpx"></u-icon>
					<text class="grid-text">应用中心</text>
				</u-grid-item>
				<u-grid-item @click="resetQuestion">
					<u-icon :name="assetUrl + 'delete.png'" size="48rpx"></u-icon>
					<text class="grid-text">清空文案</text>
				</u-grid-item>
				<u-grid-item @click="pasteContent">
					<u-icon :name="assetUrl + 'paste.png'" size="48rpx"></u-icon>
					<text class="grid-text">粘贴文案</text>
				</u-grid-item>
				<u-grid-item @click="onSubmitGPT">
					<u-icon :name="assetUrl + 'txtcheck.png'" size="48rpx"></u-icon>
					<text class="grid-text grid-text-color">立即提问</text>
				</u-grid-item>
			</u-grid>
		</view>
		<!-- #ifdef MP-WEIXIN -->
		<view class="ad-container" style="width: 94%;margin: 30rpx auto;">
			<view class="ad-view">
				<wxAdVideo />
			</view>
			<u-gap height="20rpx"></u-gap>
		</view>
		<!-- #endif -->
	</view>
</template>

<script>
	import wxAdVideo from '@/components/wxad/adVideo.vue';
	export default {
    
    
		components: {
    
    
			wxAdVideo
		},
		data() {
    
    
			return {
    
    
				gptLoading: false,
				chatParams: {
    
    
					prompt: '',
					words: 200
				},
				chatSence: [],
				chatSenceSelected: {
    
    },
				chatSenceExample: [],
				assetUrl: this.$configData.assetsUrl,
				sencePopup: false,
				whiteColor: '#fff',
				skeletonLoading: true,
				scrollTop: 0,
				scrollTopOld: 0,
				systemInfo: uni.getSystemInfoSync(),
			};
		},
		onShareAppMessage(res) {
    
    
			return {
    
    
				title: '轻松创作,爱上文案',
				path: '/pages/index/index'
			}
		},
		onShareTimeline(res) {
    
    
			return {
    
    
				title: '轻松创作,爱上文案',
				path: '/pages/index/index'
			}
		},
		onLoad() {
    
    
			this.getPromptList();
		},
		methods: {
    
    
			sencePopupScroll: function(e) {
    
    
				this.scrollTopOld = e.detail.scrollTop;
			},
			async getPromptList() {
    
    
				var _data = {
    
    
					provider: 1,
					item_id: 17
				};
				var _res = await this.$http.requestApi('GET', 'agi/getCopyWritingPrompt', _data);
				if (_res.status == 200) {
    
    
					this.chatSence = _res.data;
					this.chatSenceSelected = _res.data[0].child[0];
					this.chatSenceExample = _res.data[0].child[0].example_arr;
					this.skeletonLoading = false;
				} else {
    
    
					uni.showToast({
    
    
						icon: 'none',
						title: _res.msg
					});
				}
			},
			goAppStore() {
    
    
				uni.navigateTo({
    
    
					url: '/pages/appCenter/appCenter'
				})
			},
			sencePopupOpen() {
    
    
				this.sencePopup = true;
				this.skeletonLoading = true;
				this.scrollTop = 0;
				this.$nextTick(function() {
    
    
					this.scrollTop = this.scrollTopOld;
				});
			},
			setChatSence(senceIndex, caseIndex) {
    
    
				let that = this;
				//设置文案场景
				that.chatSenceSelected = that.chatSence[senceIndex].child[caseIndex];
				that.chatSenceExample = that.chatSenceSelected.example_arr;
				//this.sencePopup = false;
				that.chatParams.words = 200;
				that.resetQuestion();
			},
			resetExample() {
    
    
				if (this.chatSenceExample.length <= 0) {
    
    
					uni.showToast({
    
    
						icon: 'none',
						title: '暂无范文'
					});
					return;
				}
				//随机案例
				let min = 0;
				let max = this.chatSenceExample.length - 1;
				let index = Math.ceil(Math.random() * (max - min) + min);
				this.chatParams.prompt = this.chatSenceExample[index];
			},
			checkToken() {
    
    
				const token = uni.getStorageSync('token');
				if (token == '' || token == undefined) {
    
    
					return false
				} else {
    
    
					return true
				}
			},
			resetQuestion() {
    
    
				this.chatParams.prompt = '';
			},
			pasteContent() {
    
    
				var that = this;
				uni.getClipboardData({
    
    
					success: function(res) {
    
    
						that.chatParams.prompt = res.data;
					}
				});
			},
			modeChange(index) {
    
    
				this.modeCurrent = index;
			},
			imgStyleChange(type) {
    
    
				this.chatParams.style = type;
			},
			senceClose() {
    
    
				this.skeletonLoading = false;
				this.sencePopup = false;
			},
			onSubmitGPT() {
    
    
				//检测用户是否登录
				let islogin = this.checkToken();
				if (!islogin) {
    
    
					uni.navigateTo({
    
    
						url: '/pages/login/index'
					});
					return false;
				}
				this.gptLoading = true;
				//已经登录,则调用后端接口数据
				let postData = {
    
    
					question: encodeURIComponent(this.chatParams.prompt),
					words: this.chatParams.words,
					sence_id: this.chatSenceSelected.id,
					q_type: 0,
					loginType: 1
				};
				this.$http.requestApi('POST', 'aigc/question/answer', postData).then(res => {
    
    
					const resCode = res.status;
					this.gptLoading = false;
					if (resCode == 10000) {
    
    
						return false;
					}
					if (resCode == 200) {
    
    
						uni.navigateTo({
    
    
							url: '/pages/detail/index?avg=' + encodeURIComponent(res.data.qaId)
						});
					} else {
    
    
						uni.showToast({
    
    
							title: res.msg,
							duration: 2000,
							icon: 'none'
						});
					}
				})
			}
		}
	}
</script>

<style lang="scss" scoped>
	.container {
    
    
		width: 92%;
		margin: 30rpx auto;

		.switch-tabbar {
    
    
			margin: 30rpx 0;
		}

		.pre-form {
    
    
			margin: 20rpx 0;
		}

		.diy-form {
    
    
			margin: 0 auto;
			z-index: 999;

			.header {
    
    
				margin-bottom: 30rpx;

				.title {
    
    
					text-align: center;
					color: #fff;
					margin: 30rpx 0rpx;
				}
			}

			.panel {
    
    
				padding: 30rpx;
				background-color: #fff;
				border-radius: 15rpx;
				box-shadow: 0rpx 10rpx 10rpx #eee;

				.head {
    
    
					display: flex;
					flex-direction: row;
					justify-content: space-between;

					.tips {
    
    
						color: #dd6161;
					}
				}

				.textarea {
    
    
					margin-top: 30rpx;
				}

				.btn-group {
    
    
					display: flex;
					flex-direction: row;
					justify-content: space-between;
					margin-top: 30rpx;

					.get {
    
    
						width: 100%;
					}
				}
			}
		}
	}

	.option-item {
    
    
		.title {
    
    
			padding: 30rpx 0;
			font-size: 30rpx;
			font-weight: 600;
		}

		.title-padding {
    
    
			padding-top: 0 !important;
		}

		.option-item-title {
    
    
			font-size: 28rpx;
			margin: 20rpx auto;
			font-weight: 600;
		}

		.option-content-flex {
    
    
			display: flex;
			justify-content: space-between;
			flex-wrap: wrap;
		}

		.option-content {
    
    

			.sd-model-item {
    
    
				margin-bottom: 20rpx;
				background-color: #f1f2f4;
				padding: 20rpx;
				color: #222;
				border-radius: 12rpx;
				position: relative;

				.sd-item {
    
    
					display: flex;

					.sd-item-context {
    
    
						margin: 0 30rpx;
						display: flex;
						flex-direction: column;
						justify-content: center;
						line-height: 48rpx;

						.sd-item-title {
    
    
							font-size: 30rpx;
						}

						.sd-item-title-weight {
    
    
							font-weight: 600;
						}

						.sd-item-tips {
    
    
							font-size: 24rpx;
							color: #999;
							line-height: initial;
						}

						.sd-item-font {
    
    
							font-size: 28rpx;
						}
					}
				}
			}

			.sd-model-item-selected {
    
    
				background-color: #e7f9f3;
				color: #1acc89;
			}

			.sd-model-item-after {
    
    
				.sd-item::after {
    
    
					content: '';
					position: absolute;
					right: 30rpx;
					top: calc(50% - 12rpx);
					width: 20rpx;
					height: 20rpx;
					border-top: 4rpx solid;
					border-right: 4rpx solid;
					border-color: #999;
					content: '';
					transform: rotate(45deg);
				}
			}


			.sd-model-item-margin {
    
    
				margin-bottom: 30rpx;
				width: 43%;
			}

			.sd-model-item-green {
    
    
				background-color: #e7f9f3;
				color: #1acc89;

				.sd-item {
    
    
					.sd-item-context {
    
    
						.sd-item-tips {
    
    
							color: #1acc89;
							opacity: 0.5;
						}
					}
				}
			}
		}
	}

	.sence-popup-title {
    
    
		position: fixed;
		width: 100%;
		text-align: center;
		height: 50px;
		line-height: 50px;
		font-size: 36rpx;
		font-weight: bold;
	}

	.layout {
    
    
		display: flex;
		justify-content: space-between;
		align-items: center;

		.tips-item {
    
    
			font-weight: 400;
			font-size: 24rpx;
			color: #999;
		}
	}

	.tool {
    
    
		margin: 10rpx 30rpx 20rpx 30rpx;
		width: calc(100% - 60rpx);
		border-radius: 100rpx;
		background-color: #e7f9f3;
		padding: 12rpx 0;

		.u-grid {
    
    

			.u-grid-item {
    
    

				.grid-text {
    
    
					font-size: 24rpx;
					transform: scale(0.9);
					color: #222;
					padding-top: 12rpx;
				}

				.grid-text-color {
    
    
					font-weight: 600;
					color: #1acc89;
				}
			}
		}
	}
</style>

可以通过集成API的形式,首先需要登录到小程序,才能提供类似病例查询、文案生成、IT技术学习等场景。

在这里插入图片描述

4. 后管记录生成过的AI列表:

如果有人生成过一些问题,可以存到数据库,下次使用的时候,直接从数据库查,就不需要经过AI服务,当使用量大的时候,做一层缓存隔离,是非常有必要的,毕竟好刀用在刀刃上。

<div class="elTable" style="margin-top: 17px">
      <el-table
        :data="state.tableList"
        border
        style="width: 100%"
        :header-cell-style="{ background: '#EDF3FD', color: '#333333' }"
        header-align="center"
      >
        <el-table-column type="index" label="序号" width="60" header-align="center" align="center"/>
        <el-table-column prop="batchId" label="搜索文案" header-align="center" align="center"/>
        <el-table-column prop="insuredName" label="姓名" header-align="center" align="center" />
        <el-table-column prop="insuredIdNum" label="证件号" header-align="center" align="center" />
        <el-table-column prop="insuredPhone" label="手机号" header-align="center" align="center"/>
        <el-table-column prop="insuredSex" label="查询时间" header-align="center" align="center" /> -->
      </el-table>
      <div class="elPagination">
        <el-pagination
          style="margin-top: 20px; text-align: right"
          :current-page="state.pageNumber"
          :page-sizes="[10, 20, 30, 40]"
          layout="total, sizes, prev, pager, next, jumper"
          :total="state.total"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        />
      </div>
</div>

在这里插入图片描述
通过对基于“高性能应用服务HAI”的ChatGLM2-6B以API接口提供web服务,集成到小程序中,使用API来集中管理,将生成的记录同时,存一份到数据库或缓存中,下次再有相同的答案可以直接先走中间服务,不用再到AI服务器上再消耗资源,因为其实在医疗行业,有很多的问题,都是比较常用的。
在这里插入图片描述


六、基于PyTorch 实现NLP自然语言处理:

基于NLP和自然语言处理技术将门诊/住院病历、检查检验报告、处方/医嘱等医疗文档自动识别、转换为结构化数据,支持下游可视化、统计分析、推理等应用,可用于健康档案、质控、保险理赔及临床科研等业务场景,获取医疗知识,节约医疗资源。

在公司的业务场景中,患者的病例需要手动去针对性的打标签,比如,标注这个患者是眼疾,实际上会有很多的问题存在:

  • 工作的性质比较单一枯燥的动作,纯粹的人工作业方式
  • 有人工成本的消耗
  • 操作不准确,评判的标准不一致,容易产出错误

在这里插入图片描述

1. 文本csv内容准备,如下为一些患者的病例一些常见的症状描述。

在这里插入图片描述

2. 安装jieba库:

在这里插入图片描述

3. 使用结巴jieba库将语句进行分词库统计词频:

为了对中文文本数据进行预处理,以便进行NLP分析,代码使用中文分词库jieba对患者的数据进行处理。代码读取患者数据的csv文件,去除第一行(其中包含每列的标签),然后循环处理每一行数据。对于每一行,提取内容并使用jieba进行分词。

import jieba

data_path = "sources/data.csv"
data_list = open("data_path").readlines()[1:]

for item in data_list:
  label = item[0]
  content = item[2:].strip()
  seg_list = jieba.cut(content, cut_all = False)
  for seg_item in seg_list:
print(seg_item)

可以看到一些标点符号,和一些没有语义的词也会被匹配出来,得到的分词结果被过滤以去除任何停用词(不具有意义的词,如“和”或“的”)。

在这里插入图片描述

4. 停用词stopwords处理:

停用词的作用是在文本分析过程中过滤掉这些常见词语,从而减少处理的复杂度,提高算法效率,并且在某些任务中可以改善结果的质量,避免分析结果受到这些词的干扰。

在自然语言处理(NLP)研究中,停用词stopwords是指在文本中频繁出现但通常没有太多有意义的词语。这些词语往往是一些常见的功能词、虚词甚至是一些标点符号,如介词、代词、连词、助动词等,比如中文里的"的"、“是”、“和”、“了”、“。“等等,英文里的"the”、“is”、“and”、”…"等等。

import jieba

data_path = "./sources/his.csv"
data_stop_path = "./sources/hit_stopwords.txt"
data_list = open(data_path).readlines()[1:]
stops_word = open(data_stop_path, encoding='UTF-8').readlines()
stops_word = [line.strip() for line in stops_word]
stops_word.append(" ")
stops_word.append("\n")

for item in data_list:
  label = item[0]
  content = item[2:].strip()
  seg_list = jieba.cut(content, cut_all = False)
  seg_res = []
  for seg_item in seg_list:
    if seg_item in stops_word:
      continue
    seg_res.append(seg_item)

  print(content)
  print(seg_res)

在这里插入图片描述

5. 加载数据集:

使用PyTorch的提供的dataset的接口,根据项目重写dataset和dataloader。

import jieba

data_path = "./sources/his.csv"
data_stop_path = "./sources/hit_stopwords.txt"

data_list = open(data_path).readlines()[1:]

stops_word = open(data_stop_path, encoding='UTF-8').readlines()
stops_word = [line.strip() for line in stops_word]
stops_word.append(" ")
stops_word.append("\n")

voc_dict = {
    
    }
min_seq = 1
top_n = 1000
UNK = "<UNK>"
PAD = "<PAD>"

for item in data_list:
  label = item[0]
  content = item[2:].strip()
  seg_list = jieba.cut(content, cut_all = False)
  seg_res = []
  for seg_item in seg_list:
    if seg_item in stops_word:
      continue
    seg_res.append(seg_item)
if seg_item in voc_dict.keys():
      voc_dict[seg_item] += 1
    else:
      voc_dict[seg_item] = 1
voc_list = sorted([_ for _ in voc_dict.items() if _[1] > min_seq],
                  key=lambda x: x[1],
                  reverse=True)[:top_n]

voc_dict = {
    
    word_count[0]: idx for idx, word_count in enumerate(voc_list)}
voc_dict.update({
    
    UNK: len(voc_dict), PAD: len(voc_dict) + 1})

print(voc_dict)

# 保存字典
ff = open("./sources/dict.txt", "w")
for item in voc_dict.keys():
  ff.writelines("{},{}\n".format(item, voc_dict[item]))

在这里插入图片描述

6. 搭建模型结构:

import numpy as np
import jieba
from torch.utils.data import Dataset, DataLoader

def read_dict(voc_dict_path):
    voc_dict = {
    
    }
    dict_list = open(voc_dict_path).readlines()
    print(dict_list[0])
    for item in dict_list:
        item = item.split(",")
        voc_dict[item[0]] = int(item[1].strip())
    return voc_dict

# 将数据集进行处理(分词,过滤...)
def load_data(data_path, data_stop_path):
    data_list = open(data_path, encoding='utf-8').readlines()[1:]
    stops_word = open(data_stop_path, encoding='utf-8').readlines()
    stops_word = [line.strip() for line in stops_word]
    stops_word.append(" ")
    stops_word.append("\n")
    voc_dict = {
    
    }
    data = []
    max_len_seq = 0
    np.random.shuffle(data_list)
    for item in data_list[:]:
        label = item[0]
        content = item[2:].strip()
        seg_list = jieba.cut(content, cut_all=False)
        seg_res = []
        for seg_item in seg_list:
            if seg_item in stops_word:
                continue
            seg_res.append(seg_item)
            if seg_item in voc_dict.keys():
                voc_dict[seg_item] = voc_dict[seg_item] + 1
            else:
                voc_dict[seg_item] = 1
        if len(seg_res) > max_len_seq:
            max_len_seq = len(seg_res)
        data.append([label, seg_res])

        # print(max_len_seq)
    return data, max_len_seq

# 定义Dataset
class text_CLS(Dataset):
    def __init__(self, voc_dict_path, data_path, data_stop_path):
        self.data_path = data_path
        self.data_stop_path = data_stop_path

        self.voc_dict = read_dict(voc_dict_path)
        self.data, self.max_len_seq = load_data(self.data_path, self.data_stop_path)
        np.random.shuffle(self.data)

    def __len__(self):
        return len(self.data)

    def __getitem__(self, item):
        data = self.data[item]
        label = int(data[0])
        word_list = data[1]

        input_idx = []
        for word in word_list:
            if word in self.voc_dict.keys():
                input_idx.append(self.voc_dict[word])
            else:
                input_idx.append(self.voc_dict["<UNK>"])
        if len(input_idx) < self.max_len_seq:
            input_idx += [self.voc_dict["<PAD>"] for _ in range(self.max_len_seq - len(input_idx))]
            # input_idx += [1001 for _ in range(self.max_len_seq - len(input_idx))]
        data = np.array(input_idx)

        return label, data

# 定义DataLoader
def data_loader(data_path, data_stop_path, dict_path):
    dataset = text_CLS(dict_path, data_path, data_stop_path)
    return DataLoader(dataset, batch_size=10, shuffle=True)

data_path = "./sources/his.csv"
data_stop_path = "./sources/hit_stopwords.txt"
dict_path = "./sources/dict.txt"

train_dataLoader = data_loader(data_path, data_stop_path, dict_path)
for i, batch in enumerate(train_dataLoader):
    print(batch[0], batch[1].size())
print(batch[0], batch[1])

在这里插入图片描述

7. 网络模型的配置:

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np

class Config():
    def __init__(self):
        '''
        self.embeding = nn.Embedding(config.n_vocab,
                                config.embed_size,
                                padding_idx=config.n_vocab - 1)
        self.lstm = nn.LSTM(config.embed_size,
                            config.hidden_size,
                              config.num_layers,
                               bidirectional=True, batch_first=True,
                               dropout=config.dropout)
        self.maxpool = nn.MaxPool1d(config.pad_size)
        self.fc = nn.Linear(config.hidden_size * 2 + config.embed_size,
                                  config.num_classes)
        self.softmax = nn.Softmax(dim=1)
        '''
        self.n_vocab = 1002
        self.embed_size = 128
        self.hidden_size = 128
        self.num_layers = 3
        self.dropout = 0.8
        self.num_classes = 2
        self.pad_size = 32
        self.batch_size = 128
        self.is_shuffle = True
        self.learn_rate = 0.001
        self.num_epochs = 100
        self.devices = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

class Model(nn.Module):
    def __init__(self, config):
        super(Model, self).__init__()
        self.embeding = nn.Embedding(config.n_vocab,
                                     padding_idx=config.n_vocab - 1)
        self.lstm = nn.LSTM(input_size=config.embed_size,
                            hidden_size=config.hidden_size,
                            num_layers=config.num_layers,
                            bidirectional=True,
                            batch_first=True,                            dropout=config.dropout)
        self.maxpooling = nn.MaxPool1d(config.pad_size)
        self.fc = nn.Linear(config.hidden_size * 2 + config.embed_size,                            config.num_classes)
        self.softmax = nn.Softmax(dim=1)
    def forward(self, x):
        embed = self.embeding(x)
        out, _ = self.lstm(embed)
        out = torch.cat((embed, out), 2)
        out = F.relu(out)
        out = out.permute(0, 2, 1)
        out = self.maxpooling(out).reshape(out.size()[0], -1)
        out = self.fc(out)
        out = self.softmax(out)
        return out

# 测试网络是否正确
cfg = Config()
cfg.pad_size = 640
model_textcls = Model(config=cfg)
input_tensor = torch.tensor([i for i in range(640)]).reshape([1, 640])
out_tensor = model_textcls.forward(input_tensor)
print(out_tensor.size())
print(out_tensor)

在这里插入图片描述

8. 训练脚本的搭建:

model_text_cls = Model(cfg)
model_text_cls.to(cfg.devices)
loss_func = nn.CrossEntropyLoss()
optimizer = optim.Adam(model_text_cls.parameters(), lr=cfg.learn_rate)

for epoch in range(cfg.num_epochs):
    for i, batch in enumerate(train_dataloader):
        label, data = batch
        # data1 = torch.tensor(data).to(cfg.devices)
        # label1 = torch.tensor(label).to(cfg.devices)
        data1 = data.sourceTensor.clone().detach().to(cfg.devices)
        label1 = label.sourceTensor.clone().detach().to(cfg.devices)

        optimizer.zero_grad()
        pred = model_text_cls.forward(data1)
        loss_val = loss_func(pred, label1)

        print("epoch is {},ite is {},val is {}".format(epoch, i, loss_val))
        loss_val.backward()
        optimizer.step()

    if epoch % 10 == 0:
        torch.save(model_text_cls.state_dict(), "./models/{}.pth".format(epoch))

在这里插入图片描述

9. 小结:

可以通过基于PyTorch 实现NLP自然语言处理将患者病例实现AI技术进行转换,从而让业务能够快速实现自动化打标签,可以起到降本增效的结果。

在这里插入图片描述
“高性能应用服务HAI”基于PyTorch 优化的其它类似的场景应用方案:
在这里插入图片描述


总结:

随着业务的快速发展,各行各业的难题是随着模型在线推理服务数量的增加,服务也变得越来越庞大、臃肿,难以管理。这种状况不仅导致了资源浪费,还增加了维护和升级的成本。

为了解决这些“顽疾”,“高性能应用服务HAI”具有澎湃算力,即开即用,基于腾讯云GPU云服务器底层算力,提供开箱即用的高性能云服务。以应用为中心,匹配GPU云算力资源,助力中小企业及开发者快速部署LLM、AI作画、数据科学等高性能应用, 降低运行成本,大幅提升服务可用性,平均部署周期由之前的天缩短至分钟,大幅提升了研发迭代效率,从而加速商业化应用的进程,为各行各业提供新的增长动力。

在这里插入图片描述

“高性能应用服务HAI”是面向开发者和企业的云原生机器学习/深度学习工程平台,服务覆盖AI开发全链路,内置6+AI框架和模型,具备丰富的行业场景插件,在降本增效的行业背景下,“高性能应用服务HAI”已经成为AI应用落地最为明晰的方向。

猜你喜欢

转载自blog.csdn.net/m0_68635815/article/details/134850743