更新于 2026年7月12日

第1节 BERT原理与预训练任务#

在本系列文章中,我们将会以前面介绍的 「Transformer」 为基础来介绍整个BERT网络模型的原理。当然,为了使得大家能够更加清晰的理解BERT模型,这里同样也会以原理与实践相结合的方式来进行介绍,包括BERT模型的实现、常见下游任务的微调以及从零实现NSP和MLM预训练任务等。下面,让我们首先进入到第一部分原理的介绍。

1.1 引言#

经过对Transformer的学习,我们总算是对Transformer有了比较清晰的认知。不过说起Transformer模型,其实在它发表之初并没有引起太大的反响,直到它的后继者BERT[1]的出现才使得大家再次回过头来仔细研究Transformer。因此,在接下来内容中,我们将主要从BERT的基本原理、BERT模型的实现、BERT预训练模型在下游任务中的运用、Mask LM和NSP的实现与运用这几个方面来详细介绍Bert。总的来说就是先介绍BERT模型的整体原理,再介绍如何在下游任务中运用预训练的BERT模型,最后介绍如何利用Mask LM和NSP这两个任务来训练BERT模型。

关于Bert所取得的成就这里就不再细说,用论文里面作者的描述来说就是:BERT不仅在概念上很简单,并且从经验上来看它也非常强大,以至于直接刷新了11项NLP记录。

BERT is conceptually simple and empirically powerful. It obtains new state-of-the-art results on eleven natural language processing tasks.

作者之所以说BERT在概念上很简单,我们猜测这是因为BERT本质上是根据Transformer中Encoder堆叠而来所以说它简单;而作者说BERT从经验上来看非常强大,是因为BERT在训练过程中所基于的Mask LM和NSP这两个任务所以说其强大。

由于BERT是基于多层Transformer堆叠而来,因此在整篇论文中关于BERT网络结构的细节之处作者并没有提及。同时,由于论文配了一张极具迷惑性的网络结构图,使得在不看源码的基础上几乎很难弄清整个网络结构的细节之处。

BERT’s model architecture is a multi-layer bidirectional Transformer encoder based on the original implementation de- scribed in Vaswani et al. (2017) and released in the tensor2tensor library.

图 1-1. 原始BERT网络结构图
图 1-1. 原始BERT网络结构图

如图1-1所示就是论文中所展示的BERT网络结构图。看完论文后真的不知道作者为什么要画这么一个结构图,难道就是为了凸显“bidirectional”?一眼看去,对于同一层的Trm来说它到底代表什么? 是类似于time step的展开,还是每个Trm都有着不同的权重?这些你都不清楚,当然论文也没有介绍。不过在看完这部分的源码实现后你就会发现,其实真正的BERT网络结构大体上应该是如图1-2所示的模样。

图 1-2. 原始BERT网络结构图
图 1-2. 原始BERT网络结构图

虽然从图1-2来看,BERT的网络结构确实不太复杂,但是其中的Transformer模块相较于原始Transformer[2]中的实现依旧有着不小的差别,不过这并不影响我们从整体上来认识BERT。

接下来,我们希望通过这篇文章能够让大家对BERT的原理与运用有一个比较清楚的认识与理解。下面,就让我们正式走进对这篇论文的解读中。

1.2 动机#

1.2.1 面临问题#

在论文的介绍部分作者谈到,预训练语言模型(Language model pre-training)对于下游很多自然语言处理任务都有着显著的改善。但是作者继续说到,现有预训练模型的网络结构限制了模型本身的表达能力,其中最主要的限制就是没有采用双向编码的方法来对输入进行编码。

Language model pre-training has been shown to be effective for improving many natural language processing tasks. We argue that current techniques restrict the power of the pre-trained representations, especially for the fine-tuning approaches. The major limitation is that standard language models are unidirectional.

例如在 OpenAI GPT模型中,它使用了从左到右(left-to-right)的网络架构,这就使得模型在编码过程中只能够看到当前时刻之前的信息,而不能够同时捕捉到当前时刻之后的信息。

For example, in OpenAI GPT, the authors use a left-to- right architecture, where every token can only at- tend to previous tokens in the self-attention layers of the Transformer.

图 1-3. 不同方向编码示意图
图 1-3. 不同方向编码示意图

如图1-3所示,对于这句样本来说,无论模型采用的是left-to-right的编码方式还是采用right-to-left的编码方式,模型在对“it”进行编码的时候都不能很好地捕捉到其具体所指代的信息。这就类似于我们人在阅读这句话时一样,在没有看到“tired”这个词之前我们同样也无法判断“it”具体所指代的事物。例如:如果我们把“tired”这个词换成“wide”,则“it”指代的就变成了“street”。所以,如果模型采用的是双向编码的方式,那么从理论上来看就能够很好的避免这个问题,如图1-4所示。

图 1-4. 注意力机制可视化图
图 1-4. 注意力机制可视化图[3]

在图1-4中,橙色线条表示“it”应该将注意力集中在哪些位置上,颜色越深则表示注意力权重越大。通过这幅图可以发现,模型在对“it”进行编码时,将大部分注意力都集中在了“The animal”上,而这也符合我们预期的结果。

1.2.2 解决思路#

在论文中,作者提出了采用BERT(Bidirectional Encoder Representations from Transformers)这一网络结构来实现模型的双向编码学习能力。同时,为了使得模型能够有效的学习到双向编码的能力,BERT在训练过程中使用了基于掩盖的语言模型(Masked Language Model, MLM),即随机对输入序列中的某些位置进行遮蔽,然后通过模型来对其进行预测。

In this paper, we improve the fine-tuning based approaches by proposing BERT: Bidirectional Encoder Representations from Transformers. BERT alleviates the previously mentioned unidirectionality constraint by using a “masked language model” (MLM) pre-training objective.

作者继续谈到,由于MLM预测任务能够使得模型编码得到的结果同时包含上下文的语境信息,因此有利于训练得到更深的BERT网络模型。除此之外,在训练BERT的过程中作者还加入了下句预测任务(Next Sentence Prediction, NSP),即同时输入两句话到模型中,然后预测第2句话是不是第1句话的下一句话。

1.3 技术实现#

对于技术实现这部分内容,我们将会分为三个大的部分来进行介绍。第一部分主要介绍BERT的网络结构原理以及MLM和NSP这两种任务的具体原理;第二部分将主要介绍如何实现BERT以及BERT预训练模型在下游任务中的使用;第三部分则是介绍如何利用MLM和NSP这两个任务来训练BERT模型(可以是从头开始,也可以是基于开源的BERT预训练模型开始)。下面,将先对第一部分的内容进行介绍。

1.3.1 BERT网络结构#

正如图1-2所示,BERT网络结构整体上就是由多层的Transformer Encoder堆叠所形成。关于Transformer部分的具体解读可以参见文章(This post is all you need——层层剥开Transformer)[4],这里就不再赘述。

BERT’s model architecture is a multi-layer bidirectional Transformer encoder based on the original implementation de- scribed in Vaswani et al. (2017) [2].

当然,如果图1-2中的结果再细化一点便能得到如图1-5所示的网络结构图。

图 1-5. BERT网络模型细节图
图 1-5. BERT网络模型细节图

如图1-5所示便是一个详细版的BERT网络结构图,可以发现其上半部分的结构与之前介绍的Transformer Encoder差不多,只不过在Input部分多了一个Segment Embedding。下面就开始分别对其中的各个部分进行介绍。

1.3.2 Input Embedding#

如图1-6所示,在BERT中Input Embedding模块主要包含三个部分:Token Embedding、Positional Embedding和Segment Embedding。虽然前面两种Embedding在Transformer中已经介绍过,但这里需要注意的是BERT中的Positional Embedding对于每个位置的编码并不是采用公式计算得到,而是类似普通词嵌入一样为每一个位置初始化了一个向量,然后随着网络一起训练得到。

图 1-6. Input Embedding 结构图
图 1-6. Input Embedding 结构图

当然,最值得注意的一点就是BERT开源的预训练模型最大只支持512个字符的长度,这是因为其在训练过程中(位置)词表的最大长度只有512。

To speed up pretraing in our experiments, we pre-train the model with sequence length of 128 for 90% of the steps. Then, we train the rest 10% of the steps of sequence of 512 to learn the positional embeddings.

除此之外,第三部分则是BERT中所引入的Segment Embedding。由于BERT的主要目的是构建一个通用的预训练模型,因此难免需要兼顾到各种NLP任务场景下的输入。因此Segment Embedding的作用便是用来区分输入序列中的不同部分,其本质就是通过一个普通的词嵌入来区分每一个序列所处的位置。例如在NSP任务中,对于任意一个句子(一共两个)来说,其中的每一位置都将用同一个向量来进行表示,以此来区分哪部分字符是第1句哪部分字符是第2句,即此时Segment词表的长度为2。

最后,再将这三部分Embedding后的结果相加(并进行标准化)便得到了最终的Input Embedding部分的输出,如图1-7所示。

图 1-7. BERT输入图
图 1-7. BERT输入图

如图1-7所示,最上面的Input表示原始的输入序列,其中第一个字符“[CLS]”是一个特殊的分类标志,如果下游任务是做文本分类的话,那么在BERT的输出结果中可以只取“[CLS]”对应的向量进行分类即可(不过实验表明,取所有位置向量的均值往往有着更好的效果);而其中的“[SEP]”字符则是用来作为将两句话分开的标志。Segment Embedding层则同样是用来区分两句话所在的不同位置,对于每句话来说其内部各自的位置向量都是一样的,当然如果原始输入只有一句话,那么Segment Embedding层中对应的每个Token的位置向量都相同。最后,Positional Embedding则是用来标识句子中每个Token各自所在的位置,使得模型能够捕捉到文本“有序”这一特性。具体细节之处见后续代码实现。

Sentence pairs are packed together into a single sequence. We differentiate the sentences in two ways. First, we separate them with a special token ([SEP]). Second, we add a learned embed- ding to every token indicating whether it belongs to sentence A or sentence B.

1.3.3 BertEncoder#

如图1-8所示便是Bert Encoder的结构示意图,其整体由多个BertLayer(也就是论文中所指代的Transformer blocks)所构成。

图 1-8. BertEncoder结构图
图 1-8. BertEncoder结构图

具体的,在论文中作者分别用$L$来表示BertLayer的层数,即BertEncoder是由$L$个BertLayer所构成;用$H$来表示模型的维度;用$A$来表示多头注意力中多头的个数。同时,在论文中作者分别就$\text{BERT}_{\text{BASE}}(L=12,H=768,A=12)$和$\text{BERT}_{\text{LARGE}}(L=24,H=1024,A=16)$这两种尺寸的BERT模型进行了实验对比。由于这部分类似的内容在Transformer中已经进行了详细介绍,所以这里就不再赘述,细节之处见后续代码实现。

1.3.4 MLM与NSP任务#

为了能够更好训练BERT网络,论文作者在BERT的训练过程中引入两个任务,MLM和NSP。对于MLM任务来说,其做法是随机掩盖掉输入序列中 的Token(即用“[MASK]”替换掉原有的Token),然后在BERT的输出结果中取对应掩盖位置上的向量进行真实值预测。

In order to train a deep bidirectional representation, we simply mask some percentage of the input tokens at random, and then predict those masked tokens. In this case, the final hidden vectors corresponding to the mask tokens are fed into an output softmax over the vocabulary, as in a standard LM. In all of our experiments, we mask 15% of all WordPiece tokens in each sequence at random.

接着作者提到,虽然MLM的这种做法能够得到一个很好的预训练模型,但是仍旧存在不足之处。由于在fine-tuning时,由于输入序列中并不存在“[MASK]”这样的Token,因此这将导致pre-training和fine-tuning之间存在不匹配不一致的问题(GAP)。

Although this allows us to obtain a bidirectional pre-trained model, a downside is that we are creating a mismatch between pre-training and fine-tuning, since the [MASK] token does not ap- pear during fine-tuning.

为了解决这一问题,作者在原始MLM的基础了做了部分改动,即先选定 的Token,然后将其中的 替换为“[MASK]”、 随机替换为其它Token、剩下的 不变。最后取这 的Token对应的输出做分类来预测其真实值。

The training data generator chooses 15% of the token positions at random for prediction. If the i-th token is chosen, we replace the i-th token with (1) the [MASK] token 80% of the time (2) a random token 10% of the time (3) the unchanged i-th token 10% of the time.

最后,作者还给出了一个不同掩盖策略下的对比结果,如图1-9所示。

图 1-9. 不同MASK策略对比结果图
图 1-9. 不同MASK策略对比结果图

由于很多下游任务需要依赖于分析两句话之间的关系来进行建模,例如问题回答等。为了使得模型能够具备有这样的能力,作者在论文中又提出了二分类的下句预测任务。

Many important downstream tasks such as Question Answering (QA) and Natural Language Inference (NLI) are based on understanding the relationship between two sentences. In order to train a model that understands sentence relationships, we pre-train for a binarized next sentence prediction task.

具体地,对于每个样本来说都是由A和B两句话构成,其中 的情况B确实为A的下一句话(标签为IsNext),另外的 的情况是B为语料中其它的随机句子(标签为NotNext),然后模型来预测B是否为A的下一句话。

Specifically, when choosing the sentences A and B for each pretraining example, 50% of the time B is the actual next sentence that follows A (labeled as IsNext), and 50% of the time it is a random sentence from the corpus (labeled as NotNext).

如图1-10所示便是ML和NSP这两个任务在BERT预训练时的输入输出示意图,其中最上层输出的 在预训练时用于NSP中的分类任务;其它位置上的 则用于预测被掩盖的Token。

图 1-10. ML和NSP任务网络结构图
图 1-10. ML和NSP任务网络结构图

到此,对于BERT模型的原理以及NSP、MLM这两个任务的内容就介绍完了。总的来说,如果单从网络结构上来看BERT并没有太大的创新,这也正如作者所说“BERT整体上就是由多层的Transformer Encoder堆叠而来”,并且所谓的“bidirectional”其实指的也就是Transformer中的self-attention机制。同时,真正让BERT表现出色的应该是基于MLM和NSP这两种任务的预训练过程,使得训练得到的模型具有强大的表征能力。

在下一节中,将会详细介绍如何动手来实现BERT模型,以及如何载入现有的模型参数并运用在下游任务中。

阅读 --

第1节 多头注意力机制原理

本文是《Attention Is All You Need》精读系列第1讲,从 RNN 串行瓶颈出发讲清 Transformer 为什么必须引入自注意力,再用图解与公式拆解 Scaled Dot-Product …