从Word Embedding到Bert模型——NLP中的预训练技术发展史

最近在学习预训练模型相关的文章,发现了一篇很棒的文章从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史 - 知乎,这篇文章是对原文作出的精炼以便之后的复习查阅。

这篇文章的主题是NLP中的预训练过程,文章中阐述了NLP中的预训练技术是一步一步如何发展到Bert模型的,从中可以很自然地看到Bert的思路是如何逐渐形成的,Bert的历史延续和革新是什么?继承了什么?创新了什么?为什么效果那么好,主要原因是什么?

串起整篇文章的脉络就是NLP的预训练过程,但是落脚点还是在Bert上。

自然语言处理的预训练是从图像领域的预训练发展起来的。

图像领域的预训练

自从深度学习火起来后,预训练过程就是做图像或者视频领域的一种比较常规的做法,有比较长的历史了,而且这种做法很有效,能明显促进应用的效果。

图像领域的预处理

上图展示了图像领域预处理的过程。在设计好网络结构以后,对于图像来说一般是CNN的多层叠加网络结构,可以先用某个训练集合A或者训练集合B对这个网络进行预先训练,在A任务上或者B任务上学会网络参数,然后存起来以备后用。假设我们面临第三个任务C,网络结构采取相同的网络结构,在比较浅的几层CNN结构,网络参数初始化的时候可以加载A任务或者B任务学习好的参数,其他CNN高层参数仍然随机初始化。之后用C任务的训练数据来训练网络,此时有两种做法,一种是浅层加载的参数在训练C任务过程中不动,这种方法被称为”Frozen“;另外一种是底层网络参数尽管被初始化了,在C任务训练过程中仍然随着训练的进程不断改变,这种一般叫“Fine-tuning”,顾名思义,就是更好地把参数进行调整使得更适应当前的C任务。一般图像或者视频领域的预训练都这么做。

这么做有几个好处,首先,如果手头任务C的训练集合数据量较少的话,现阶段好用的CNN比如Resnet/Densenet/Inception等网络结构层数很深的模型都有上百万或者上千万参数训练数据少很难很好地训练这么复杂的网络,但是如果其中大量参数通过大的训练集合比如ImageNet预先训练好直接拿来初始化大部分网络参数结构参数,然后再用C任务比较少的数据在Fine-tuning阶段去调整参数让它们更加适合解决C任务。这样原先训练不了的任务就能得以解决,即使手头任务训练数据也不少,加个预训练过程也能极大加快任务训练的收敛速度。

预训练模型思路

在浏览上述陈述的过程中可能会想,为什么这种加载其他模型参数的预训练方法是可行的?还是在图像领域说明,目前我们已知,对于层级的CNN结构来说,不同层级的神经元学习到了不同类型的图像特征,由底向上特征形成层级结构,如上图所示,以人脸识别任务为例,训练好网络后,把每层神经元学习到的特征可视化看一下每层学到的特征,会发现最底层的神经元学到的是线段等特征,图示的第二个隐层学到的是五官的轮廓,第三层学到的是人脸的轮廓,通过三步形成了特征的层级结构,越是底层的特征越是所有不论什么领域的图像都会具备的比如边角线弧线等底层基础特征,越往上抽取的特征越与手头任务相关。正因如此,预训练好的网络参数尤其是底层的网络参数抽取出特征与具体任务越无关,越具备任务的通用性,所以这是为何一般用底层预训练好的参数初始化新任务网络参数的原因。而高层特征跟任务关联比较大,实际可以不用使用,或者采用Fine-tuning用新数据集合清洗掉高层无关的特征抽取器。

既然在图像领域预训练这么好用,为什么不在NLP领域进行应用呢?其实早就有人尝试过了,但总体而言不太成功而已。2003年提出的 word embedding 其实就是NLP里的早期预训练技术。当然也不能说 word embedding 不成功,一般加到下游任务里,都能有1到2点的性能提升,只是没有那么耀眼的成功而已。所以预训练模型的历史还是需要从 word embedding 开始说起。

Word Embedding

在说 Word Embedding 之前,需要先粗略地说下语言模型,因为NLP中做预训练一般的选择是用语言模型任务来做。

语言模型

什么是语言模型?配合上面这张图加以理解,为了能够量化地衡量哪个句子更像一句人话,可以设计如上图所示函数,核心函数P的思想是根据句子里面前面的一系列前导单词预测后面跟哪个单词的概率大小(理论上除了上文之外,也可以引入单词的下文联合起来预测单词出现概率),句子中的每个单词都有个根据上文预测自己的过程,把所有这些单词的产生概率乘起来,数值越大代表这越像一句人话。(语言模型的更多知识可以查阅其他资料)

下面介绍神经网络语言模型(NNLM)。它出现于2003年Bengio发表在JMLR上的论文,但是却火与2013,十分神奇。

说说NNLM的思路,NNLM训练过程。学习任务是输入某个句中单词$W_t = “Bert”$前面句子的$t-1$个单词,要求网络正确预测单词Bert,即最大化:
$P(W_t = “Bert”|W_1,W_2,…,W(t-1);\theta)$
前面任意单词$W_i$用 onehot 编码(比如:0001000)作为原始单词输入,之后乘以矩阵$Q$后获得向量$C(W_i)$,每个单词的$C(W_i)$拼接,上接隐层,然后接softmax去预测后面应该接哪个单词。这个$C(W_i)$的每一行对应了一个词在高维空间中的向量化表达,即单词对应的 Word embedding 值,矩阵$Q$包含$V$行,$V$代表词典大小,每一行内容也是代表对应单词的 Word embedding 值(补充:这里很容易混淆,我一开始就搞混了,为什么矩阵$C$和矩阵$Q$都代表词向量?那他俩数值不是应该相等嘛?这些都是我最初的疑问,后来通过NLP预训练演进 - from Word2Vec to XLNet - 知乎这篇文章才得以分清。矩阵$C$是将 one-hot 编码形式的输入词变换为定长形式的向量表示,矩阵$Q$是将隐层输出H映射到softmax层上每一维输入的连接权值矩阵,两个矩阵的数值含义其实都是 Word embedding ,只不过矩阵$C$代表的词向量称为输入词向量而矩阵$Q$代表的词向量称为输出词向量。)。只不过$Q$的内容也是网络参数需要通过学习得到,训练刚开始用随机值初始化矩阵$Q$,当这个网络训练好之后,矩阵$Q$的内容被正确复制,每一行代表一个单词对应的 Word embedding 值。

Q1:什么是Word embedding?
Word embedding通俗的翻译是词嵌入,就是把X所属空间的单词映射为到Y空间的多维向量,那么该多维向量相当于嵌入到Y所属空间中,一个萝卜一个坑。Word embedding 就是找到一个映射或者函数,声称在一个新的空间上的表达,这个表达就是 word representation。推广开来还有 KG embedding 都是一种将源数据映射到另外一个空间。什么是 word embedding? - 知乎

2013年最火的用语言模型做 Word Embedding 的工具是 Word2Vec ,后来又作出了 Glove ,Word2Vec是如何工作的呢?看下图。

Word2Vec

Word2Vec网络结构与NNLM是基本类似的,是亲兄弟。不过这里需要指出:尽管网络结构相近,而且也是做语言模型任务,但是其训练方法不太一样。Word2Vec有两种训练方法(这里的训练方法是指以高效地生产词向量为直接目的的算法),一种叫CBOW模型,核心思想是从一个句子中把一个词扣掉,用这个词的上文和下文去预测被扣掉的这个词;第二个叫做Skip-gram模型,和CBOW正好相反,输入某个单词要求网络预测它的上下单词。回顾一下NNLM是如何训练的,是输入一个单词的上文,去预测这个单词。这是有显著差异的。为什么Word2Vec这么处理?原因很简单,因为Word2Vec和NNLM任务不一样,NNLM的主要任务是要学习一个解决语言模型任务的网络结构,语言模型就是要看到上文预测下文,而 word embedding 只是无心插柳的一个副产品。但是Word2Vec目标不一样,它单纯就是要 Word embedding 的,这是主产品,所以它可以随性地去训练网络。

之所以要讲 Word2Vec,主要是要引出CBOW的训练方法,BERT其实跟它有关系,后面会说它们之间是如何的关系,然而BERT的作者却没有说这种关系,这种关系是否相似需要自己判断。

Word embedding的例子

使用 Word2Vec 或者 Glove,通过做语言模型任务,就可以获得每个单词的 Word embedding,那么这种方法的效果如何呢?上图给了网上找的几个例子,可以看出有些例子效果还是很不错的,一个单词表达成 Word embedding 后,很容易找出语义相近的其它词汇。

Q2:如何通过Word2Vector得到Word embedding?

有人可能会想 Word embedding 这种做法能算是预训练嘛?这其实就是标准的预训练过程。要理解这一点要看看学会 Word embedding 后下游任务是怎么用它的。

Word embedding的使用

假设如上图所示,有个NLP的下游任务,比如问答问题QA。所谓问答问题,指的是给定一个问题X,给定另外一个句子Y,要判断句子Y是否是问题X的正确答案。问答问题假设设计的网络结构如上图所示。它的训练方法其实和前面讲的NNLM是一样的,句子中每个单词以onehot形式作为输入,然后乘以学好的Word embedding矩阵Q,就直接取出单词对应的 Word embedding 了。这乍看上去好像是个查表操作,不像是预训练的做法。其实不然,使用 Word Embedding 等价于把 onehot 层到 embedding 层的网络用预训练好的参数矩阵Q初始化了(补充:我的理解是省略了 onehot 乘以随机初始化矩阵$C(W)$的过程,而是直接乘以输出词向量矩阵$Q$,这个矩阵$Q$是通过其他任务得到的输出词向量,所以后面说用 Word embedding 初始化第一层网络参数并且这个过程相当于预训练过程。)。这跟前面讲的图像领域的低层预训练过程其实是一样的,区别无非是 word embedding 只能初始化第一层网络参数,再高层的参数就无能为力了。下游任务在使用 word embedding 的时候也类似图像有两种做法,一种是Frozen,就是 Word embedding 那层网络参数固定不动;另外一种是 Fine-tuning,就是 Word embedding 这层参数使用新的训练集合训练也需要跟着训练过程更新掉。

补充:在这里解释一下为什么上面有句话说看起来像是个查表操作查表操作举例
以上图矩阵乘法比作NNLM第一层网络的训练为例,左边形式表明,这是一个以$2 \times 6$的 one hot 矩阵为输入、中间层节点数为3的全连接神经网络层,但是观察右边可以发现输出矩阵恰好相当于在$w_{ij}$这个矩阵中取出第1、2行,与所谓的字向量的查表(从表中找出对应字的向量)是完全相同的。这就是所谓的 Embedding 层,Embedding 层就是以 one hot 为输入、中间层节点为字向量维数的全连接层,而这个全连接层的参数,就是一个”字向量表”。从这个层面来看,字向量没有做任何事情,它就是 one hot,字向量就是 one hot 的全连接层的参数。
从运算上来看,one hot型的矩阵相乘,就像是相当于查表,于是它直接用查表作为操作,而不写成矩阵再运算,这大大降低了运算量。再次强调,降低了运算量不是因为词向量的出现,而是因为把one hot型的矩阵运算简化为查表操作。这是运算层面的。思想层面上就是它得到了这个全连接层的参数之后,直接用这个全连接层的参数作为特征,或者说用这个全连接层的参数作为字、词的表示,从而得到了字、词向量,最后发现了一些有趣的性质,比如向量夹角的余弦能够在某种程度上表示字、词的相似度。

补充:补充:解释一下为什么说字词向量会有些性质,比如向量的夹角余弦、向量的欧式距离都能在一定程度上反映字词之间的相似性?
这是因为,在用语言模型进行无监督训练时,是开了窗口的,通过前$n$个字预测下一个字的概率,这个$n$就是窗口的大小,同一个窗口内的词语,会有相似的更新,这些更新会累积,而具有相似模式的词语就会把这些相似更新累积到可观的程度。举一个例子,“忐”和“忑”这两个字,几乎是连在一起用的,更新“忐”的同时,几乎也会更新“忑”,因为它们的更新几乎都是相同的,这样“忐”、“忑”的字向量必然几乎是一样的。“相似的模式”指的是在特定的语言任务中,它们是可替换的,比如在一般的泛化预料中,“我喜欢你”中的“喜欢”,以及一般语境下的“喜欢”,替换为“讨厌”后还是一个成立的句子,因此“喜欢”与“讨厌”必然具有相似的词向量,但如果词向量是通过情感分类任务训练的,那么“喜欢”和“讨厌”就会有差异较大的词向量。

词向量与Embedding究竟是怎么回事? - 科学空间|Scientific Spaces

上面这种做法就是18年前NLP领域内采用预训练的典型做法,之前说过 Word Embedding 其实对于很多下游NLP任务是有帮助的,只是帮助没有那么大。效果不好的原因是 Word Embedding 有问题,然而有什么问题呢?这是个好问题。

Word embedding的问题

这个问题就是多义词问题。多义词是自然语言中经常出现的现象,也是语言灵活性和高效性的一种体现。多义词对 Word Embedding 的负面影响如上图所示,比如多义词 bank ,但是 Word Embedding 在对bank这个单词进行编码时无法区分这两个含义,因为尽管它们上下文环境中出现的单词不同,但是在用语言模型训练的时候,是区分不开这两个含义的,因为它们尽管上下文环境中出现的单词不同,但是在用语言模型训练的时候,不论什么上下文的句子经过 word2vec,都是预测相同的单词 bank ,而同一个单词占的是同一行的参数空间,这导致两种不同的上下文信息都会编码到相同的 word embedding 空间里去。所以 Word Embedding 无法区分多义词的不同语义,这就是它的一个比较严重的问题。

很多研究人员试图解决这个问题,但是从今天往回看,这些方法看上去都成本太高或者太繁琐了,直到ELMO提供了一种简洁优雅的解决方案。

从Word Embedding到ELMO

ELMO是”Embedding from Language Models”的简称,其实这个名词并没有反映它的本质思想,提出ELMO的论文题目:“Deep contextualized word representation”更能体现其精髓,而精髓是什么?在deep contextualized这个短语,一个是deep,一个是context,其中context更关键。在此之前的 Word Embedding 本质上是个静态的方式,所谓静态指的是训练好之后每个单词的表达就固定住了,以后使用的时候,无论新句子上下文单词是什么,这个单词的 Word Embedding 不会跟着上下文场景的变化而改变,所以对于比如 bank 这个词,它事先学好的 Word Embedding 中混合了几种语义,在应用中来了个新句子,即使从上下文中(比如句子包含money等词)明显可以看出它代表的是”银行”的含义,但对应的 Word Embedding 内容也不会变,它还是混合了多种语义。这是为何说它是静态的,这也是问题所在。ELMO的本质思想是:事先用语言模型学好一个单词的 Word Embedding,此时多义词无法区分,不过这没关系。在实际使用 Word Embedding 的时候,单词已经具备了特定的上下文了,这时可以根据上下文单词的语义去调整单词的Word Embedding 表示,这样经过调整后的 Word Embedding 更能表达在这个上下文中的具体含义,自然也就解决了多义词的问题。所以ELMO本身是个根据当前上下文对 Word Embedding 动态调整的思路。如何调整呢?

ELMO

ELMO采用了典型的两阶段过程,第一个阶段是利用语言模型进行预训练;第二个阶段是在做下游任务时,从预训练网络中提取对应单词的网络各层的 Word Embedding 作为新特征补充到下游任务中。上图展示的是其预训练过程,它的网络结构采用了双层双向LSTM,目前语言模型训练的任务目标是根据单词$W_i$的上下文去正确预测单词$W_i$,$W_i$之前的单词序列 Context-before 称为上文,之后的单词序列 Context-after 称为下文。图中左端的前向双层LSTM代表正方向编码器,输入的是从左到右顺序的除了预测单词外$W_i$的上文Context-before;右端的逆向双层LSTM代表反向编码器,输入的是从右到左的逆序的句子下文 Context-after;每个编码器的深度都是两层LSTM叠加。这个网络结构其实在NLP中是很常用的,使用这个网络结构利用大量语料做语言模型任务都能得到对应的3个Embedding:最底层是单词的 Wording Embedding,往上走是第一层双向LSTM中对应单词位置的Embedding,这层编码单词的句法信息更多一些;再网上走是第二层LSTM中对应单词位置的Embedding,这层编码单词的语义信息更多一些。也就是说,ELMO的预训练过程不仅仅学会单词的 Word Embedding,还学会了一个双层双向的LSTM网络结构,而这两者后面都有用。

训练EMLO后

上面介绍的是EMLO的第一阶段:预训练阶段。那么预训练好网络结构后,如何给下游任务使用呢?上图展示了下游任务的使用过程,以下游任务仍是QA问题为例,此时对于问句$X$,可以先将句子$X$作为预训练好的EMLO网络的输入,这样句子$X$中每个单词在ELMO网络中都能获得对应的三个Embedding,之后给予这三个Embedding中的每一个Embedding一个权重$a$,这个权重可以学习得来,根据各自权重累加求和,将三个Embedding整合成一个。然后将整合后的这个Embedding作为$X$句在自己任务的那个网络结构中对应单词的输入,以此作为补充的新特征给下游任务使用。对于上图所示下游任务QA中的回答句子$Y$来说也是如此处理。因为ELMO给下游提供的是每个单词的特征形式,所以这一类与训练方法被称为”Feature-based Pre-Training“。

ELMO解决多义词问题

前面提高静态 Word Embedding 无法解决多义词的问题,那么ELMO引入上下文动态调整单词的 embedding 后多义词问题解决了嘛?解决了,而且比期待的解决的还要好。上图给出了例子,对于Glove训练出的 Word Embedding 来说,多义词比如play,根据它的 embedding 找出的最接近的其它单词大多数集中在体育领域,这很明显是因为训练数据中包含 play 的句子中体育领域的数量明显占优导致的;而使用ELMO,根据上下文动态调整后的 embedding 不仅能够找出对应的”演出”的相同语义的句子,而且还可以保证找出的句子中的 play 对应的词性也是相同的,这是超出期待之处。之所以会这样,是因为上面提到过,第一层LSTM编码了很多句法信息,这在这里起到了重要作用。

ELMO的效果

ELMO经过这般操作之后实验效果见上图,6个NLP任务中性能都有幅度不同的提升,最高的提升达到25%左右,而且这6个任务的覆盖范围比较广,包含句子语义关系判断,分类任务,阅读理解等多个领域,这说明其适用范围是非常广的,普适性强,这是一个非常好的优点。

ELMO的缺点

ELMO也有值得改进的缺点.首先,一个非常明显的缺点在特征抽取器选择方面,ELMO使用了LSTM而非Transformer,很多研究表明Transformer提取特征的能力是要远强于LSTM的。另一点是,ELMO采取双向拼接这种融合特征的方式能力可能比Bert一体化的融合特征方式弱,但是这只是猜测目前还没有具体实验说明这一点。

如果把ELMO这种与训练方法和图像领域的预训练方法对比,可以发现两者模式看上去还有较大差异,除了以ELMO为代表的这种基于特征融合的预训练方法外,NLP里还有一种典型做法,这种做法和图像领域的方式就是看上去一致的了,一般将这种方法称为”基于Fine-tuning的模式“,而GPT就是这一模式的典型开创者。

从Word Embedding到GPT

GPT

GPT是”Generative Pre-Training“的简称,从名字看起含义指的是生成式的预训练。GPT也采用两阶段过程,其实和ELMO是类似的,主要不同在于两点:首先,特征抽取器不是用的RNN,而是用的Transformer,上面提到过它的特征抽取能力要强于RNN;其次,GPT的预训练虽然仍然是以语言模型作为目标任务,但是采用的是单向的语言模型,所谓的”单向“的含义是指:语言模型训练的任务目标是根据$W_i$单词的上下文去正确预测单词$W_i$,$W_i$之前的单词序列Context-before称为上文,之后的单词序列Context-after称为下文。ELMO在做语言模型预训练的时候,预测单词$W_i$同时使用了上文和下文,而GPT则只采用Context-before这个单词的上文来进行预测,而抛开了下文。这个选择并不是很好,因为没有把单词的下文融合进来,这限制了其在更多应用场景的效果,比如阅读理解这种任务,在做任务的时候是可以允许同时看到上文和下文一起做决策的。如果与训练时候不把单词的下文嵌入到Word Embedding中会白白丢失很多信息。

上面讲的是GPT如何进行第一阶段的预训练,那么假设预训练好了网络模型,后面的下游任务如何去用?它和ELMO的方式大有不同。

训练后的GPT

上图展示了GPT在第二阶段如何使用。首先,对于不同的下游任务来说,现在不能随意设计自己的网络结构了,要向GPT的网络结构看齐,把任务的网络结构改造成和GPT的网络结构是一样的。然后,在做下游任务的时候,利用第一步预训练好的参数初始化GPT的网络结构,这样通过预训练学到的语言学知识就被引入到你手头的任务里来了。其次,你可以用手头的任务去训练这个网络,对网络参数进行Fine-tuning,使得这个网络更适合解决手头的问题。

这里引入了一个新问题:对于NLP各种花样的不同人物,如何改造才能靠近GPT的网络结构?

改造GPT

GPT论文给出改造方式:对于分类问题,加上一个起始和终结符号即可;对于句子关系判断问题,比如Entailment,两个句子中间再加个分隔符即可;对文本相似性判断问题,把两个句子顺序颠倒下作出两个输入即可,这是为了告诉模型句子顺序不重要;对于多项选择问题,则多路输入,每一路把文章和答案选项拼接作为输入即可。从上图可看出,这种改造很方便,不同任务只需要在输入部分改造即可。

GPT效果

GPT效果是非常惊人的,在12个任务里,9个达到了最好的效果,有些任务性能提升非常明显。

而GPT需要改进的地方最主要还是单向语言模型,但总而言之GPT仍然是非常非常好的一个工作。

Bert

Bert

Bert采用和GPT完全相同的两阶段模型,首先是语言模型预训练;其次是使用Fine-tuning模式解决下游任务。和GPT的最主要不同在于在预训练阶段采用了类似ELMO的双向语言模型,另一点是语言模型的数据规模要比GPT大。

训练后的Bert

第二阶段,Fine-Tuning阶段,这个阶段的做法和GPT是一样的。当然,它也面临着下游任务网络结构改造的问题,在改造任务方面Bert和GPT有些不同,下面简单介绍一下。

改造Bert

上图给出示例,对于句子关系类任务,和GPT类似,加上一个起始符号对应的Transformer最后一层位置上面串接一个softmax分类层即可。对于分类问题,与GPT一样,只需增加起始和终止符号,输出部分和句子关系判断任务类似改造;对于序列标注问题,输入部分和单句分类是一样的,只要输出部分Transformer最后一层每个单词对应位置都进行分类即可。从这里可以看出,上面列出的NLP四大任务里,除了生成类任务外,Bert其他都覆盖到了,而且改造起来很简单直观。虽然Bert没有提到,但是其实对于机器翻译或者文本摘要,聊天机器人这种生成式任务,同样可以稍作改造即可引入Bert的预训练成果。只需要附着在S2S结构上,encoder 部分是个深度Transformer结构,decoder 部分也是个深度Transformer结构,根据任务选择不同的预训练数据初始化 encoder 和 decoder 即可,这是相当直观的一种改造方法。也可以更简单一点,比如直接在单个Transformer结构上加装隐层产生输出也是可以的。总而言之,可以看出NLP四大类任务都可以比较方便地改造成Bert能够接受的方式。这也是Bert非常大的优点,这意味着它几乎可以做任何NLP的下游任务,具备普适性。

Bert效果

Bert采用这种两阶段方式解决各种NLP任务在11个各种类型的NLP任务中达到目前最好的效果,某些任务性能有极大的提升。

四种模型的关系

梳理一下几个模型之间的演进关系。从上图可见,Bert其实和ELMO及GPT存在千丝万缕的关系,比如把GPT预训练阶段换成双向语言模型,那么就得到了Bert;如果把ELMO的特征抽取器换成Transformer,那么也会得到Bert。所以可以看出:Bert最关键的两点,一点是特征抽取器采用Transformer;第二点是预训练的时候采用双向语言模型。

那么新的问题是:对于Transformer来说,怎样才能在这个结构上做双向语言模型任务呢?Bert的做法类似于上文提到过的CBOW训练方法,它的核心思想是:在做语言模型任务的时候,把要预测的单词扣点,然后根据它的上文 Context-Before 和 下文 Context-after 去预测单词。从这里看出,Bert在模型方面其实没有太大的创新,更像是一个最近几年NLP重要技术的集大成者,正原因在于此,但是Bert本身的效果好和普适性强才是最大的亮点。

Bert的创新

虽然Bert创新不大,但是仍有创新。创新就是论文中指出的 Masked 语言模型和 Next Sentence Prediction 。而 Masked 语言模型之前说过,本质思想就是 CBOW ,但是细节方面有改进。

Masked语言模型

Masked 双向语言模型像上图展示这么做:随机选择语料中15%的单词,把它抠掉,就是用[Mask]掩码代替原始单词,然后要求模型去正确预测被抠掉的单词。但是这里有个问题:训练过程有[mask]标记,但是真正后面用的时候是不会有这个标记,这自然会有问题。为了避免这个问题,Bert改造了一下,在15%被选中要用[Mask]替代的中只有80%(相当于总单词数的12%)真正被替换成[mask]标记,10%(相当于总单词书的1.5%)随机替换成另外一个单词,10%(相当于总单词书的1.5%)不做改动,这就是Masked双向语言模型的具体做法。

NextSentencePrediction

至于说”Next Sentence Prediction”,指的是做语言模型预训练的时候,分两种情况选择两个句子,一种是选择语料中真正顺序相连的两个句子;另外一种是第二个句子从语料库中抛色子,随机选择几个拼到第一个句子后面。要求模型除了做上述的 Masked 语言模型任务外,附带再做个句子关系预测,判断第二个句子是不是真的是第一个句子的后续句子。之所以这么做,是考虑到很多NLP任务是句子关系判断任务,单词预测粒度的训练到不了句子关系这个层级,增加这个任务有助于下游句子关系判断任务。所以可以看到,它的预训练是个多任务过程,这也是Bert的一个创新。

Bert输入部分的处理

Bert的输入部分也算是特色。它的输入部分是个线性序列,两个句子通过分隔符分隔,最前面和最后面增加两个标识符号。每个单词有三个Embedding:

  1. 位置信息Embedding,这是因为NLP中单词顺序是很重要的特征,需要在这里对位置信息进行编码;
  2. 单词Embedding,这个就是之前一直提到的单词Embedding;
  3. 句子Embedding,因为前面提到训练数据都是由两个句子构成,那么每个句子有个句子整体的Embedding项对应给每个单词;

把单词对应的三个Embedding叠加,就形成了Bert的输入。

Bert输出部分

Bert在预训练的输出部分如何组织,可以参考上图的注释。

Bert有效因子分析

Bert效果特别好,到底是什么因素起作用呢?如上图所示,对比实验可以证明,跟GPT相比,双向语言模型起到了最主要的作用,对于那些需要看到下文的任务来说尤其如此。而预测下个句子来说对整体性能来说影响不算太大,跟具体任务关联度比较高。

Bert的评价和意义

Bert是NLP中里程碑式的工作,对于后面NLP的研究和工业应用会产生长久的影响,这点毫无疑问。但是从上文介绍可以看出,从模型或者方法角度看,Bert借鉴了ELMO,GPT及CBOW,主要提出了Masked语言模型及Next Sentence Prediction,但是这里Next Sentence Prediction 基本不影响大局,而Masked LM明显借鉴了CBOW的思想。所以说Bert模型没什么大的创新,更像是最近几年NLP重要进展的集大成者。如果归纳一下这些进展就是:首先是两阶段模型,第一阶段双向语言模型预训练,这里注意要用双向而不是单向,第二阶段采用具体任务Fine-tuning或者特征继承;其次,是特征抽取要用Transformer作为特征抽取器而不是RNN或者CNN;再者,双向语言模型可以采取CBOW的方法去做(这个是细节问题,不算太关键,前两个因素比较关键)。Bert最大的亮点在于效果好及普适性强,几乎所有NLP任务都可以套用Bert这种两阶段解决思路,而且效果应该会有明显提升。可以预见未来一段时间在NLP应用领域内,Transformer将占据主导地位,而且这种两阶段预训练方法也会主导各种应用。

另外,我们应该弄清楚预训练这个过程本质是在做什么事情,本质上预训练是通过设计好一个网络结构来做语言模型任务,然后把大量甚至是无穷尽的无标注的自然语言文本利用起来,与训练任务把大量语言学知识抽取出来编码到网络结构中,当手头任务带有标注信息的数据有限时,这些先验的语言学特征会对手头任务有极大的特征补充作用,因为当数据有限时,很多语言学现象是覆盖不到的,泛化能力就弱,集成尽量通用的语言学知识自然会加强模型的泛化能力。如果引入先验的语言学知识其实一直是NLP尤其是深度学习场景下的NLP的主要目标之一,不过一直没有太好的解决办法,而ELMO/GPT/Bert的这种两阶段模式看起来无疑是解决这个问题自然又简洁的方法,这也是这些方法的主要价值所在。

对于当前NLP的发展方向,作者认为两点非常重要,一个是需要更强的特征抽取器,目前看来Transformer会逐渐担当大任,但是肯定还不够,需要更强的特征抽取器;第二个就是如何优雅地引入大量无监督数据中包含的语言学知识,注意这里强调地是优雅,而不是引入,此前相当多的工作试图做各种语言学知识的嫁接或者引入,但是很多方法看起来似乎有点强求。目前看预训练这种两阶段方法还是十分有效的,也非常简洁,未来肯定还有会有更好的模型出现。

这就是自然语言模型预训练的发展史。