
导读:“达观杯”文本智能信息抽取挑战赛已吸引来自中、美、英、法、德等26个国家和地区的2400余名选手参赛,目前仍在火热进行中(点击阅读原文进入比赛页面,QQ群见上图或文末二维码)。达观数据目前已经举行过两次围绕比赛的技术直播分享,并开源了baseline模型。本文是这两次技术直播的内容总结,包括信息抽取传统算法和前沿算法详解、比赛介绍,以及比赛baseline模型代码分析和改进建议。
在前半部分,达观数据的联合创始人高翔详细讲解了自然语言处理中信息抽取算法技术。在后半部分,达观数据的工程师们分享并介绍了“达观杯”文本信息抽取挑战赛的baseline代码以及改进建议。最后,针对参赛选手和其他观众的疑问,三位专家也一一做了解答。
作者介绍
高翔是达观数据联合创始人,达观数据前端产品组、文本挖掘组总负责人;自然语言处理技术专家,负责文本阅读类产品、搜索引擎、文本挖掘及大数据调度系统的开发工作,在自然语言处理和机器学习等技术方向有着丰富的理论与工程经验。
目录
第一部分:文本信息抽取详解
第二部分:“达观杯”baseline代码分享
第三部分:问题答疑
第一部分:文本信息抽取详解


自然语言处理真正的黄金时期是从上世纪90年代开始,那时候我们搞了统计学,做了很多基于统计机器学习的算法。从下图中我们可以发现,统计模型的效果让自然语言处理的应用领域更加广泛,产生了很大进步。其实在上世纪90年代的时候,自然语言处理已经可以在很多场景表现得很不错了,比之前的技术要先进很多。

从2006年到现在,深度学习已经开始起步。之前“神经网络”这个概念已经有了,只是当时受限于各种各样的算法和硬件,没法做得很好。但现在各方面都成熟之后,大家发现深度学习是一个神器。其实深度学习最早的时候在图像领域的应用较多,但目前自然语言处理也逐渐开始过渡到深度学习的阶段。尤其是去年像BERT这样的模型出来之后,我们发现自然语言处理的评测经常被屠榜,这说明神经网络非常有效,但也说明数据也很重要,后文中我们会解释数据的重要性。

我们对比一下人类和计算机之间的差异。其实我们人类短时间内阅读理解文字的能力还不错,但是时间久了很容易遗忘。但计算机基本不会忘,只要硬盘不坏。人脑难以长期记忆,但我们对内容的推理能力比计算机强。因此,我们可以请计算机来做一些比较细节的工作。例如文字比对,我们检查错误要逐字逐句地看,非常累。计算机能做到秒看,却很难做复杂的逻辑和推理。
我们在接受信息时能很快地理解整体,但是难以记住细节。我们看完一个东西立刻能知道它的中心思想。例如,我们浏览了一个企业的信息之后,就能做出“这个企业比较靠谱,愿意投资”的判断。但是企业收入、竞争利润、负债这些具体数字很难全部记清楚。所以人去寻找局部信息的能力和计算机比非常慢。计算机的优点就是找这种局部信息,越细的东西它找得越快。

其实在一些比较固定的,相对简单,不需要特别复杂的逻辑推理的场景中,机器学习算法已经可以完成信息抽取任务。我们正努力让计算机在这些场景落地,这不仅仅是算法的问题,也是应用的问题。这也是我们一直在思考的问题。
抽取算法概述
现在我们具体讲讲信息抽取的几种最主流的算法。
什么是信息抽取?其实就是从文本中找到指定类型的实体。大家应该听过命名实体识别(NER),其实命名实体识别只是抽取中的一种。广义上的信息抽取,除了命名实体识别之外,还包括关系抽取、事件抽取等。其实在我看来,关系抽取和事件抽取比命名实体识别的应用层次更高级一点。因为这两个抽取同需要做NER,只是在做NER的基础之上,还要做一些其他的工作,来满足场景需求。
我们先从最简单的NER开始。命名实体一般是指人物、地点、机构、时间等内容。现在我们以公司抽取为例详细说明一下。

但是你会发现这种场景并不常见。比如,如果抽取所有公司(不仅限于上市公司)就不能用这种办法,因为公司实在太多了。十年前如果你看到“饿了么”,如果没有上下文,你不会觉得这是一个公司,但因为现在大家经常点“饿了么”,都知道这是一个公司的名字。而且,每天都有大量新公司产生,所以整体的公司是一个没法穷尽的集合。在这种情况下,我们没办法用字典很好地完成绝大多数任务。

但这样做也有很大的问题,因为我们语言表述的方法太多了。例如,“我是A公司的”,“我来自B公司”以及很多种其他不同的表述都是一个意思,我们无法穷尽所有的表述方法。甚至周星弛的电影也能增加这种做法的难度。我们以前说“我先走了”,现在会说“我走了先”、“我吃了先”,这其实跟我们传统的语法都不太一样,但现实生活中就有这么多表述。不过,和上面的字典类似,在特定的场合,比如一些特定领域的公文等文书文章,还是有套路或者标准写法,也许可以用这种方法。总的来说这种方法比较简单。

更高级的是基于统计机器学习的方法,从算法上来说是用序列标注的方式来做。这种方法要求我们标注数据,例如上图中我们标注了一句话:“达观数据是人工智能公司”。现在它会预测“上海的虚拟数据”中的“虚拟数据”也是一家公司。它是怎么做到的?后文会详细介绍。这种做法就跟模板匹配完全不一样了。在图中,可能第一个预测“虚拟数据是人工智能公司”还有模板的性质,但后面两个表述和前面完全不同,所以这种基于统计机器学习的方式有了一定的预测能力。
但问题是什么?它需要两个条件。首先是数据。大部分的机器学习都是监督学习,要做数据标注。而且我们传统机器学习经常要做特征工程。甚至在很多任务中,一个特征工程可能要占到我们项目时间和精力的90%。我们之前参加CIKM评测并拿到冠军的任务中,就耗费了大量时间构建特征。举个例子,我们实际工作中完成文本分类任务的时候,仅仅把文字的长度这个特征加进去,效果一下子提升了很多。这种特征我们很难想到。特征的选择可能有时候还有一定的逻辑推理,但有的时候就是拍脑袋。所以特征工程做好是很难的,需要很多的经验,还需要有扩散性的思维。
此外训练和预测需要很多计算资源。 某些机器学习(尤其是传统的机器学习)的训练过程中,特征有时候会特别耗费内存,可能不一定训练得完,所以对机器有一定的限制。当然,现在做深度学习,限制可能是GPU。深度学习相对于传统机器学习,对数据量地要求更高。因为传统的机器学习模型的各种参数没有深度学习这么多。


上图还可以看到,在分词之外,命名实体我们用另外一个标签集。我们做词性分析可能用不同的标签集。可以看到,不同的标签集可以用来做不同的事情。所以无论是传统的机器学习,还是深度学习,我们都是在解决一个叫做“序列标注”的问题。所以标签集和标注方式都是基础的、几乎是一样的。有什么样不同?后文会具体讨论。
传统抽取算法介绍
其实传统抽取算法有很多,这里会介绍一些大家比较常用,也比较好理解的模型。第一个模型叫生成式模型。生成式模型的一个代表就是隐马尔科夫模型(HMM)。另外一个是判别式模型,代表是条件随机场(CRF)。这两个模型都结合了概率论还有图论的一些内容,也都基于统计机器学习的算法。它们都能根据训练集训练出不同的结果。下面我们详细介绍一下这两个模型。
我人生第一次做序列标注任务的时候,用的就是HMM模型。马尔可夫这个名字一听就像是个数学很厉害的俄国人,但其实HMM模型并不难。大家只要记住两部分内容:两个序列、三个矩阵。如下图所示。我们要做的就就是把这五个部分定义好,整个模型和要解决的问题就定义清楚了。


第一个是初始状态矩阵。 我们现在举的例子都是有序列标注,例如多轮分词。下图是一个真实的多轮分词模型里面的图,这是我们自己训练的一个模型。可以看到,初始状态只可能是S(ingle)或B(egin),因为不可能从代表词结尾的标记开始一个句子。所以我们要从所有的语料中统计,单字词S和多字词B开始的概率是多少。仅仅统计这两个矩阵就可以,因为其他两个标记M(iddle)和E(en)是不可能出现在句首的。图中的概率有负数,是因为经过log和相关处理,从而可以方便后续的计算,但本质的含义还是概率。



解码算法基本是用Viterbi来做。当然你也可以把当前最好的状态输出来,找到在当前序列下能够输出的最大标签,通过自己的一些解码逻辑(比如B后面一定是M或者E,不可能是S)优化一些内容。但我们经常还是用Viterbi去做整体的解码,取得最优路径的概率。Viterbi解码算法大家一定要掌握,因为后面有有不少算法与它类似。只要把Viterbi学会了,后面的很多东西就很好理解了。
HMM是我个人学的第一个模型,但是我现在基本上不用这个模型。为什么不用?因为它的效果还是相对差一点。但它也有优点。因为做极大似然估计就是简单的统计,速度非常快。所以这个模型的更新可以做到秒级。你做一个数据的修改,跑一遍立刻把数据统计出来,修改矩阵以后很快就对这个模型做一个更新。所以在项目的初始阶段,我们可以快速地用这个方法来做baseline或者动态的修改。尤其在实际业务中,可能客户做了一些修改后他需要实时知道反馈,这时候可以用HMM,虽然可能不能保证有好的效果。

在实际应用中我们用的最多还是条件随机场(CRF)。因为CRF往往效果更好。下图说明了HMM和CRF的关系是什么,我们可以看到一个HMM是链式传递,但加上一个条件就是我们最常见的链式条件随机场。通用CRF就是下图中右下角的图,但是我们做序列标注的话可能是最下面一行中间的这个图,也就是链式的CRF。它跟上面一行的图的区别是什么?大家可以看到下面一行图中有好多小的黑色正方形,这就是我们说的条件。我们是如何得出条件的?下面我们就来介绍一下如何通过真实训练得到条件。


首先看第一个特征:U00: %X[-3,0]。 U00表示把我们要研究的字左边的第三个字作为特征,向量后一个数0表示我们没有添加人工特征。我们把这些拼接起来就是一个最终的特征。


下面这张图代表了标签之间的转移,这跟HMM非常像,也可以算出来。所以CRF最终在一个全局最优的情况下达到了一个最优点。我们可以存储这个最优点情况下每一个特征的值,用来解码。

CRF的解码较为简单,我们根据当前序列的位置,根据特征的模板生成很多特征函数,直接去查我们的模型,找到其对应的特征函数权重,之后每一个特征函数权重加起来。查到这个特征函数就把相应的权重取出来,加起来,没有查到就是0,就不用去做了,最终有一个得分,这样每一个标签都会有相关的得分。这个字生成的Score会有BEMOS相对应的,最终得到一个图,我们就用Viterbi解码,跟前面一样就能解出来了。
以上内容就是HMM和CRF这两个传统的算法。
基于深度学习的抽取算法
经典机器学习的很多算法需要比较强的数学功底,通过数学公式做出优美完整的论证。但现在经典机器学习算法的收益已经没有以前大了。原因如下图所示,图中列出了文本挖掘领域中,经典的机器学习和深度学习的对比。

而深度学习不在乎特征。模型定好之后只管输入,有了输入就能输出一个最好的结果。基本不用改代码的,只需要调参。如果数据小,还需要修改一下过拟合方面的东西就可以了。但是用经典机器学习做特征工程可能要改很多代码才能做出一个非常好的特征,这就是传统机器学习和深度学习最大的区别。
用深度学习做文本处理基本绕不开LSTM。虽然现在有很多模型,但也采用LSTM做baseline。下面是一篇著名的介绍LSTM的文章的截图,建议大家看一下原文。文章中最精华的就是下面四张图,展示了LSTM的工作原理。
第一个步骤是单元状态丢弃(如下图)。 图中有两个量x_t和h_t-1。x_t就是当前的输入,h_t-1是上一时刻的隐层的输出。这个公式求出来一个0-1之间的值,决定要留下多少东西。(任何东西乘以0-1其实就是计算要留多少东西,乘以0什么都留不了,乘以1就都留下,乘0.8就留80%。)
第二步新信息的选择。 当前输入包括上一时刻隐层的输出和当前的输入。这一步骤判断应该留下来多少内容。它还是计算两个系数,一个i_t,这也是一个0-1之间的值。第二个是C_t,表示当前cell的状态。计算完毕后需要把这两个系数的值保存下来。

第三步是更新状态。 上面一步已经决定可以留下的新内容和老内容。这一步要决定如何组合新老内容。老内容可以乘以第一步计算出的f_t,新内容可以乘以第二步算出来的i_t,然后把新老内容相加,就是最新的状态了。

第四步是得出最后的输出值。 Cell不会一股脑输出,而是计算出了系数o_t和状态相关的函数结果相乘后得出输出。

以上四步定义了LSTM基本的原理。LSTM其实提出来已经很多年了,在很多场景下都经受了考验。所以希望大家一定要把上面介绍的基础原理了解好。
下图显示了基于深度学习的信息抽取技术Bi-LSTM+CRF的原理。这个方法代表了深度学习和传统的机器学习一个很好的结合。传统CRF最大的问题是特征很稀疏,想做一个很好的特征要花费很多时间。我们可能会有几套比较经典的特征,但不一定保证效果最好,特别是训练数据发生变化以后。而词向量和Bi-LSTM可以做很多的特征提取工作。

如果不用CRF,可能整体效果还不错,但会出现很多badcase。比如B后面出现S,S后面出现O。因为算法只考虑当前的最优输出,没有考虑整个序列的最优结果。而CRF是一个考虑全局的算法,也考虑到标签间的转移概率。所以用CRF会得到一个比较可控的结果。
总得来说,上图介绍的Bi-LSTM+CRF方法,结合了CRF和Bi-LSTM,把“小明去达观数据开会”这几个字变成向量,通过中间的Bi-LSTM隐层,提取出来高维的特征,输入CRF层,CRF最后就会给出标签和结果。
下面我们会介绍这篇文章最重要的部分:预训练模型。深度学习除了不用做大量的特征工程,还可以对文本做非常好的表示。这里的例子是用Word2Vec做出词向量,然后用TensorBoard可视化,如下图所示。

上图用的是Word2Vec模型。下图还有一些其他的模型,比如Glove。这两个模型都是静态表示。静态表示有天然的缺陷,例如它们很难区分“苹果好吃”和“苹果手机”中的两个“苹果”。就好像我们学技术的时候什么都想学,但因为时间是有限,所以每种技术学得都不够深入。

所以从2018年开始,出现了很多新的预训练模型,不少模型都用《芝麻街》里怪物的名字命名,比如ELMO、BERT和ERNIE。除此之外还有微软的MASS,Google最新的XLNet等等。这些模型本质上都用深度学习的神经网络做表示,虽然有的用Attention,有的用Transform,但本质差别不大。
这些模型和Word2Vec/Glove最大的区别在于它们是动态模型。下图是一个真实的例子。输入“苹果好吃”和“苹果手机”后,用BERT对每个字建模,发现前两个字的向量很不一样。这说明BERT可以根据不同的上下文语境编码每个字,或者说可以根据上下文语境对同一个字做出不同的表示。

BERT可以根据上下文,对同一个字做出不同的表示
如何选择预训练模型呢? 我建议大家可以都尝试一下。大部分同学都可以训练ELMO,它的结构和LSTM很像,我们可以自己训练一个语言模型。BERT训练的成本就要高很多,但现在已经有一些其他的框架或语言做处理。我们自己用中文维基百科训练BERT只用了几天,也没有用很多显卡,当然我们也做了不少优化工作。可以先试着用Word2Vec看看效果,有可能效果已经很不错。关键在于要找到在能力范围内按时训练完的模型。
抽取算法在达观的具体实践
首先我们要注重场景。 应用场景一般就是客户提供的文档,包括财务报表、基金合同等等。文档处理的核心是自然语言处理,特别是抽取技术。我们也需要考虑实际应用,结合一些其他的工程技术,比如外部系统、分布式技术、数据库技术等等。


还有一种方法是非监督的Embeddin的学习。 下图是我们的一个真实的例子。当时登贝莱刚转会到巴塞罗那俱乐部。我们用标准语料去训练,发现“登贝莱”这个名字一定会被切开,无论怎么训练分词都不行。潜在的解决方法之一是增加很多登贝莱相关的标注数据,但是这么做收益不足。所以我们就找了很多外部的语料做嵌入。

除了NER,还可以抽取别的内容。例如知识图谱就要做关系抽取。输入一句话,“美国总统特朗普将考察苹果公司,该公司由乔布斯创立”,怎么抽取关系?有两种方法。一种方式是把实体抽出来,然后两两实体做一些分类,分到一些关系里面。另一种依靠序列标注,也就是基于联合标注的方法。这么做的好处是不用修改标注框架。


所以我们最终的思考是:第一要尽可能地收集数据、理解数据,这是所有做机器学习的同学第一步就应该做的事情。我们应该去分析数据、看数据,而不是一开始就上模型。如果不做数据清洗,好数据、乱数据、脏数据都在里面,模型是做不好的。就像教孩子一样,如果好的坏的都教,他就不知道什么是好坏了。而且我们要分析问题的本质,选择合适的模型。例如,对于已有数据的数据量,选先进模型有用吗?如果没有用,就要赶紧去收集数据。
而且在任务一开始的阶段,我比较推荐大家做传统的机器学习,因为这些模型比较现成,也比较通用。在做了一个非常好的baseline之后,你就知道底线在哪,然后再引用深度学习。去年的达观杯我们就发现很多参赛者一上来就在用深度学习,结果做了各种调参,效果还不如我们自己20行代码的传统的机器学习。所以刚开始的时候一定要让传统机器学习帮助你,这样你更有信心做后面的事情。另外,这句话一定要送给大家:“数据决定效果上限,模型逼近此上限”,所以大家一定要重视数据清理,数据的分析真的比调参调模型收益更大。
如果遇到疑难杂症,端到端技术经常会有惊喜,但不能保证每次都有惊喜。大家在学习的过程中一定要关心最前沿的技术。
做机器学习肯定会遇到失败和挫折,重要的是从挫折中总结规律才是最重要的,不要被同一个坑绊。这样的经验很难依靠别人教会,因为所处的环境、场景、场合、数据不可能完全一致,所以需要有自己的思考。
最后,看完了这篇文章能做什么呢?可以参加我们的“达观杯”文本智能信息抽取挑战赛。这是我们第三次组织“达观杯”比赛。比赛的一等奖有30000元奖金,二等奖2支队伍有10000元的奖金,三等奖有5000元的奖金,优胜奖还有3000元。除此之外,TOP30同学直接直通面试。

比赛数据有两部分,一部分是有标注的数据,另外一部分是一个规模达到上百万的非标注的数据。比赛的关键就是如何利用这些非标注的数据来提升整个模型的效果。而这就是我们最终在实际生活和工作中遇到的问题:只有少量标注数据,但是有大量的未标注数据。欢迎大家在比赛中实际运用一些算法和理论。因为有时候光看别人的分享难以获得深刻的理解,但是经过“达观杯”这样的比赛就能把知识掌握地更好。

比赛页面: Introductionbiendata.com

第二部分:“达观杯”baseline代码分享
在前一章中,高翔老师给大家提到过做命名实体识别的几种方式:1) 基于规则;2)基于机器学习;3)基于深度学习。因为这次达观杯比赛的数据经过了特殊处理,所以没法用基于规则的方法做。在这里我们介绍一下后两种方法。
对于传统的机器学习算法来说,特征工程是特别重要的一项,常常会占用我们特别多的时间。而且baseline提供的算法来说,设计特征模板也是一个重要的步骤,它会影响最后出来模型的整体效果。
而如果要用深度学习的方法做信息抽取,就需要比较多的机器资源,可能还需要更多的标注数据,才能在深度学习的算法上获得较好的效果。
下面我们看一下baseline代码。首先需要引入相关的库:
import codecs
import os
整个代码分成以下5个部分:
# 0 install crf++ https://taku910.github.io/crfpp/
# 1 train data in
# 2 test data in
# 3 crf train
# 4 crf test
# 5 submit test
首先我们需要CRF++工具,大家可以到https://taku910.github.io/crfpp/下载工具。然后我们可以分析一下代码:
第一步:处理训练数据
# step 1 train data in
with codecs.open('train.txt','r', encoding='utf-8')as f:
lines = f.readlines()
results =[]
for line in lines:
features =[]
tags =[]
samples = line.strip().split(' ')
for sample in samples:
sample_list = sample[:-2].split('_')
tag = sample[-1]
features.extend(sample_list)
tags.extend(['O']* len(sample_list))if tag =='o'else tags.extend(['B-'+tag]+['I-'+ tag]*(len(sample_list)-1))
results.append(dict({'features': features,'tags': tags}))
train_write_list =[]
with codecs.open('dg_train.txt','w', encoding='utf-8')as f_out:
for result in results:
for i in range(len(result['tags'])):
train_write_list.append(result['features'][i]+'\t'+ result['tags'][i]+'\n')
train_write_list.append('\n')
f_out.writelines(train_write_list)
在这里大家也可以添加一些其他的特征。对于NLP来说,常见的特征包括词性、词频、词边界、实体的边界等。多加入几个这样的特征,可能会对效果有一些影响。
第二步: 处理测试集
# step 2 test data in
with codecs.open('test.txt','r', encoding='utf-8')as f:
lines = f.readlines()
results =[]
for line in lines:
features =[]
sample_list = line.split('_')
features.extend(sample_list)
results.append(dict({'features': features}))
test_write_list =[]
with codecs.open('dg_test.txt','w', encoding='utf-8')as f_out:
for result in results:
for i in range(len(result['features'])):
test_write_list.append(result['features'][i]+'\n')
test_write_list.append('\n')
f_out.writelines(test_write_list)
第三步:CRF++训练
# 3 crf train
crf_train ="crf_learn -f 3 template.txt dg_train.txt dg_model"
os.system(crf_train)
# Unigram
U00:%x[-3,0]
U01:%x[-2,0]
U02:%x[-1,0]
U03:%x[0,0]
U04:%x[1,0]
U05:%x[2,0]
U06:%x[3,0]
U07:%x[-2,0]/%x[-1,0]/%x[0,0]
U08:%x[-1,0]/%x[0,0]/%x[1,0]
U09:%x[0,0]/%x[1,0]/%x[2,0]
U10:%x[-3,0]/%x[-2,0]
U11:%x[-2,0]/%x[-1,0]
U12:%x[-1,0]/%x[0,0]
U13:%x[0,0]/%x[1,0]
U14:%x[1,0]/%x[2,0]
U15:%x[2,0]/%x[3,0]
# Bigram
B
第四步: CRF++生成预测结果
# 4 crf test
crf_test ="crf_test -m dg_model dg_test.txt -o dg_result.txt"
os.system(crf_test)
第五步:生成可提交的文件
# 5 submit data
f_write =codecs.open('dg_submit.txt','w', encoding='utf-8')
with codecs.open('dg_result.txt','r', encoding='utf-8')as f:
lines = f.read().split('\n\n')
for line in lines:
if line =='':
continue
tokens = line.split('\n')
features =[]
tags =[]
for token in tokens:
feature_tag = token.split()
features.append(feature_tag[0])
tags.append(feature_tag[-1])
samples =[]
i =0
while i < len(features):
sample =[]
if tags[i]=='O':
sample.append(features[i])
j = i +1
while j < len(features)and tags[j]=='O':
sample.append(features[j])
j +=1
samples.append('_'.join(sample)+'/o')
else:
if tags[i][0]!='B':
print(tags[i][0]+'error start')
j = i +1
else:
sample.append(features[i])
j = i +1
while j < len(features)and tags[j][0]=='I'and tags[j][-1]== tags[i][-1]:
sample.append(features[j])
j +=1
samples.append('_'.join(sample)+'/'+tags[i][-1])
i = j
f_write.write(' '.join(samples)+'\n')
第三部分:问答环节
关于比赛:数据,baseline 问:比赛的训练数据都是词向量吗? 达观数据工程师: 不是的,由于我们数据的特殊性,我们的数据都是字符级别的。因为我们的数据已经做了脱敏处理,分词的特征已经没有了。 问:Baseline模型可以到多少分? 达观数据工程师: Baseline非常简单,如果装了CRF++工具,能够马上跑出来,大概能有0.85的F1。大家如果选到更好的特征模板,就能把CRF调到一个更高的分数。因为CRF本身也是很有门道的,可能需要花一些时间,不过研究一下会很有收获。 问:比赛中提供的未标注数据有什么用?
达观数据工程师: 我的看法是用来训练语言模型,如果你有一些别的特别酷炫的想法也可以尝试。因为提供未标注数据的初衷,是我们看到NLP最近一年的发展,自从ELMo、BERT出现,后面还有XLNet,这些模型都是在告诉我们NLP其实也可以借鉴一下CV超大数据量预训练模型的思路。因为在NLP领域标注的数据非常难获取,其实NLP的数据比CV的数据更难标,但是我们有大量无监督数据,比如神奇的被翻来覆去调教了N次的维基百科,这种未监督数据量足够大,你总能发现里面的语言学规律,这里面的规律可以用来做特征,来增强模型的泛化。特别是现在做文本相似度以及做NER等基础任务,用了BERT以后泛化能力会提高很多,BERT现在经常被作为基础的特征提取模型。 问:为什么我的模型分数只有 0.72?
高翔: 其实就如前文所说,应该先研究一下数据,并用传统的方法提出一些baseline模型。否则就不知道这个任务的底线,也可能会出现过拟合。我们自己内部用Python串起来十几行代码,就能跑到0.8+。我觉得不到0.8可能是出现了过拟合,没有使用预训练数据,只是使用了标注数据。所以建议先用标准模型试试,得到一个baseline,获得一些信息,再去做一些比较复杂的模型。 比赛相关技术:调参,BERT,ELMo,LSTM和CRF 问:如何调参? 高翔: 这个问题特别深奥。很多情况下我们把一些同学叫“调包侠”,他们没有很好地理解算法本质,只是在瞎调。比如我曾经遇到一个同学在LSTM里把ReLu当成激活函数。但LSTM要求输出为0-1,而ReLu的输出范围是0到无穷大,所以梯度直接就爆炸了。我觉得调参有两个重要的方面,首先是经验的积累,这点只能靠自己;其次需要对模型和数学有一定的了解,这些不会直接告诉你如何调参,但是能给你一些灵感和方向。我也建议大家搜索一些网上的经典套路。 问:BiLSTM+CRF能用于比赛吗?
达观数据工程师: 如果用深度模型也可以,但是我们这次比赛的数据量有点少,用深度学习模型的话很容易过拟合。目前已经有不少参赛选手反馈,用BiLSTM+CRF模型调参,不管怎样调,结果甚至还不如CRF随便跑一下好。这是因为我们给的训练集只有17000条,而且并不是每一条都有标注的,所以训练集比较少。所以大家如果要做的话,就需要尝试用训练语言模型的方式去做深度学习模型了。
问:BERT+BiLSTM+CRF呢?
达观数据工程师: 如果是用于我们这个比赛,我怀疑你在BERT的训练过程中会过拟合。 问:BERT能不能把比赛数据解密? 达观数据工程师: 我觉得逆向解密可能跟BERT关系不大,跟你的统计能力以及侦探小说看得多不多有关系。 问:如何使用ELMo能训练出更好的词向量? 高翔: 这个要看与什么比较。我们的实践经验不一定跟你相符。我们发现,ELMo训练出来的东西的确会比Word2Vec会好,而且要好不少,但跟BERT相比还是会差一些。如果你要训练一个不停地迭代的模型,可能花很多时间调参,但是可能没有换掉整个模型框架的收益大。因为BERT效果的确要好很多,无论从机制还是attention思路来说,都会比简单的LSTM这种方式做得更好。
达观数据工程师: 虽然BERT很难用于本次比赛,但我觉得ELMo也可以用在比赛里。ELMo有两种方式,一种是自己分词,然后再进LSTM。还有一种是直接用字向量。你其实可以跳过自己分词,直接把每个字当成ELMo中的词向量来训练。 比赛给出的未监督数据不可能到维基中文数据的量级。所以我个人建议是从ELMo这样的Baseline开始,看ELMo会不会在比赛数据量规模上过拟合,如果会的话,可以把ELMo的模型复杂度自己裁剪,或者你用一些更复杂更炫酷的词向量去拼接ELMo。 问:能否再讲解一下BiLSTM+CRF?
达观数据工程师: CRF可以做的东西,BiLSTM+CRF应该都可以做。但是这次比赛没有给分词的信息,所以可以用字向量来做。但是用字向量来做,一是容易过拟合(就像前文提到的数据量不是很多)。如果你们要玩这种深度学习模型,首先要面对的首要问题是过拟合,不过我们已经帮你们排除掉了最容易过拟合的事情,就是词向量。
所以,现在只需要做字向量,而字向量的空间比词向量少了很多。词向量一般来说是几万级的,再乘以常用的200维,这样就容易出现严重的过拟合。
字向量一般是千级别(比如五六千),再乘以一个100维,不过可能还是有可能会过拟合,因为我们的数据量比较少。
这次比赛做的命名实体识别,基本上给的是比较短的文本。你可以做一件很简单的事情,就是做数据增强:随机把2句、3句,甚至4句、5句话拼在一起。拼完以后你的实体还是在原来的位置,这样数据量可以直接变成2倍到3倍。而现在比赛这个量级的数据做BiLSTM+CRF是一定会过拟合的。
当然,你可以有一些更神奇的操作。比如如果你怀疑过拟合主要出现在字向量层或者LSTM层的话,你可以去把字向量层的学习率调低,或者把LSTM层的学习率调低,或者加L2正则化。
另外值得一提的是,我们在比赛中给了一部分未监督语料。未监督语料量级其实也不是特别大,我前两天在比赛群里看到有人在企图训练BERT,我认为这么做不是特别科学。这么小的语料训练BERT一定是训练不出来的。我们也有过BERT的训练,基本上用了整个维基百科的数据。如果数据量少或者质量差的话,都会影响到BERT的训练效果,特别是这个比赛用的数据量级会比维基百科少了太多。
语言模型从ELMo到BERT,都是数据量多大,模型能力就有多大。深度学习一定要记住这样一件事情:数据量多大决定你要用多复杂的模型才不会过拟合。
这个问题回答有点长,但是这是一个相当广泛的,也是一个比较实用的问题。
达观数据工程师: BiLSTM+CRF已经是一个2015年提出来的很老的Baseline了。还有很多很酷炫的方法(比如IDCNN+CRF)也出现了挺久了。它的主要特点是性能高,在上下文关联不是很长,而且对训练速度要求高的情况下可以试一下。
我个人观点,在机器学习这块更好的思路不是唯模型论,而是一个概率编程的思路。也就是说,当你的规则很难去维护时,就说明你的数据量已经足够去做模型了。你可以做一个很小的模型,解决一个很小的问题,然后把这些东西拼起来。 问:数据量规模和神经网络的层数有什么关系,10万样本需要几层网络?
达观数据工程师: 这种玄学问题很难简单地概括清楚。我觉得样本质量比数量重要太多,有时你洗洗数据比你调一两层模型有意义多了。
即使不考虑数据质量,相比样本数量来说,你可以做的数据增强以及你样本当中实际的模式也是很重要的一件事情。如果是标准的NER问题(比如抽取人名、地名、机构名这种实体),而且数据量有10万样本,我觉得LSTM层数差不多1-2层,最多3层就可以了。
但这是一个经验值,如果你有足够的时间,可以用先用BERT去微调(finetune)做一个Baseline,供其他模型参考。然后更重要的是,你怎样去发现是否在这个数据上出现了过拟合。如果你在过拟合这个数据,很多时候并不是LSTM层数的关系。
关于隐层维度的上限,假如你说的是BiLSTM+CRF的话,它的前级特征,比如如何得到字向量和词向量,是否有锁定词向量,以及数据是否有增强,比LSTM的层数重要多了。维度一般都在数百维左右。 问:能否再详细介绍一下数据增强?
达观数据工程师: NER的语料基本是识别一句话,比如“小姐姐某某某来到达观数据” 和“孙杨去参加了游泳比赛”。那么现在我们有了两条语料,你可以这两条语料拼在一起,模型理论上还是应该给出正确结果,但是你喂给模型的语料就变成了三条。
其实模型有可能并不是在过拟合你所理解的那种模式,它其实是在记住数据中相同的东西。 问:长度过长的句子需要截断吗?
达观数据工程师: 这就看你怎么定义“过长”了。比如你统计下来,99%的句子都在200个字以下,你完全可以选择在200个字截断,或者你做了各种花式拼接以后再统计一下。如果有些特别长尾的东西,就可以在那个长度截断。 问:深度学习和传统的机器学习方法,哪个好?
达观数据工程师: 这个问题比较泛,深度学习和传统机器学习方法哪个好一些?机器学习本质上是个实验科学。我认为实验科学的意思就是试一试哪个方法效果好,哪个方法就好。从理论上有时很难推断出来,因为使用的数据经常千奇百怪,存在各种异常。 关于达观数据与招聘 问:比赛排名第31能面试吗?如何发简历?
高翔: 如果你的成绩是第31名,和第30名差了0.01,我们不在乎这种差异,可以直接来。简历可以发到“达观杯”专用投递邮箱maxinyi@datagrand.com,注明参加了“达观杯”比赛。 问:达观工作的氛围如何?
其他的福利,水果、零食、聚餐、团建,大多互联网公司有的也都有。另外还有年度海外游、部门团建基金、不定期各种聚餐、桌游和户外活动。
对于NLPer来说,是一个非常好的选择。公司正处于快速发展期,欢迎有兴趣的小伙伴们加入,可以积极投递简历。
问:只有CV的背景能投NLP吗?
达观数据工程师: 我觉得可以呀,只要你是真的感兴趣。
关于“达观杯”
比赛页面: https://biendata.com/competition/datagrand/?source=pw2
