迁移学习与模型预训练:何去何从

2018年是nlp的收获大年,模型预训练技术终于被批量成功应用于多项nlp任务。之前搞nlp的人一直羡慕搞cv的人,在imagenet上训练好的模型,居然拿到各种任务里用都非常有效。现在情形有点逆转了。搞cv的人开始羡慕搞nlp的人了。cv界用的还是在有监督数据上训练出来的模型,而nlp那帮家伙居然直接搞出了在无监督数据上的通用预训练模型!要知道nlp中最不缺的就是无监督的文本数据,几乎就是要多少有多少。还有个好消息是目前nlp中通用预训练模型的效果还远没达到极限。目前发现只要使用更多的无监督数据训练模型,模型效果就会更优。这种简单粗暴的优化方法对大公司来说实在再经济不过。而且,算法本身的效果也在快速迭代中。nlp的未来真是一片光明啊~
bert发布之后,点燃了nlp各界的欢腾,各路神仙开始加班加点各显神通,很多相关工作被发表出来。本文会介绍其中的一些代表性工作,但更重要的是希望理清这些背后的逻辑,为它们归归类。通过这些思考,我自己也对nlp以后的工作方向有些预测,供大家参考。
本文的内容主要包括以下几部分:
我对迁移学习和模型预训练的一些思考,以及对未来工作方向的粗略预测
各类代表性工作的具体介绍(熟悉的同学可忽略),又细分为以下几大类:
有监督数据预训练
自监督训练
无监督数据预训练
多个有监督数据同时训练:多任务学习
3. 一些我们的实践经验、别人和自己的观点、以及总结和感想
第一和第三部分内容相对少,原创密度大点,大家要是赶时间的话看这两部分就够了。第二部分的内容都是具体技术,有很多很好的文章都介绍过。放在本文当中一是为了文章的完备性,另一个是里面提到的一些知识点在其他地方没怎么提到。第三部分也会涉及到我们(爱因互动)自己在一些任务上的实验工作,期望这些结果能坚定大家在自己的工作中把模型预训练技术用起来。
终于可以开始了。
一、迁移学习与模型预训练:何去何从
▌迁移学习分类
把我们当前要处理的nlp任务叫做t(t称为目标任务),迁移学习技术做的事是利用另一个任务s(s称为源任务)来提升任务t的效果,也即把s的信息迁移到t中。至于怎么迁移信息就有很多方法了,可以直接利用s的数据,也可以利用在s上训练好的模型,等等。
依据目标任务t是否有标注数据,可以把迁移学习技术分为两大类,每个大类里又可以分为多个小类。
第一大类是t没有任何标注数据,比如现在很火的无监督翻译技术。但这类技术目前主要还是偏学术研究,离工业应用还有挺长距离的。工业应用中的绝大部分任务,我们总是能想办法标注一些数据的。而且,目前有监督模型效果要显著优于无监督模型。所以,面对完全没有标注数据的任务,最明智的做法是先借助于无监督技术(如聚类/降维)分析数据,然后做一些数据标注,把原始的无监督任务转变为有监督任务进行求解。基于这些原因,本文不再介绍这大类相关的工作。
第二大类是t有标注数据,或者说t是个有监督任务。这类迁移学习技术又可以依据源任务是否有监督,以及训练顺序两个维度,大致分为四小类:
源任务s是无监督的,且源数据和目标数据同时用于训练:此时主要就是自监督(self-supervised)学习技术,代表工作有之后会讲到的cvt。
源任务s是有监督的,且源数据和目标数据同时用于训练:此时主要就是多任务(multi-task)学习技术,代表工作有之后会讲到的mt-dnn。
源任务s是无监督的,且先使用源数据训练,再使用目标数据训练(序贯训练):此时主要就是以bert为代表的无监督模型预训练技术,代表工作有elmo、ulmfit、gpt/gpt-2、bert、mass、unilm。
源任务s是有监督的,且先使用源数据训练,再使用目标数据训练(序贯训练):此时主要就是有监督模型预训练技术,类似cv中在imagenet上有监督训练模型,然后把此模型迁移到其他任务上去的范式。代表工作有之后会讲到的cove。
何去何从
▌现状分析
先说说上表中四个类别的各自命运。以bert为代表的无监督模型预训练技术显然是最有前途的。之前也说了,nlp中最不缺的就是无监督数据。只要堆计算资源就能提升效果的话,再简单不过了。
而无监督预训练的成功,也就基本挤压掉了自监督学习提升段位的空间。这里说的自监督学习不是泛指,而是特指同时利用无监督数据和当前有监督数据一起训练模型的方式。既然是同时训练,就不太可能大规模地利用无监督数据(要不然就要为每个特定任务都训练很久,不现实),这样带来的效果就没法跟无监督预训练方式相比。
但自监督学习还是有存在空间的,比如现在发现在做有监督任务训练时,把语言模型作为辅助损失函数加入到目标函数中,可以减轻精调或多任务学习时的灾难性遗忘(catastrophic forgetting)问题,提升训练的收敛速度。所以有可能在训练时加入一些同领域的无监督数据,不仅能减轻遗忘问题,还可能因为让模型保留下更多的领域信息而提升最终模型的泛化性。但这个方向迎来大的发展可能性不大。
而类似cv中使用大规模有监督数据做模型预训练这条路,看着也比较暗淡,它自己单独不太可能有很大前景。
几个原因:
1) 这条路已经尝试了很久,没有很显著的效果提升。
2) nlp中获取大规模标注数据很难,而且还要求对应任务足够复杂以便学习出的模型包含各种语言知识。虽然机器翻译任务很有希望成为这种任务,但它也存在很多问题,比如小语种的翻译标注数据很少,翻译标注数据主要还是单句形式,从中没法学习到背景信息或多轮等信息。但从另一个方面看,nlp搞了这么久,其实还是积累了很多标注或者结构化数据,比如知识图谱。如何把这些信息融合到具体任务中最近一直都是很活跃的研究方向,相信将来也会是。只是bert出来后,这种做法的价值更像是打补丁,而不是搭地基了。
多任务学习作为代价较小的方法,前景还是很光明的。多个同领域甚至同数据上的不同任务同时训练,不仅能降低整体的训练时间,还能降低整体的预测时间(如果同时被使用),还能互相提升效果,何乐而不为。当然,多任务学习的目标一开始就不是搭地基。
上面说了这么多,其实想说的重点在下面。这些技术不一定非要单独使用啊,组合起来一起用,取长补短不是就皆大欢喜了嘛。
先回顾下现在的无监督模型预训练流程,如下图:
首先是利用大的无监督数据预训练通用模型,优化目标主要是语言模型(或其变种)。第二步,利用有监督数据精调上一步得到的通用模型。这么做的目的是期望精调以后的通用模型更强调这个特定任务所包含的语言信息。这一步是可选的(所以图中对应加了括号),有些模型框架下没有这个步骤,比如bert里面就没有。第三步才是利用有监督数据中对应的标注数据训练特定任务对应的模型。
那这个流程接下来会怎么发展呢?
▌未来可期
上面我已经对四类方法做了分别的介绍,包括对它们各自前途的简单判断,也介绍了当下效果最好的模型预训练流程。相信未来nlp的很多工作都会围绕这个流程的优化展开。我判断这个流程会继续发展为下面这个样子:
详细说明下每个步骤:
第一步还是利用大的无监督数据预训练通用模型。但这里面目前可以改进的点有很多,比如发展比transformer更有效的特征抽取结构,现在的evolved transformer和universal transformer等都是这方面的探索。发展更有效更多样化的预训练模型目标函数。目前预训练模型的目标函数主要是(masked) lm和next sentence prediction (nsp),还是挺单一的。面向文档级背景或多轮这种长文本信息,未来应该会发展出更好的目标函数。比如有可能会发展出针对多轮对话这种数据的目标函数。
bert主要面向的是nlu类型的任务,目前微软提出的mass、unilm从不同的角度把bert框架推广到nlg类型的任务上了,细节我们之后会讲到。gpt-2利用更大的模型获得了更好的语言模型。更多更好的数据,更大的模型带来的改进有没有极限?目前还不知道,相信很多公司已经在做这方面的探索了。但这个游戏目前还是只有大公司能玩得起,训练通用大模型太耗钱了。提升训练效率,很自然的就是另一个很重要的优化方向。
第二步是利用其他大任务的标注数据或已有结构化知识精调第一步获得的通用模型。这一步不一定以单独的形式存在,它也可以放到第一步中,在预训练通用模型时就把这些额外信息注入进去,比如百度的ernie就是在预训练时就把实体信息注入进去了。既然人类在漫长的ai研究史上积累了大量各式各样的结构化数据,比如机器翻译标注数据,没理由不把它们用起来。相信未来会有很多知识融合(注入)这方面的工作。
第三步和前面流程的第二步相同,即利用当前任务数据进一步精调上一步得到的通用模型。这么做的目的是期望精调后的模型更强调这个特定任务所包含的语言信息。elmo的实验结论是,加入这一步往往能提升下一步的特定任务有监督训练的收敛速度,但仅在部分任务上最终模型获得了效果提升(在另一部分任务上持平)。
另一种做法是把这一步与下一步的特定任务有监督训练放在一块进行,也即在特定任务有监督训练时把语言模型作为辅助目标函数加入到训练过程中,以期提升模型收敛速度,降低模型对已学到知识的遗忘速度,提升最终模型的效果。gpt的实验结论是,如果特定任务有监督训练的数据量比较大时,加入辅助语言模型能改善模型效果,但如果特定任务有监督训练的数据量比较小时,加入辅助语言模型反而会降低模型效果。但ulmfit上的结论刚好相反。所以就试吧。
利用多任务或者单任务建模方式在有监督数据集上训练特定任务模型。多任务的很多研究相信都能移植到这个流程当中。我们之后会介绍的微软工作mt-dnn就是利用bert来做多任务学习的底层共享模型。论文中的实验表明加入多任务学习机制后效果有显著提升。相信在这个方向还会有更多的探索工作出现。在单任务场景下,原来大家发展出的各种任务相关的模型,是否能在无监督预训练时代带来额外的收益,这也有待验证。
总结下,未来nlp的主要工作可能都会围绕这个流程展开。对流程前面步骤的优化带来的收益比后面步骤大,也更难。所以诸君请自己拿捏吧~。
二、各类代表性工作
套用下前面对迁移学习分类的方式,把接下来要介绍的具体模型放到对应的模块里,这样逻辑会更清楚一些。
我们先介绍cove和cvt。
▌有监督模型预训练:cove
cove是在 mccann et al., learned in translation: contextualized word vectors 这个论文中提出的。自然语言中的一词多义非常常见,比如“苹果手机”和“苹果香蕉”里的“苹果”,含义明显不同。以word2vec为代表的词表示方法没法依据词所在的当前背景调整表示向量。所以nlper一直在尝试找背景相关的词表示法(contextualized word representation)。cove就是这方面的一个尝试。
cove首先在翻译标注数据上预训练encoder2decoder模型。其中的encoder模块使用的是bilstm。训练好的encoder,就可以作为特征抽取器,获得任意句子中每个token的带背景词向量:
使用的时候,只要把和拼接起来就行。
论文作者在分类和匹配下游任务对cove的效果做过验证,效果肯定是有一些提升了,但提升也不是很明显。
总结下cove的特点:
预训练依赖于有监督数据(翻译数据)。
cove结果以特征抽取的方式融合到下游任务模型中,但下游任务还是要自定义对应的模型。
▌自监督学习同时训练:cvt
cvt (cross-view training)在利用有监督数据训练特定任务模型时,同时会使用无监督数据做自监督学习。encoder使用的是2层的cnn-bilstm,训练过程使用标注数据和非标注数据交替训练。利用标注数据训练主预测模块,同时构造多个辅助模块,辅助模块利用非标注数据拟合主模块的预测概率。辅助模块的输入仅包含所有输入中的部分信息,这个思想和dropout有点像,可以提高模型的稳定性。不同的特定任务,辅助模块的构造方式不同,如何选输入中部分信息的方式也不同。
例如,对于序列标注任务,论文中以bilstm第一层和第二层的状态向量拼接后输入进主预测模块。而4个辅助模块则使用了第一层的各个单向状态向量作为输入。使用的是第一层前向lstm当前词的状态向量,使用的是第一层后向lstm当前词的状态向量。使用的是第一层前向lstm前一个词的状态向量,而使用的是第一层后向lstm后一个词的状态向量。
作者也在多任务学习上验证了cvt带来效果提升。cvt使用多个标注数据和非标注数据交替训练。使用标注数据训练时,cvt随机选择一个任务,优化对应任务的主模块目标函数。使用非标注数据训练时,cvt为所有任务产生对应的辅助模块。这些辅助模块同时被训练,相当于构造了一些所有任务共用的标注数据。这种共用的训练数据能提升模型收敛速度。作者认为效果提升的主要原因是,同时训练多个任务能降低模型训练一个任务时遗忘其他任务知识的风险。
总结下cvt的特点:
在训练特定任务模型时加入无监督数据做自监督学习,获得了精度的提升。其中辅助模块的构建是关键。
嗯,需要为不同任务定制不同的辅助模块。
应用于mtl问题效果比elmo好。
▌无监督模型预训练
elmo
elmo (embedding from language models) 的目的是找到一种带背景的词向量表示方法,以期在不同的背景下每个词能够获得更准确的表示向量。
elmo的使用过程分为以下三个步骤:
第一步是预训练阶段,elmo利用2层的bilstm和无监督数据训练两个单向的语言模型,它们统称为bilm。
第二步利用特定任务的数据精调第一步得到的bilm。作者发现这步能显著降低bilm在特定任务数据上的ppl,结果如下图。但对特定任务最终的任务精度未必有帮助(但也不会降低任务精度)。作者发现在snli(推断)任务上效果有提升,但在sst-5(情感分析)任务上效果没变化。
第三步是训练特定的任务模型。任务模型的输入是上面已训练bilm的各层状态向量的组合向量。
其中是经过softmax归一化后的权重,是整体的scale参数。它们都是任务模型中待学习的参数。
可以以额外特征的方式,加入到特定任务的输入和输出特征中。作者发现,对于某些任务,把同时加入到输入和输出特征中效果最好,具体见下图。
作者发现,bilm底层lstm的输出状态对句法任务(如pos)更有帮助,而高层lstm的输出状态对语义任务(如wsd)更有帮助。elmo对(标注)数据量少的有监督任务精度提升较大,对数据量多的任务效果提升就不明显了。这说明elmo里存储的信息比较少,还是它主要功能是帮助有监督数据更好地提炼出其中的信息?
总结下elmo的特点:
把无监督预训练技术成功应用于多类任务,获得了效果提升。
elmo以特征抽取的形式融入到下游任务中,所以不同下游任务依旧需要使用不同的对应模型。
elmo改进的效果依赖于下游任务和对应的模型,且改进效果也不是特别大。
ulmfit & siatl
ulmfit (universal language model fine-tuning) 使用和elmo类似的流程:
使用通用数据预训练lm,模型使用了3层的awd-lstm。
在特定任务数据上精调lm,其中使用到差异精调和倾斜三角lr两个策略。
以lm作为初始值,精调特定任务分类模型,其中使用到逐层解冻、差异精调和倾斜三角lr三个策略。经过awd-lstm之后,输出给分类器的向量为三个向量的拼接:。
最后一层最后一个词对应的向量;
最后一层每个词向量做max pooling;
最后一层每个词向量做mean pooling。
论文中提出了几个优化策略,能够提升精调后模型的最终效果。
论文中的实验主要针对各种分类任务,相比于之前最好的结果,ulmfit把分类错误率降低了18-24%。
论文中也设计了实验来说明流程中第二步(在特定任务数据上精调lm)的作用。结果表明第二步的加入,能够让第三步的分类任务在很少的数据量下获得好的结果。只要使用1%~10%的标注数据,就能达到不加第二步时的模型效果。
作者也设计了去除实验验证论文中提出的三个策略的效果:差异精调(discr)、倾斜三角lr(stlr)、逐层解冻(freez)。结果表明相比于其他人提出的策略,这几个策略能获得更好的结果。而且,相比于不使用discr和stlr机制的精调策略(full),ulmfit模型更稳定,没出现灾难性遗忘。
之后的另一篇论文 an embarrassingly simple approach for transfer learning from pretrained language models 建议了一些新的策略,解决精调时的灾难性遗忘问题。模型称为siatl(single-step auxiliary loss transfer learning)。siatl只包含两个步骤:无监督数据预训练lm、精调分类模型。但在精调分类模型时,siatl把lm作为辅助目标加入到优化目标函数当中。siatl的第二步相当于把ulmfit的第二步和第三步一起做了。所以它们的流程其实是一样的。
预训练模型使用的是两层lstm+linear,而分类模型在预训练模型的上面增加了一层带self-attention的lstm和输出层。siatl建议的几个策略:
论文发现辅助lm目标对于小数据集更有用,可能是辅助lm减轻了小数据集上的过拟合问题。其中的系数,论文实验发现初始取值为0.2,然后指数下降到0.1效果最好。的取值需要考虑到和的取值范围。这个结论和ulmfit中验证第二步流程作用的实验结果相同,也侧面说明了它们本质上差不多。
另一个发现是如果预训练用的无监督数据和任务数据所在领域不同,序贯解冻带来的效果更明显。这也是合理的,领域不同说明灾难性遗忘问题会更严重,所以迁移知识时要更加慎重,迁移过程要更慢。序贯解冻主要就是用途就是减轻灾难性遗忘问题。
论文还发现,和ulmfit相比,siatl在大数据集上效果差不多,但在小数据集要好很多。
总结下 ulmfit 和 siatl:
ulmfit使用序贯训练的方式组合特定任务lm和任务目标函数,而siatl使用同时训练的方式,也即加入辅助lm目标函数。
它们建议的策略都是在解决灾难性遗忘问题,也都解决的不错。可以考虑组合使用这些策略。
它们在小数据集上都提升明显,只要使用 1%~10% 的标注数据,就能达到之前的效果。
虽然它们只在分类任务上验证了各自的效果,但这些策略应该可以推广到其他任务上。
gpt/gpt-2
前面介绍的工作中预训练模型用的都是多层lstm,而openai gpt首次使用了transformer作为lm预训练模型。gpt使用12层的transformer decoder训练单向lm,也即mask掉当前和后面的词。
在做精调时,使用最高层最后一个词的向量作为后续任务的输入,类似siatl也加入了辅助lm目标函数。
gpt的另一个大贡献是为下游任务引入了统一的模型框架,也即不再需要为特定任务定制复杂的模型结构了。不同的任务只需把输入数据做简单的转换即可。
gpt在多种类型的任务上做了实验,12个任务中的9个任务有提升,最高提升幅度在9%左右,效果相当不错。
针对预训练、辅助lm和transformer,论文中做了去除实验,结果表明预训练最重要,去掉会导致指标下降14.8%,而transformer改为lstm也会导致指标下降5.6%。比较诡异的是去掉辅助lm的实验结果。去掉辅助lm,只在qqp (quora question pairs)和nli上导致指标下降。在其他任务上反而提升了指标。作者观察到的趋势是辅助lm对于大的数据集比小的数据集更有帮助。这也跟ulmfit和siatl中的结论相反。
总结下gpt的主要贡献:
验证了transformer在unsupervised pretraining中的有效性。
验证了更大的模型效果更好:6 --> 12 层。
为下游任务引入了通用的求解框架,不再为任务做模型定制。
之后openai又训练一个更大的模型,叫gpt-2。gpt-2把gpt中12层的transformer提升到48层,参数数量是gpt的十几倍,达到了15亿。
gpt-2依旧使用单向lm训练语言模型,但使用数量更多、质量更好、覆盖面更广的数据进行训练。而且,gpt-2没有针对特定模型的精调流程了。作者想强调的是,预训练模型中已经包含很多特定任务所需的信息了,只要想办法把它们取出来直接用即可,可以不用为特定任务标注数据,真正达到通用模型的能力。
那,没有精调如何做特定任务呢?一些任务说明如下:
不做精调的gpt-2不仅在很多特定任务上已经达到了sota,还在生成任务上达到了吓人的精度。
bert
和gpt一样,bert的基本模型使用了transformer,只是模型又变大了(12层变成了24层)。
相比于gpt的单向lm,bert使用了双向lm。但显然预测时不能让待预测的词看到自己,所以需要把待预测词mask掉。bert建议了masked lm机制,即随机mask输入中的k%个词,然后利用双向lm预测这些词。
但mask时需要把握好度。mask太少的话,训练时每次目标函数中包含的词太少,训练起来就要迭代很多步。mask太多的话,又会导致背景信息丢失很多,与预测时的情景不符。而且,简单的mask会带来预训练和精调训练的不一致性:精调阶段,输入数据里是不mask词的。
bert建议了以下的策略,解决这些问题:
bert的另一大贡献,是引入了新的预训练目标next sentence prediction (nsp)。对于两个句子a和b,nsp预测b是不是a的下一个句子。训练时nsp的正样本就是从文档从随机选的两个临近句子,而负样本就是b是随机从文档中选取的,与a的位置没关系。nsp可以学习句子与句子间的关系。
预训练的目标函数是masked lm和nsp的加和。
bert的输入词向量是三个向量之和:
token embedding:wordpiece tokenization subword词向量。
segment embedding:表明这个词属于哪个句子(nsp需要两个句子)。
position embedding:学习出来的embedding向量。这与transformer不同,transformer中是预先设定好的值。
bert也为下游任务引入了通用的求解框架,不再为任务做模型定制。对于分类和匹配任务,下游任务只要使用第一个词[cls]对应的最上层输出词向量作为分类器的输入向量即可。对于抽取式qa和序列标注问题,使用每个词对应的最上层输出词向量作为下游任务的输入即可。
bert的惊艳结果,引爆了nlp行业。bert在11个任务上获得了最好效果,glue上达到了80.4%,提升了整整7.6个点,把squad v1.1 f1又往上提升了1.5个点,达到了93.2 。
bert的去除实验表明,双向lm和nsp带了的提升最大。
另一个结论是,增加模型参数数量可以提升模型效果。
bert预训练模型的输出结果,无非就是一个或多个向量。下游任务可以通过精调(改变预训练模型参数)或者特征抽取(不改变预训练模型参数,只是把预训练模型的输出作为特征输入到下游任务)两种方式进行使用。bert原论文使用了精调方式,但也尝试了特征抽取方式的效果,比如在ner任务上,最好的特征抽取方式只比精调差一点点。但特征抽取方式的好处可以预先计算好所需的向量,存下来就可重复使用,极大提升下游任务模型训练的速度。
后来也有其他人针对elmo和bert比较了这两种使用方式的精度差异。下面列出基本结论:
总结下bert的主要贡献:
引入了masked lm,使用双向lm做模型预训练。
为预训练引入了新目标nsp,它可以学习句子与句子间的关系。
进一步验证了更大的模型效果更好:12 --> 24 层。
为下游任务引入了很通用的求解框架,不再为任务做模型定制。
刷新了多项nlp任务的记录,引爆了nlp无监督预训练技术。
mass
bert只能做nlu类型的任务,无法直接用于文本产生式(nlg)类型的任务,如摘要、翻译、对话生成。nlg的基本框架是encoder2decoder,微软的mass (masked sequence to sequence pre-training)把bert推广到nlg任务。mass的结构如下,它的训练数据依旧是单句话,但是会随机mask这句话中连续的k个词,然后把这些词放入decoder模块的相同位置,而encoder中只保留未被mask的词。mass期望decoder利用encoder的信息和decoder前面的词,预测这些被mask的词。
比较有意思的是,bert和gpt都是mass的特例。当k=1时,也即随机mask单个词时,mass就退化成bert;当k=句子长度时,也即mask所有词时,mass就退化成gpt,或者标准的单向lm。
论文中使用了4层的transformer作为encoder和decoder,跟encoder使用bert,decoder 使用标准单向lm的框架bert+lm做了效果对比,ppl上降低了不少。而且作者也对比了k取不同值时的效果变化,结果发现在多个任务上它取50%句子长度都是最优的。
为什么mass能取得比较好的效果?作者给出了以下解释:
encoder中mask部分tokens,迫使它理解unmasked tokens。
decoder中需要预测masked的连续tokens,让decoder能获取更多的语言信息。
decoder中只保留了masked的tokens,而不是所有的tokens,迫使decoder也会尽量从encoder中抽取信息。
作者也做了两个去除实验验证上面的后两条解释。
总结下mass的特点:
把bert推广到nlg类型任务,并且统一了bert和传统单向lm框架。
实验表明mass效果比bert+lm好,但实验使用的模型太小,不确定这种优势在模型变大后是否还会存在。
unilm
unilm (unified pretrained language model)是微软另一波人最近放出的论文。unilm同时训练bert中的双向lm、gpt中的单向lm和seq2seq中的lm。用的方法也很自然,核心思想在transformer那篇论文中其实就已经在用了。
unilm中的核心框架还是transformer,只是用无监督数据预训练模型时,同时以双向lm、单向lm和seq2seq lm为目标函数。这些目标函数共享一个transformer结构,训练也都使用了类似bert中的[mask]机制。
和bert的双向lm不同的是,单向lm在做self-attention时不能使用这个词后面的词。seq2seq lm在做decoder 预测时也有类似的约束,做self-attention时能使用encoder中的所有词,以及decoder中当前词(替换为[mask]了)和前面的词,而不能使用decoder中这个词后面的词。unilm在做self-attention时通过mask机制来满足这些约束,也即在softmax函数中把后面词对应的向量元素值改为-∞。
seq2seq lm是把两个句子拼起来(和bert相同)直接输入一个transformer(只是预测encoder和decoder中被mask的词时,对self-attention使用了不同的约束条件),所以encoder和decoder使用的是同一个transformer。seq2seq lm的训练样本,和nsp任务类似,为连续的两个句子,然后随机mask掉两个句子中的词让模型进行预测。
对词随机mask的机制和bert类似,只是会以一定概率mask临近的两个或三个词,具体说明如下:
训练时目标函数的设定也参照bert,只是要同时兼顾双向lm、单向lm和seq2seq lm。作者使用的模型大小同,也即用了24层的transformer。
精调阶段,对于nlu类型的任务unilm和bert相同。对于nlg类型的任务,unilm随机mask decoder中的一些词,然后再预测它们。以下是unilm应用于生成式qa任务的做法,效果提升很明显。
对于glue的所有任务,unilm据说是首次不添加外部数据打赢bert的模型!
总结下unilm的特点:
预训练同时训练双向lm、单向lm和seq2seq lm,使用mask机制解决self-attention中的约束问题。
可以处理nlu和nlg类型的各种任务。
在glue上首次不加外部数据打赢了bert。
多任务学习:mt-dnn
mt-dnn (multi-task deep neural network)是去年年底微软的一篇工作,思路很简单,就是在mtl中把bert引入进来作为底层共享的特征抽取模块。
预训练就是bert,精调时每个batch随机选一个任务进行优化。整体算法步骤如下:
mt-dnn在glue上效果比bert好不少,当然主要原因可能是加入了额外的数据了。作者也对比了多任务与单任务的结果,多任务确实能给每个任务都带来效果提升。
总结下mt-dnn的特点:
框架简单明了:mt-dnn = bert + mtl。
三、实践、观点、总结
▌实践与建议
虽然前面介绍的很多模型都能找到实现代码。但从可用性来说,对于nlu类型的问题,基本只需考虑elmo,ulmfit和bert。而前两个没有中文的预训练模型,需要自己找数据做预训练。bert有官方发布的中文预训练模型,很多深度学习框架也都有bert的对应实现,而且bert的效果一般是最好的。但bert的问题是速度有点慢,使用12层的模型,对单个句子(30个字以内)的预测大概需要100~200毫秒。如果这个性能对你的应用没问题的话,建议直接用bert。
对于分类问题,如果特定任务的标注数据量在几千到一两万,可以直接精调bert,就算在cpu上跑几十个epoches也就一两天能完事,gpu上要快10倍以上。如果标注数据量过大或者觉得训练时间太长,可以使用特征抽取方式。先用bert抽取出句子向量表达,后续的分类器只要读入这些向量即可。
我们目前在很多分类问题上测试了bert的效果,确实比之前的模型都有提升,有些问题上提升很明显。下图给出了一些结果示例。
爱因互动作为企业对话机器人服务提供商,我们会处理很多的qa (query answer)和qq (query question)匹配任务。比如在常用的检索机器人faqbot中,用户的一个query来了,faqbot首先从标准问答库中检索出一些候选问题/答案,然后排序或匹配模块再计算query跟每个候选问题/答案的匹配度,再按这些匹配度从高到低排序,top1的结果返回给用户。上图中给出了一个qq 匹配的结果,原始模型的准确度为83.5%,bert精调后的模型准确度提升到88.3%。
bert当然可以直接用来计算两个句子的匹配度,只要把query和每个候选句子拼起来,然后走一遍bert就能算出匹配度。这样做的问题是,如果有100个候选结果,就要算100次,就算把它们打包一起算,cpu上的时间开销在线上场景也是扛不住的。但如果使用siamese结构,我们就可以把候选句子的bert向量表达预先算好,然后线上只需要计算query的bert向量表达,然后再计算query和候选句子向量的匹配度即可,这样时间消耗就可以控制在200ms以内了。
使用siamese这种结构理论上会降低最终的匹配效果,之前也有相关工作验证过在一些问题上确实如此。我们目前在自己的三个数据上做了对比实验(见下图),发现在两个问题上效果确实略有下降,而在另一个问题上效果基本保持不变。我估计只要后续交互层设计的合理,siamese结构不会比原始bert精调差很多。
▌观点
按理elmo的想法很简单,也没什么模型创新,为什么之前就没人做出来然后引爆无监督模型预训练方向?bert的一作jacob devlin认为主要原因是之前使用的数据不够多,模型不够大。无监督预训练要获得好效果,付出的代价需要比有监督训练大到1000到10w倍才能获得好的效果。之前没人想到要把数据和模型规模提高这么多。
为了让预训练的模型能对多种下游任务都有帮助,也即预训练模型要足够通用,模型就不能仅仅只学到带背景的词表示这个信息,还需要学到很多其他信息。而预测被mask的词,就可能要求模型学到很多信息,句法的,语义的等等。所以,相对于只解决某个下游特定任务,预训练模型要通用的话,就要大很多。目前发现只要使用更多(数量更多、质量更好、覆盖面更广)的无监督数据训练更大的模型,最终效果就会更优。目前还不知道这个趋势的极限在什么量级。
bert虽然对nlu的各类任务都提升很大,但目前依旧存在很多待验证的问题。比如如何更高效地进行预训练和线上预测使用,如何融合更长的背景和结构化知识,如何在多模态场景下使用,在bert之后追加各种任务相关的模块是否能带来额外收益等等。这些机会我在第一部分已经讲到,就不再赘述了。
▌总结和一点感(敢)想
最后,简单总结一下。
无监督预训练技术已经在nlp中得到了广泛验证。bert成功应用于各种nlu类型的任务,但无法直接用于nlg类型的任务。微软最近的工作mass把bert推广到nlg类型任务,而unilm既适用于nlu也适用于nlg任务,效果还比bert好一点点。
相信未来nlp的很多工作都会围绕以下这个流程的优化展开:
在这个过程中,我们还收获了诸多副产品:
相对于bilstm,transformers在知识抽取和存储上效果更好,潜力还可发掘。它们之间的具体比较,推荐俊林老师的“放弃幻想,全面拥抱transformer:自然语言处理三大特征抽取器(cnn/rnn/tf)比较”,里面介绍的很清楚。
目前无监督模型预训练常用以下几种目标函数:
一般的lm。基于token的交叉熵。
masked lm。相比于一般的lm,masked lm能够使用双向tokens,且在模型训练和预测时的数据使用方式更接近,降低了它们之间的gap。
consecutive masked lm。mask时不仅随机mask部分离散的token,还随机mask一些连续的tokens,如bi-grams、tri-grams等。这种consecutive mask机制是否能带来普遍效果提升,还待验证。
next sentence prediction。预测连续的两个句子是否有前后关系。
精调阶段,除了任务相关的目标函数,还可以考虑把lm作为辅助目标加到目标函数中。加入lm辅助目标能降低模型对已学到知识的遗忘速度,提升模型收敛速度,有些时候还能提升模型的精度。精调阶段,学习率建议使用linear warmup and linear decay机制,降低模型对已学到知识的遗忘速度。如果要精调效果,可以考虑ulmfit中引入的gradual unfreezing和discriminative fine-tuning:机制。
使用数量更多、质量更好、覆盖面更广的无监督数据训练更大的模型,最终效果就会更优。目前还不知道这个趋势的极限在什么地方。
最后说一点自己的感想。
nlp中有一部分工作是在做人类知识或人类常识的结构化表示。有了结构化表示后,使用时再想办法把这些表示注入到特定的使用场景中。比如知识图谱的目标就是用结构化的语义网络来表达人类的所有知识。这种结构化表示理论上真的靠谱吗?人类的知识真的能完全用结构化信息清晰表示出来吗?显然是不能,我想这点其实很多人都知道,只是在之前的技术水平下,也没有其他的方法能做的更好。所以这是个折中的临时方案。
无监督预训练技术的成功,说明语言的很多知识其实是可以以非结构化的方式被模型学习到并存储在模型中的,只是目前整个过程我们并不理解,还是黑盒。相信以后很多其他方面的知识也能找到类似的非结构化方案。所以我估计知识图谱这类折中方案会逐渐被替代掉。当然,这只是我个人的理解或者疑惑,仅供他人参考。

电渣压力焊预防措施
5G射频技术创新,半导体工艺技术的发展扮演重要角色
苹果以2亿美元收购人工智能公司Turi
四维图新旗下杰发科技获盖世汽车“智能座舱芯片优质供应商”奖项
薄膜电容器的作用
迁移学习与模型预训练:何去何从
怎样对路灯控制系统中进行漏电监测呢 配电箱内单杆路灯方案
英特尔联手台湾大学 意欲迅速推动M2M商用进程
热缩管在电机上的运用
水质净化厂远程监控物联网系统解决方案
C语言_二维数组与一维指针
【节能学院】防火门监控系统在某住宅项目上的应用
让人工智能模型获得人类的联想能力
苹果今晨发布iOS10.2 Beta5版本:新增72个emoji表情
可信赖的银联宝5v1A电源IC U65113E
Zemax不同面型的归一化半径如何设置
新一代PXI测试平台提升移动终端测试效率
向日葵完成银河麒麟V10兼容适配,国产远程控制生态再强化
两步走,让你的LoRaWAN网关连上阿里云
无线话筒主要性能的测试方法
s