BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding

学习一下 SOTA 语言模型

这篇文章可以称得上是 2018 年 NLP 方面一个里程碑式的论文了。当时,BERT 模型在 GLUE 评测榜上横扫其他所有模型,在 11 个 NLP 任务上达到最高。尽管这篇论文的阅读笔记在各种博客、论坛等地方都能看到,但我觉得仍然有必要仔细的阅读一遍原文。一来可以加深对论文的理解,二来通过阅读笔记的形式可以更好地记忆这篇文章的细节,不容易忘记。BERT 这篇文章通俗易懂,整体结构完整,条理非常清晰,适合所有学习 NLP 的人阅读。但阅读前需要对 Transformer 有所了解。

模型结构

BERT
如上图所示,BERT 模型几乎完全基于 Transformer 结构的堆叠,更确切地说,BERT 模型是基于 Transformer 结构的 Encoder 部分。这也是该模型与 GPT 模型的最大不同,后者使用的是 Transformer 结构的 Decoder 部分,这意味着句子中的每个单词在计算 self-attention 时只能看到它左边的部分。

简单地回顾一下 Transformer 结构,它由 6 层 Encoder 和 6 层 Decoder 组成,Encoder 用于将输入转变成某种中间表示形式,而 Decoder 则从中间表示形式输出具体的序列结果。两者的区别还包括,Encoder 的 self-attention 是双向的,每个单词都会和句子中的所有其他单词做点积。而 Decoder 的 self-attention 为了防止提前看到后面的单词,在计算 self-attention 时会先乘以一个上三角的 mask 矩阵。

BERT 与 Transformer 的另外一个主要区别是,BERT 中的 Positional Embedding 是由模型自己学习的,而 Transformer 中则是硬编码的。但 BERT 这篇论文中没有介绍 Positional Embedding 具体是如何学习的。

一种显而易见的办法是,单独添加一个 Embedding 层,然后学习一个 $\text {seq_length} \times \text {word_dim}$ 的矩阵,这样就可以构建一个 Lookup 表来处理任意位置的 Positional Embedding。

最后,BERT 的输入由三部分求和得到:单词的 Embedding、Positional Embedding 以及 Segment Embedding,Segment Embedding 用于区分输入的两句句子。输入之所以是两句句子主要是训练 BERT 过程中的 Next Sentence Prediction (NSP) 任务,这在后面一节会继续介绍。

训练方法

搞清楚 BERT 模型的结构之后,下面来看训练 BERT 的具体方法。BERT 通过两个子任务进行训练。1. Masked LM (MLM) 2. Next Sentence Prediction (NSP)
这两个任务是同时进行的,如上图所示。模型的一系列输出中,左侧的 NSP 标签是 NSP 任务的输出结果,而后面的所有输出都是 MLM 任务的输出结果。

Masked LM

该任务相比传统的 Language Model 任务,多了一个 Mask 的操作。具体来说,由于 BERT 使用了双向的 Transformer Encoder 结构,每个单词都能看到句子中的所有其他单词,因此如果直接使用 Language Model 任务来训练 BERT,那么由于模型已经 “看到” 了整个句子,因此很容易就能预测出所有的单词。为了解决整个问题,BERT 提出了 MLM 任务来对模型进行训练,就是将句子输入到模型中时,随机的遮掉一些单词,BERT 使用 [MASK] 这个 token 来代替句子中的原有单词。同时,如果一直使用 [MASK] 来代替句子中的原有单词,那么在后续对 BERT 作 fine-tuning 时由于输入数据不一定含有 [MASK],会导致输入空间不一致的问题。BERT 并不总是使用 [MASK] 替换单词。事实上,对于一句句子,BERT 首先选择 $15\%$ 的单词。然后对于选中的哪些单词,以 $80\%$ 的概率替换为 [MASK],$10\%$ 的概率随机替换为另一个单词,$10\%$ 的概率保持不变。

一个可能存在的问题是,这一做法是否会影响 BERT 对 Language Model 的学习效果?作者在附录中提到,由于随机替换为另一个单词只占全部数据的 $15\% \times 10\% =1.5\%$,因此不会影响 Language Model 的学习效果。

Next Sentence Prediction

LM 任务只能学习句子本身的特征,对于如问答、自然语言推断等 NLP 任务,需要学习句子之间的关系,BERT 提出使用 NSP 任务来学习句子之间的关系。每一个训练样本中包含两个句子 A 和 B,NSP 要求判断 B 是不是 A 的后面一句句子。训练样本中 $50\%$ 的数据满足 B 是 A 的后续句子,剩下的 $50\%$ 则是随机选择的句子作为 B。后续的实验也表明,NSP 任务的训练使得 BERT 在问答、句子推断等任务上取得了很好的效果。

BERT 同时 使用 MLM 和 NSP 这两个任务进行训练。比如以下是两个样本例子:
1.

1
2
Input:   [CLS]   the man went to [MASK] store [SEP] he bought a gallon [MASK] milk [SEP]
Output: <IsNext> the man went to the store [SEP] he bought a gallon of milk [SEP]

2.
1
2
Input:   [CLS]    the man went to [MASK] store [SEP] penguin [MASK] are flight ##less birds [SEP]
Output: <NotNext> the man went to the store [SEP] penguin ##s are flight ##less birds [SEP]

NSP 和 MLM 是两个不同的分类任务,直接在 transformer 结构后面接一层全连接,然后再套一个 softmax 就可以用交叉熵来计算 Loss 了。训练的总 Loss 就是这两部分 Loss 的和。

下游任务

训练好了 BERT,怎么把 BERT 运用到具体的 NLP 任务中呢?作者建议使用两种办法,feature-base 和 fine-tuning。feature-base 就是固定 BERT 的参数,直接使用 BERT 的输出来作为提取的特征,接到其他的模型中。而 fine-tuning 就是直接在 BERT 后面接一层全连接 + softmax,然后直接在 BERT 上面跑 end-to-end 地跑下游任务。 作者在论文中说,基本上只需要 3-4 个 epoch 就能跑到相当不错的效果了,因此 fine-tuning 需要的计算开销非常小 。并且,由于 BERT 使用句子对进行预训练,因此对于单个句子的 NLP 任务,比如句子分类、标注任务,只需要让 A 等于那个句子,B 置空即可。而对于多句句子的任务,可以适当地分配 A 和 B。比如在阅读理解中,可以把 A 作为阅读材料,B 作为问题;对于句子关系判断任务,可以直接将两句句子放到 A 和 B 中等。

实验部分这里就不细讲了,简单地说,就是 BERT 在 GLUE 评测的 12 个 NLP 任务中的 11 个横扫其他全部模型,总分跃居第一,而且很多任务的准确率相比 SOTA 甚至有 $10\%-20\%$ 的提升,关于具体的实验结果可以去看原论文。

总结

BERT 的提出象征着 NLP 的一个飞跃式的发展,NLP 方面的深度学习方法从此从预训练词向量发展到预训练模型。虽然作者谦虚的表示,BERT 的提升最本质的原因只是把 GPT 的单向 Transformer 模型改进到双向的 Transformer,但是从大量的实验上仍然可以表明,BERT 的贡献无疑是十分巨大的。另一方面,BERT 的成功还表明了海量无标签文本语料的重要性,催生了后续一大批以更大量文本作为预训练数据的模型的诞生。

评论