知识图谱命名实体识别(NLP)
Posted ZSYL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识图谱命名实体识别(NLP)相关的知识,希望对你有一定的参考价值。
命名实体识别
实验内容
从本实验开始,我们将学习如何从不规则的文本中提取信息,将信息规则化,从而构建可以生成知识图谱的数据。 在本节实验中,我们学习如何从文本中识别命名实体。
在本实验中,你将掌握:
- 命名实体识别任务的定义与理论解决方法
- 命名实体识别任务中的数据集处理方法
- 命名实体识别模型——BiLstm-CRF 的理论知识
- 用 Keras 构建 BiLstm-CRF 模型
- BiLstm-CRF 的训练与预测方法
实验原理
命名实体识别任务
命名实体识别是自然语言处理中的一项基础任务,命名实体指文本中具有特定意义的实体,通常包括人名,地名,专有名词等。
如在文本 “张无忌,金庸武侠小说《倚天屠龙记》人物角色,中土明教第三十四代教主。武当七侠之一张翠山与天鹰教紫微堂主殷素素之子,明教四大护教法王之一金毛狮王谢逊义子。” 中,
- 人名实体有:张无忌,张翠山,殷素素,谢逊
- 书名实体有:倚天屠龙记
- 门派实体有:明教,武当,天鹰教
因此,命名实体识别任务通常包括两部分
- 实体的边界识别:如正确识别“张翠山”,而不是“张翠”或“张翠山与”等
- 确定实体的类型:如张无忌为人名实体,而不是门派实体或者书名实体
命名实体的标注方法有多种,在本实验中使用 BMEO 标注方法
- B 实体词首
- M 实体词中
- E 实体词尾
- O 非实体
结合实体类型,“武当七侠之一张翠山与天鹰教紫微堂主殷素素之子” 这份文本就会被标注为 “武/门派_B 当/门派_E 七/O 侠/O 之/O 一/O 张/人名_B 翠/人名_M 山/人名_E 与/O 天/门派_B 鹰/门派_M 教/门派_E 紫/O 微/O 堂/O 主/O 殷/人名_B 素/人名_M 素/人名_E 之/O 子/O”
序列标注
命名实体识别任务本质上是一个序列标注问题,即给序列中的每一帧进行分类,在这里每一帧代表一个字。如 ”武当七侠之一张翠山“,不考虑实体类型,则共有四个标签 BMEO。既然是分类问题,就很自然地想到逐帧分类:即训练一个判别器,输入一个字,输出该字的类别,如下图所示:
但是实际上,并不是说“张”这个字一定代表实体词首,有可能是“张开”这个词的起始,但“张开”并非实体。因此,每一帧都是上下文关联的,如“张”后面跟着“翠山”,那么“张”就是实体词首,反之则不一定,如下图所示:
同时目标输出序列本身会带有一些上下文的关联,比如实体词尾前一帧不可能是非实体,实体词中后一帧要么是实体词中要么是实体词尾。这与普通的分类任务不同。如果一个输入有 n 帧,每一帧的标签有 k 种可能性,那么理论上就有 k^n 种不同的输出。如下图所示,每一个点代表一个标签的可能性,点之间的连线表示标签之间的关联,而每一条完整的路径,表示一种输出。
综上所述,逐帧分类是将序列标注看成 n 个 k 分类问题,而真正的序列标注是 1 个 k^n 分类问题。
条件随机场
条件随机场(conditional random field,简称 CRF),是一种鉴别式机率模型。在序列标注问题中,我们要计算的是条件概率 P(y1,…yn|x),x=(x1,…xn)。 结合上一小节序列标注的内容,可以理解为给予图中的边以权重,并找到权重最高的一条路径作为输出。 CRF 中定义了特征函数来给边赋予权重,特征函数定义为 f(s, i, li, li-1)
- s 输入的句子
- i 句子 s 中第 i 个词
- li 第 i 个词的标签
- li-1 第 i-1 个词的标签
BiLSTM-CRF
长短期记忆网络(Long Short-Term Memory,简称 LSTM),是循环神经网络(Recurrent Neural Network,简称 RNN)的一种,BiLSTM 是由前向 LSTM 与后向 LSTM 组合而成,由于其设计的特点,在自然语言处理任务中都常被用来建模上下文信息。
与 CRF 不同的是,BiLSTM 依靠神经网络超强的非线性拟合能力,在训练时将数据变换到高维度的非线性空间中去,从而学习出一个模型。虽然 BiLSTM 的精度非常的高,但是在预测时,会出现一些明显的错误,如实体词尾后一帧依然预测为实体词尾等,而在 CRF 中,因为特征函数的存在,限定了标签之间的关系。因此,将 CRF 接到 BiLSTM 上,就可以将两者的特点结合,取长补短,通过 BiLSTM 提取高效的特征,让 CRF 的学习更加有效。
实验步骤
先安装需要的包:
pip install tensorflow==1.13.1
pip install keras==2.2.4
Tensorflow 2.0 最新版(2.4.1) 安装教程
1. 数据处理
原始文本和标签分别定义为
raw_text = '''张无忌,金庸武侠小说《倚天屠龙记》人物角色,中土明教第三十四代教主。武当七侠之一张翠山与天鹰教紫微堂主殷素素之子,明教四大护教法王之一金毛狮王谢逊义子。
张翠山,《倚天屠龙记》第一卷的男主角,在武当七侠之中排行第五,人称张五侠。与天鹰教殷素素结为夫妇,生下张无忌,后流落到北极冰海上的冰火岛,与谢逊相识并结为兄弟。
殷素素,金庸武侠小说《倚天屠龙记》第一卷的女主人公。天鹰教紫薇堂堂主,容貌娇艳无伦,智计百出,亦正亦邪。与武当五侠张翠山同赴王盘山,结果被金毛狮王谢逊强行带走,三人辗转抵达冰火岛。殷素素与张翠山在岛上结为夫妇,并诞下一子张无忌。
谢逊,是金庸武侠小说《倚天屠龙记》中的人物,字退思,在明教四大护教法王中排行第三,因其满头金发,故绰号“金毛狮王”。
'''
annotations = {'name':['张无忌','张翠山','殷素素','谢逊'], 'book':['倚天屠龙记'],'org':['明教','武当','天鹰教']}
raw_text, annotations
1.1将标注转换为 BMEO 格式
import re
# 先去掉原始文本中的换行和空格符
raw_text = raw_text.replace('\\n', '').replace(' ', '')
# 初始化 label:将其全部初始化为 O
labels = len(raw_text)*['O']
# 通过 key-value 的方式遍历 annotations 字典,进行转换
for ann, entities in annotations.items():
for entity in entities:
# 先生成实体对应的 BME 标注类型
B, M, E = [['{}_{}'.format(ann,i)] for i in ['B','M','E']]
# 计算实体词中的数量
M_len = len(entity) - 2
# 生成 label,如果词中数为0,则直接为 BE,不然按数量添加 M
label = B + M * M_len + E if M_len else B + E
# 从原始文本中找到实体对应出现的所有位置
idxs = [r.start() for r in re.finditer(entity, raw_text)]
for idx in idxs:
# 替换原 label 中的 O 为实际 label
labels[idx:idx+len(entity)] = label
# 打印原始文本和对应转换后的 label
for ann,label in zip(raw_text,labels):
print(ann, label)
1.2 数据集预处理
在自然语言处理中,需要将文本数据特征提取为向量数据,才能被模型使用。在本实验中使用的是词袋模型,忽略文本的语法和语序要素,将其仅仅看做是若干个词汇的集合。
from collections import Counter
import numpy as np
from keras.preprocessing.sequence import pad_sequences
先统计训练集中每个字出现的次数,然后建立字典表,只记录出现次数不小于 2 的字
# 统计每个字出现的次数
word_counts = Counter(raw_text)
# 建立字典表,只记录出现次数不小于 2 的字
vocab = [w for w, f in iter(word_counts.items()) if f >= 2]
word_counts, vocab
原始的数据集是字符串格式的,每句话用句号隔开,在训练过程中,我们需要把每句话拆开作为一个样本,因为每句话的长度不同,所以要定义一个最大长度,对于小于这个最大长度的句子,在左边或者右边填充固定的数字。
label_set = list(set(labels))
# 拆分训练集,每一句话作为一个样本,先找到每个句号的位置
sentence_len = [r.start()+1 for r in re.finditer('。', raw_text)]
# 进行拆分,这里要注意最后一个句号后面不需要拆分,所以最后一个位置不需要取到
split_text = np.split(list(raw_text), sentence_len[:-1])
split_label = np.split(labels, sentence_len[:-1])
split_text, split_label
# 构建词袋模型,这里要将字典从 2 开始编号,把 0 和 1 空出来,0 作为填充元素,1 作为不在字典中的字的编号
word2idx = dict((w,i+2) for i,w in enumerate(vocab))
label2idx = [[label_set.index(w) for w in s] for s in split_label]
word2idx, label2idx
# 构建输入,即对于样本中每一个字,从词袋模型中找到这个字对应的 idx,出现频率过低的字,并没有出现在词袋模型中,此时将这些字的 idx 取为 1
train_x = [[word2idx.get(w, 1) for w in s] for s in split_text]
max_len = 64
# 在输入的左边填充 0,在输出的左端填充-1
train_x = pad_sequences(train_x, max_len, value=0)
train_y = pad_sequences(label2idx, max_len, value=-1)
train_y = np.expand_dims(train_y, 2)
train_x.shape, train_y.shape
2. 构建网络模型
在 Keras 中,已经包含了 BiLSTM 模型中的各个组件,只需导入构建就可以了,而 CRF 层需要导入第三方库 keras-contrib 来使用。
首先安装 keras-contrib
pip install git+https://www.github.com/keras-team/keras-contrib.git
from keras.models import Sequential
from keras.layers import Embedding, Bidirectional, LSTM
from keras_contrib.layers import CRF
from keras_contrib.losses import crf_loss
# 定义模型的超参
EMBED_DIM = 200
BiRNN_UNITS = 200
# 初始化模型
model = Sequential()
# 添加 Embedding 层,将输入转换成向量
model.add(Embedding(len(vocab)+2, EMBED_DIM, mask_zero=True))
# 添加 BiLstm 层
model.add(Bidirectional(LSTM(BiRNN_UNITS // 2, return_sequences=True)))
# 初始化 crf
crf = CRF(len(train_y), sparse_target=True)
# 将 crf 添加到模型中
model.add(crf)
model.summary()
# 编译模型
model.compile('adam', loss=crf_loss, metrics=[crf.accuracy])
3. 模型训练
model.fit(train_x, train_y, batch_size=9, epochs=120)
model.save('model.h5')
4. 模型预测
在这里我们使用训练集中出现的一句话进行预测
text = '谢逊,是金庸武侠小说《倚天屠龙记》中的人物,字退思,在明教四大护教法王中排行第三,因其满头金发,故绰号“金毛狮王"。'
text
# 将预测数据转换为特征向量
pred_x = [word2idx.get(w, 1) for w in text]
pred_x = pad_sequences([pred_x], max_len)
pred_x
# 使用模型进行预测
pred = model.predict(pred_x)
pred.shape
# 去除多余的维度
pred = np.squeeze(pred)[-len(text):]
pred.shape
# 把输出向量转换为 label 对应的 idx
result = [np.argmax(r) for r in pred]
result
# 打印输出结果
reslut_labels = [label_set[i] for i in result]
for w, l in zip(text, reslut_labels):
print(w, l)
总结
在本实验中,我们了解了命名实体识别任务的定义,并用了 BiLstm-CRF 模型,结合简单的数据集实现了整个命名实体识别任务中的数据处理、训练与预测。 虽然在本节实验中数据集规模较小,而且并没有切分验证集与测试集,但在实际的调试中,为了先确保数据管道与网络模型是否搭建正确,应先用少量数据集训练至过拟合,然后逐渐增大数据规模,并切分验证集和测试集,在验证集上对模型进行调优。
命名实体识别除了应用在构建知识图谱前期的数据结构化之外,还可以用于知识图谱构建完成后的智能问答上,如提问 “张无忌是谁?”,从中提取到人名实体“张无忌”,然后转化为 Cypher 语言 match (n:角色) where n.name='张无忌' return n.desc
进行查询,最后返回查询到的结果作为回答。
NLP 暑假等我哦!现在这上面的内容我也不懂,还是实力欠缺o(╥﹏╥)o
小猪梦想变大牛
好远!
加油!
以上是关于知识图谱命名实体识别(NLP)的主要内容,如果未能解决你的问题,请参考以下文章
领域图谱之命名实体识别-Named Entity Recognition Using a Semi-supervised Model Based on BERT and Bootstrapping(代