BERT是自然语言处理领域的里程碑模型,它的出现刷新了多项NLP任务的记录。本文从底层原理出发,深入剖析BERT的模型结构、预训练任务、注意力机制、输入表示等核心概念,帮助你真正理解BERT为什么这么强,以及它是怎么工作的。

一、BERT是什么

BERT(Bidirectional Encoder Representations from Transformers)是Google在2018年提出的预训练语言模型,它的核心思想是用大规模无标注文本进行预训练,学习通用的语言表示,然后在下游任务上进行微调。

在BERT之前,NLP模型大多是单向的或者浅层双向的,无法充分利用上下文信息。BERT的创新在于用Transformer的编码器构建了一个深度双向的语言模型,能同时利用左右两边的上下文信息,学习到更丰富的语言表示。

BERT的出现是NLP领域的一个转折点,它在11项NLP任务上取得了state-of-the-art的结果,包括问答、自然语言推理、文本分类、命名实体识别等。后来的很多模型(RoBERTa、ALBERT、DistilBERT等)都是在BERT的基础上改进的。

二、BERT的整体结构

BERT的核心是Transformer的编码器。Transformer是Google在2017年提出的模型,用自注意力机制替代了RNN,能并行处理序列,同时捕捉长距离依赖。BERT用了Transformer的编码器部分,没有用解码器,因为BERT的目标是学习语言表示而不是生成文本。

BERT有两个主要版本:

  • BERT-base:12层编码器,12个注意力头,隐藏层维度768,参数约1.1亿
  • BERT-large:24层编码器,16个注意力头,隐藏层维度1024,参数约3.4亿

BERT的整体流程是:输入文本经过词嵌入和位置编码,加上特殊标记,然后通过多层Transformer编码器,每层都有多头自注意力和前馈神经网络,最后输出每个词的上下文表示。这些表示可以用于各种下游任务。

三、输入表示

BERT的输入是三个嵌入的和:词嵌入(Token Embedding)、段嵌入(Segment Embedding)、位置嵌入(Position Embedding)。

1. 词嵌入

BERT用WordPiece分词,把词拆成子词。比如"playing"会被拆成"play"和"##ing"。这样可以减少词表大小,同时能处理未登录词。BERT的词表大小是30522(英文),中文BERT用的是字级别的分词。

每个词被映射成一个768维(base版)的向量。

2. 段嵌入

BERT可以处理两个句子的输入(比如句子对任务),用段嵌入区分第一个句子和第二个句子。第一个句子的段嵌入是EA,第二个是EB。单句任务都用E_A。

3. 位置嵌入

因为Transformer没有递归结构,无法感知词的顺序,所以需要位置嵌入来编码位置信息。BERT用的是可学习的位置嵌入,每个位置对应一个向量,最大支持512个token。

最终的输入是这三个嵌入相加,然后经过LayerNorm和Dropout,进入编码器。

4. 特殊标记

BERT有几个特殊标记:

  • <[BOSneverused_51bce0c785ca2f68081bfa7d91973934]>:每个输入的第一个token,它的最终隐藏状态用于分类任务
  • [SEP]:句子分隔符,用于分隔两个句子,也放在输入末尾
  • [MASK]:掩码标记,用于MLM预训练任务

四、Transformer编码器详解

BERT的每一层编码器都包含两个子层:多头自注意力和前馈神经网络,每个子层都有残差连接和LayerNorm。

1. 自注意力机制

自注意力是Transformer的核心。它的计算过程是:对于输入序列中的每个词,计算它和所有词(包括自己)的注意力分数,然后用这些分数对所有词的表示加权求和,得到这个词的上下文表示。

具体来说,自注意力用三个矩阵把输入映射成查询(Query)、键(Key)、值(Value)。查询和所有键做点积得到注意力分数,经过softmax归一化后,对值加权求和。公式是:

Attention(Q, K, V) = softmax(QK^T / sqrt(d_k))V

除以sqrt(d_k)是为了防止点积过大导致softmax梯度消失。

自注意力的优势是能并行计算,而且能直接捕捉任意两个词之间的依赖,不管距离多远,这比RNN一步步传递信息高效得多。

2. 多头注意力

多头注意力是把自注意力做多次,每次用不同的查询、键、值矩阵,学习不同的注意力模式。比如有的头关注语法关系,有的头关注语义关系,有的头关注长距离依赖。最后把多个头的输出拼接起来,经过一个线性变换。

BERT-base用12个注意力头,每个头的维度是64(768/12)。多头注意力让模型能从不同子空间学习不同的表示,表达能力更强。

3. 前馈神经网络

每个编码器层还有一个前馈神经网络,对每个位置的表示独立做两次线性变换,中间用GELU激活函数。公式是:

FFN(x) = max(0, xW1 + b1)W2 + b2

BERT用的是GELU激活而不是ReLU,GELU是一种平滑的激活函数,在深度学习中表现更好。前馈网络的中间层维度是3072(base版),是隐藏层维度的4倍。

4. 残差连接和LayerNorm

每个子层都有残差连接:输出 = LayerNorm(x + Sublayer(x))。残差连接能缓解梯度消失,让深层网络更容易训练。LayerNorm对每个样本的特征维度做归一化,稳定训练过程。

五、BERT的预训练任务

BERT的强大来自于两个预训练任务:掩码语言模型(MLM)和下一句预测(NSP)。

1. 掩码语言模型(Masked Language Model)

MLM是BERT最核心的创新。传统的语言模型是单向的,只能用左边的词预测右边的词(或者反过来),无法同时利用双向上下文。BERT用MLM实现了双向预训练:随机把输入中的一些词替换成[MASK]标记,然后让模型预测这些被掩码的词。

因为预测的时候被掩码的词已经被替换成[MASK]了,所以模型可以同时看左右两边的上下文来预测,这就是双向的含义。

BERT的MLM策略是:随机选择15%的词进行掩码,其中:

  • 80%的概率替换成[MASK]
  • 10%的概率替换成一个随机的词
  • 10%的概率保持原词不变

这样做是因为[MASK]标记在微调阶段不会出现,训练和微调有差异。用10%的随机词和10%的原词,可以让模型不知道哪些词是被掩码的,从而被迫对每个词都学习好的表示,而不是只学习预测[MASK]。

MLM的损失是交叉熵,只计算被掩码位置的预测损失。

2. 下一句预测(Next Sentence Prediction)

NSP是一个二分类任务,给模型两个句子A和B,预测B是不是A的下一句。50%的概率B是A的实际下一句(正样本),50%的概率B是语料中随机选的一个句子(负样本)。用<[BOSneverused_51bce0c785ca2f68081bfa7d91973934]>的表示经过一个线性层和softmax做二分类。

NSP的目的是让模型学习句子之间的关系,这对问答、自然语言推理等需要理解句子关系的任务有帮助。

不过后来的研究(比如RoBERTa)发现NSP的作用不大,甚至可能有负面影响,因为负样本的构造太简单了。RoBERTa去掉了NSP,用更长的序列和更多数据训练,效果更好。

3. 预训练数据

BERT用了大规模的无标注文本进行预训练:BookCorpus(8亿词)加上英文维基百科(25亿词),总共约33亿词。预训练用了64块TPU,base版训练了4天,large版训练了16天。

预训练的batch size是256个序列,每个序列最大512个token。前90%的训练步用128的序列长度,后10%用512的序列长度,这样既能加快训练速度又能学习长序列的位置嵌入。

六、BERT的微调

预训练之后,BERT可以在各种下游任务上微调。微调的方法很简单:在BERT的输出上加一个任务特定的输出层,然后用下游任务的标注数据训练整个模型(包括BERT的参数)。

不同任务的微调方式:

1. 句子对分类

比如自然语言推理、问答匹配。输入两个句子,用<[BOSneverused_51bce0c785ca2f68081bfa7d91973934]>的表示经过一个分类层,输出类别概率。

2. 单句分类

比如情感分析、主题分类。输入一个句子,同样用<[BOSneverused_51bce0c785ca2f68081bfa7d91973934]>的表示做分类。

3. 问答任务

比如SQuAD,输入问题和文章,输出答案在文章中的起始和结束位置。用两个线性层分别预测每个位置是答案起点和终点的概率。

4. 命名实体识别

序列标注任务,每个词输出一个标签。用每个词的最终表示经过一个分类层,预测该词的实体类型。

5. 句子相似度

输入两个句子,用<[BOSneverused_51bce0c785ca2f68081bfa7d91973934]>的表示计算相似度,或者用双塔结构分别编码两个句子再计算相似度。

微调的超参数:学习率一般用2e-5到5e-5,batch size 16或32,训练轮数2到4轮。BERT的微调比较稳定,不同随机种子的结果差异不大。

七、BERT为什么这么强

总结一下BERT成功的原因:

1. 深度双向表示

MLM让BERT能同时利用左右上下文,学习到深度双向的语言表示,这比单向模型(如GPT)和浅层双向模型(如ELMo)的表示更丰富。

2. Transformer架构

Transformer的自注意力机制能高效捕捉长距离依赖,而且能并行计算,让训练深层大模型成为可能。

3. 大规模预训练

BERT用了33亿词的大规模语料预训练,参数量达到1.1亿到3.4亿,模型容量大,能学到丰富的语言知识。

4. 通用表示+微调

预训练学习通用语言表示,微调适配具体任务,这种范式迁移能力强,在各种任务上都能取得好效果,而且微调只需要少量标注数据。

5. 开源和易用

Google开源了BERT的代码和预训练模型,降低了使用门槛,让整个社区都能用起来,推动了NLP的发展。

八、BERT的局限和改进

BERT虽然强大,但也有一些局限:

1. 预训练和微调的差异

MLM预训练时用了[MASK]标记,但微调时没有[MASK],这造成了预训练和微调的不一致。虽然用10%随机词和10%原词缓解了这个问题,但没有完全解决。

2. 只能处理512个token

BERT的最大序列长度是512,无法处理长文档。虽然有一些改进(如Transformer-XL、Longformer),但原生BERT不支持长序列。

3. 模型大,推理慢

BERT-large有3.4亿参数,推理速度慢,不适合对延迟要求高的在线服务。后来有了DistilBERT(蒸馏版,参数减少一半速度快一倍)、ALBERT(参数共享,参数大幅减少)等轻量化版本。

4. NSP任务效果不好

如前所述,NSP的作用有限,RoBERTa去掉了NSP并用更多数据训练,效果超过了BERT。

后续的改进模型包括:

  • RoBERTa:去掉NSP,用更多数据、更大batch、更长序列训练
  • ALBERT:用因子化词嵌入和跨层参数共享,大幅减少参数
  • DistilBERT:知识蒸馏,参数减少一半,速度快一倍,保留97%的能力
  • XLNet:用排列语言模型替代MLM,解决预训练微调差异
  • ELECTRA:用生成器替换词,判别器判断每个词是否被替换,训练效率更高

九、写在最后

BERT是NLP领域的里程碑,它的预训练+微调范式彻底改变了NLP的研究和应用方式。理解BERT的原理,不仅能帮助我们更好地使用它,也能理解后续很多NLP模型的设计思想。

本文从输入表示、Transformer编码器、预训练任务、微调方法等方面剖析了BERT的底层机制。BERT的核心创新是MLM实现的深度双向表示和Transformer的强大建模能力,加上大规模数据预训练,造就了它的成功。

如果你想深入学习,建议读一读BERT的原始论文,再看看Hugging Face的Transformers库的源码,动手跑一跑BERT的微调任务,理论结合实践才能真正理解。