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 | for i, token in enumerate(input_tokens): |
总结一问:
- 论文中的“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 的“无监督训练”其实是任务驱动的自监督;
- 你不能只“训练一个大网络”,你需要“一个有意义的训练任务”作为学习信号源;
- 所以,设计有效的自监督任务本身,就是研究的核心价值点。
总结
想要模型学到你想要的表示,就必须设计一个它必须依赖该表示才能完成的任务,并且要允许它在不确定性中做出稳定的决策。