BERT论文中的两个细节再思考

本文是我在精读 BERT 论文《BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding》时,遇到的两个重要但难以理解的问题。虽然论文中只用几行文字描述,但通过查阅资料和向GPT请教,我终于理解了背后的逻辑。在这里记录下来,方便自己日后获得启发。


问题一:MaskedLM 掩码策略到底怎么操作的?

论文原文:

We mask 15% of all tokens in the input. Of these:

  • 80% are replaced with the [MASK] token,
  • 10% are replaced with a random token,
  • 10% are left unchanged.

这段话看似简单,实则藏着三层操作,论文没有明确讲清楚,在附录中给出了一些解释:


详细步骤:三步构造掩码

假设我们有如下输入序列(长度为 8):

1
["我", "爱", "华", "中", "科", "技", "大", "学"]

第一步:从中选出 15% 的 token 作为预测目标(而不是全部)

  • 15% × 8 ≈ 1 个 → 假设我们选中了 "科" 这个词。

这个位置就是需要预测的目标 token 位置


第二步:对这个位置执行掩码扰动策略

对被选中的每一个 token(“科”),有 3 种扰动方式,按比例分布:

替换方式 概率 输入会变成 Label 是
替换为 [MASK] 80% ["我", "爱", "华", "中", [MASK], "技", "大", "学"] "科"
替换为随机 token 10% ["我", "爱", "华", "中", "的", "技", "大", "学"] "科"
保持原词不变 10% ["我", "爱", "华", "中", "科", "技", "大", "学"] "科"

注意,无论掩码前是否修改了 token,最终模型都要预测原来的词 “科”

这样做是为了增强模型的鲁棒性,避免它在预训练时学会“看到 [MASK] 就预测”,但在下游任务中却从来没有 [MASK]。


第三步:其他 token 设置为不预测

BERT 的损失只计算被选中的 15% 的 token。其他位置设置为 -100(忽略)。


伪代码示意:

1
2
3
4
5
6
7
8
9
10
11
12
for i, token in enumerate(input_tokens):
if random() < 0.15: # 15% 概率选择作为目标
prob = random()
if prob < 0.8:
input_tokens[i] = "[MASK]"
elif prob < 0.9:
input_tokens[i] = random_token()
else:
pass # 保持原词
labels[i] = original_token # 记录要预测的词
else:
labels[i] = -100 # 不参与预测损失

总结一问:

  • 论文中的“15%”指的是预测目标,不是掩码数量;
  • 在那 15% 中再细分为三类扰动,80% mask,10% 随机词,10% 保留;
  • 不论输入被怎么扰动,预测目标都是“原始词”;
  • 比起ELMo或传统LMs,MaskedLM的这个策略更像填空题,更有效训练双向语义。

问题二:BERT 是无监督的,那我们怎么训练 [CLS] 分类能力?


我的问题详细描述是这样的:

我知道 [CLS] 是代表整个句子的分类 token,但我们在预训练阶段又没有任务标签,它是怎么被训练出来的?难道模型自己就知道哪个句子属于哪一类?如果没有监督,它是怎么学会分类的?


真相是:我们确实给了一个“伪监督任务”,就是 —— Next Sentence Prediction(NSP)

NSP 任务内容:

给定两个句子 A 和 B,模型要判断:

  • B 是 A 的下一句(IsNext) → label = 1
  • B 是随机句子(NotNext) → label = 0

输入格式如下:

1
[CLS] Sentence A [SEP] Sentence B [SEP]

训练目标是:用 [CLS] 的输出向量去预测 “IsNext / NotNext”


这样 [CLS] 就被“监督”起来了:

组件 作用
[CLS] 聚合 Sentence A+B 的语义信息
NSP 头 一个简单分类器(linear + softmax)
标签 是不是下一句(来自语料)

虽然不是人工标注的任务,但这就是一个自监督分类任务正是用于训练 [CLS] 表达句子对语义


下游任务中我们继续用 [CLS]

  • 文本分类任务 → 用 [CLS] 输出 + 分类器;
  • 句子对匹配任务 → 用 [CLS] 输出判断语义关系;
  • 甚至在 ViT 中也有类似的 [CLS] token!

➡️ 所以,我们不是“盲目训练 [CLS]”,而是在 NSP 任务中明确地对其进行了训练!


总结二问:

  • [CLS] 是通过 NSP 任务被训练出来的;
  • NSP 是一个“伪监督”的二分类任务,本质上就是让模型学会句子级别的语义关系;
  • 虽然是“无监督预训练”,但我们提供了“伪标签”任务,实际是一种自监督学习
  • 这也说明了:预训练阶段并不等于“什么监督都没有”

总结

这两个问题一开始真的让我卡住了,但搞懂之后豁然开朗:

问题 我的理解
掩码策略怎么用? 先选 15%,再三种扰动,预测原词
[CLS] 怎么学会分类? NSP 是自监督任务,明确训练 [CLS]
预训练是完全无监督的吗? 不是,是自监督,有伪标签任务

启发


问题一背后的思想:引入扰动但保留原目标 = 鲁棒训练

MLM 的掩码策略:15% token → 80% mask + 10% random + 10% unchanged,但预测的始终是原词

启示 1:训练时要主动制造“不确定性”,但目标要一致

  • 给模型输入扰动,让它学会“从不确定中恢复正确答案”;
  • 即使输入被修改,目标保持不变,这就提升了泛化能力

在之后的研究中可以类比使用的思路有:

  • 输入扰动、增强、数据缺失,但仍对齐原任务目标;
  • 比如图像中加入遮挡,文本中随机丢词、换词,但目标语义不变;
  • 对抗训练(adversarial training);

启示 2:伪标签和结构噪声是“必要的信号干扰”,不是错误

  • 不完美的训练数据有时比完美更有利于学习鲁棒性;
  • 设计训练任务时可以引入一定比例的“不可预测元素”,但监督信号要清晰。

问题二背后的思想:任务接口与无监督目标结合,实现功能性表示学习

[CLS] 是下游任务的接口,但我们在预训练时通过 NSP(一个“伪任务”)来监督它

启示 3:要训练某种“用途向量”,就设计一个“结构性任务”让它发挥作用

  • 想让模型学会“整个句子的表示” → 设计一个必须依赖句子整体语义才能完成的任务(如 NSP);
  • [CLS] 并不是天生能代表句子,它是被训练出来的,因为它承担了一个任务角色。

启示 4:无监督 ≠ 无目标

  • BERT 的“无监督训练”其实是任务驱动的自监督
  • 你不能只“训练一个大网络”,你需要“一个有意义的训练任务”作为学习信号源;
  • 所以,设计有效的自监督任务本身,就是研究的核心价值点

总结

想要模型学到你想要的表示,就必须设计一个它必须依赖该表示才能完成的任务,并且要允许它在不确定性中做出稳定的决策。