先记住一句话
BERT 擅长把完整输入编码成上下文表示,GPT 擅长从左到右生成,T5 用 encoder 理解输入、decoder 自回归地产生输出。
0. 先看三条完整计算路径
1. 三种结构先看信息流
| 范式 | 可见信息 | 典型目标 | 擅长接口 |
|---|---|---|---|
| BERT / encoder-only | 输入 token 双向互看 | Masked Language Modeling | 分类、检索、序列标注、表示 |
| GPT / decoder-only | 每个位置只看左侧 | Causal Language Modeling | 开放式生成、对话、统一提示接口 |
| T5 / encoder-decoder | encoder 双向;decoder 因果;decoder 可看全部 encoder | Text-to-Text / span corruption | 输入到输出的条件生成 |
“encoder”和“decoder”不是由有没有文字输出决定的,而是由 block 中的 attention 连接方式决定。三者都使用 Transformer 组件,但 mask 和模块连接不同。
例 1:长度 4 时,三种 self-attention 可见多少格?
BERT:$4\times4=16$ 格全部可见。
GPT:下三角可见格数 $1+2+3+4=10$。
T5 encoder:16 格;若 decoder target 长 3,decoder causal self-attention 有 $1+2+3=6$ 格,另有 $3\times4=12$ 个 decoder→encoder cross-attention 分数。
因此“同样长度的 token”在三种架构里经过的连接并不相同。
2. BERT:先遮住,再利用两边恢复
BERT 把部分输入 token 替换或隐藏,让 encoder 根据左右两边上下文恢复它们。例如:
the robot [MASK] the door
↓
opens
因为所有未遮位置彼此可见,bank 在 “river bank” 和 “bank account” 中会形成不同的上下文表示。这类表示很适合回答“整段输入表达了什么”“每个 token 属于什么类别”“两段文本是否相似”。
但 BERT 预训练不是按从左到右生成完整句子;若直接拿它连续生成,每一步的输入分布与 masked pretraining 并不一致。它的优势是理解和编码,不是天然的自由生成接口。
例 2:BERT 的一个 masked-token loss
句子 robot [MASK] door 中,正确 token 是 opens。假设 MLM head 给三个候选 logits:
| 候选 | opens | closes | blue |
|---|---|---|---|
| logit | 2 | 1 | 0 |
| $e^z$ | 7.389 | 2.718 | 1 |
| 概率 | 0.665 | 0.245 | 0.090 |
$p(\text{opens})=7.389/11.107=0.665$,该位置 loss 为 $-\ln0.665\approx0.408$。未选作预测目标的位置通常不贡献 MLM loss。
3. GPT:把所有任务都写进同一条序列
GPT 使用 decoder-only causal mask,优化:
早期 GPT 展示了“无标签语言建模预训练 → 有标签任务微调”的迁移路线。随着规模和数据扩大,任务说明、示例和答案都可以串成 token 序列:
Instruction: Translate to Chinese.
Input: The robot opens the door.
Output: 机器人打开门。
同一个输出头始终只做 next-token prediction。分类可以生成标签,问答可以生成答案,工具调用可以生成结构化参数。统一接口减少了为每个任务设计专用 head 的需要。
例 3:GPT 一次 forward 同时得到三道 next-token 题
序列 [BOS, I, run, EOS] 产生输入 [BOS, I, run] 与标签 [I, run, EOS]。若正确 token 概率依次是 $[0.8,0.5,0.25]$:
三个 loss:$[-\ln0.8,-\ln0.5,-\ln0.25]=[0.223,0.693,1.386]$。
平均 loss:$(0.223+0.693+1.386)/3=0.767$。
Perplexity:$e^{0.767}\approx2.15$。
4. T5:输入和输出职责分开
T5 把所有 NLP 任务统一成 text-to-text。Encoder 双向读取完整输入,decoder 一边查看 encoder 表示,一边从左到右生成输出:
encoder input: translate English to German: That is good.
decoder target: Das ist gut.
T5 预训练常用 span corruption:遮掉连续片段并让 decoder 生成缺失内容。这比逐 token MLM 更接近条件生成,又保留 encoder 对输入的双向理解。
例 4:一次 cross-attention
某 decoder query 对三个 encoder key 的缩放分数为 $[0,\ln2,\ln3]$,指数恰好为 $[1,2,3]$,所以权重为 $[1/6,2/6,3/6]$。若 encoder Values 是 $[1,0]$、$[0,3]$、$[2,2]$:
decoder 的这一步可以读取 encoder 的所有位置,但仍不能在 causal self-attention 中读取未来 target。
5. 为什么通用助手多走 decoder-only?
- 接口统一:指令、上下文、中间推理、工具结果和回答都能写成一条序列。
- 训练与部署统一:预训练和生成共享 causal objective,KV cache 等推理路径成熟。
- 上下文学习自然:把少量示例直接放在 prompt 中,后续预测便能条件于这些示例。
- 规模化简单:无需维护 encoder/decoder 两套堆栈和 cross-attention 接口。
这不是“decoder-only 在一切任务上都更好”。高吞吐 embedding、reranking、双向特征提取仍常用 encoder;输入很长而输出较短、输入输出职责明确的任务也可能适合 encoder-decoder。
例 5:长输入、短输出时 cache 的直觉
输入长 1,000、输出长 20。Encoder-decoder 可先把 1,000-token 输入编码一次,之后 20 个 decoder step 都 cross-attend 这份固定表示。Decoder-only 则把输入和已生成输出放在同一 causal 序列里,并靠 KV cache 避免每步重算前缀。两者都不是“免费”,只是计算结构不同。
6. 真正要学的是设计轴,不是品牌名
看到新模型时,先问四个问题:
- 每个 token 能看到哪些位置?
- 训练时哪些位置计算 loss?
- 输入与输出是否由不同模块处理?
- 部署时需要一次编码,还是持续自回归解码?
“双向”不意味着 BERT 能预测未来;它表示编码某个位置时可以使用左右上下文。因果模型在生成当前 token 时不能使用尚未生成的未来。
自测:先算后展开
1. BERT 与 GPT 最核心的结构差异是什么?
Self-attention 的可见范围不同:BERT encoder 双向互看,GPT decoder 使用 causal mask 只看当前位置及左侧。
2. T5 的 cross-attention 在连接什么?
Decoder 的 Query 关注 encoder 输出形成的 Key/Value,使生成的每一步都能条件于完整输入。
3. 为什么分类也能由 decoder-only 模型完成?
把类别名称表示成输出 token,分类就变成在给定输入后生成正确标签,仍然使用同一 next-token 接口。
4. 长度 5 的 causal mask 有多少个可见位置?
$1+2+3+4+5=15$;双向 attention 则有 $5^2=25$。
5. 正确 token 概率为 0.2 时 loss 是多少?
$-\ln0.2\approx1.609$。