BERT:掩码语言建模 本节摘要:GPT 预测下一个词,BERT 预测一个被挖掉的词。就这一句话的差别,带来了此后五年一切「嵌入形态」的半壁江山。2018 年之前,每个 NLP 任务——情感、命名实体识别(NER)、问答、蕴含——都得用自己的标注数据从头训一个模型,没有「预训练好的懂英语」检查点可供微调。BERT(Devlin 等 2018)问了一个简单问题:拿一个 Transformer 编码器,用全网所有句子训练,逼它从两侧上下文预测被挖掉的词,会怎样?然后在你的下游任务上只微调一个小头。参数效率是启示性的——18 个月内 BERT 及其变体(RoBERTa、ALBERT、ELECTRA)横扫所有 NLP 榜单。
本节摘要:GPT 预测下一个词,BERT 预测一个被挖掉的词。就这一句话的差别,带来了此后五年一切「嵌入形态」的半壁江山。2018 年之前,每个 NLP 任务——情感、命名实体识别(NER)、问答、蕴含——都得用自己的标注数据从头训一个模型,没有「预训练好的懂英语」检查点可供微调。BERT(Devlin 等 2018)问了一个简单问题:拿一个 Transformer 编码器,用全网所有句子训练,逼它从两侧上下文预测被挖掉的词,会怎样?然后在你的下游任务上只微调一个小头。参数效率是启示性的——18 个月内 BERT 及其变体(RoBERTa、ALBERT、ELECTRA)横扫所有 NLP 榜单。到 2026 年,编码器型模型仍是分类、检索、结构化抽取的正确工具:每 token 比 decoder 快 5~10 倍,它的嵌入是每个现代检索栈的骨架。本节将带你实现掩码语言建模(MLM)的三段式掩码规则(80% 换
[MASK]、10% 换随机词、10% 原样保留),理解为什么必须这么「不诚实」,并用 ModernBERT(2024)看看编码器在 2026 年长什么样。
阅读完本节,你应当能够:
[MASK]」,以及它如何缓解预训练与微调之间的分布偏移。2018 年,ELMo 用双向 LSTM 预训练上下文嵌入,有帮助但不泛化。BERT 的赌注:把 Transformer 编码器训成「懂英语」,然后下游任务只微调一个头。结果是一年内横扫所有 NLP 榜单,到 2020 年地球上每个搜索引擎、内容审核、语义搜索系统里都有一个 BERT。
取一句话:the quick brown fox jumps over the lazy dog。随机盖住 15% 的 token:
输入: the [MASK] brown fox jumps [MASK] the lazy dog 目标: the quick brown fox jumps over the lazy dog
训练模型在掩码位置预测原词。因为编码器是双向的,位置 1 处预测 [MASK] 可以用位置 2+ 的 brown fox jumps——这正是 GPT 做不到的(GPT 只能看左侧)。
在被选中的 15% token 里:
[MASK]。为什么不全部换 [MASK]?因为 [MASK] 在推理时永远不出现。如果训练时 100% 的掩码位置都是 [MASK],模型就只在「这个特殊符号」上能干,微调或推理时面对真实 token 会产生分布偏移。10% 随机 + 10% 原样让模型保持「诚实」——它必须学会对真实的、可能错误的 token 也能预测。
原版 BERT 还有第二个任务 NSP(Next Sentence Prediction):给两个句子 A 和 B,预测 B 是否真的接在 A 后面。RoBERTa(2019)做了消融实验,证明 NSP 有害而非有益——它逼模型学一个对大多数下游任务无用的弱信号,反而拖累主任务。2019 年后的编码器全部跳过 NSP。
2024 年的 ModernBERT 论文用 2026 年的原语重建了块:
| 组件 | 原 BERT(2018) | ModernBERT(2024) |
|---|---|---|
| 位置 | 可学习绝对 | RoPE |
| 激活 | GELU | GeGLU |
| 归一化 | LayerNorm | Pre-norm RMSNorm |
| 注意力 | 完整稠密 | 交替局部(128)+ 全局 |
| 上下文长度 | 512 | 8192 |
| 分词器 | WordPiece | BPE |
而且与 2018 版不同,它原生支持 Flash Attention。在 8K 序列长度上推理比 DeBERTa-v3 快 2~3 倍,GLUE 分数还更高。
💡 交替局部/全局注意力:每几层插一层全局注意力,其余层只看前后 128 token。长序列下显存从
O(N²)降到接近O(N·128),但仍有少量全局层捕捉远距离依赖——Longformer 发明的技巧。
| 任务 | 编码器赢 decoder 的原因 |
|---|---|
| 检索 / 语义搜索嵌入 | 双向上下文 → 每 token 嵌入质量更高 |
| 分类(情感、意图、毒性) | 一次前向,无生成开销 |
| NER / token 标注 | 每位置输出,天然双向 |
| 零样本蕴含(NLI) | 编码器顶上接分类头 |
| RAG 重排器 | 交叉编码器打分,比 LLM 重排快 10 倍 |
完整代码见原课程 phases/07-transformers-deep-dive/06-bert-masked-language-modeling/code/main.py。create_mlm_batch 接收 token ID 列表、词表大小、掩码概率,返回输入 ID(已应用掩码)和标签(仅掩码位置有值,其余为 -100,PyTorch 的忽略索引约定):
def create_mlm_batch(tokens, vocab_size, mask_prob=0.15, rng=None): input_ids = list(tokens) labels = [-100] * len(tokens) # -100 = PyTorch 损失忽略 for i, t in enumerate(tokens): if rng.random() < mask_prob: labels[i] = t # 只在掩码位置算损失 r = rng.random() if r < 0.8: input_ids[i] = MASK_ID # 80% [MASK] elif r < 0.9: input_ids[i] = rng.randrange(vocab_size) # 10% 随机 # else: 原样保留 # 10% return input_ids, labels
在 20 个词的词表、200 个句子上训一个 2 层编码器 + MLM 头。本节无梯度,只做前向合理性检查;完整训练需要 PyTorch。
演示三段式规则如何让模型在没有 [MASK] 时也能用。对一句未掩码的句子和一句掩码的句子分别预测——两者都应产出合理的 token 分布,因为训练里两种模式都见过。
在玩具情感数据集上把 MLM 头换成分类头。只有头训练,编码器冻结。这是每个 BERT 应用都遵循的模式:预训练一次,微调无数次。
from transformers import AutoModel, AutoTokenizer tok = AutoTokenizer.from_pretrained("answerdotai/ModernBERT-base") model = AutoModel.from_pretrained("answerdotai/ModernBERT-base") text = "Attention is all you need." inputs = tok(text, return_tensors="pt") out = model(**inputs).last_hidden_state # (1, N, 768)
sentence-transformers 系列(如 all-MiniLM-L6-v2)就是用对比损失训的 BERT,编码器不变,只换损失。[CLS] query [SEP] doc [SEP],输出相关性分。query 和 doc 之间的双向注意力正是交叉编码器比双编码器质量更高的原因——它让两者互相看见。原课程产出 outputs/skill-bert-finetuner.md:一个微调规划 Skill,为一个新分类或抽取任务规划 BERT 微调(骨干选择、头规格、数据、评估、停训条件)。
code/main.py,在 10000 个 token 上打印掩码分布。确认约 15% 被选中,其中约 80% 变成 [MASK]。[CLS] token 微调到 SST-2 情感分类,与等参的 decoder-only 基线对比——谁赢?[MASK]、10% 随机词、10% 原样,缓解预训练-微调分布偏移(推理时没有 [MASK])。下一节,我们换到硬币的另一面——GPT 的因果语言建模,只看左侧预测下一个 token,看自回归生成如何 scale 成统治语言的基础范式。