HelloAI
📄 论文精读 🏆 必读经典 · 2018 · NAACL 2019

BERT: Pre-training of Deep Bidirectional Transformers

Jacob Devlin, Ming-Wei Chang, Kenton Lee, Kristina Toutanova
TL;DR
2018 年的 NLP 核爆。提出 Masked Language Modeling + 双向 Transformer,让"预训练 + 微调"成为 NLP 主流范式。
#BERT#NLP#预训练#必读

为什么这篇论文重要

2018 年 10 月,Google 发布 BERT。整个 NLP 界震动了 6 个月

任务之前的 SOTABERT
SQuAD(问答)83.1 F193.2 F1
GLUE(综合)72.882.1
命名实体识别92.494.6

所有任务都被 BERT 拿下了 SOTA。 之后 1 年内,NLP 顶会几乎全是基于 BERT 的微调研究

这是 NLP 从”为每个任务训一个模型”到”预训练 + 微调”的转折点。

论文的两大贡献

贡献 1:双向 Transformer(不是 GPT 的单向)

GPT-1(2018 年早)已经证明 Transformer 强——但用的是单向(因果掩码)。

BERT 用双向:每个 token 能看左右两边所有 token。 理解任务上更强——比如填空类问题。

但双向不能直接生成文本(不知道该停哪)—— 所以 BERT 选择只做 encoder(理解),不做 decoder(生成)。

贡献 2:Masked Language Modeling(MLM)

如果用普通的”下一个词预测”,双向就作弊了—— 因为模型能看到要预测的词的”右边”。

BERT 的招数:随机遮蔽(mask)15% 的 token,让模型猜

原句: "I love eating apples at the park"
遮蔽: "I love [MASK] apples at the [MASK]"
任务: 猜 [MASK] = "eating" / "park"

要做对这个,模型必须同时看左右上下文—— “apples at the ___” + “love [MASK] apples” → “eating”。

MLM 是 BERT 的核心创新——后来 RoBERTa、ALBERT 等都基于它。

训练流程

阶段 1:预训练

  • 数据:BookCorpus(8亿词)+ Wikipedia(25亿词)
  • 目标:MLM + Next Sentence Prediction(后来证明 NSP 没太大用)
  • 时间:4 天(4 张 TPU pod,每个 64 块 v3 芯片)
  • 模型:BERT-Base(110M 参数)/ BERT-Large(340M 参数)

阶段 2:微调

针对每个下游任务(分类、问答、NER)— 在预训练 BERT 后加一个简单的任务头,再用少量任务数据微调几个 epoch。

预训练 BERT → 任务头(一个 Linear) → 任务输出

              针对这个任务训

关键洞察:99% 的能力在预训练阶段获得,微调只是”将能力指向特定任务”。

几个有趣的实验细节

[CLS] token

BERT 在每个输入句子前加一个特殊的 [CLS] token:

[CLS] I love eating apples at the park [SEP]

它的输出向量代表整句话的”摘要”——分类任务直接用 [CLS] 的输出。

词嵌入 + 位置 + 段落

BERT 的输入向量 = 三种 embedding 之和:

  1. Token embedding:词本身
  2. Positional embedding:位置(学的,不是 sin/cos)
  3. Segment embedding:句子 A 还是句子 B(NSP 任务需要)

80/10/10 mask 策略

15% 的 mask 不只用 [MASK]

  • 80% 替换成 [MASK]
  • 10% 替换成随机词
  • 10% 保留原词

为什么:微调时没有 [MASK]——如果只用 [MASK] 训练,模型会过度依赖它。这个策略让模型”对所有 token 都警惕”。

论文的实际数字

BERT 发表后:

  • 1 个月内:所有 NLP 顶会论文必引
  • 3 个月内:几乎所有 NLP 任务的 SOTA 被刷新
  • 6 个月内:HuggingFace 库爆火(最早就是为发布 BERT 而生)
  • 1 年内:Google 把 BERT 用到了实际搜索引擎——影响每秒几十亿次搜索

BERT 之后的演化

RoBERTa (2019 Facebook)

移除 NSP,加大训练数据和时长——比 BERT 显著好。 结论:BERT 训得不够。

ALBERT (2019 Google)

参数共享,减小模型尺寸——同样效果但更小。

DistilBERT (2019 HuggingFace)

模型蒸馏——50% 大小,95% 性能。

ELECTRA (2020 Google)

替换 MLM 任务为”判断 token 是否被替换”——效率高 4 倍。

DeBERTa (2020 Microsoft)

改进位置编码——更好的双向理解。

这些变种现在仍在工业界广泛使用——特别是在搜索、嵌入、抽取任务。

BERT 和 GPT 的对比

详见 HelloAI L3-09 BERT vs GPT。简短版本:

维度BERTGPT
训练目标MLM(填空)CLM(预测下一个)
注意力双向因果(单向)
适合理解生成
范式预训练 + 微调In-context learning

2023 年后,GPT 范式占了上风——但 BERT 在嵌入、检索等场景仍是首选。

BERT 今天的角色

不要以为 BERT 过时了——它仍然广泛使用

  • 句子嵌入:sentence-transformers 库(基于 BERT)是搜索/检索的事实标准
  • 搜索引擎:Google Search、Bing 都用 BERT 类模型做查询理解
  • RAG 系统:embedding 模型几乎全是 BERT 衍生品
  • 特定任务微调:医疗、法律、金融领域的专用 BERT 仍有市场

2026 年估算:每秒钟有 100+ 亿次 BERT 类模型调用——比 GPT 调用还多。

历史细节

”BERT” 这个名字

致敬 Sesame Street(芝麻街)里的角色 Bert—— 和 Elmo(早期类似工作)一样,都是芝麻街梗。

后来这个传统延续:ERNIE(百度)、KERMIT、GROVER 等都是芝麻街角色名。

Jacob Devlin

第一作者,Google AI。 BERT 让他成为 NLP 圈名人。 后来去了创业公司,又回来。

训练成本

BERT-Large 训练成本估计**只有 7,000美元——2018年的小钱。今天训BERTLarge大概只要7,000 美元** —— 2018 年的小钱。 今天训 BERT-Large 大概只要 100-200——TPU 进步太快。

当年的”昂贵研究”现在变成了个人项目。

代码

用 HuggingFace 一行做文本分类:

from transformers import pipeline

classifier = pipeline("sentiment-analysis")  # 默认 BERT 微调版
print(classifier("I love this product!"))
# [{'label': 'POSITIVE', 'score': 0.999}]

微调你自己的 BERT:

from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
model = AutoModelForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=2)

# 准备数据集...

trainer = Trainer(model=model, args=training_args, train_dataset=train_data, eval_dataset=eval_data)
trainer.train()

30 行代码微调一个 SOTA 文本分类器——这是 BERT 时代以来 NLP 工程师的标配工作流。

推荐配套阅读

  • HelloAI: L3-09 BERT vs GPT
  • The Illustrated BERT(Jay Alammar) —— 图解
  • HuggingFace Transformers Tutorial
💡 一个反思

2018 年没人想到 BERT 会被 GPT 全面超越。 2026 年也没人能完全确定下一个范式是什么—— SSM?Mamba?还是某个未出现的架构?

保持谦逊 —— ML 领域的”今天的真理”经常是明天的过去式。

📬

想要更多论文精读

订阅每周精选 —— 下一篇论文笔记直接送邮箱。

💬

讨论区

· 用 GitHub 账号登录评论
⚠️ Giscus 评论未配置 —— 在 src/components/Comments.astro 顶部填入 仓库 ID 和分类 ID(见组件注释里的配置步骤)。