0


BERT+TextCNN实现医疗意图识别项目

BERT+TextCNN实现医疗意图识别项目

一、说明

本项目采用医疗意图识别数据集CMID传送门
数据集示例:

  1. {"originalText":"间质性肺炎的症状?","entities":[{"label_type":"疾病和诊断","start_pos":0,"end_pos":5}],"seg_result":["间质性肺炎","的","症状","?"],"label_4class":["病症"],"label_36class":["临床表现"]}

模型使用BERT、TextCNN实现意图分类

二、BERT模型加载

使用苏建林开发的bert4keras深度学习框架加载BERT模型

  1. from bert4keras.backend import keras,set_gelu
  2. from bert4keras.models import build_transformer_model # 加载BERT的方法from bert4keras.optimizers import Adam # 优化器
  3. set_gelu('tanh')

1.定义函数加载BERT

  1. defbuild_bert_model(config_path , checkpoint_path , class_nums):# config_path配置文件的路径 checkpoint_path预训练路径 class_nums类别的数量
  2. bert = build_transformer_model(
  3. config_path = config_path ,
  4. checkpoint_path = checkpoint_path ,
  5. model ='bert',
  6. return_keras_model=False)# BERT模型输出中抽取[CLS]
  7. cls_features = keras.layers.Lambda(lambda x:x[:,0],name='cls-token')(bert.model.output)# [:,0]选取输出的第一列,BERT模型的输出中[CLS]在第一个位置 shape = [batch_size ,768]
  8. all_token_embedding = keras.layers.Lambda(lambda x:x[:,1:-1],name='all-token')(bert.model.output)# 获取第2列至倒数第二列的所有token shape = [batch_size ,maxlen-2,768] 除去CLSSEP# textcnn抽取特征
  9. cnn_features = textcnn(all_token_embedding, bert.initializer)# 输入all_token_embedding shape = [batch_size,cnn_output_dim]# cls_features cnn_features 进行拼接
  10. concat_features = keras.layers.concatenate([cls_features,cnn_features],axis=-1)# 全连接层
  11. dense = keras.layers.Dense (
  12. units=512,# 输出维度
  13. activation ='relu',# 激活函数
  14. kernel_initializer= bert.initializer # bert权重初始化)(concat_features)# 输入# 输出
  15. output = keras.layers.Dense (
  16. units= class_nums,# 输出类别数量
  17. activation='softmax',# 激活函数 (多分类输出层最常用的激活函数)
  18. kernel_initializer= bert.initializer # bert权重初始化)(dense)# 输入
  19. model = keras.models.Model(bert.model.input,output)# (bert.model.input输入,output输出)print(model.summary())return model

2.实现TextCNN

  1. deftextcnn(input,kernel_initializer):# 3,4,5
  2. cnn1 = keras.layers.Conv1D(256,# 卷积核数量3,# 卷积核大小
  3. strides=1,# 步长
  4. padding='same',# 输出与输入维度一致
  5. activation='relu',# 激活函数
  6. kernel_initializer = kernel_initializer # 初始化器)(input)# shape = [batch_size ,maxlen-2,256]
  7. cnn1 = keras.layers.GlobalAvgPool1D()(cnn1)# 全局最大池化操作 shape = [batch_size ,256]
  8. cnn2 = keras.layers.Conv1D(256,# 卷积核数量4,# 卷积核大小
  9. strides=1,# 步长
  10. padding='same',# 输出与输入维度一致
  11. activation='relu',# 激活函数
  12. kernel_initializer=kernel_initializer # 初始化器)(input)
  13. cnn2 = keras.layers.GlobalAvgPool1D()(cnn2)# 全局最大池化操作 shape = [batch_size ,256]
  14. cnn3 = keras.layers.Conv1D(256,# 卷积核数量5,# 卷积核大小
  15. strides=1,# 步长
  16. padding='same',# 输出与输入维度一致
  17. kernel_initializer=kernel_initializer # 初始化器)(input)
  18. cnn3 = keras.layers.GlobalAvgPool1D()(cnn3)# 全局最大池化操作 shape = [batch_size ,256]# 将三个卷积结果进行拼接
  19. output = keras.layers.concatenate([cnn1,cnn2,cnn3],
  20. axis=-1)
  21. output = keras.layers.Dropout(0.2)(output)# 最后接Dropoutreturn output

3.程序入口

  1. if __name__ =='__main__':
  2. config_path ='.\chinese_L-12_H-768_A-12\\bert_config.json'
  3. checkpoint_path ='.\chinese_L-12_H-768_A-12\\bert_model.ckpt'
  4. class_nums =13
  5. build_bert_model(config_path , checkpoint_path , class_nums)

其中BERT模型文件可以自行在Github中下载,也可私信。
在这里插入图片描述
当程序开始加载模型时,表示运行成功。
切记!运行代码前,检查TensorFlow、bert4keras等第三方库的版本是否一致,否则容易报错!
4.本项目第三方库以及对应的版本

  1. pyahocorasick==1.4.2
  2. requests==2.25.1
  3. gevent==1.4.0
  4. jieba==0.42.1
  5. six==1.15.0
  6. gensim==3.8.3
  7. matplotlib==3.1.3
  8. Flask==1.1.1
  9. numpy==1.16.0
  10. bert4keras==0.9.1
  11. tensorflow==1.14.0
  12. Keras==2.3.1
  13. py2neo==2020.1.1
  14. tqdm==4.42.1
  15. pandas==1.0.1
  16. termcolor==1.1.0
  17. itchat==1.3.10
  18. ahocorasick==0.9
  19. flask_compress==1.9.0
  20. flask_cors==3.0.10
  21. flask_json==0.3.4
  22. GPUtil==1.4.0
  23. pyzmq==22.0.3
  24. scikit_learn==0.24.1
三、数据预处理

抽取CMID.json中的数据,并划分为训练集与测试集
从中选取13个类别作为最终意图分类的标签

定义
病因
预防
临床表现(病症表现)
相关病症
治疗方法
所属科室
传染性
治愈率
禁忌
化验/体检方案
治疗时间
其他

1.抽取数据

  1. defgen_training_data(row_data_path):
  2. label_list =[line.strip()for line inopen('./dataset/label','r',encoding='utf8')]print(label_list)# 映射id,为每一条数据添加id
  3. label2id ={label : idx for idx, label inenumerate(label_list)}
  4. data =[]withopen('./dataset/CMID.json','r',encoding='utf8')as f :
  5. origin_data = f.read()
  6. origin_data =eval(origin_data)
  7. label_set =set()for item in origin_data :
  8. text = item['originalText']
  9. label_class = item['label_4class'][0].strip("'")if label_class =='其他':
  10. data.append([text , label_class ,label2id[label_class]])continue
  11. label_class = item["label_36class"][0].strip("'")# 所有的意图标签都从label_36class中取出
  12. label_set.add(label_class)if label_class notin label_list:continue
  13. data.append([text, label_class ,label2id[label_class]])print(label_set)
  14. data = pd.DataFrame(data , columns=['text','label_class','label'])print(data['label_class'].value_counts())
  15. data['text_len']= data['text'].map(lambda x :len(x))# 序列长度print(data['text_len'].describe())
  16. plt.hist(data['text_len'], bins=30, rwidth=0.9, density=True)
  17. plt.show()del data['text_len']
  18. data = data.sample(frac =1.0)# 将数据集拆分为测试集和训练集
  19. train_num =int(0.9*len(data))
  20. train , test = data[:train_num],data[train_num:]
  21. train.to_csv('./dataset/train.csv', index=False)
  22. test.to_csv('./dataset/test.csv', index =False)

2.加载训练数据集

  1. # 加载训练数据集defload_data(filename):
  2. df = pd.read_csv(filename , header=0)return df[['text','label']].values

3.数据集信息可视化
在这里插入图片描述
数据样本长度基本上在100以内,此时在BERT模型中可以设置样本最大长度为128.
4.划分的训练集与测试集示例
训练集
在这里插入图片描述
测试集
在这里插入图片描述

四、模型训练

1.定义配置文件以及超参数

  1. # 定义超参数和配置文件
  2. class_nums =13
  3. maxlen =128
  4. batch_size =32
  5. config_path ='./chinese_rbt3_L-3_H-768_A-12/bert_config_rbt3.json'
  6. checkpoint_path ='./chinese_rbt3_L-3_H-768_A-12/bert_model.ckpt'
  7. dict_path ='./chinese_rbt3_L-3_H-768_A-12/vocab.txt'
  8. tokenizer = Tokenizer(dict_path)

2.定义数据生成器,将样本传递到模型中

  1. # 定义数据生成器 将数据传递到模型中classdata_generator(DataGenerator):"""
  2. 数据生成器
  3. """def__iter__(self , random =False):
  4. batch_token_ids , batch_segment_ids , batch_labels =[],[],[]# 对于每一个batchsize的训练,包括 token 分隔符segment 标签label三者的序列for is_end,(text , label )in self.sample(random):
  5. token_ids , segments_ids = tokenizer.encode(text , maxlen=maxlen)# [1,3,2,5,9,12,243,0,0,0] 编码token和分隔符segment序列,按照最大长度进行padding
  6. batch_token_ids.append(token_ids)
  7. batch_segment_ids.append(segments_ids)
  8. batch_labels.append([label])iflen(batch_token_ids)== self.batch_size or is_end :
  9. batch_token_ids = sequence_padding(batch_token_ids)
  10. batch_segment_ids =sequence_padding(batch_segment_ids)
  11. batch_labels = sequence_padding(batch_labels)yield[batch_token_ids , batch_segment_ids],batch_labels
  12. batch_token_ids,batch_segment_ids,batch_labels =[],[],[]

3.程序入口

  1. if __name__ =='__main__':# 加载数据集
  2. train_data = load_data('./dataset/train.csv')
  3. test_data = load_data('./dataset/test.csv')# 转换数据集
  4. train_generator = data_generator(train_data,batch_size)
  5. test_generator = data_generator(test_data,batch_size)
  6. model = build_bert_model(config_path, checkpoint_path ,class_nums)print(model.summary())
  7. model.compile(
  8. loss='sparse_categorical_crossentropy',# 离散值损失函数 交叉熵损失
  9. optimizer=Adam(5e-6),
  10. metrics=['accuracy'])
  11. earlystop = keras.callbacks.EarlyStopping(
  12. monitor='var_loss',
  13. patience=3,
  14. verbose=2,
  15. mode='min')
  16. bast_model_filepath ='./chinese_L-12_H-768_A-12/best_model.weights'
  17. checkpoint = keras.callbacks.ModelCheckpoint(
  18. bast_model_filepath ,
  19. monitor ='val_loss',
  20. verbose=1,
  21. save_best_only=True,
  22. mode='min')
  23. model.fit_generator(
  24. train_generator.forfit(),
  25. steps_per_epoch=len(train_generator),
  26. epochs=10,
  27. validation_data=test_generator.forfit(),
  28. validation_steps=len(test_generator),
  29. shuffle=True,
  30. callbacks=[earlystop,checkpoint])
  31. model.load_weights(bast_model_filepath)
  32. test_pred =[]
  33. test_true =[]for x, y in test_generator:
  34. p = model.predict(x).argmax(axis=1)
  35. test_pred.extend(p)
  36. test_true = test_data[:1].tolist()print(set(test_true))print(set(test_pred))
  37. target_names =[line.strip()for line inopen('label','r',encoding='utf8')]print(classification_report(test_true , test_pred ,target_names=target_names))
五、运行

在这里插入图片描述
在这里插入图片描述


本文转载自: https://blog.csdn.net/qq_45556665/article/details/130474092
版权归原作者 敷衍zgf 所有, 如有侵权,请联系我们删除。

“BERT+TextCNN实现医疗意图识别项目”的评论:

还没有评论