Bi-LSTM-CRF命名实体识别实战
一、数据集介绍
本项目的数据集来自于天池——基于糖尿病临床指南和研究论文的实体标注构建(瑞金医院MMC人工智能辅助构建知识图谱大赛第一赛季)。即提供与糖尿病相关的学术论文以及糖尿病临床指南,要求在学术论文和临床指南的基础上,做实体的标注。实体类别共十五类。
类别名称和定义
疾病相关:
1、疾病名称 (Disease),如I型糖尿病。
2、病因(Reason),疾病的成因、危险因素及机制。比如“糖尿病是由于胰岛素抵抗导致”,胰岛素抵抗是属于病因。
3、临床表现 (Symptom),包括症状、体征,病人直接表现出来的和需要医生进行查体得出来的判断。如"头晕" "便血" 等。
4、检查方法(Test),包括实验室检查方法,影像学检查方法,辅助试验,对于疾病有诊断及鉴别意义的项目等,如甘油三酯。
5、检查指标值(Test_Value),指标的具体数值,阴性阳性,有无,增减,高低等,如”>11.3 mmol/L”。
治疗相关:
6、药品名称(Drug),包括常规用药及化疗用药,比如胰岛素。
7、用药频率(Frequency),包括用药的频率和症状的频率,比如一天两次。
8、用药剂量(Amount),比如500mg/d。
9、用药方法(Method):比如早晚,餐前餐后,口服,静脉注射,吸入等。
10、非药治疗(Treatment),在医院环境下进行的非药物性治疗,包括放疗,中医治疗方法等,比如推拿、按摩、针灸、理疗,不包括饮食、运动、营养等。
11、手术(Operation),包括手术名称,如代谢手术等。
12、不良反应(SideEff),用药后的不良反应。
常规实体:
13、部位(Anatomy),包括解剖部位和生物组织,比如人体各个部位和器官,胰岛细胞。
14、程度(level),包括病情严重程度,治疗后缓解程度等。
15、持续时间(Duration),包括症状持续时间,用药持续时间,如“头晕一周”的“一周”。
链接:https://tianchi.aliyun.com/competition/entrance/231687/information
二、Bi-LSTM-CRF模型介绍
(一)Bi-LSTM
RNN为循环神经网络(Recurrent Neural Network),与全连接网络的不同之处是其隐藏层之间是有连接的,即每一时刻的输出都跟当前时刻的输入和上一时刻的输出有关,由于其具有记忆特性,可以处理前后输入有关系的序列数据。
LSTM为长短期记忆网络(Long-Short Term Memory),作为一种改进之后的RNN,LSTM的cell代替了普通RNN的隐单元,通过门控状态来控制传输状态,记住需要长时间记忆的,忘记不重要的信息。相比普通的RNN,LSTM能够在更长的序列中有更好的表现,解决RNN在长序列训练过程中的梯度消失和梯度爆炸问题。
Bi-LSTM为双向长短时记忆网络(Bi-directional Long-Short Term Memory)。LSTM对句子进行建模还存在一个问题:无法编码从后到前的信息。实际应用中,网络输出可能依赖于整个输入序列。Bi-LSTM是由前向LSTM与后向LSTM组合而成,通过Bi-LSTM可以更好的捕捉双向的语义依赖。
(二)CRF
CRF为条件随机场(Conditional Random Field),属于判别式概率图模型。CRF能够在已知观测变量序列的条件下,标记序列发生的概率。在该项任务中,观测序列为单词序列,标记序列为对应的词性序列,标记序列具有线性的序列结构。
Bi-LSTM的优点是能够通过双向的设置学习到观测序列(输入的字)之间的依赖,在训练过程中,LSTM能够根据目标(比如识别实体)自动提取观测序列的特征,但是缺点是无法学习到标记序列(输出的标注)之间的关系。在命名实体识别任务中,标注之间是有一定的关系的,比如B类标注(表示某实体的开头)后面不会再接一个B类标注,所以LSTM在解决NER这类序列标注任务时,虽然可以省去很繁杂的特征工程,但是也存在无法学习到标注上下文的缺点。
相反,CRF的优点就是能对标记序列建模,学习标记序列的特点,但它的缺点是需要手动提取观测序列特征。所以一般的做法是,在LSTM后面再加一层CRF,以获得两者的优点。
三、实战
(一)环境
Python 3.7.3
Tensorflow 2.1.0
(二)代码
1.数据处理
数据有两种文件*.txt和*.ann,*.txt文件为原始文档,*.ann文件为标注信息,标注实体以T开头,后接实体序号,实体类别,起始位置和实体对应的文档中的词。
*.txt文件的内容为:
...
糖控制水平的公认指标,但应该控制的理想水平即目
标值究竟是多少还存在争议。糖尿病控制与并发症试
验(DCCT,1993)、熊本(Kumamoto,1995)、英国前瞻性
糖尿病研究(UKPDS,1998)等高质量临床研究已经证
实,对新诊断的糖尿病患者或病情较轻的患者进行严
...
*.ann的内容为:
T1 Disease 1845 1850 1型糖尿病
T2 Disease 1983 1988 1型糖尿病
....
文字处理:
(1)讲*.txt文件中段落,按"。"句号切割,一共得到26869个句子,并划分训练集和测试集。
(2)讲数字按照"0"处理,增加识别新知识的能力。
(3)形成汉字对应序号的字典,字典中,<PAD>由0表示,<UNK>由1表示,将段落中没出现在字典中的字用<UNK>表示。
(4)将每个句子分别做分字处理,用字向量表示,字向量为字在字典中的序号构成的列表。处理后形成train_char列表。
(4)将每个句子用jieba分词工具做分词处理,用词向量表示,词向量为0、1、2、3构成的向量,0表示单字,1表示词的起始字,3表示词的终止字,2表示词的中间字。处理后形成train_seg列表。
标注处理:
BIOES标注含义,B,即Begin,表示开始;I,即Intermediate,表示中间;E,即End,表示结尾;S,即Single,表示单个字符;O,即Other,表示其他,用于标记无关字符。
(1)形成十五类标注对应的缩写的字典:
'Level': 'LEV',
'Test_Value': 'TSV',
'Test': 'TES',
...
(2)形成BIOES标注对应数字序号的字典和数字序号对应BIOES标注的字典,共有58种不同的标注方式:
0:O
1:I-TES
2:I-DIS
...
O:0
I-TES:1
I-DIS:2
...
(3)将每个句子的BIOES标注通过字典映射为序号构成的列表。处理后形成train_seg数组。
2.数据截断、补全
train_char_ = tf.keras.preprocessing.sequence.pad_sequences(train_char, maxlen=maxlen,padding='pre',truncating='pre',value=0.0)
train_seg_ = tf.keras.preprocessing.sequence.pad_sequences(train_seg, maxlen=maxlen,padding='pre',truncating='pre',value=0.0)
train_target_ = tf.keras.preprocessing.sequence.pad_sequences(train_target, maxlen=maxlen,padding='pre',truncating='pre',value=0.0)test_char_ = tf.keras.preprocessing.sequence.pad_sequences(test_char, maxlen=maxlen,padding='pre',truncating='pre',value=0.0)
test_seg_ = tf.keras.preprocessing.sequence.pad_sequences(test_seg, maxlen=maxlen,padding='pre',truncating='pre',value=0.0)
test_target_ = tf.keras.preprocessing.sequence.pad_sequences(test_target, maxlen=maxlen,padding='pre',truncating='pre',value=0.0)
3.模型构建
(1)输入层
设置两个输入层,输入层1为字向量信息,[batch_size, maxlen] -> [batch_size, maxlen],输入层2为词向量信息,[batch_size, maxlen] -> [batch_size, maxlen],每个句子固定maxlen个词,上述取1000。
(2)Embedding层(Embedding)
对应两个输入层,设置两个Embedding层,其中字向量对应的字嵌入层为[batch_size, maxlen] -> [batch_size, maxlen, char_embedding_dims],将字进行char_embedding_dims长度的编码,char_embedding_dims上述取100;词向量对应的词嵌入层为[batch_size, maxlen] -> [batch_size, maxlen, seg_embedding_dims],将词进行char_embedding_dims长度的编码,char_embedding_dims上述取20。
(3)拼接(Concatenate)
取字嵌入层和词嵌入层最后一维拼接起来,得到输出维度为[batch_size, maxlen, 120]。
(4)Bi-LSTM层(Bidirectional-LSTM)
叠加两层双向LSTM层,激活函数分别为tanh和softmax,得到输出维度为[batch_size, maxlen, 58],即58种不同的标注方式的预测分值。
(5)CRF层(CRF)
CRF层中的损失函数包括两种类型的分数,一是Emission Score,发射分数(状态分数),这些状态分数来自Bi-LSTM层的输出,即每个位置是各个标签的预测分值,是一个maxlen×58的矩阵;二是Transition Score,转移分数,即标签间的转移分数,是一个58*58的矩阵。
某个序列的分数si=Emission Score + Transition Score,
我们的训练目标通常是最小化损失函数,定义对数损失函数:
Bi-LSTM之上的CRF与普通CRF的区别:普通CRF的样本概率受特征函数和相关权值的影响,而Bi-LSTM上的CRF则没有特征函数,也没有权值,结果受Bi-LSTM层输出的各个位置标签概率,以及标签间的状态转移矩阵影响。对于Bi-LSTM+CRF的CRF层来说,要学习的就只有标签间状态转移矩阵而已。
根据tensorflow中的CRF.py,crf_log_likelihood函数输出的transition_params,就是要求解的状态转移矩阵。viterbi_decode(score, transition_params),就是通过Bi-LSTM的输出score和求解的状态转移矩阵transition_params来解码最终结果。
viterbi(维特比)算法是动态规划算法,每个子部分只存储最优子路径。其在计算过程中,有两类变量:obs 和 previous。previous存储的是上一个步骤的最终结果,即上一个单词对应各类别的最佳路径得分,obs代表当前单词包含的信息(发射分数)。有两个变量来储存历史信息,alpha0 和 alpha1,alpha0 是历史最佳的分数 ,alpha1 是最佳分数所对应的类别索引。最后一步,根据alpha0和alpha1存储的信息用来找到最佳路径。
得到输出维度为[batch_size, maxlen]
import tensorflow as tf
import tensorflow_addons as tfa
import numpy as np
import tqdm
from tensorflow.keras.models import Sequential
from tensorflow.keras.callbacks import TensorBoard
from CRF import CRF# from CRF import CRFclass MyBiLSTMCRF:def __init__(self, vocabSize, maxlen, tagIndexDict, tagSum, sequence_lengths=None):self.vocabSize = vocabSizeself.maxlen = maxlenself.tagSum = tagSumself.sequence_lengths = sequence_lengthsself.tagIndexDict = tagIndexDictself.vecSize = 100self.segSize = 20self.buildBiLSTMCRF()def getTransParam(self, y, tagIndexDict):self.trainY = np.argmax(y, axis=-1)yList = self.trainY.tolist()transParam = np.zeros([len(list(tagIndexDict.keys())), len(list(tagIndexDict.keys()))])for rowI in range(len(yList)):for colI in range(len(yList[rowI]) - 1):transParam[yList[rowI][colI]][yList[rowI][colI + 1]] += 1for rowI in range(transParam.shape[0]):transParam[rowI] = transParam[rowI] / np.sum(transParam[rowI])return transParamdef buildBiLSTMCRF(self):input_1 = tf.keras.layers.Input(shape=(self.maxlen,), name='char')input_2 = tf.keras.layers.Input(shape=(self.maxlen,), name='seg')eb_1 = tf.keras.layers.Embedding(self.vocabSize, self.vecSize)(input_1)eb_2 = tf.keras.layers.Embedding(4, self.segSize)(input_2)concat = tf.keras.layers.Concatenate()([eb_1, eb_2])x = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(self.tagSum, return_sequences=True, activation="tanh"), merge_mode='sum')(concat)x = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(self.tagSum, return_sequences=True, activation="softmax"), merge_mode='sum')(x)crf = CRF(self.tagSum, name='crf_layer')output = crf(x)myModel = tf.keras.models.Model([input_1, input_2], output)myModel.compile('adam', loss={'crf_layer': crf.get_loss})self.myBiLSTMCRF = myModeldef fit(self,X, y, epochs=100, transParam=None):if len(y.shape) == 3:y = np.argmax(y, axis=-1)if self.sequence_lengths is None:self.sequence_lengths = [row.shape[0] for row in y]log_dir = "logs"tensorboard_callback = TensorBoard(log_dir=log_dir, histogram_freq=1)history = self.myBiLSTMCRF.fit(X, y, epochs=epochs, callbacks=[tensorboard_callback])return historydef predict(self, X):preYArr = self.myBiLSTMCRF.predict(X)return preYArr
Bi-LSTM-CRF命名实体识别实战相关推荐
- 【项目实战课】基于BiLSTM+CRF的命名实体识别实战
欢迎大家来到我们的项目实战课,本期内容是<基于BiLSTM+CRF的命名实体识别实战>.所谓项目课,就是以简单的原理回顾+详细的项目实战的模式,针对具体的某一个主题,进行代码级的实战讲解. ...
- 【NLP实战系列】Tensorflow命名实体识别实战
实战是学习一门技术最好的方式,也是深入了解一门技术唯一的方式.因此,NLP专栏计划推出一个实战专栏,让有兴趣的同学在看文章之余也可以自己动手试一试. 本篇介绍自然语言处理中一种非常重要的任务:命名实体 ...
- BiLSTM+CRF的损失由发射矩阵和转移矩阵计算而得 BiLSTM+CRF命名实体识别:达观杯败走记(下篇
如果是训练,那么直接用发射矩阵和真实标签去计算Loss,用于更新梯度. 这需要用到CRF中的forward函数. 如果是预测,那么就用发射矩阵去进行维特比解码,得到最优路径(预测的标签). 这需要用到 ...
- 命名实体识别实战(BERT)
命名实体识别实例(BERT) 一.背景 二.数据预处理 三.训练模型 四.对预测结果进行转换 一.背景 本实例是当时参加第八届泰迪杯数据挖掘挑战赛C题的一部分,该赛题是智慧政务方面的,主要是根据群众的 ...
- CRF++命名实体识别(NER)初步试探
背景 CRF++是著名的条件随机场的开源工具,支持windows,linux系统.本文中CRF++,指的不是一种模型,不是一种算法,而是一个开源工具. CRF++的官方文档:http://taku91 ...
- bert+lstm+crf ner实体识别
https://blog.csdn.net/weixin_42357472/article/details/108010305
- bert+lstm+crf ner实体识别 带源码
https://blog.csdn.net/weixin_42357472/article/details/108010305 正版手册 https://www.cnpython.com/pypi/k ...
- NLP的命名实体识别 -- 嵌套实体问题
NLP的命名实体识别 – 嵌套实体问题 NER是一个比较常见的NLP任务,通常采用LSTM+CRF处理一些简单NER任务.NER还存在嵌套实体问题(实体重叠问题),实体嵌套是指在一句文本中出现的实体, ...
- Pytorch: 命名实体识别: BertForTokenClassification/pytorch-crf
文章目录 基本介绍 BertForTokenClassification pytorch-crf 实验项目 参考 基本介绍 命名实体识别:命名实体识别任务是NLP中的一个基础任务.主要是从一句话中识别 ...
最新文章
- pythonshellnohup_python nohup 实现远程运行不宕机操作
- NanoPi NEO Air使用十:自己编写驱动来控制LED
- UNITY polygon collider不随物体旋转
- spock 集成测试_使用Spock Mocks进行Grails 3.3集成测试
- C++获取PE文件的入口点
- php copy array,ES6中Array.copyWithin()函数用法的详解
- java读word_java读word文件(示例代码)
- r语言plot函数设置y轴的范围及刻度_R语言之简单绘图
- SQL常用的几个窗口函数
- Oracle 19.8新特性asmcmd credverify and asmcmd credfix
- Dijkstra算法(求一点到任意一点的最短距离)
- Java的BIO,NIO和AIO的区别于演进
- php 差错,PHP 错误处理
- OpenCV 教程入门篇
- 网站服务器开启cookies,浏览器如何开启cookie(图解浏览器cookie功能使用)
- 喜马拉雅xm格式转化mp3_强大的视频格式转换工具
- EBS之JTF_Grid 开发总结
- linux相关操作命令(*)
- HDFS dfsclient读文件过程 源码分析
- “沉迷单车的追风少年”的2021年年末总结
热门文章
- 泰国ATM机被入侵致1200多万泰铢被盗,幕后黑客留疑团
- Opencv笔记(十七)——轮廓性质
- mex文件生成c语言,用C语言编写MEX文件.doc
- 别再漫无目的分析数据,手把手教你学会,如何体系化搭建数据指标
- IntelliJ IDEA 设置鼠标悬停提示相关信息及F2重命名设置
- Blob分析---ball.hdev
- 《Python程序设计》——第1章 计算与问题求解简介 1.1 计算与Python简介
- css3总结之: text-align: justify (两端对齐)
- justify-content 属性
- gitpush出现remote: Support for password authentication was removed on August 13, 2021.