三个月之前 NLP 课程结课,我们做的是命名实体识别的实验。在MSRA的简体中文NER语料(我是从这里下载的,非官方出品,可能不是SIGHAN 2006 Bakeoff-3评测所使用的原版语料)上训练NER模型,识别人名、地名和组织机构名。尝试了两种模型:一种是手工定义特征模板后再用CRF++开源包训练CRF模型;另一种是最近两年学术界比较流行的 BiLSTM-CRF 模型。

小白一枚,简单介绍一下模型和实验结果,BiLSTM-CRF 模型的数据和代码在GitHub上。

命名实体识别(Named Entity Recognition)

命名实体识别(Named Entity Recognition, NER)是 NLP 里的一项很基础的任务,就是指从文本中识别出命名性指称项,为关系抽取等任务做铺垫。狭义上,是识别出人名、地名和组织机构名这三类命名实体(时间、货币名称等构成规律明显的实体类型可以用正则等方式识别)。当然,在特定领域中,会相应地定义领域内的各种实体类型。

汉语作为象形文字,相比于英文等拼音文字来说,针对中文的NER任务来说往往要更有挑战性,下面列举几点:

(1) 中文文本里不像英文那样有空格作为词语的界限标志,而且“词”在中文里本来就是一个很模糊的概念,中文也不具备英文中的字母大小写等形态指示

(2) 中文的用字灵活多变,有些词语在脱离上下文语境的情况下无法判断是否是命名实体,而且就算是命名实体,当其处在不同的上下文语境下也可能是不同的实体类型

(3) 命名实体存在嵌套现象,如“北京大学第三医院”这一组织机构名中还嵌套着同样可以作为组织机构名的“北京大学”,而且这种现象在组织机构名中尤其严重

(4) 中文里广泛存在简化表达现象,如“北医三院”、“国科大”,乃至简化表达构成的命名实体,如“国科大桥”。

专著 [1] 里比较详细地介绍了 NER 的各种方法(由于出版年限较早,未涵盖神经网络方法),这里笼统地摘取三类方法:

1. 基于规则的方法:利用手工编写的规则,将文本与规则进行匹配来识别出命名实体。例如,对于中文来说,“说”、“老师”等词语可作为人名的下文,“大学”、“医院”等词语可作为组织机构名的结尾,还可以利用到词性、句法信息。在构建规则的过程中往往需要大量的语言学知识,不同语言的识别规则不尽相同,而且需要谨慎处理规则之间的冲突问题;此外,构建规则的过程费时费力、可移植性不好。

2. 基于特征模板的方法

统计机器学习方法将 NER 视作序列标注任务,利用大规模语料来学习出标注模型,从而对句子的各个位置进行标注。常用的应用到 NER 任务中的模型包括生成式模型HMM、判别式模型CRF等。比较流行的方法是特征模板 + CRF的方案:特征模板通常是人工定义的一些二值特征函数,试图挖掘命名实体内部以及上下文的构成特点。对于句子中的给定位置来说,提特征的位置是一个窗口,即上下文位置。而且,不同的特征模板之间可以进行组合来形成一个新的特征模板。CRF的优点在于其为一个位置进行标注的过程中可以利用到此前已经标注的信息,利用Viterbi解码来得到最优序列。对句子中的各个位置提取特征时,满足条件的特征取值为1,不满足条件的特征取值为0;然后把特征喂给CRF,training阶段建模标签的转移,进而在inference阶段为测试句子的各个位置做标注。关于这种方法可以参阅文献 [2] 和 [3]。

3. 基于神经网络的方法

近年来,随着硬件能力的发展以及词的分布式表示(word embedding)的出现,神经网络成为可以有效处理许多NLP任务的模型。这类方法对于序列标注任务(如CWS、POS、NER)的处理方式是类似的,将token从离散one-hot表示映射到低维空间中成为稠密的embedding,随后将句子的embedding序列输入到RNN中,用神经网络自动提取特征,Softmax来预测每个token的标签。这种方法使得模型的训练成为一个端到端的整体过程,而非传统的pipeline,不依赖特征工程,是一种数据驱动的方法;但网络变种多、对参数设置依赖大,模型可解释性差。此外,这种方法的一个缺点是对每个token打标签的过程中是独立的分类,不能直接利用上文已经预测的标签(只能靠隐状态传递上文信息),进而导致预测出的标签序列可能是非法的,例如标签B-PER后面是不可能紧跟着I-LOC的,但Softmax不会利用到这个信息。

学界提出了 LSTM-CRF 模型做序列标注。文献[4][5]在LSTM层后接入CRF层来做句子级别的标签预测,使得标注过程不再是对各个token独立分类。引入CRF这个idea最早其实可以追溯到文献[6]中。文献[5]还提出在英文NER任务中先使用LSTM来为每个单词由字母构造词并拼接到词向量后再输入到LSTM中,以捕捉单词的前后缀等字母形态特征。文献[8]将这个套路用在了中文NER任务中,用偏旁部首来构造汉字。关于神经网络方法做NER,可以看博客[9] ,介绍的非常详细~

基于字的BiLSTM-CRF模型

这段讲得比较啰嗦,大概看看就好。

使用基于字的BiLSTM-CRF,主要参考的是文献[4][5]。使用Bakeoff-3评测中所采用的的BIO标注集,即B-PER、I-PER代表人名首字、人名非首字,B-LOC、I-LOC代表地名首字、地名非首字,B-ORG、I-ORG代表组织机构名首字、组织机构名非首字,O代表该字不属于命名实体的一部分。如:

这里当然也可以采用更复杂的BIOSE标注集。

以句子为单位,将一个含有 $n$ 个字的句子(字的序列)记作

$$x=(x_{1},x_{2},...,x_{n})$$

其中 $x_{i}$ 表示句子的第 $i$ 个字在字典中的id,进而可以得到每个字的one-hot向量,维数是字典大小。

模型的第一层是 look-up 层,利用预训练或随机初始化的embedding矩阵将句子中的每个字 $x_{i}$ 由one-hot向量映射为低维稠密的字向量(character embedding)$\boldsymbol x_{i}\in\mathbb R^{d}$ ,$d$ 是embedding的维度。在输入下一层之前,设置dropout以缓解过拟合。

模型的第二层是双向LSTM层,自动提取句子特征。将一个句子的各个字的char embedding序列 $(\boldsymbol x_{1},\boldsymbol x_{2},...,\boldsymbol x_{n})$ 作为双向LSTM各个时间步的输入,再将正向LSTM输出的隐状态序列 $(\overset{\longrightarrow}{\boldsymbol h_1},\overset{\longrightarrow}{\boldsymbol h_2},...,\overset{\longrightarrow}{\boldsymbol h_n})$ 与反向LSTM的 $(\overset{\longleftarrow}{\boldsymbol h_1},\overset{\longleftarrow}{\boldsymbol h_2},...,\overset{\longleftarrow}{\boldsymbol h_n})$ 在各个位置输出的隐状态进行按位置拼接 $\boldsymbol h_{t}=[\overset{\longrightarrow}{\boldsymbol h_t};\overset{\longleftarrow}{\boldsymbol h_t}]\in\mathbb R^{m}$ ,得到完整的隐状态序列

$$({\boldsymbol h_1},{\boldsymbol h_2},...,{\boldsymbol h_n})\in\mathbb R^{n\times m}$$

在设置dropout后,接入一个线性层,将隐状态向量从 $m$ 维映射到 $k$ 维,$k$ 是标注集的标签数,从而得到自动提取的句子特征,记作矩阵 $P=({\boldsymbol p_1},{\boldsymbol p_2},...,{\boldsymbol p_n})\in\mathbb R^{n\times k}$ 。可以把 $\boldsymbol p_i\in\mathbb R^{k}$ 的每一维 $p_{ij}$ 都视作将字 $x_{i}$ 分类到第 $j$ 个标签的打分值,如果再对 $P$ 进行Softmax的话,就相当于对各个位置独立进行 $k$ 类分类。但是这样对各个位置进行标注时无法利用已经标注过的信息,所以接下来将接入一个CRF层来进行标注。

模型的第三层是CRF层,进行句子级的序列标注。CRF层的参数是一个 $(k+2)\times (k+2)$ 的矩阵 $A$ ,$A_{ij}$ 表示的是从第 $i$ 个标签到第 $j$ 个标签的转移得分,进而在为一个位置进行标注的时候可以利用此前已经标注过的标签,之所以要加2是因为要为句子首部添加一个起始状态以及为句子尾部添加一个终止状态。如果记一个长度等于句子长度的标签序列 $y=(y_1,y_2,...,y_n)$ ,那么模型对于句子 $x$ 的标签等于 $y$ 的打分为

$$score(x,y)=\sum_{i=1}^{n}P_{i,y_{i}}+\sum_{i=1}^{n+1}A_{y_{i-1},y_{i}}$$

可以看出整个序列的打分等于各个位置的打分之和,而每个位置的打分由两部分得到,一部分是由LSTM输出的 $\boldsymbol p_i$ 决定,另一部分则由CRF的转移矩阵 $A$ 决定。进而可以利用Softmax得到归一化后的概率:

$$P(y|x)=\frac{\exp(score(x,y))}{\sum_{y'}\exp(score(x,y'))}$$

模型训练时通过最大化对数似然函数,下式给出了对一个训练样本 $(x,y^{x})$ 的对数似然:

$$\log P(y^{x}|x)=score(x,y^{x})-\log(\sum_{y'}\exp(score(x,y')))$$

如果这个算法要自己实现的话,需要注意的是指数的和的对数要转换成 $\log\sum_i\exp(x_i) = a + \log\sum_i\exp(x_i - a)$(TensorFlow有现成的CRF,PyTorch就要自己写了),在CRF中上式的第二项使用前向后向算法来高效计算。

模型在预测过程(解码)时使用动态规划的Viterbi算法来求解最优路径:
$$y^{*}=\arg\max_{y'}score(x,y')$$

整个模型的结构如下图所示:

实验结果

关于CRF模型的特征模板就不细讲了,是参考 [3] 来做的。提好特征之后用CRF++工具包即可,这部分是小伙伴做的~

实验结果如下表:

下面开始一本正经地胡说八道:

1. 总的来说,经过仔细选择特征模板的CRF模型在人名上的识别效果要优于BiLSTM-CRF,但后者在地名、组织机构名上展现了更好的性能。究其原因,可能是因为:
      (1) 人名用字较灵活且长度比较短,用特征模板在窗口内所提取的特征要比神经网络自动学习的特征更有效、干扰更少
      (2) 地名、组织机构名的构成复杂、长度较长,使用双向LSTM能够更好地利用句子级的语义特征,而特征模板只能在窗口内进行提取,无法利用整句话的语义。

2. 对于CRF模型来说,使用 {字符,词性,词边界,实体列表} 这一组合模板的效果在CRF模型系列中表现最好(各个单一模板以及其他组合模板的结果未列出)。

3. 对于BiLSTM-CRF模型来说,这里在每一层的处理都是比较简单的,还有可以提高的空间。例如字向量embedding的初始化方式,这里只是用了最简单的随机初始化,然而由于语料规模比较小,所以不太合适。可以考虑对句子做分词,然后将字向量初始化为该字所在词的词向量(可以用在别的大型语料上的预训练值)。此外,还可以尝试文献[5][7][8]的思路,将low-level的特征经过一个RNN或CNN,进而通过“组合”的方式来得到字级别的embedding(英文是用字母构造单词,中文是用偏旁部首构造汉字),将其与随机初始化的字向量拼接在一起。

另外要提的一点是BiLSTM-CRF在这应该是过拟合了,迭代轮数(120轮)给大了,测试集指标在大约60轮之后已经开始下降。应该划个验证集做early stopping。

BiLSTM-CRF模型的代码在GitHub上,README.md里介绍了如何训练、测试。我是用笔记本的显卡训练的,batch_size 取64,Adam优化器训练120个epoch,大概用了4个多小时。如果机器条件允许,不妨试试 batch_size 直接取1,优化器用 SGD+Momentum 。

参考:

[1] 《统计自然语言处理》

[2] 向晓雯. 基于条件随机场的中文命名实体识别[D]. , 2006.

[3] 张祝玉, 任飞亮, 朱靖波. 基于条件随机场的中文命名实体识别特征比较研究[C]//第 4 届全国信息检索与内容安全学术会议论文集. 2008.

[4] Huang Z, Xu W, Yu K. Bidirectional LSTM-CRF models for sequence tagging[J]. arXiv preprint arXiv:1508.01991, 2015.

[5] Lample G, Ballesteros M, Subramanian S, et al. Neural Architectures for Named Entity Recognition[C]//Proceedings of NAACL-HLT. 2016: 260-270.

[6] Collobert R, Weston J, Bottou L, et al. Natural language processing (almost) from scratch[J]. Journal of Machine Learning Research, 2011, 12(Aug): 2493-2537.

[7] Ma X, Hovy E. End-to-end sequence labeling via bi-directional lstm-cnns-crf[J]. arXiv preprint arXiv:1603.01354, 2016.

[8] Dong C, Zhang J, Zong C, et al. Character-Based LSTM-CRF with Radical-Level Features for Chinese Named Entity Recognition[C]//International Conference on Computer Processing of Oriental Languages. Springer International Publishing, 2016: 239-250.

[9] http://www.cnblogs.com/robert-dlut/p/6847401.html

DL4NLP —— 序列标注:BiLSTM-CRF模型做基于字的中文命名实体识别的更多相关文章

  1. 基于BERT预训练的中文命名实体识别TensorFlow实现

    BERT-BiLSMT-CRF-NERTensorflow solution of NER task Using BiLSTM-CRF model with Google BERT Fine-tuni ...

  2. 零基础入门--中文命名实体识别(BiLSTM+CRF模型,含代码)

    自己也是一个初学者,主要是总结一下最近的学习,大佬见笑. 中文分词说到命名实体抽取,先要了解一下基于字标注的中文分词.比如一句话 "我爱北京天安门”. 分词的结果可以是 “我/爱/北京/天安 ...

  3. 基于 bi-LSTM和CRF的中文命名实体识别

    follow: https://github.com/zjy-ucas/ChineseNER  这里边主要识别的实体如图所示,其实也就主要识别人名PER,机构ORG和地点LOC: B表示开始的字节,I ...

  4. NLP 基于kashgari和BERT实现中文命名实体识别(NER)

    准备工作,先准备 python 环境,下载 BERT 语言模型 Python 3.6 环境 需要安装kashgari Backend pypi version desc TensorFlow 2.x ...

  5. NLP入门(八)使用CRF++实现命名实体识别(NER)

    CRF与NER简介   CRF,英文全称为conditional random field, 中文名为条件随机场,是给定一组输入随机变量条件下另一组输出随机变量的条件概率分布模型,其特点是假设输出随机 ...

  6. 用深度学习做命名实体识别(七)-CRF介绍

    还记得之前介绍过的命名实体识别系列文章吗,可以从句子中提取出人名.地址.公司等实体字段,当时只是简单提到了BERT+CRF模型,BERT已经在上一篇文章中介绍过了,本文将对CRF做一个基本的介绍.本文 ...

  7. NLP(二十五)实现ALBERT+Bi-LSTM+CRF模型

      在文章NLP(二十四)利用ALBERT实现命名实体识别中,笔者介绍了ALBERT+Bi-LSTM模型在命名实体识别方面的应用.   在本文中,笔者将介绍如何实现ALBERT+Bi-LSTM+CRF ...

  8. 基于条件随机场(CRF)的命名实体识别

    很久前做过一个命名实体识别的模块,现在有时间,记录一下. 一.要识别的对象 人名.地名.机构名 二.主要方法 1.使用CRF模型进行识别(识别对象都是最基础的序列,所以使用了好评率较高的序列识别算法C ...

  9. pytorch实现BiLSTM+CRF用于NER(命名实体识别)

    pytorch实现BiLSTM+CRF用于NER(命名实体识别)在写这篇博客之前,我看了网上关于pytorch,BiLstm+CRF的实现,都是一个版本(对pytorch教程的翻译), 翻译得一点质量 ...

随机推荐

  1. Oracle数据库进行撤销

    第一步:在v$sqlarea 这视图里面找到你操作那条SQL的时间;select r.FIRST_LOAD_TIME,r. from v$sqlarea r order by r.FIRST_LOAD ...

  2. replace的运用

    replace() 方法用于在字符串中用一些字符替换另一些字符, 或替换一个与正则表达式匹配的子串. 语法: stringObject.replace(regexp / substr, replace ...

  3. Spring Boot—20Zookeeper

    https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/ pom.xml <dependency&g ...

  4. Flutter: 图解 ListView 的多种绑定方式

       小菜昨天刚学习了一下底部状态栏 BottomNavigationBar 的基本使用方法,今天学习一下 ListView 的基本用法.       小菜觉得 Flutter 中 ListView ...

  5. canvas验证码 - 随机字母数字

    基于canvas制作随机生成数字英文组合验证码效果,点击或刷新会自动重组.输入验证码提交验证效果代码. <div class="verification"> <i ...

  6. Python 执行主程序

    主程序里的代码包含的东西比较多, 如果在程序的.py文件里执行还要再调一遍方法, 但通常这个调用在测试完结后是要删掉的. 那么问题来了, 如果把这个代码直接发给别人, 执行时要再加上调用, 这个就很烦 ...

  7. Vue2学习笔记:组件(Component)

    组件 组件(Component)是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能.在有些情况 ...

  8. PowerShell管理SCOM2007R2

    get-operationsmanagercommand #定义RMS服务器名称(SCOM管理控制台所在服务器名称)#Connect to the RMS server and initialize ...

  9. September 25th 2017 Week 39th Monday

    No man is rich enough to buy back his own past. 没有人富有到可以赎回自己的过去. Those rich are not willing to buy b ...

  10. November 15th 2016 Week 47th Tuesday

    Success is finding satisfaction in giving a little more than you take. 成功就是付出比得到多,仍然心满意足. Can I find ...