自然语言处理在文本信息抽取、自动审校、智能问答、情感分析等场景下都有非常多的实际应用需求,在人工智能领域里有极为广泛的应用场景。然而在实际工程应用中,最经常面临的挑战是我们往往很难有大量高质量的标注语料。

“巧妇难为无米之炊”,在缺少语料的情况下,如何达到良好的NLP应用效果,是这些场景要落地所必须解决的问题。我们通常称其为“低资源问题”,或者称为“小样本学习”问题,本文从达观数据的实践经验出发,用命名实体识别(NER)任务为例,来介绍在小标注数据量下进行NLP处理的经验和方法,希望对大家有所启发。

经典的低资源NLP方法

在众多文本处理场景中,NER(Named Entity Recognition,命名实体识别)又称专名识别,是最为常见的一项任务,使用的范围非常广,因此本文中我们以NER任务为例来讲解。命名实体通常指文本中具有特别意义或者指代性非常强的事物,例如人名、地名、机构名、书名、时间、以及其他专有名词等。NER的任务就是从原始的非机构化文本中自动抽取出上述实体,或者按业务需求识别出更多特定类别的实体,比如产品名称、型号、价格等。实体这个概念可以很广,只要是业务需要的特殊文本片段都可以称为实体。例如在金融行业文本中,债权人、债务人、利润总额、资产负载率等,这些特定意义的信息,都可以视为实体。

在实际应用中,由于标注数据稀少(这个原因来自很多实际条件的限制),但又期望能达到足够好的效果,在经典的机器学习方法里,往往可以通过对特征进行概率统计学习,来形成抽取模型。其具体算法思想如下:

先由工程师标定特征,通过对训练数据进行特征统计和挖掘,形成抽取模型。

下面简单举例说明,假设标注的样本数据是:

百度是一家人工智能公司  à NER (公司名:百度)

需要抽取出“参加本次活动的达观数据是一家人工智能公司”这句话里的公司名。通过分词、词性标注、句法结构分析等,掌握到“参加本次活动”这样的定语修饰词,以及后续13个字,经典方法是用概率计算方法判断出现在“是人工智能公司”前面的词汇是公司名的概率。

在经典NER方法中,达观的经验是条件随机场(CRF)效果较好。条件随机场使用势函数和图结构上的团来定义条件概率P(y | x)。给定观测序列x,链式条件随机场主要包含两种关于标记变量的团,即单个标记变量{yi}以及相邻的标记变量{yi-1,yi}。在条件随机场中,通过选用合适的势函数,并引入特征函数,可以得到条件概率的定义:

其中:

其中tk(yi- 1, yi, x, i)是定义在观测序列的两个相邻标记位置上的转移特征函数,用于刻画相邻标记变量之间的相关关系以及观测序列对它们的影响,sl(yi, x, i)是定义在观测序列的标记位置i上的状态特征函数,用于刻画观测序列对标记变量的影响,λk和ul为参数,Z为规范化因子。

可以将tk(yi - 1, yi, x, i)和sl(yi, x, i)两个特征函数统一为:fk(yi-1, yi, x, i),则有:

其中:

已知训练数据集,由此可知经验概率分布,可以通过极大化训练数据的对数似然函数来求模型参数。加入惩罚项后,训练数据的对数似然函数为:

其中的σ是可以调节的惩罚权重。对似然函数L(w)中的w求偏导,令:

可以依次求出wi。在上述情况下,如果带来干扰的训练样本不多,则CRF还是可以取得尚可的效果的。但是前置的句法结构分析、词性分析等一旦出现误差,会带来连锁反应。例如“参加本次活动的”这样的定语有时需要进行剔除才能确保NER识别的精度,不得不让工程师针对每个场景进行很多繁琐的预处理和后处理工作。

深度学习与小标注数据训练

使用深度学习的优点是不需要工程师告诉算法要提取哪些特征,而是由算法从标注数据中自动学习并寻找到关键特征,再进行预测(提取)。深度学习源自经典的BP神经网络模型,一般由输入层,隐藏层,输出层组成,其中隐藏层的数目按需确定。深度学习增加了网络层数,将每一层的输出作为下一层的输入,将底层的简单特征进行多层组合抽象为高层的特征表示。NER最常使用的深度神经网络结构是长短时记忆网络LSTM(Long ShortTerm Memory)。长短期记忆网络的原理可见下图:

第一步,如何做长期记忆的更新?输入Ht-1和Xt,Ht-1是上一个时刻这个cell隐状态的输出,Xt是当前输入,它们两个通过这个函数计算后的输出是0-1之间的某一个值。这一步,决定上个时刻神经元状态留下的比率是多少。

第二步,上下文中获得了新的信息,不能只是把老的神经元状态更新,还要把新的信息添进去,通过这两个公式来添,第一个公式输出0-1的系数,第二个公式要选出量是多少。有了第一步和第二步之后就开始第三步神经元状态更新。

第三步,第一步的输出0-1和Ct-1相乘决定上一时刻这个神经元状态留下多少。第二步算出来系数和信息量相乘决定留下多少新增信息,然后把上一步剩下的和这一步新增的加起来,做一个更新,这个更新就是现的神经元状态值。

 

第四步,现在单元的状态更新完了,接下来就要输出,这个输出有两个:第一个,对外是一样,还是隐层的输出Ht。决定留下多少老的信息,决定留下多少新的信息,第二个再把老的信息和新的信息加起来就是最终的结果。

使用深度学习的方法通常需要有大量的训练数据,在小数据集下往往很难对网络结构进行充分训练。多任务学习(Multi-task Learning)可通过端到端的学习方式,直接在当前任务中引入其他相关任务的标注信息作为监督学习的样本。2008年Collobert等人最早提出了NLP中应用Multi-task的思想,通过不同任务的标注数据,共同训练一个神经网络模型,来共同提升数据的综合利用程度。多任务学习可以设计为可共享网络的核心层次,在输出层对不同任务设计特定的网络结构。达观在实际使用中,也会使用Bi-LSTM和CRF结合的网络结构,效果略有提升,但受限于数据规模,并非有质的提升。

引入预训练神经网络

前面所提的方法只依赖了测试场景下已有的训练数据,而很多实际场景下获取标注语料非常困难,那为了达到好的效果还有什么不同的思路吗?这些专有名词除了出现在标注语料中,还有很多文本中也一样会出现,无论是字、词或者句子,都大量存在。所以是否可以使用其他文本中的未标注过的语料,来改进当前测试场景下的效果?这就是近年来在NLP领域大放异彩的预训练思路。而词向量(Word Embedding)是普遍使用的方法,相比传统的对于词语进行One-Hot编码,词向量携带了更加丰富的语义信息。

字面上不相关的词在中文中有可能是非常相近甚至是同义词,如“电脑”和“计算机”,“香蕉”和“水果”,“公司”和“企业”,如果模型可以结合这些信息,能有效提高抽取的泛化能力。词向量主要的几代技术有Word2Vec,ELMO和BERT。

Word2Vec

Word2Vec是google在2013年推出的一个NLP工具,它的特点是将所有的词向量化。Word2Vec中最重要的两个模型是CBOW(Continuous Bag-of-Word)模型和Skip-gram(ContinuousSkip-gram)模型,两个模型都包含三层:输入层,投影层,输出层。CBOW模型的作用是已知当前词Wt的上下文环境(Wt-2,Wt-1,Wt+1,Wt+2)来预测当前词,Skip-gram模型的作用是根据当前词Wt来预测上下文(Wt-2,Wt-1,Wt+1,Wt+2)

在模型求解中,和一般的机器学习方法类似,也是定义不同的损失函数,使用梯度下降法寻找最优值。Word2vec模型求解中,使用了HierarchicalSoftmax方法和NegativeSampling两种方法。通过使用Word2vec,我们可以方便的将词转化成向量表示,让计算机和理解图像中的每个点一样,数字化词的表现。

ELMO

相同的词在不同上下文是可能有不同的含义。如“苹果”,在“我吃了一个苹果”,和“我买了一个苹果手机”两个句子下的含义完全不同。所以word embedding 对于每个词只有一个唯一的向量,是无法区分不同语义下相同词的不同含义。ELMO(Embeddingfrom Language Models)通过上下文来调整word  embedding 的方式, 可以比较好的解决这个问题。

上图展示的是其预训练过程,它的网络结构采用了双层双向 LSTM,目前语言模型训练的任务目标是根据单词的上下文去正确预测单词,单词之前的单词序列称为上文,之后的单词序列称为下文。图中左端的前向双层LSTM代表正方向编码器,输入的是从左到右顺序的除了预测单词外的上文。右端的逆向双层 LSTM 代表反方向编码器,输入的是从右到左的逆序的句子下文。每个编码器的深度都是两层 LSTM 叠加。这个网络结构其实在NLP 中是很常用的。

使用这个网络结构利用大量语料做语言模型任务就能预先训练好这个网络,如果训练好这个网络后,输入一个新句子,句子中每个单词都能得到对应的三个Embedding:最底层是单词的WordEmbedding,往上走是第一层双向LSTM中对应单词位置的Embedding,这层编码单词的句法信息更多一些;再往上走是第二层 LSTM 中对应单词位置的Embedding,这层编码单词的语义信息更多一些。所以,ELMO不仅仅学会单词的 WordEmbedding,还学会了一个双层双向的LSTM 网络结构。

BERT

ELMO一个非常明显的缺点在特征抽取器选择方面,ELMO使用了 LSTM 而不是新贵Transformer,Transformer 是谷歌在 17 年做机器翻译任务的“Attentionis all you need”的论文中提出的,引起了相当大的反响,很多研究已经证明了 Transformer 提取特征的能力远强于LSTM。

BERT的全称是Bidirectional Encoder Representation from Transformers,在机器阅读理解顶级水平测试SQuAD1.1中表现出惊人的成绩:全部两个衡量指标上全面超越人类!并且还在11种不同NLP测试中创出最佳成绩,包括将GLUE基准推至80.4%(绝对改进7.6%),MultiNLI准确度达到86.7%(绝对改进率5.6%)等。

Bert使用双向Transformer的Encoder,因为decoder是不能获要预测的信息的。模型的主要创新点都在预训练方法上,即用了Masked Language Model和Next Sentence Prediction两种方法分别捕捉词语和句子级别的语义。

Masked Language Model(MLM)是指在训练的时候随即从输入预料上mask掉一些单词,然后通过的上下文预测该单词,该任务非常像我们在中学时期经常做的完形填空。正如传统的语言模型算法和RNN匹配那样,MLM的这个性质和Transformer的结构是非常匹配的。在BERT的实验中,15%的Token会被随机Mask掉。在训练模型时,一个句子会被多次喂到模型中用于参数学习,但是Google并没有在每次都mask掉这些单词,而是在确定要Mask掉的单词之后,80%的时候会直接替换为[Mask],10%的时候将其替换为其它任意单词,10%的时候会保留原始Token。这么做的原因是如果句子中的某个Token100%都会被mask掉,那么在fine-tuning的时候模型就会有一些没有见过的单词。加入随机Token的原因是因为Transformer要保持对每个输入token的分布式表征,否则模型就会记住这个[mask]是token ‘hairy’。至于单词带来的负面影响,因为一个单词被随机替换掉的概率只有15%*10% =1.5%,这个负面影响其实是可以忽略不计。

Next Sentence Prediction(NSP)的任务是判断句子B是否是句子A的下文。如果是的话输出‘IsNext’,否则输出‘NotNext’。训练数据的生成方式是从平行语料中随机抽取的连续两句话,其中50%保留抽取的两句话,它们符合IsNext关系,另外50%的第二句话是随机从预料中提取的,它们的关系是NotNext。

达观数据在实践中发现,使用预训练方法,通过词嵌入,对于比较常见的字段抽取可以有明显的提升,比如人名类字段(甲方,乙方,律师,原告等),很少的标注语料就可以达到很好的效果,但对于行业性质比较强的字段,由于本身能获取到的未标注语料总量也不够大,相关字词的出现频率不够多,限制了方法的效果。

迁移学习(Transfer Learning)方法

现在需要处理的任务标注样本不足,但其他相关的任务有大量的标注样本,并且有个比较好的模型。所以是否可以将大量标注样本数据的任务来优化这个样本不足任务?迁移学习就是基于这样的思路,核心思想就是将一个已经成熟的任务应用于另外一个任务。举例来说,比如采购合同往往数据量比较大,而租赁合同数据量比较小,可以用采购合同的模型来优化租赁合同的场景。

迁移学习根据迁移的知识进行分类,可以分为基于样本的迁移,基于模型的迁移,基于特征的迁移,及基于关系的迁移。

基于样本的迁移学习是根据一定的权重生成规则,对数据样本进行重用,来进行迁移学习。经典的算法是TrAdaBoost,从源场景中筛选有效数据,过滤掉与目标场景不同的数据,通过 Boosting方法建立一种权重调整机制,增加有效数据权重,降低无效数据权重。

基于模型的迁移是目前比较容易落地的,前面提到的租赁合同和采购合同,达观也是基于模型的迁移进行的处理。基于模型的迁移又叫多任务学习,网络结构如下图所示,任务与任务之间共享隐藏层,保留每个任务的输出层。

基于特征的迁移方法是指将通过特征变换的方式互相迁移,来减少源场景和目标场景之间的差距;或者将源场景和目标场景的数据特征变换到统一特征空间中,然后利用传统的方法进行识别。典型的方法是迁移成分分析方法。该方法的核心内容是以最大均值差异作为度量准则,将不同数据领域中的分布差异最小化。

基于关系的迁移学习方法比较关注源场景和目标场景的样本之间的关系。目前研究和应用都比较少。

半监督(Semi-supervised Learning)学习方法

一些少标注数据的场景,是标注成本比较高,比如招股说明书,一份都打几百页甚至上千页,一个人要几天才能标注完一篇文档。这种场景下可以考虑使用半监督学习方法。

半监督学习方法最简单的做法是,通过已有的标注数据进行建模,对未标注数据进行预测,预测结果中概率比较大的,则认为是正确的,加入到训练样本中。这种方法达观实践下来效果一般,原因是这种方式加入的样本里,正确的样本都是原来模型可以准确预测,而且特征明显(预测概率高),所以对模型的补充性不一定很高,只是一些小特征的补充。而且更严重的是这里面可以有些是误判的,当成训练数据对模型往往影响就会比较大。

半监督学习方法的另外一种方法伪标记半监督学习算法,用在深度学习的网络结构中。当输入的样本是一个有标记的样本的时候,我们需要最小化模型输出和样本标记的交叉熵,这就是监督学习,那么没有标记的怎么办,这时候就需要一个伪标记。

这样我们就获得了一个伪标记。我们在训练模型的时候定义损失函数

其中y和f代表监督学习的输入和输出,为伪标记,α了加权系数,而t代表了当前的迭代次数。通过求解这个新的网络,得到最终的模型。所以这里的方法就是网络对无标签数据的预测,作为无标签数据的标签(即伪标签)。模型不会做为正确标签进行处理,从而避免上面算发判错带来的影响。

 

引入业务知识&领域常识

达观数据服务了非常多的大型企业,发现命名实体识别在大型企业里面的应用场景,基本都是对一些行业内常见类型的文本进行实体抽取,进而通过RPA(机器人流程自动化)代替人进行自动操作。如财务合同,可自动抽取出甲方,乙方,总金额等数十个字段,进行财务核算;比如几百页的招股说明书,需要抽取出董事,监事,高管,财务表,重大合同,上下游供应商等数千个字段;比如司法裁判文书,需抽取出原告,被告,律师,罪名,判罚结果等上百个字段。这些场景有几个共同的特点是:

1、都是具备特定格式的规范文书。相比于互联网中的五花八门的各类评论和文章,这些行业文档内容规范,行文准确,很少会出现错字,语法错误等问题。文档的撰写会遵从行业规范,每个人撰写风格影响小,会有特定行业固定的套路。

2、这些文档训练语料极为稀少,比如招股说明书或者合同,即便是大型企业内部历史积累的语料也不会很多,获得标注的更少

3、这些场景由于行业属性非常强,所以通过全网文书计算词向量的方式效果往往不好,用行业语料进行训练,由于数据量较少,也不能达到很好的效果。达观数据在服务上百家大型客户实践中,研发了一套结合行业经验的算法模型,可以在这些低资源文档的场景,达到非常好的效果。

 

这个算法的核心思想是,利用行业专家经验,通过知识沉淀的方法,帮助系统掌握行业规律,通过知识图谱将专家经验输入给模型,极大提升算法的效果。

 

对于每个抽取的字段,行业专家可以梳理出这个字段的重要词,重要句式,重要段落,重要位置,重要上下文,把这些信息进行编码加入到模型中。

上图是将行业专家梳理到核心词使用的例子。假设“委员”和“委员会”是核心词。需要对“美国联邦通信委员会最近正式批准苹果展开5G通信试验”的每个字生成词向量。这里的方法是通过2-gram,3-gram,4-gram和5-gram对每个字进行编码,编成8个位,每种gram各2个位表示上文是否是核心词和下文是否是核心词。以“委”字为例编码方式为:

 

2-gram,就是“信委”和“委员”,“信委”不是核心词,而“委员”是核心词,所以编码为“01”

3-gram,就是“通信委”和“委员会”,“通信委”不是核心词,而“委员会”是核心词,所以编码为“01”

4-gram,就是“邦通信委”和“委员会最”都不是核心词,所以编码为“00”

5-gram,就是“联邦通信委”和“委员会最近”都不是核心词,所以编码为“00”

然后我们再通过训练两个独立的LSTM双向网络(如图所示),一个是用经典LSTM结构,一个是将以上专家特征(或者领域知识)合并进来后,并最终将把所有的行业向量和原始的字向量进行拼接,作为CRF层的输入,这样双层BiLSTM+CRF模型可以较好的融合领域知识来提升提取效果。

本文小结

本文以NER任务为例,详细阐述了达观在小标注语料情况下进行算法优化的经验。在标注语料稀缺的情况下,仅仅依靠传统的NLP模型很难达到理想的效果,我们往往需要因地制宜的深入研究具体的业务场景,实事求是的运用各种方法,引入更多相关的数据和资源,融会贯通,更好的理解业务并实现技术的落地。

A

BOUT

关于作者

纪达麒:达观数据首席技术官(CTO),研发团队总负责人,中国计算机学会(CCF)会员。拥有10年技术团队管理经验,在加入达观前,曾担任腾讯文学数据中心高级研究员、盛大文学技术总监,搜狗广告系统高级研发工程师,百度工程师等职务,擅长数据挖掘以及实时服务系统架构设计工作。曾代表公司多次参加国际数据挖掘竞赛,是ACM KDD-Cup,CIKM Competition等世界一流数据挖掘竞赛获胜队伍的核心成员。

相关阅读

达观数据CTO纪达麒:小标注数据量下自然语言处理实战经验的更多相关文章

  1. CocoStuff—基于Deeplab训练数据的标定工具【二、用已提供的标注数据跑通项目】

    一.说明 本文为系列博客第二篇,主要讲述笔者在使用该团队提供已经标注好的COCO数据集进行训练的过程. 由于在windows中编译Caffe和Deeplab特别的麻烦,笔者并没有去探索,后续可能会去尝 ...

  2. Fine-tuning Convolutional Neural Networks for Biomedical Image Analysis: Actively and Incrementally如何使用尽可能少的标注数据来训练一个效果有潜力的分类器

    作者:AI研习社链接:https://www.zhihu.com/question/57523080/answer/236301363来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...

  3. "大中台、小前台”新架构下,阿里大数据接下来怎么玩? (2016-01-05 11:39:50)

    "大中台.小前台”新架构下,阿里大数据接下来怎么玩?_炬鼎力_新浪博客 http://blog.sina.com.cn/s/blog_1427354e00102vzyq.html " ...

  4. 现在有m组n个有序数组,例如{1,2,3,4},{2,3,4,6},{1,3,5,7},在这些数组中选择第k小的数据,然后返回这个值

    问题描述:现在有m组n个有序数组,例如{1,2,3,4},{2,3,4,6},{1,3,5,7},在这些数组中选择第k小的数据,然后返回这个值 思路:参照两个数组归并的过程,每次选取最小的数据进行比较 ...

  5. 微信小程序数据请求方法wx.request小测试

    微信小程序数据请求方法 wx.request wxml文件: <view> <textarea value="{{textdata}}"/> </vi ...

  6. 自制 COCO api 直接读取类 COCO 的标注数据的压缩文件

    第6章 COCO API 的使用 COCO 数据库是由微软发布的一个大型图像数据集,该数据集专为对象检测.分割.人体关键点检测.语义分割和字幕生成而设计.如果你要了解 COCO 数据库的一些细节,你可 ...

  7. 目标检测 的标注数据 .xml 转为 tfrecord 的格式用于 TensorFlow 训练

    将目标检测 的标注数据 .xml 转为 tfrecord 的格式用于 TensorFlow 训练. import xml.etree.ElementTree as ET import numpy as ...

  8. 微信小程序 -- 数据请求

    微信小程序 -- 数据请求 微信小程序请求数据,并不是一个可以在url打开有数据就可以拿到数据那么简单 浏览器地址输入 可以获取参数的url 微信小程序中 代码展示 wxml <view> ...

  9. flume采集微信小程序数据

    flume采集微信小程序数据 flume收集前端埋点数据[1]POST请求http://f.x.com:50000数据格式: JsonArray数据格式示例:[{ "headers" ...

随机推荐

  1. java如何访问memcache

    1       Memcache是什么 Memcache是danga.com的一个项目,最早是为 LiveJournal 服务的,目前全世界不少人使用这个缓存项目来构建自己大负载的网站,来分担数据库的 ...

  2. vue组件通信全面总结

    写在前面 组件间的通信是是实际开发中非常常用的一环,如何使用对项目整体设计.开发.规范都有很实际的的作用,我在项目开发中对此深有体会,总结下vue组件间通信的几种方式,讨论下各自的使用场景 文章对相关 ...

  3. 逐行粒度的vuex源码分析

    vuex源码分析 了解vuex 什么是vuex vuex是一个为vue进行统一状态管理的状态管理器,主要分为state, getters, mutations, actions几个部分,vue组件基于 ...

  4. Wireshark抓包常见问题解析(转)

    1. tcp out-of-order(tcp有问题) 解答: 1). 应该有很多原因.但是多半是网络拥塞,导致顺序包抵达时间不同,延时太长,或者包丢失,需要重新组合数据单元 因为他们可能是通过不同的 ...

  5. Promise https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544

    在JavaScript的世界中,所有代码都是单线程执行的. 由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行.异步执行可以用回调函数实现: function ca ...

  6. 【python小随笔】函数的初始化与私有化

    1:初始化 class test(object): def __init__(self,name):#初始化函数 self.name = name#构造初始化一个变量为类的全局变量, 类的所有函数都可 ...

  7. objectarx之画多段线和画直线

    void CCommonFuntion::DrowPloyLine(AcGePoint2dArray& inputpoints){ if (inputpoints.length() < ...

  8. 两种最常用的 HTTP 方法:GET 和 POST。

    什么是 HTTP? 超文本传输协议(HTTP)的设计目的是保证客户机与服务器之间的通信. HTTP 的工作方式是客户机与服务器之间的请求-应答协议. web 浏览器可能是客户端,而计算机上的网络应用程 ...

  9. 笔记:在 Windows 10 WSL Ubuntu 18.04 安装 Odoo12 (2019-06-09)

    笔记:在 Windows 10 WSL Ubuntu 18.04 安装 Odoo12 原因 为了和服务器一样的运行环境. 使用 Ubuntu 运行 Odoo 运行更快. 方便使用 Windows 10 ...

  10. phpcms url路由规则、多站点、PC手机切换

    解决一个分站点pc手机共存的问题 首先需要有PC手机两套模板.通过修改url路由规则,在同一目录下生成PC手机两套静态网站,PC使用默认url路由规则,手机端使用文件名追加“_m”的路由规则. 然后通 ...