BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
引言
BERT (Bidirectional Encoder Representations from Transformers) 是Google在2018年提出的革命性自然语言处理模型,它通过在无标注文本上进行预训练,学习深层的双向语言表示,在下游任务上取得了突破性的成果。
BERT的核心创新在于双向上下文编码,与之前的ELMo(浅层双向)和GPT(单向)不同,BERT使用Transformer编码器同时利用上下文信息,彻底改变了NLP领域的预训练范式。
背景知识
预训练语言模型的发展
在BERT之前,主流的预训练方法存在以下局限性:
- 单向语言模型(如GPT):只能从左到右或从右到左进行编码,无法同时利用双向上下文
- 浅层双向模型(如ELMo):虽然考虑了双向信息,但只是简单拼接左右向表示,而非深度双向,网络架构比较老,使用的RNN
为什么需要双向编码?
语言的理解往往需要同时考虑前后文信息。例如:
- “银行” 这个词在 “我去银行存钱” 和 “河边的银行” 中含义完全不同
- 只有同时看到前后文,才能准确理解词义
论文核心思想
主要贡献
- 双向预训练:通过Masked Language Model (MLM) 实现真正的双向编码
- 统一的预训练框架:一个模型可以适应多种下游任务
- 迁移学习的成功:证明了大规模预训练+微调的有效性
核心架构
BERT基于Transformer的编码器部分,主要包含:
1 | BERT = Transformer Encoder × N层 |
- BERT-Base: 12层Transformer,768维隐藏层,12个注意力头,110M参数
- BERT-Large: 24层Transformer,1024维隐藏层,16个注意力头,340M参数
预训练方法
1. Masked Language Model (MLM)
目标:预测被掩码的词汇
方法:
- 随机选择15%的token进行掩码
- 其中:
- 80%替换为
[MASK] - 10%替换为随机token
- 10%保持不变
- 80%替换为
为什么不完全用[MASK]?
- 预训练时用[MASK],但微调时没有[MASK],会造成不匹配
- 通过随机替换,模型学会在缺少明确信号时也能预测
数学表示:
1 | P(w_i | w_{context}) = softmax(W_h_i) |
其中,h_i是第i个token的上下文表示
2. Next Sentence Prediction (NSP)
目标:判断两个句子是否是连续的
方法:
- 输入格式:
[CLS] 句子A [SEP] 句子B [SEP] - 50%的概率是连续句子(IsNext)
- 50%的概率是随机句子(NotNext)
为什么需要NSP?
- 许多下游任务(如问答、自然语言推理)需要理解句子间关系
- MLM主要学习词级表示,NSP帮助学习句子级表示
输入表示
BERT的输入由三个embedding相加:
1 | Input = Token Embedding + Segment Embedding + Position Embedding |
Token Embedding
- 使用WordPiece分词
- 特殊token:
[CLS]:分类任务的表示[SEP]:句子分隔符[MASK]:掩码token[UNK]:未知词
Segment Embedding
- 区分句子A和句子B
- E_A = 0,E_B = 1
Position Embedding
- 学习的位置编码(而非Transformer的固定位置编码)
- 最大序列长度:512
模型架构详解
Transformer Encoder层
每个Transformer Encoder包含:
多头自注意力机制 (Multi-Head Self-Attention)
1
2Attention(Q, K, V) = softmax(QK^T / √d_k)V
MultiHead = Concat(head_1, ..., head_h)W^O前馈神经网络 (Feed-Forward Network)
1
FFN(x) = max(0, xW_1 + b_1)W_2 + b_2
残差连接和层归一化
1
output = LayerNorm(x + Sublayer(x))
BERT的输出
- 最后一层的输出:每个token的上下文表示
[CLS]token的输出:用于分类任务的句子级表示
微调策略
下游任务适配
BERT可以通过简单的修改适应各种任务:
单句分类(如情感分析)
1
[CLS] 句子 [SEP] → 分类层
句子对分类(如自然语言推理)
1
[CLS] 句子A [SEP] 句子B [SEP] → 分类层
问答任务(如SQuAD)
1
[CLS] 问题 [SEP] 段落 [SEP] → 起始位置 + 结束位置
序列标注(如命名实体识别)
1
[CLS] token1 token2 ... [SEP] → 每个token的标签
微调技巧
- 学习率:预训练的学习率通常较小(如2e-5)
- Batch size:16或32通常效果较好
- Epochs:2-4个epoch通常足够
- 学习率调度:线性衰减或warmup
实验结果
GLUE基准测试
BERT在11个NLP任务上取得了state-of-the-art的结果:
- MNLI: 84.6% (4.6%提升)
- QQP: 71.2% F1 (4.2%提升)
- QNLI: 90.5% (5.1%提升)
- SST-2: 93.5% (2.0%提升)
- CoLA: 52.1% (5.6%提升)
SQuAD v1.1
- F1: 93.2%
- EM: 87.4%
消融实验
- MLM的影响:移除MLM导致显著性能下降
- NSP的影响:对某些任务有帮助,但不是必需的
- 模型大小的影响:更大的模型带来更好的性能
- 训练步数的影响:更多训练步数持续提升性能
代码实现
使用Hugging Face Transformers
1 | from transformers import BertTokenizer, BertModel |
文本分类示例
1 | from transformers import BertForSequenceClassification |
自定义BERT模型(简化版)
1 | import torch |
技术细节与优化
注意力机制计算
1 | def scaled_dot_product_attention(Q, K, V, mask=None): |
预训练损失函数
1 | def compute_bert_loss(mlm_logits, nsp_logits, mlm_labels, nsp_labels, mlm_mask): |
BERT的优缺点
优点
- 强大的表示能力:双向编码捕获丰富的上下文信息
- 通用性强:一个模型适应多种任务
- 迁移学习效果好:预训练+微调范式非常有效
- 开源可用:提供了多种规模的预训练模型
缺点
- 计算成本高:参数量大,推理速度慢
- 最大长度限制:只能处理512个token
- 预训练任务局限:MLM和NSP可能不是最优的预训练目标
- 单向生成困难:由于双向特性,不适合生成任务
BERT的后续发展
改进方向
模型压缩:
- DistilBERT:知识蒸馏减小模型
- ALBERT:参数共享降低参数量
效率提升:
- ELECTRA:更高效的预训练任务
- RoBERTa:去除NSP,优化训练策略
长文本处理:
- Longformer:处理更长序列
- BigBird:稀疏注意力机制
多语言扩展:
- mBERT:多语言BERT
- XLM:跨语言预训练
总结
BERT通过双向Transformer编码器和创新的预训练任务(MLM + NSP),为NLP领域带来了革命性的变化。其核心思想是:
- 双向编码:同时利用前后文信息
- 预训练+微调:大规模无监督预训练 + 任务特定微调
- 统一架构:一个模型适应多种下游任务
BERT的成功证明了大规模预训练语言模型的有效性,为后续的GPT、T5等模型奠定了基础。
参考文献
Devlin, J., Chang, M. W., Lee, K., & Toutanova, K. (2018). BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. arXiv preprint arXiv:1810.04805.
Vaswani, A., et al. (2017). Attention is all you need. Advances in neural information processing systems, 30.
Radford, A., et al. (2018). Improving language understanding by generative pre-training.
Howard, J., & Ruder, S. (2018). Universal language model fine-tuning for text classification. arXiv preprint arXiv:1801.06146.
思考题
- 为什么BERT使用15%的mask比例?这个比例是否可以调整?
- BERT的MLM任务中,为什么要用80% [MASK]、10% 随机、10% 不变的方式?
- NSP任务对BERT的性能有多大影响?为什么RoBERTa去掉了NSP?
- BERT为什么不适合生成任务?如果要用于生成,应该怎么改进?
- 如何理解BERT的双向编码?它与ELMo的双向有什么本质区别?
思考题答案
1. 为什么BERT使用15%的mask比例?这个比例是否可以调整?
15% mask比例的原因:
- 平衡学习效率与难度:如果mask比例太低(如5%),模型看到的有效训练信号太少,学习效率低;如果太高(如50%),输入信息损失过多,模型难以学习有效的语言表示。
- 经验最优值:15%是经过实验验证的平衡点,既能提供足够的训练信号,又不会过度破坏句子的完整性。
- 计算效率:只预测15%的token,相比预测所有token,计算成本更低。
是否可以调整?
可以调整,但需要权衡:
- 更低的mask比例(5-10%):训练更稳定,但可能需要更多训练步数
- 更高的mask比例(20-30%):可能学到更强的表示,但训练难度增加,可能影响性能
实验发现:
- RoBERTa的实验表明,15%仍然是一个较好的选择
- 对于特定领域或任务,可能需要微调这个比例
2. BERT的MLM任务中,为什么要用80% [MASK]、10% 随机、10% 不变的方式?
这是BERT设计中的一个关键创新,主要解决预训练与微调的不匹配问题:
问题背景:
- 预训练时:模型看到大量
[MASK]token - 微调时:模型看不到
[MASK]token,只有真实词汇 - 如果只使用
[MASK],模型会过度依赖这个特殊token,导致微调时性能下降
三种策略的作用:
80% [MASK]:
- 主要学习目标:让模型学会从上下文预测被掩盖的词
- 这是MLM的核心任务
10% 随机替换:
- 引入噪声:让模型学会在"错误"信息下也能正确预测
- 提高鲁棒性:模拟真实场景中可能出现的错误或噪声
- 防止过拟合:避免模型只记住
[MASK]的模式
10% 保持不变:
- 关键设计:让模型在微调时能够利用真实词汇的信息
- 缓解不匹配:预训练时也看到真实词汇,与微调场景更一致
- 保持语言理解:确保模型不仅学习预测,还学习理解真实词汇
数学直觉:
1 | 如果只使用[MASK]: |
实验验证:
- 如果100%使用
[MASK],在微调任务上性能会下降约2-3% - 混合策略使得预训练和微调更加一致
3. NSP任务对BERT的性能有多大影响?为什么RoBERTa去掉了NSP?
NSP的影响分析:
正面影响:
- 对需要理解句子关系的任务有帮助:如自然语言推理(MNLI)、问答(QNLI)
- 帮助模型学习句子级表示,而不仅仅是词级表示
负面影响:
- 任务过于简单:模型可能只关注句子边界信息,而非深层语义关系
- 训练信号弱:相比MLM,NSP提供的学习信号较弱
- 可能引入噪声:随机选择的负样本可能包含一些有用的信息,但被标记为"不相关"
RoBERTa去掉NSP的原因:
实验发现NSP效果有限:
- 在某些任务上,去掉NSP反而性能更好
- NSP带来的提升主要来自更长的训练,而非任务本身
NSP任务设计有问题:
- 负样本(随机句子对)可能包含有用的信息
- 模型可能学到"只要不是连续句子就是负样本"的简单模式
MLM已经足够强大:
- MLM本身就能学习到句子间的关系
- 通过跨句子的上下文,模型自然能理解句子关系
简化训练流程:
- 去掉NSP后,训练更简单,只需要MLM任务
- 可以专注于优化MLM的训练策略
实验结果:
- RoBERTa去掉NSP后,在大多数任务上性能持平或略有提升
- 证明了NSP并非必需,MLM已经足够学习句子级表示
4. BERT为什么不适合生成任务?如果要用于生成,应该怎么改进?
BERT不适合生成任务的原因:
双向编码的本质:
- BERT在编码时同时看到整个序列(包括"未来"的信息)
- 生成任务需要自回归(从左到右),不能看到未来信息
- 这违反了生成任务的基本要求
架构限制:
- BERT只有编码器,没有解码器
- 无法进行自回归生成
预训练目标不匹配:
- MLM是"填空"任务,不是"续写"任务
- 模型没有学习到生成下一个token的能力
改进方案:
使用BERT作为编码器 + 独立解码器:
1
BERT Encoder + Transformer Decoder
- 编码器:用BERT理解输入
- 解码器:用Transformer解码器进行自回归生成
- 应用:机器翻译、摘要生成
单向BERT变体:
- 训练时使用因果掩码(只能看到左侧信息)
- 类似GPT,但可以保留BERT的其他优势
序列到序列BERT(BART):
- 使用BERT的编码器 + GPT的解码器
- 预训练任务:文本去噪(删除、打乱、填充等)
- 既保留BERT的理解能力,又具备生成能力
T5(Text-to-Text Transfer Transformer):
- 统一的编码器-解码器架构
- 所有任务都转换为文本生成任务
- 更强的生成能力
实际应用:
- BART:专门为生成任务设计的BERT变体
- T5:统一的文本到文本模型
- GPT系列:更适合纯生成任务
5. 如何理解BERT的双向编码?它与ELMo的双向有什么本质区别?
BERT的双向编码:
同时编码:
- 在单次前向传播中,每个token都能同时看到左侧和右侧的所有信息
- 通过自注意力机制,所有位置的信息同时参与计算
深度双向:
- 多层Transformer编码器,每一层都是双向的
- 信息在多层间双向流动和融合
数学表示:
1
h_i^l = Transformer_Encoder([h_1^{l-1}, ..., h_n^{l-1}])
其中,h_i^l 同时依赖于所有位置的 h_j^{l-1}
ELMo的双向:
分别编码:
- 使用两个独立的LSTM:前向LSTM和后向LSTM
- 前向LSTM:从左到右编码,h_i^forward 只看到左侧信息
- 后向LSTM:从右到左编码,h_i^backward 只看到右侧信息
浅层拼接:
- 最终表示 = [h_i^forward; h_i^backward]
- 只是简单拼接,没有深度融合
数学表示:
1
2
3h_i^forward = LSTM_forward(x_1, ..., x_i)
h_i^backward = LSTM_backward(x_i, ..., x_n)
h_i = [h_i^forward; h_i^backward]
本质区别:
| 特性 | ELMo | BERT |
|---|---|---|
| 编码方式 | 两个独立的单向编码器 | 一个双向编码器 |
| 信息融合 | 浅层拼接 | 深度融合(多层) |
| 同时性 | 分别处理,后拼接 | 同时处理所有位置 |
| 架构 | RNN(LSTM) | Transformer |
| 表示质量 | 词级表示为主 | 上下文相关表示 |
| 计算效率 | 顺序计算,较慢 | 并行计算,较快 |
关键差异示例:
假设要理解句子 “The bank is closed” 中的 “bank”:
ELMo:
- 前向LSTM看到 “The bank”,可能理解为"银行"
- 后向LSTM看到 “bank is closed”,也可能理解为"银行"
- 拼接后得到表示,但两个方向的信息是独立计算的
BERT:
- 自注意力机制同时考虑 “The”、“bank”、“is”、“closed”
- 所有位置的信息在每一层都相互影响
- 最终表示融合了完整的上下文信息
为什么BERT的双向更好?
- 信息融合更充分:不是简单拼接,而是深度交互
- 并行计算:Transformer可以并行处理,效率更高
- 长距离依赖:自注意力机制能更好地捕捉长距离依赖
- 表示能力更强:多层双向编码产生更丰富的表示
总结:
- ELMo是"伪双向":两个单向模型的拼接
- BERT是"真双向":真正的双向同时编码和融合






