Skip to content

BERT: Bidirectional Encoder Representations from Transformers

BERT (Bidirectional Encoder Representations from Transformers) 是 Google 于 2018 年提出的预训练语言模型,标志着 NLP 从"特征工程"时代正式进入"预训练 + 微调"范式。BERT 在 11 项 NLP 基准任务上刷新了当时的记录,深刻改变了自然语言处理的研究方向。

"BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding" -- Devlin et al., Google AI Language, 2018


背景与动机

NLP 预训练的演进

在 BERT 之前,NLP 领域经历了一条清晰的预训练技术演进路线:

阶段 方法 年份 核心思想 局限
1 Word2Vec / GloVe 2013 静态词向量,每个词一个固定表示 无法处理一词多义("苹果"是水果还是公司?)
2 ELMo 2018 用双向 LSTM 生成上下文相关的词表示 特征拼接,非深度双向;基于 LSTM 架构
3 GPT-1 2018 用 Transformer Decoder 做单向语言模型预训练 单向(left-to-right),无法同时看到上下文
4 BERT 2018 用 Transformer Encoder 做双向预训练 预训练-微调不一致([MASK] 问题)

为什么需要双向?

GPT-1 使用的是标准的自回归语言模型,在预测第 \(t\) 个词时只能看到前面的 \(t-1\) 个词:

\[ P(w_t | w_1, w_2, \ldots, w_{t-1}) \]

这意味着在编码一个词的表示时,模型只能利用左侧上下文。考虑以下两个句子:

(1) 我去银行存钱。        → "银行" = 金融机构
(2) 我去河的银行散步。    → "银行" = 河岸 (bank)

在句 (1) 中,如果只能看到"我去",模型无法确定"银行"的含义;但如果能同时看到右边的"存钱",就能轻松消歧。这就是双向上下文的价值。

ELMo 的'双向'与 BERT 的'双向'不同

ELMo 分别训练一个前向 LSTM 和一个后向 LSTM,然后将两个方向的隐藏状态拼接起来。这是两个单向模型的拼接,并非真正的深度双向交互。BERT 在每一层的 Self-Attention 中,每个 token 都同时关注序列中所有位置,实现了真正的双向

BERT 的核心创新

传统的语言模型只能是单向的,因为如果让模型同时看到左右上下文,在预测某个词时就会"看到答案"。BERT 提出了一个巧妙的解决方案:Masked Language Model (MLM)

核心思路:不是让模型预测下一个词,而是随机遮住(mask)输入中的一些词,让模型根据双向上下文来预测被遮住的词。这样既避免了"看到答案"的问题,又实现了真正的双向预训练。


BERT 架构详解

整体架构

BERT 只使用 Transformer 的 Encoder 部分(不使用 Decoder),通过堆叠多层 Transformer Encoder 来构建深层双向表示。

                        BERT 整体架构
 ═══════════════════════════════════════════════════════

 输入文本:  [CLS]  我  喜欢  自然  语言  处理  [SEP]
              |    |    |     |    |    |     |
              v    v    v     v    v    v     v
         ┌─────────────────────────────────────────┐
         │  Token Embedding (词嵌入)                │
         │  +  Segment Embedding (段嵌入)           │
         │  +  Position Embedding (位置嵌入)        │
         └─────────────────────────────────────────┘
              |    |    |     |    |    |     |
              v    v    v     v    v    v     v
         ┌─────────────────────────────────────────┐
         │         Transformer Encoder Layer 1      │
         │   [Multi-Head Self-Attention + FFN]      │
         └─────────────────────────────────────────┘
              |    |    |     |    |    |     |
              v    v    v     v    v    v     v
         ┌─────────────────────────────────────────┐
         │         Transformer Encoder Layer 2      │
         │   [Multi-Head Self-Attention + FFN]      │
         └─────────────────────────────────────────┘
              |    |    |     |    |    |     |
              :    :    :     :    :    :     :
              |    |    |     |    |    |     |
              v    v    v     v    v    v     v
         ┌─────────────────────────────────────────┐
         │         Transformer Encoder Layer L      │
         │   [Multi-Head Self-Attention + FFN]      │
         └─────────────────────────────────────────┘
              |    |    |     |    |    |     |
              v    v    v     v    v    v     v
           T_CLS  T_1  T_2   T_3  T_4  T_5  T_SEP
              |
              v
         分类/池化输出 (用于下游任务)

为什么 BERT 只用 Encoder 不用 Decoder?

Transformer 的 Decoder 包含因果掩码(Causal Mask),限制每个位置只能看到它之前的位置,这正是 BERT 要避免的。BERT 的目标是让每个 token 都能关注到序列中的所有位置,因此只需要 Encoder 的无掩码 Self-Attention 即可。

输入表示

BERT 的输入表示是三种 Embedding 的逐元素相加

\[ \text{Input}(x_i) = \text{TokenEmb}(x_i) + \text{SegmentEmb}(x_i) + \text{PositionEmb}(i) \]
 Token:     [CLS]  我  喜欢  猫  [SEP]  猫  是  动物  [SEP]
              |    |    |    |    |      |   |    |     |
 Token Emb:  E_CLS E_我 E_喜欢 E_猫 E_SEP  E_猫 E_是 E_动物 E_SEP
     +        +    +    +    +    +      +   +    +     +
 Segment:    E_A  E_A  E_A  E_A  E_A   E_B E_B  E_B   E_B
     +        +    +    +    +    +      +   +    +     +
 Position:   E_0  E_1  E_2  E_3  E_4   E_5 E_6  E_7   E_8
     =        =    =    =    =    =      =   =    =     =
 最终输入:   [  每个位置得到一个 d_model 维的向量  ]

三种 Embedding 的说明:

Embedding 维度 说明
Token Embedding \(V \times d_{\text{model}}\) 使用 WordPiece 分词后的词嵌入。词表大小 \(V = 30522\)
Segment Embedding \(2 \times d_{\text{model}}\) 区分句子 A 和句子 B。只有两个可能的值:\(E_A\)\(E_B\)
Position Embedding \(L_{\max} \times d_{\text{model}}\) 可学习的位置嵌入(不同于原始 Transformer 的正弦位置编码),\(L_{\max} = 512\)

Position Embedding 的区别

原始 Transformer 使用的是固定的正弦/余弦位置编码,而 BERT 使用的是可学习的位置嵌入。实验表明两种方式效果差异不大,但可学习的版本实现更简单。缺点是最大序列长度受限于训练时的 \(L_{\max}\),无法外推到更长序列。

特殊 Token

BERT 引入了两个关键的特殊 token:

[CLS] (Classification Token)

  • 始终放在输入序列的最前面
  • 经过 \(L\) 层 Transformer Encoder 后,[CLS] 位置的输出向量 \(T_{\text{CLS}} \in \mathbb{R}^{d_{\text{model}}}\) 作为整个序列的聚合表示
  • 在分类任务中,直接在 \(T_{\text{CLS}}\) 上接一个分类头
  • 为什么 [CLS] 能代表整个序列?因为 Self-Attention 让它可以关注到序列中的每一个 token

[SEP] (Separator Token)

  • 放在每个句子的末尾,用于分隔两个句子
  • 单句输入:[CLS] 句子A [SEP]
  • 句对输入:[CLS] 句子A [SEP] 句子B [SEP]

模型规格

BERT 发布了两个版本:

参数 BERT-Base BERT-Large
Transformer 层数 \(L\) 12 24
隐藏层维度 \(H\) (\(d_{\text{model}}\)) 768 1024
注意力头数 \(A\) 12 16
每个头的维度 \(d_k = H/A\) 64 64
Feed-Forward 维度 \(d_{ff}\) 3072 (\(4H\)) 4096 (\(4H\))
总参数量 110M 340M
最大序列长度 512 512

BERT-Base 的参数量与 GPT-1 相当(110M vs 117M),便于公平比较。


预训练任务

BERT 使用两个无监督任务进行预训练:MLM 和 NSP。

任务一:Masked Language Model (MLM)

MLM 是 BERT 最核心的创新。随机遮住输入中 15% 的 token,让模型预测被遮住的原始 token。

遮蔽策略:

对于被选中的 15% 的 token,不是简单地全部替换为 [MASK],而是采用以下策略:

概率 操作 示例(原词:"猫") 目的
80% 替换为 [MASK] "我 喜欢 [MASK]" 让模型学习从上下文推断被遮蔽的词
10% 替换为随机词 "我 喜欢 汽车" 迫使模型不要只在看到 [MASK] 时才做预测
10% 保持不变 "我 喜欢 猫" 让模型学习保留正确表示,偏向真实输入

为什么不全部用 [MASK]?

如果所有被选中的 token 都替换为 [MASK],会产生一个严重问题:预训练-微调不一致(pretrain-finetune discrepancy)。在微调阶段,输入中不会出现 [MASK] token,模型从未学过如何处理"正常"的输入。80/10/10 的混合策略缓解了这个问题:10% 保持不变让模型学习正常输入的表示,10% 随机替换防止模型只在看到 [MASK] 时才激活预测能力。

MLM 的损失函数:

只计算被 mask 的 token 的交叉熵损失(非 mask 位置不参与损失计算):

\[ \mathcal{L}_{\text{MLM}} = -\sum_{i \in \mathcal{M}} \log P(x_i | \mathbf{x}_{\backslash \mathcal{M}}) \]

其中 \(\mathcal{M}\) 是被 mask 的 token 位置集合,\(\mathbf{x}_{\backslash \mathcal{M}}\) 表示除被 mask 位置外的所有输入。

具体计算过程:

原始输入: [CLS] 我 喜欢 自然 语言 处理 [SEP]
                          ↓ 随机选中 "自然" 和 "处理"
遮蔽输入: [CLS] 我 喜欢 [MASK] 语言 处理 [SEP]
                                          ↓ "处理" 被随机替换
修改输入: [CLS] 我 喜欢 [MASK] 语言 苹果 [SEP]
                   ↓ 送入 BERT Encoder
输出:     T_CLS  T_1  T_2  T_3   T_4  T_5  T_SEP
                          |             |
                          v             v
                     预测 "自然"     预测 "处理"
                      (softmax)      (softmax)

任务二:Next Sentence Prediction (NSP)

NSP 让模型学习理解句子间的关系。训练时构造句对:

标签 构造方式 比例 示例
IsNext 句子 B 是句子 A 的真实下一句 50% A="猫坐在垫子上。" B="它看起来很舒服。"
NotNext 句子 B 是从语料中随机采样的 50% A="猫坐在垫子上。" B="股市今天大涨。"

使用 [CLS] 位置的输出 \(T_{\text{CLS}}\) 进行二分类:

\[ P(\text{IsNext} | T_{\text{CLS}}) = \text{softmax}(T_{\text{CLS}} \cdot W_{\text{NSP}}) \]
\[ \mathcal{L}_{\text{NSP}} = -\left[y \log P(\text{IsNext}) + (1 - y) \log(1 - P(\text{IsNext}))\right] \]

总损失:

\[ \mathcal{L} = \mathcal{L}_{\text{MLM}} + \mathcal{L}_{\text{NSP}} \]

NSP 的争议

后续研究(特别是 RoBERTa)发现 NSP 任务对大多数下游任务帮助不大甚至有害。原因可能是:(1) NSP 的"随机负样本"任务太简单,模型只需要判断两个句子是否话题一致即可;(2) NSP 与 MLM 可能存在目标冲突。RoBERTa 直接去掉了 NSP,效果反而更好。

训练细节

项目 设置
训练数据 BooksCorpus (800M 词) + English Wikipedia (2500M 词)
总 token 数 约 33 亿
Batch Size 256 序列
训练步数 1,000,000 步
学习率 \(1 \times 10^{-4}\) (Adam, warmup + linear decay)
训练时间 4 天 (16 个 TPU v3 / BERT-Base), 4天 (64 个 TPU v3 / BERT-Large)
序列长度 前 90% 步用 128 长度,最后 10% 步用 512 长度

前向传播数值示例

为了直观理解 BERT 的计算过程,我们用一个极简的例子来展示。

设置: 序列长度 \(n = 4\)\(d_{\text{model}} = 4\),单头注意力(\(A = 1\)),单层 Encoder。

Step 1: 输入嵌入

假设输入为 [CLS] 我 喜欢 [SEP],三种 Embedding 叠加:

\[ \text{TokenEmb} = \begin{bmatrix} 0.1 & 0.2 & 0.3 & 0.4 \\ 0.5 & 0.1 & 0.2 & 0.3 \\ 0.3 & 0.4 & 0.1 & 0.5 \\ 0.2 & 0.3 & 0.4 & 0.1 \end{bmatrix} \]
\[ \text{SegmentEmb} = \begin{bmatrix} 0.01 & 0.02 & 0.01 & 0.02 \\ 0.01 & 0.02 & 0.01 & 0.02 \\ 0.01 & 0.02 & 0.01 & 0.02 \\ 0.01 & 0.02 & 0.01 & 0.02 \end{bmatrix} \quad \text{(全部属于句子A)} \]
\[ \text{PositionEmb} = \begin{bmatrix} 0.10 & 0.00 & 0.10 & 0.00 \\ 0.04 & 0.08 & 0.04 & 0.08 \\ 0.01 & 0.05 & 0.01 & 0.05 \\ 0.00 & 0.03 & 0.00 & 0.03 \end{bmatrix} \]

三者相加得到输入矩阵 \(X \in \mathbb{R}^{4 \times 4}\)

\[ X = \begin{bmatrix} 0.21 & 0.22 & 0.41 & 0.42 \\ 0.55 & 0.20 & 0.25 & 0.40 \\ 0.32 & 0.47 & 0.12 & 0.57 \\ 0.21 & 0.35 & 0.41 & 0.15 \end{bmatrix} \]

Step 2: Self-Attention 计算

假设权重矩阵 \(W^Q, W^K, W^V \in \mathbb{R}^{4 \times 4}\) 均为简化的单位矩阵(仅为演示目的),即 \(Q = X, K = X, V = X\)

(a) 计算注意力分数 \(QK^T\)

\[ S = QK^T = X \cdot X^T \in \mathbb{R}^{4 \times 4} \]

例如 \(S_{11} = 0.21^2 + 0.22^2 + 0.41^2 + 0.42^2 = 0.04 + 0.05 + 0.17 + 0.18 = 0.44\)

(b) 缩放:除以 \(\sqrt{d_k} = \sqrt{4} = 2\)

\[ S_{\text{scaled}} = \frac{S}{2} \]

(c) Softmax:对每一行做 softmax

\[ \alpha_{ij} = \frac{\exp(S_{\text{scaled},ij})}{\sum_{k=1}^{4} \exp(S_{\text{scaled},ik})} \]

每一行的注意力权重之和为 1。注意在 BERT 的 Encoder 中没有因果掩码,所以每个位置可以关注所有位置(包括自己和后面的位置)。

(d) 加权求和:

\[ \text{Output} = \alpha \cdot V = \alpha \cdot X \in \mathbb{R}^{4 \times 4} \]

BERT 与 GPT 的关键区别就在这里

在 GPT 中,计算注意力分数后需要应用因果掩码,将对角线以上的值设为 \(-\infty\),使得每个位置只能关注到自己和之前的位置。而 BERT 不使用任何掩码(除了 padding mask),每个位置可以自由关注整个序列——这就是"双向"的含义。

Step 3: FFN + 残差 + LayerNorm

经过 Self-Attention 后的输出再通过 Feed-Forward Network:

\[ \text{FFN}(x) = \text{GELU}(xW_1 + b_1)W_2 + b_2 \]

注意 BERT 使用的激活函数是 GELU(Gaussian Error Linear Unit),而非原始 Transformer 中的 ReLU:

\[ \text{GELU}(x) = x \cdot \Phi(x) = x \cdot \frac{1}{2}\left[1 + \text{erf}\left(\frac{x}{\sqrt{2}}\right)\right] \]

每个子层(Self-Attention 和 FFN)外面都包裹残差连接和 Layer Normalization:

\[ \text{output} = \text{LayerNorm}(x + \text{SubLayer}(x)) \]

微调 (Fine-tuning)

BERT 的预训练模型可以通过简单地添加一个输出层来适配各种下游任务,只需要少量标注数据进行微调。

微调的核心思路

 预训练 BERT (无监督, 大规模语料)
              |
              v
 ┌─────────────────────────────┐
 │   冻结或微调 BERT 的参数     │
 │   + 新增一个任务特定的输出层  │
 └─────────────────────────────┘
              |
              v
 下游任务 (少量标注数据)

所有参数(包括 BERT 的原始参数和新增的输出层参数)一起用下游任务的标注数据进行端到端微调。学习率通常设得很小(\(2 \times 10^{-5}\)\(5 \times 10^{-5}\)),避免破坏预训练学到的知识。

任务一:文本分类

 输入:   [CLS]  这  部  电影  太  好看  了  [SEP]
           |    |   |    |   |    |   |    |
           v    v   v    v   v    v   v    v
        ┌──────────────────────────────────────┐
        │              BERT Encoder             │
        └──────────────────────────────────────┘
           |    |   |    |   |    |   |    |
           v
        T_[CLS]  (其余位置的输出忽略)
           |
           v
        ┌──────────────┐
        │  Linear + Softmax  │
        │  W ∈ R^(H x C)    │
        └──────────────┘
           |
           v
        情感标签: 正面 (p=0.92)
\[ P(c | \text{text}) = \text{softmax}(T_{\text{CLS}} \cdot W + b), \quad W \in \mathbb{R}^{H \times C} \]

其中 \(C\) 是类别数,\(H\) 是隐藏层维度。

任务二:序列标注 (NER / 词性标注)

 输入:   [CLS]  乔布斯  在  加州  创办  了  苹果  [SEP]
           |      |    |    |    |    |    |     |
           v      v    v    v    v    v    v     v
        ┌──────────────────────────────────────────┐
        │                BERT Encoder               │
        └──────────────────────────────────────────┘
           |      |    |    |    |    |    |     |
                  v    v    v    v    v    v
               T_1   T_2  T_3  T_4  T_5  T_6
                |     |    |    |    |    |
                v     v    v    v    v    v
              ┌─────────────────────────────┐
              │  每个 token: Linear + Softmax  │
              └─────────────────────────────┘
                |     |    |    |    |    |
                v     v    v    v    v    v
              B-PER  O  B-LOC  O    O  B-ORG

每个 token 的输出 \(T_i\) 独立通过分类头预测标签:

\[ P(y_i | x) = \text{softmax}(T_i \cdot W + b), \quad i = 1, 2, \ldots, n \]

任务三:问答 (Extractive QA)

给定一段上下文(Passage)和一个问题(Question),模型需要在上下文中找到答案的起始位置结束位置

 输入:   [CLS] 问题 tokens [SEP] 上下文 tokens [SEP]
           |       |         |        |          |
           v       v         v        v          v
        ┌──────────────────────────────────────────┐
        │                BERT Encoder               │
        └──────────────────────────────────────────┘
           |       |         |        |          |
                                      v
                              上下文每个位置的输出
                                      |
                              ┌───────┴───────┐
                              v               v
                         Start 向量 S     End 向量 E
                         (S ∈ R^H)       (E ∈ R^H)
                              |               |
                              v               v
                         与每个 token      与每个 token
                         输出做点积        输出做点积
                              |               |
                              v               v
                         softmax          softmax
                              |               |
                              v               v
                        start position   end position
\[ P_{\text{start}}(i) = \frac{\exp(S \cdot T_i)}{\sum_j \exp(S \cdot T_j)}, \quad P_{\text{end}}(i) = \frac{\exp(E \cdot T_i)}{\sum_j \exp(E \cdot T_j)} \]

其中 \(S, E \in \mathbb{R}^H\) 是两个可学习的向量。最终答案就是使 \(P_{\text{start}}(i) \times P_{\text{end}}(j)\)\(j \geq i\))最大的 span \([i, j]\)

任务四:句对关系判断 (NLI / 语义相似度)

 输入:   [CLS]  句子 A  [SEP]  句子 B  [SEP]
           |       |      |       |      |
           v       v      v       v      v
        ┌──────────────────────────────────────┐
        │              BERT Encoder             │
        └──────────────────────────────────────┘
           |
           v
        T_[CLS]
           |
           v
        ┌──────────────────┐
        │  Linear + Softmax │
        └──────────────────┘
           |
           v
        蕴含 / 矛盾 / 中性

微调超参数建议

参数 推荐范围
学习率 \(2 \times 10^{-5}\), \(3 \times 10^{-5}\), \(5 \times 10^{-5}\)
Batch Size 16, 32
Epochs 2, 3, 4
Warmup 总步数的 10%
最大序列长度 128 (短文本) 或 512 (长文本)

微调的关键优势

相比从头训练,BERT 微调只需要极少的标注数据和计算资源。一个在 16GB GPU 上微调 BERT-Base 的分类任务,通常只需要几千条标注样本和不到一小时的训练时间,就能达到很好的效果。这大大降低了 NLP 的门槛。


BERT 的局限与后续改进

主要局限

1. 预训练-微调不一致 (Pretrain-Finetune Discrepancy)

预训练时输入包含 [MASK] token,但微调和推理时不会出现 [MASK]。虽然 80/10/10 的策略在一定程度上缓解了这个问题,但不一致仍然存在。

2. 独立性假设

MLM 假设被 mask 的 token 之间是相互独立的。例如输入 "New [MASK] [MASK]",MLM 分别预测两个被 mask 的 token,不考虑它们之间的依赖关系(实际上应该联合预测 "York" 和 "City")。

3. NSP 任务设计不够好

随机采样负例太简单,模型可能只需要判断话题一致性而非真正的句间推理。

4. 训练效率低

每次只有 15% 的 token 参与损失计算,而自回归模型(如 GPT)的每个 token 都参与损失,训练信号更密集。

5. 不擅长生成任务

BERT 是 Encoder-only 架构,缺少自回归生成能力,不适合文本生成、翻译等任务。

后续改进

模型 年份 核心改进 关键变化
RoBERTa 2019 更鲁棒的训练策略 去掉 NSP;动态 masking;更大 batch size;更多数据;更长训练
ALBERT 2019 参数高效 嵌入层分解 (\(V \times H \to V \times E + E \times H\));跨层参数共享
DistilBERT 2019 模型蒸馏压缩 6 层代替 12 层,保留 97% 性能,速度快 60%
ELECTRA 2020 替换检测 (Replaced Token Detection) 用生成器产生替换 token,判别器判断每个 token 是否被替换。所有 token 都参与训练
DeBERTa 2020 解耦注意力 内容和位置分别计算注意力;增强的 mask decoder
SpanBERT 2020 连续 span masking mask 连续 span 而非随机 token;去掉 NSP;加入 Span Boundary Objective

ELECTRA 的巧妙设计

ELECTRA 彻底解决了 BERT 15% 训练效率的问题。它使用一个小型生成器(类似小 BERT)来"填空"被 mask 的 token,然后让判别器(主模型)判断序列中每个 token 是原始的还是被生成器替换的。这样 100% 的 token 都参与训练,大大提高了效率。在同等计算预算下,ELECTRA 显著优于 BERT。


BERT vs GPT 对比

这是 NLP 预训练领域最重要的两条技术路线。理解它们的差异有助于把握整个领域的发展脉络。

维度 BERT GPT
架构 Transformer Encoder Transformer Decoder
上下文方向 双向 (Bidirectional) 单向 (Left-to-right)
预训练目标 MLM + NSP 自回归语言模型 \(P(w_t \| w_{<t})\)
注意力掩码 无因果掩码(全部可见) 因果掩码(只看过去)
输入特殊 token [CLS], [SEP], Segment Emb 仅需 BOS/EOS
擅长任务 理解型:分类、NER、QA、NLI 生成型:文本生成、对话、翻译
微调方式 加输出层,端到端微调 早期:加输出层微调;后期(GPT-3+):In-context learning
训练效率 低(仅 15% token 参与损失) 高(每个 token 都参与损失)
扩展趋势 参数量增长相对缓慢 参数量急剧增长(GPT-3: 175B, GPT-4: 未公开)
代表性后续 RoBERTa, DeBERTa, ELECTRA GPT-2, GPT-3, GPT-4, ChatGPT
 BERT (Encoder-only)              GPT (Decoder-only)
 ┌──────────────┐                ┌──────────────┐
 │  完全可见的   │                │  因果掩码的   │
 │ Self-Attention│                │ Self-Attention│
 │              │                │   ╲           │
 │  ○ ○ ○ ○    │                │  ○ ╲ ╲ ╲    │
 │  每个token   │                │  每个token    │
 │  看到所有    │                │  只看到左边   │
 └──────────────┘                └──────────────┘
        |                               |
        v                               v
   理解 (Understanding)           生成 (Generation)
   分类、匹配、抽取              续写、对话、翻译

思考与讨论

为什么 BERT 在生成任务上不好?

BERT 的根本设计哲学是理解而非生成。具体原因:

  1. 缺乏自回归能力:BERT 没有因果掩码,无法按顺序逐个生成 token。在生成第 \(t\) 个 token 时,它需要看到第 \(t+1, t+2, \ldots\) 个 token 的信息,而这些 token 还没有被生成。

  2. 训练目标不匹配:MLM 训练的是"填空"能力(给定上下文预测缺失词),而生成任务需要的是"续写"能力(给定前文生成后文)。两种能力在本质上不同。

  3. 条件独立假设:MLM 假设被 mask 的多个 token 之间独立,无法建模生成时 token 之间的顺序依赖关系。

Encoder-only vs Decoder-only 的哲学差异

  Encoder-only (BERT)                    Decoder-only (GPT)
  ─────────────────                      ──────────────────
  "我要理解整个输入"                      "我要一个接一个地生成"
       |                                       |
  全部信息同时可见                         只看已知信息,预测下一个
       |                                       |
  适合需要全局理解的任务                   适合需要顺序生成的任务
  (分类、匹配、抽取)                      (对话、写作、翻译)
       |                                       |
  双向注意力                               单向注意力(因果)
       |                                       |
  高效编码,但不能生成                     可以生成,但编码有偏

从信息论的角度看:

  • BERT 建模的是 \(P(x_{\text{mask}} | x_{\text{observed}})\):给定上下文,预测缺失部分
  • GPT 建模的是 \(P(x_t | x_{<t})\):给定历史,预测未来

两者本质上都是在学习语言的概率分布,但方式不同:BERT 是去噪自编码器(Denoising Autoencoder)的思路,GPT 是自回归模型(Autoregressive Model)的思路。

历史的选择

有趣的是,尽管 BERT 在 2018-2020 年间统治了 NLP 的学术排行榜,但最终大规模语言模型的主流路线选择了 GPT 的 Decoder-only 架构。原因包括:(1) Decoder-only 更容易 scaling up;(2) 自回归目标天然支持生成;(3) In-context learning 能力使得 Decoder-only 模型可以"免微调"完成理解任务;(4) 工程上更简单统一。然而,BERT 类模型在搜索引擎(如 Google 搜索)、推荐系统、短文本分类等场景中仍然被广泛使用,因为它们在理解任务上的效率和效果依然出色。

BERT 的历史地位

BERT 的贡献远超其具体的技术细节,它确立了 NLP 的 "预训练 + 微调"范式

  1. 范式革命:从"为每个任务设计特定模型"转变为"一个通用预训练模型 + 轻量级微调"
  2. 规模效应的验证:证明了在大规模无标注数据上预训练可以学到通用的语言知识
  3. 迁移学习的成功:展示了在一个领域/任务上学到的表示可以有效迁移到其他任务
  4. 开源的力量:Google 开源了预训练模型和代码,极大推动了 NLP 研究的民主化

BERT 对 NLP 的影响,类似于 ImageNet 预训练对计算机视觉的影响——它让"预训练 + 微调"成为了默认做法。即使在今天 GPT 系列主导的时代,BERT 的核心思想(双向理解、预训练迁移)仍然深刻影响着每一个新模型的设计。


总结

 BERT 知识脉络总览
 ═══════════════════════════════════════════════════════

 Word2Vec ──→ ELMo ──→ GPT-1 ──→ BERT ──→ RoBERTa
 (静态)     (浅层双向) (深层单向) (深层双向) (更好训练)
                                    |
                                    ├──→ ALBERT   (参数高效)
                                    ├──→ DistilBERT (蒸馏压缩)
                                    ├──→ ELECTRA  (替换检测)
                                    ├──→ SpanBERT (span masking)
                                    └──→ DeBERTa  (解耦注意力)

 BERT 的核心贡献:
 ┌─────────────────────────────────────────────────────┐
 │ 1. Masked LM ──→ 真正的双向预训练                   │
 │ 2. [CLS] + 输出层 ──→ 通用的微调范式                │
 │ 3. 大规模预训练 ──→ 少量数据即可达到好效果           │
 │ 4. 开源模型 ──→ 推动 NLP 研究民主化                 │
 └─────────────────────────────────────────────────────┘

评论 #