BERT相关总结

本文参考自 关于BERT的若干问题整理记录 ,部分内容有删改。

BERT自从2018年横空出世后,有关BERT的论文和比赛就不断刷屏。之前写了一篇博文的介绍了BERT的来世今生,转眼就来到了2019年底,因此这一篇博文就相当于一个BERT的年终总结。废话不多说,我们直奔主题。

基本原理

BERT来自谷歌论文 Pre-training of Deep Bidirectional Transformers for Language Understanding ,整体就是一个自编码模型(Autoencoder LM),并且其设计了两个任务来训练该模型。第一个任务是采用MaskLM方式来训练语言模型,通俗地来说就是输入一句话的时候,随机地选一些要预测的词,然后用一个特殊的符号[MASK]来替代它们,之后模型根据所给的标签去学习这些地方该填的词。第二个任务在双向语言模型的基础上额外增加了一个句子级别的连续性预测任务,即预测输入BERT的单文本是否为连续的文本,引入这个任务可以更好地让模型学到连续文本片段之间的关系。虽然这个任务后来被证明不如不加,反而影响了BERT的性能表现。

BERT相较于原来的RNN、LSMTM可以做到并发只想,同时提取词在句子中的关系特征,并且能在多个不同层次提取关系特征,进而更全面反映句子语义。相较于word2vec,其又能根据句子上下文获取词义,从而避免歧义出现。同时缺点也是显而易见,模型参数太多,且模型太大,少量数据训练时,容易过拟合。

训练过程

MASKed LM

Masked LM的任务描述为:给定一句话,随机抹去这句话中的一个或几个词,要求根据剩余词汇预测被抹去的几个词分别是什么,如下图所示。

BERT 模型的这个预训练过程其实就是在模仿我们学语言的过程,思想来源于 完形填空 的任务。具体来说,文章作者在一句话中随机选择 15% 的词汇用于预测。对于在原句中被抹去的词汇, 80% 情况下采用一个特殊符号 [MASK] 替换, 10% 情况下采用一个任意词替换,剩余 10% 情况下保持原词汇不变。这么做的主要原因是:在后续微调任务中语句中并不会出现 [MASK] 标记,而且这么做的另一个好处是:预测一个词汇时,模型并不知道输入对应位置的词汇是否为正确的词汇( 10% 概率), 这就迫使模型更多地依赖于上下文信息去预测词汇 ,并且赋予了模型一定的纠错能力。上述提到了这样做的一个缺点,其实这样做还有另外一个缺点,就是每批次数据中只有 15% 的标记被预测, 这意味着模型可能需要更多的预训练步骤来收敛

Next Sentence Prediction

Next Sentence Prediction的任务描述为:给定一篇文章中的两句话,判断第二句话在文本中是否紧跟在第一句话之后,

这个类似于 段落重排序 的任务,即:将一篇文章的各段打乱,让我们通过重新排序把原文还原出来,这其实需要我们对全文大意有充分、准确的理解。Next Sentence Prediction 任务实际上就是 段落重排序的简化版 :只考虑两句话,判断是否是一篇文章中的前后句。在实际预训练过程中,文章作者从文本语料库中随机选择 50% 正确语句对和 50% 错误语句对进行训练,与 Masked LM 任务相结合, 让模型能够更准确地刻画语句乃至篇章层面的语义信息

BERT 模型通过对 Masked LM 任务和 Next Sentence Prediction 任务进行联合训练,使模型输出的每个字 / 词的向量表示都能尽可能全面、准确地刻画输入文本(单句或语句对)的整体信息,为后续的微调任务提供更好的模型参数初始值。

BERT VS ELMO

BERT的效果优于ELMO,主要原因有以下几点:

  1. LSTM抽取特征的能力远弱于Transform;
  2. 拼接方式双向融合特征能力偏弱;
  3. BERT的训练数据和模型参数均多于ELMO,这一点很重要。

ELMo模型是通过语言模型任务得到句子中单词的embedding表示,以此作为补充的新特征给下游任务使用。因为ELMO给下游提供的是每个单词的特征形式,所以这一类预训练的方法被称为“Feature-based Pre-Training”。而BERT模型是“基于Fine-tuning的模式”,这种做法和图像领域基于Fine-tuning的方式基本一致,下游任务需要将模型改造成BERT模型,才可利用BERT模型预训练好的参数。

BERT局限性

从XLNet论文中,提到了BERT的两个缺点,分别如下:

  1. BERT在第一个预训练阶段,假设句子中多个单词被Mask掉,这些被Mask掉的单词之间没有任何关系,是条件独立的,然而有时候这些单词之间是有关系的,比如”New York is a city”,假设我们Mask住”New”和”York”两个词,那么给定”is a city”的条件下”New”和”York”并不独立,因为”New York”是一个实体,看到”New”则后面出现”York”的概率要比看到”Old”后面出现”York”概率要大得多。

    但是需要注意的是,这个问题并不是什么大问题,甚至可以说对最后的结果并没有多大的影响,因为本身BERT预训练的语料就是海量的(动辄几十个G),所以如果训练数据足够大,其实不靠当前这个例子,靠其它例子,也能弥补被Mask单词直接的相互关系问题,因为总有其它例子能够学会这些单词的相互依赖关系。

  2. BERT的在预训练时会出现特殊的[MASK],但是它在下游的fine-tune中不会出现, 这就出现了预训练阶段和fine-tune阶段不一致的问题 。其实这个问题对最后结果产生多大的影响也是不够明确的,因为后续有许多BERT相关的预训练模型仍然保持了[MASK]标记,也取得了很大的结果,而且很多数据集上的结果也比BERT要好。但是确确实实引入[MASK]标记,也是为了构造自编码语言模型而采用的一种折中方式。

另外还有一个缺点,是BERT在分词后做[MASK]会产生的一个问题,为了解决OOV的问题,我们通常会把一个词切分成更细粒度的WordPiece。BERT在Pretraining的时候是随机Mask这些WordPiece的,这就可能出现只Mask一个词的一部分的情况,例如,probability这个词被切分成”pro”、”#babi”和”#lity”3个WordPiece。有可能出现的一种随机Mask是把”#babi” Mask住,但是”pro”和”#lity”没有被Mask。这样的预测任务就变得容易了,因为在”pro”和”#lity”之间基本上只能是”#babi”了。这样它只需要记住一些词(WordPiece的序列)就可以完成这个任务,而不是根据上下文的语义关系来预测出来的。类似的中文的词”模型”也可能被Mask部分(其实用”琵琶”的例子可能更好,因为这两个字只能一起出现而不能单独出现),这也会让预测变得容易。

为了解决这个问题,很自然的想法就是词作为一个整体要么都Mask要么都不Mask,这就是所谓的Whole Word Masking。这是一个很简单的想法,对于BERT的代码修改也非常少,只是修改一些Mask的那段代码。

一些疑问

BERT为什么要用mask?

BERT通过在输入X中随机Mask掉一部分单词,然后预训练过程的主要任务之一是根据上下文单词来预测这些被Mask掉的单词。其实这个就是典型的Denosing Autoencoder的思路,那些被Mask掉的单词就是 在输入侧加入的所谓噪音。 类似BERT这种预训练模式,被称为DAE LM。因此总结来说BERT模型 [Mask] 标记就是引入噪音的手段。

关于DAE LM预训练模式,优点是它能比较自然地融入双向语言模型,同时看到被预测单词的上文和下文,然而缺点也很明显,主要在输入侧引入[Mask]标记,导致预训练阶段和Fine-tuning阶段不一致的问题。

mask相对于CBOW有什么异同点?

相同点:CBOW的核心思想是:给定上下文,根据它的上文 Context-Before 和下文 Context-after 去预测input word。而BERT本质上也是这么做的,但是BERT的做法是给定一个句子,会随机Mask 15%的词,然后让BERT来预测这些Mask的词。

不同点:首先,在CBOW中,每个单词都会成为input word,而BERT不是这么做的,原因是这样做的话,训练数据就太大了,而且训练时间也会非常长。

其次,对于输入数据部分,CBOW中的输入数据只有待预测单词的上下文,而BERT的输入是带有[MASK] token的“完整”句子,也就是说BERT在输入端将待预测的input word用[MASK] token代替了。

另外,通过CBOW模型训练后,每个单词的word embedding是唯一的,因此并不能很好的处理一词多义的问题,而BERT模型得到的word embedding(token embedding)融合了上下文的信息,就算是同一个单词,在不同的上下文环境下,得到的word embedding是不一样的。

word2vec到BERT又改进了什么?

word2vec到BERT的改进之处其实没有很明确的答案,如同上面的问题所述,BERT的思想其实很大程度上来源于CBOW模型,如果从准确率上说改进的话,BERT利用更深的模型,以及海量的语料,得到的embedding表示,来做下游任务时的准确率是要比word2vec高不少的。实际上,这也离不开模型的“加码”以及数据的“巨大加码”。再从方法的意义角度来说,BERT的重要意义在于给大量的NLP任务提供了一个泛化能力很强的预训练模型,而仅仅使用word2vec产生的词向量表示,不仅能够完成的任务比BERT少了很多,而且很多时候直接利用word2vec产生的词向量表示给下游任务提供信息,下游任务的表现不一定会很好,甚至会比较差。

参考

关于BERT的若干问题整理记录

XLNet原理