Decoder-Only 与自回归
完整 Transformer 的哲学是「先理解,再生成」:编码器深入理解整个输入句形成全局上下文记忆,解码器基于这份记忆生成翻译。但 OpenAI 开发 GPT 时换了个更简单的假设(Radford et al., Improving language understanding by generative pre-training, OpenAI 2018):
语言的核心任务,不就是预测下一个最有可能出现的词吗?
回答问题、写故事、生成代码,本质上都是在已有文本序列后面一个词一个词地添加最合理的内容。基于这个假设,GPT 做了一个大胆简化:完全抛弃编码器,只保留解码器。这就是 Decoder-Only 架构。
自回归:形式化
Decoder-Only 的工作模式叫自回归(Autoregressive),过程就是「文字接龙」:
自回归生成循环
[w1 … w_t](当前上下文)
│
▼
一次完整前向 ──▶ 词表上的概率分布
│
▼
取一个 token ──▶ 贪心 / 温度 / top-k(采样参数那一篇的主题)
│
▼
追加到上下文末尾 ──▶ [w1 … w_t, w_{t+1}]
│
└──────────────▶ 回到「一次完整前向」
退出条件:遇到停止符,或达到 max_tokens
每一步都要重跑一次完整前向 —— 这是「推理成本由生成长度决定」的来源形式化上,它用的是概率链式法则:整段序列的联合概率被分解成一连串条件概率的乘积。
这个分解是整条线的地基,几个后果都从它推出来:
| 后果 | 说明 |
|---|---|
| 一个目标函数统一所有任务 | 只要把任务表述成文本,就都变成「预测下一个词」 |
| 生成必须串行 | 要算 |
| 每一步的输出是整词表上的分布 | 怎么从这个分布里取词,是 采样参数 的事——贪心、温度、top-k 都作用在这一步 |
| 误差会累积 | 前面生成错了,后面的条件分布就都建立在错误前提上(见 Agent Loop 的错误累积) |
掩码自注意力:为什么不会「偷看」
训练时模型一次性拿到完整文本,它怎么保证学预测第
机制的位置很关键——在注意力分数矩阵算出来之后、Softmax 归一化之前,应用一个「因果掩码」:
attn_scores = QK^T / sqrt(d_k)
attn_scores = masked_fill(attn_scores, mask == 0, -1e9) ← 因果掩码:屏蔽当前位置之后的所有词元
attn_probs = softmax(attn_scores)把所有位于当前位置之后的词元对应的分数替换成极大负数,过 Softmax 后这些位置的概率变为 0。这样模型在计算任意位置的表示时,从数学上被阻止关注它后面的信息。
掩码的形状是一个下三角矩阵——第
一个实现惯例:用
-1e9这类「足够大的负数」而不是-inf。数学上-inf过 Softmax 得到精确的 0 更干净,但半精度浮点下容易出现NaN(涉及-inf - (-inf)这类运算)。这是数值稳定性对数学纯洁性的一次常见让步。
生成阶段更直接:未来的词还没生成出来,模型只能把已生成的内容当上下文。
掩码自注意力保证训练时的学习方式与生成时的自回归使用方式一致,模型始终只依赖当前位置之前的信息。这一点是 Decoder-Only 能工作的前提。
因果掩码作用在分数矩阵上,形状是一个下三角。
分数矩阵 S = QKᵀ / √d_k(4 个 token,只看结构不看具体数值)
w1 w2 w3 w4
w1 [ s11 s12 s13 s14 ]
w2 [ s21 s22 s23 s24 ]
w3 [ s31 s32 s33 s34 ]
w4 [ s41 s42 s43 s44 ]
masked_fill(mask == 0, -1e9) 之后
w1 w2 w3 w4
w1 [ s11 -1e9 -1e9 -1e9 ]
w2 [ s21 s22 -1e9 -1e9 ]
w3 [ s31 s32 s33 -1e9 ]
w4 [ s41 s42 s43 s44 ]
└── 只剩下三角:第 i 行只有前 i 列保留 ──┘
再 softmax(dim=-1):右上角的 −1e9 被压成 0
第 i 个位置在数学上无法看到它后面的任何 token。训练侧的另一半:shifted labels
掩码解决的是「模型不会看到未来」,但还有一个问题:一次前向只有一次,怎么一次性得到 T 个位置的训练信号?
答案是把标签整体左移一位:
输入 x: [w1, w2, w3, w4]
标签 y: [w2, w3, w4, w5] ← 整体左移一位
于是同一次前向的 T 个位置上,各有一个「预测下一个词」的训练信号
位置 1 看到 [w1] 要预测 w2
位置 2 看到 [w1 w2] 要预测 w3
位置 3 看到 [w1 w2 w3] 要预测 w4
位置 4 看到 [w1 w2 w3 w4] 要预测 w5
└─ 配合因果掩码,每个位置只用到它前面的信息 ─┘
│
▼
一次前向 = T 个训练信号
对照生成侧(同一个分解的两面)
训练:T 个位置一次算完 ← 参数规模能推到万亿的前提
生成:T 个 token 要 T 次前向 ← 推理成本由生成长度决定于是一次前向同时在 T 个位置上产生 T 个「预测下一个词」的训练信号。这带来两个重要收益:
- 训练是高度并行的(虽然生成是串行的)——这个不对称是 Decoder-Only 能训到万亿参数的关键
- 配合因果掩码,每个位置都只能用到它前面的信息,与推理时的条件分布严格对应
这种「用真实的前缀作为每一步的输入」的训练方式通常叫 teacher forcing。它有一个已知的副作用:训练时模型看到的前缀永远是正确的,推理时看到的却包含自己生成的错误——这个训练与推理的分布差异,是曝光偏差(exposure bias)问题的来源。
与另外两种架构的对照
理解了 Decoder-Only 的选择,要放到三条路线的对照里才看得清:
| Encoder-Only | Encoder-Decoder | Decoder-Only | |
|---|---|---|---|
| 代表 | BERT | 原始 Transformer、T5 | GPT 系列、Llama、Qwen |
| 注意力 | 双向(能看到两侧) | 编码器双向 + 解码器因果 | 因果(只看左侧) |
| 预训练目标 | 掩码语言建模(完形填空) | 去噪 / 序列到序列 | 下一个词预测 |
| 天然擅长 | 理解类:分类、抽取、相似度 | 转换类:翻译、摘要 | 生成类:对话、写作、代码 |
| 生成能力 | 没有(非自回归,不是生成模型) | 有 | 有 |
| 统一任务的方式 | 加一个任务头 | 输入-输出两个序列 | 把任务写成 prompt |
最后一行是 Decoder-Only 真正的胜出原因。前三代架构要给每类任务配不同的头或不同的训练流程;Decoder-Only 只需要把任务表述成文本续写——分类就是把标签写成下一个词,抽取就是把答案写成后续文本。架构不区分任务,任务在数据里。
三条优势
| 优势 | 说明 |
|---|---|
| 训练目标统一 | 唯一任务是「预测下一个词」,非常适合在海量无标注文本上做预训练 |
| 训练并行、生成串行 | 靠 shifted labels,一次前向产生 T 个信号——训练侧可以吃满算力,这让参数规模能推到数千亿到万亿(GPT-4、Llama) |
| 天然适合生成任务 | 自回归模式与对话、写作、代码生成等所有生成式任务契合 |
| 不预设任务结构 | 任务通过 prompt 表达而不是通过架构表达——这才有了后续「同一个模型什么都干」的形态 |
「训练并行、生成串行」这个不对称值得单独记住:它同时解释了两件事——为什么这类模型能训得那么大,以及为什么推理成本会由生成长度决定(每个 token 都要一次完整前向)。
相关
- 02-Transformer 架构 —— 掩码自注意力是在那里讲的自注意力上加因果掩码
- KV Cache 与推理优化 —— 串行生成带来的成本,以及怎么把它压下来
- 04-采样参数 —— 每一步从词表分布里怎么取词
- 06-缩放法则 —— 「训练侧能并行」是规模能推上去的前提之一
- 05-文本分词与子词算法:BPE、WordPiece 与 Unigram —— 输入从文本变成词元序列的那一步
参考
- 《Hello-Agents》第三章 §3.1.3
- Radford, A., et al. Improving language understanding by generative pre-training. OpenAI, 2018.
- 本专栏 02-Transformer 架构 的 Encoder-Decoder 一节
YJ