知识图谱命名实体识别(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 种不同的输出。如下图所示,每一个代表一个标签的可能性,点之间的连线表示标签之间的关联,而每一条完整的路径,表示一种输出

在这里插入图片描述

综上所述,逐帧分类是将序列标注看成 nk 分类问题,而真正的序列标注是 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)的主要内容,如果未能解决你的问题,请参考以下文章

第1章 NLP基础

领域图谱之命名实体识别-Named Entity Recognition Using a Semi-supervised Model Based on BERT and Bootstrapping(代

知识图谱——命名实体识别(NER)

知识图谱关系抽取与总结展望

知识图谱1

知识图谱抽取总结