我们就来看看如何通过BiLSTM+CRF来进行命名实体识别的任务。 命名实体识别 通俗来说,命名实体识别,就是给一句话或一段话,设计某种算法来把其中的命名实体给找出来。啥叫命名实体呢?说白了不值一提,命名实体,其实就是实际存在的具有专门名字的物体。命名实体识别,其实就是实体名字的识别。
例如: 我 们 的 藏 品 中 有 几 十 册 为 北 京 图 书 馆 等 国 家 级 藏 馆 所 未 藏 。 其中北京图书馆就是一个专有的实体名称。 一般命名实体有分:人名、地名、组织名、机构名等等之分,根据不同的任务有不同的划分。
命名实体识别的解法 目前命名实体识别领域比较流行的方法都是把命名实体识别问题转换为一个序列标注的问题,然后通过序列标注的方法来解决。
一般序列标注的解决方法有:隐马尔科夫模型HMM或 条件随机场 CRF 或BiLSTM+CRF 或BiLSTM+最大熵。其中前两种是统计学习方法,后面两种是神经网络的方法。
本文只介绍神经网络的方法。 当把命名实体识别转换为一个序列标注的问题后,问题就简化成了一个结构化分类的问题了。
什么意思呢?例如,对于人名识别的任务来说,我们把每个字分类为三类:O,B-PER,I-PER。O表示这个字不是人名,B-PER表示这个字是一个人名的开头,I-PER表示这个字是一个人名的中间,前面一定存在一个最近的B-PER使得从B-PER到I-PER形成的连续子串构成一个人名。
例如:
其中“周恩来”是一个人名,于是这三个词被标注为B-PER I-PER I-PER。 同理“马骏”也是一个人名。 做了这个处理以后,这个任务就简单的多了。 很明显,这是一个有监督的分类问题,训练语料一定要给出训练文本对应的标注。基于训练集,自然也就能学习到一个分类模型。 Bi-LSTM+最大熵 解法 Bi-LSTM+最大熵 解法是特别简单粗暴的一种解法,它的核心思想是通过一个Bi-LSTM计算得到某个词标注为各类标签的势能(其实就可以理解为概率)分布,然后取这些标签里面,势能最大的那个标签作为分类结果输出。
这种方法很简单,实现也方便。但是这种方法把各个词的标注结果独立开来,过度“相信”神经网络会自己学到词的标注结果之间的某种关系。
例如: 如果存在一个这样一个标注序列:B-PER,I-LOC,I-LOC,I-LOC 自然是不合理的。
经典模型:
Bi-LSTM +CRF是在原来的Bi-LSTM+最大熵的基础上优化过来的,它最大的思想就是在Bi-LSTM的上面挂了一层条件随机场模型作为模型的解码层,在条件随机场模型里面考虑预测结果之间的合理性。
经典模型:
模型:CRF的转移矩阵A由神经网络的CRF层近似得到,而P矩阵 也就是发射矩阵由Bi-LSTM近似得到。
词向量,即可以预先训练,也可以一并训练。
访问AI图谱 技术分享社区
https://loveai.tech
数据处理模块主要是为了实现两个函数:next_train_batch和next_valid_batch,用于从训练集和预测集获取一个batch的数据,注意这里的batch不是随机的,而是序惯的。
注意这里面的pad 填充函数,它会把序列填充到给定的sentence_length的长度,填充方法是倍增填充。
神经网络模型
命名实体识别的准确率是判断标准答案里面的命名实体集Ssupervise
Ssupervise,与预测的实体集SpredicSpredict之间交集占各自的比例。
这个模型不难,但是却让我调试了1个月,原来的模型实现中模型始终预测出"O",调试中看了各个词的发射概率scores ,发现"O"标签的概率最大,让人如何也想不出问题所在。
后来,在一个偶然的机会中,本人意识到一个问题:那就是dynamic_rnn函数的有一个参数sequence_length 是需要正确设置的。
之前对sequence_length理解不深,后面翻阅文档知道这个参数的含义是:
也就是说,这个sequence_length反映的是序列真实的有效的长度,如果不指定就按照完整序列来迭代rnn。大家想之前为了矩阵表示的方便,最起码在每个batch里面我们需要让各个序列的长度相同,不够长度的我们采用一些填充的办法。 我一开始的实现是让每个句子的长度都填充或者截断为100,于是rnn需要对每一个长度为100的序列进行迭代,大家都知道LSTM/GRU 在序列长度大于30的时候效果会急剧下降,因此我一开始把所有序列长度设置为100后,又不在dynamic_rnn函数中指定实际的序列长度,那么模型始终输出“O” 也就是可以解释了。后面我把句子的长度都截断为25后,效果里面就好了很多,模型也能够收敛了。 对于长度都为100的序列,LSTM的确无能为力啊! 当然这样截断的方式也不好,最好的方式是在dynamic_rnn函数中指定各个序列的实际有效长度。 本例,最大的启发是,dynamic_rnn中sequence_length参数的作用,以及序列填充后需要考虑序列长度是否是lstm可有效接受的。 需要养成一个习惯:认真对待sequence_length参数,尤其是当填充后的序列特别特别长的时候。
原文 https://blog.csdn.net/jmh1996/article/details/84779680