您的位置:首页 > 大数据 > 人工智能

阅读笔记:BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding

2019-01-18 15:53 399 查看

简介

转自:https://baijiahao.baidu.com/s?id=1619193829009842342&wfr=spider&for=pc
google AI 团队发布,被NLP业内公认为里程碑式的进步。

回顾

原文链接:https://blog.csdn.net/triplemeng/article/details/83053419
现在有很多利用预训练的语言表征来完成下游NLP任务的研究,作者把他们概括为两类:feature-based 和fine-tuning

分类 代表 task-specific模型 使用方案
feature-based ELMo 需要 把表征作为feature提供给下游任务
fine-tuning OpenAI GPT, ULMFiT 不需要 fine tuning预训练的参数

这两类方法的共性在于:它们在预训练中都是用了一样的目标函数,也都使用了单向的语言模型。
作者对这些方法的批评在于它们没有很好地利用上下文信息。尽管如ELMo这样的算法利用了正向和反向的语言模型,可本质上仍然是两个unidirectional模型的叠加。对于SQuAD这种阅读理解式的任务,额能够同时从两个方向提取context信息至关重要,然而现存的方法有巨大的局限性。

BERT,OpenAI GPT, ELMo之间的区别如下:

创新之处

作为fine-tuning这一类的方法,作者提出了改进的方案:BERT(Bidirectional Encoder Representations from Transformers)

具体做法:

  1. 采用新的预训练的目标函数:the masked language model(MLM),随机mask输入中的一些tokens,然后在预训练中对他们进行预测。这样做的好处是学习到的表征能够融合两个方向上的context。这个做法我觉得非常向skip-gram。过去的同类算法在这里有所欠缺,比如上文提到的EMLo,但是只利用了一个方向的注意力机制,本质上也一样是单向的语言模型。
  2. 增加了句子级别的任务next sentence prediction:作者认为很多的NLP任务比如QA 和NLI 都需要对两个句子之间的关系理解,然而这些语言模型不能很好地直接产生这种理解。为了理解句子关系,作者同时pre-traine 了一个next sentence prediction任务。具体做法是:随机替换一些句子,然后利用上一句进行 IsNext/ NotNext的预测。

在实际的预训练中,这两个任务是jointly training

BERT 模型架构

论文使用了两种模型:

  1. BERTBASE:L=12,H=768,A=12,TotalParameters=110MBERT_{BASE}:L=12,H=768,A=12,Total Parameters=110MBERTBASE​:L=12,H=768,A=12,TotalParameters=110M
  2. BERTLARGE:L=24,H=1024,A=16,TotalParameters=340MBERT_{LARGE}:L=24,H=1024,A=16,Total Parameters=340MBERTLARGE​:L=24,H=1024,A=16,TotalParameters=340M

LLL 是layer的层数(即 transformer blocks个数);
HHH 是hidden vector size;
AAA 是self-attention的“头数”。

在NLP领域,10层以上的layers还是比较“惊人的”,印象中的Attention is all you need第一次提出transformer的时候,在MT任务中用了6层。
当然从结构上来讲,transformers 之间用的就是 residual connection,并且有batch normarlization这种“常规”操作,多层不是什么问题。
有意思的是,这么多层结构究竟学到了什么?NLP不能喝CV做简单的类比,网络层数并不是多多益善;有的论点认为底层偏向于语法特征学习,高层偏向于语义特征学习。希望将来的研究能够给出更充分更有启发性的观点。

输入的表示

针对不同的人物,模型能够明确的表达一个句子,或者对句子对(比如说[问题,答案])。对于每一个token,它的表征由对应的token embedding,段表征(segment embedding),位置表征(position embedding)相加产生。如下如图:

具体细节如下:

  • 论文使用了 wordPiece embeddings
  • 使用了positional embeddings,长达512位,即句子的最大长度
  • 每句话的第一个token总是[CLS]。对应它的最终的hidden state(即transformer的输出),用来表征整个句子,可以用于下游的分类任务
  • 模型能够处理句子对。为了区别两个句子,用一个特殊的token [SEP]隔开它们,另外针对不同的句子,把学习到的segment embedding加到每个token 的embedding上(如图)
  • 对于单个句子仅是用一个segment embedding

预训练的任务

Masked LM
具体细节论文上解释的很清楚了,这里从略了。
提一下值得注意的一点吧:为了达到真正的bidirectional的LM的效果,作者创新性的提出了Masked LM,但是缺点是如果常常把一些词mask起来,未来的fine tuning过程中模型有可能没见过这些词。这个量积累下来还是很大的。因为作者在他的实现中随机选择了句子中15%的WordPiece tokens作为要mask的词。

为了解决这个问题,作者在做mask的时候,

  • 80%的时间真的用[MASK]取代被选中的词。比如 my dog is hairy -> my dog is [MASK]
  • 10%的时间用一个随机词取代它:my dog is hairy -> my dog is apple
  • 10%的时间保持不变: my dog is hairy -> my dog is hairy
  • 为什么要以一定的概率保持不变呢? 这是因为刚才说了,如果100%的时间都用[MASK]来取代被选中的词,那么在fine tuning的时候模型会有一些没见过的词。那么为啥要以一定的概率使用随机词呢?这是因为Transformer要保持对每个输入token分布式的表征,否则Transformer很可能会记住这个[MASK]就是"hairy"。至于使用随机词带来的负面影响,文章中说了,所有其他的token(即非"hairy"的token)共享15%*10% = 1.5%的概率,其影响是可以忽略不计的。

Next Sentence Prediction
具体做法很容易理解,这里仍然从略。
简单说一下这么做的原因。很多NLP的任务比如QA和NLI都需要理解两个句子之间的关系,而语言模型并不能直接反应这种关系。为了是预训练出来的模型很好的适应这些任务,作者提出了这样的一个预训练任务。实验表明,增加这样的一个任务在针对下游的QA和NLI任务时效果非常好。

在预训练中文章使用了BooksCorpus(800M 词)和English Wikipedia(2,500M 词)。

微调过程
对于句子级的分类任务,BERT的微调方法非常直观。论文用刚才介绍过的特殊符号[CLS]来对应整个句子的表征。我们只需要把它作为输入通过一层网络,最后做softmax就可以了。

(后面待续……)

发展历程

  1. 2015年,微软研究院何凯明等人发布了残差网络相关论文,第一次通过残差的方式将卷积神经网络推进到100层以上,并且在图像识别的任务上刷新了当时的最高纪录。
  2. 从此以后,随着网络不断加深,效果也在不断提升,但是训练一个模型所需的成本也在不断增加。
    自此,在计算机视觉处理中,人们越来越多的采用与训练好的大型网络来提取特征,然后进行后续任务。
  3. 与图像领域类似,自然语言处理通常会使用预训练的词向量来进行后续任务。但是,词向量是通过浅层网络进行无监督训练,虽然在词的级别上有着不错的特性,但是缺少对连续文本的内在联系和语言结构的表达能力
    大家希望,NLP也能像图像领域那样,通过大量数据来预训练一个大型的神经网络,然后用他来对文本提取特征然后进行后续任务,以期能得到一个更好的效果。
  4. AllenAI提出了ELMo(https://arxiv.org/pdf/1802.05365.pdf),由于其在后续任务上的优异表现,获得了不少关注。
  5. ELMo成功时候,FastAI就退出了ULMFiT(https://arxiv.org/abs/1801.06146),其答题思路是:在微调时,对每一层设置不同的学习率。
  6. 之后,OpenAI又提出了GPT(https://blog.openai.com/language-unsupervised/)
  7. 从上面提及的这些论文结果以及学界和工业界的反馈来看,这种使用大量的预料进行预训练,然后再在预训练好的模型上进行后续任务训练,虽然训练方式各有不同,但是在后续任务都有不同程度的提高。
  8. BERT就是在OpenAI的GPT基础上对于训练的目标进行了修改,并且用更大的模型以及更多的数据去进行预训练,从而得到了目前最好的效果。
    transformer的编码器结构:

BERT的主体结构

BERT模型沿袭了GPT模型的结构,采用transformer(https://arxiv.org/abs/1706.0376)的编码器作为主题模型结构。

transformer舍弃了RNN的循环式网络结构,完全基于注意力机制来对一段文本进行建模。

transformer所使用的注意力机制的核心思想:计算一句话中的每个词对于这句话中所有词的相互关系,然后认为这些词与词之间的相互关系在一定程度上反映了这句话中不同词之间的关联性以及重要程度。因而再利用这些相互关系来调整每个词的重要性(权重)就可以获得每个词新的表达。

这个新的表征不但蕴含了该词本身,还蕴含了这个词与其他词之间的关系,因此和单纯的词向量想必这是一个更加全局的表达。

transformer通过对输入的文本不断进行这样的注意力基质层和普通的非线性层交叠来得到最终的文本表达。
Transformer的注意力层得到的词-词之间关系:

GPT 简介

GPT则利用了transformer的结构来进行单向语言模型的训练。其目标是给定一个序列文本,预测下一个位置会出现的词。

模型学习的过程和我们人学习一门语言的过程类似,我们学习语言的时候会不断地练习怎么选用合适的词来造句,对模型来说也是这样。例如:

今天 天气 不错, 我们 去 公园 玩 吧 。

这句话,单向语言模型在学习的时候是从左向右进行学习的,先给模型看到“今天”、“天气”两个词,然后告诉模型想一个要填的词是“不错”。

然而单向语言模型有一个欠缺,就是模型学习的时候总是按照句子的方向去学的,因此模型学习每个词的时候,只能看到上文,并没有看到下文。

更加合理的方式应该是让模型通过上下文去学习,这个过程有点类似与完形填空,例如:

今天 天气 (),我们 去 公园 玩 吧。

通过这样的学习,模型能够更好地把握“不错”这个词所出现的上下文语境。

BERT 创新点

BERT 对 GPT 的第一个改进就是引入了双向的语言模型任务。

此前其实也有一些语言模型这个任务上使用了双向的方法,例如:ELMo,它是通过双向的两层RNN结构对两个方向进行建模,但是两个方向的loss计算相互独立。

BERT认为:两个方向相互独立,或者只有单层的双向编码可能没有发挥最好的效果,我们不仅仅需要双向编码,还要加深网络的层数。
但是加深双向编码网络却会引入一个问题,导致模型最终可以间接的“窥探”到需要预测的词。
这个“窥探”过程如下图所示:

(后面没看懂,有时间继续……)

从图中可以看到经过两层的双向操作,每个位置上的输出就已经带有了原本这个位置上的词的信息了。这样的“窥探”会导致模型预测词的任务变得失去意义,因为模型已经看到每个位置上是什么词了。

为了解决这个问题,我们可以从预训练的目标入手。我们想要的其实是让模型学会某个词适合出现在怎样的上下文语境当中;反过来说,如果给定了某个上下文语境,我们希望模型能够知道这个地方适合填入怎样的词。

从这一点出发,其实我们可以直接去掉这个词,只让模型看上下文,然后来预测这个词。但这样做会丢掉这个词在文本中的位置信息,那么还有一种方式是在这个词的位置上随机地输入某一个词,但如果每次都随机输入可能会让模型难以收敛。

BERT的作者提出了采用MaskLM的方式来训练语言模型。

通俗地说就是在输入一句话的时候,随机地选一些要预测的词,然后用一个特殊的符号来代替它们。尽管模型最终还是会看到所有位置上的输入信息,但由于需要预测的词已经被特殊符号代替,所以模型无法事先知道这些位置上是什么词,这样就可以让模型根据所给的标签去学习这些地方该填的词了。

然而这里还有一个问题,就是我们在预训练过程中所使用的这个特殊符号,在后续的任务中是不会出现的。

因此,为了和后续任务保持一致,作者按一定的比例在需要预测的词位置上输入原词或者输入某个随机的词。当然,由于一次输入的文本序列中只有部分的词被用来进行训练,因此BERT在效率上会低于普通的语言模型,作者也指出BERT的收敛需要更多的训练步数。

BERT另外一个创新是在双向语言模型的基础上额外增加了一个句子级别的连续性预测任务。这个任务的目标也很简单,就是预测输入BERT的两端文本是否为连续的文本,作者指出引入这个任务可以更好地让模型学到连续的文本片段之间的关系。在训练的时候,输入模型的第二个片段会以50%的概率从全部文本中随机选取,剩下50%的概率选取第一个片段的后续的文本。

除了模型结构,模型大小和数据量都很重要

以上的描述涵盖了BERT在模型结构和训练目标上的主要创新点,而BERT的成功还有一个很大的原因来自于模型的体量以及训练的数据量。

BERT训练数据采用了英文的开源语料BooksCropus 以及英文维基百科数据,一共有33亿个词。同时BERT模型的标准版本有1亿的参数量,与GPT持平,而BERT的大号版本有3亿多参数量,这应该是目前自然语言处理中最大的预训练模型了。

当然,这么大的模型和这么多的数据,训练的代价也是不菲的。谷歌用了16个自己的TPU集群(一共64块TPU)来训练大号版本的BERT,一共花了4天的时间。

对于是否可以复现预训练,作者在Reddit上有一个大致的回复,指出OpenAI当时训练GPT用了将近1个月的时间,而如果用同等的硬件条件来训练BERT估计需要1年的时间。不过他们会将已经训练好的模型和代码开源,方便大家训练好的模型上进行后续任务。

虽然训练的代价很大,但是这个研究还是带来了一些思考和启发。例如双向语言模型的运用,多任务对预训练的帮助以及模型深度带来的收益。相信在未来的一段时间,自然语言处理中预训练的神经网络语言模型会得到更多的关注和运用。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐