Decoder-only Transformer
从标准 Transformer 到现代 LLM
在最初的论文语境里,Transformer 经常以 encoder-decoder 结构出现。
例如机器翻译:
- encoder 读入源语言句子
- decoder 在 encoder 输出的条件下逐步生成目标语言句子
但现代大语言模型很多时候采用的是更简单、也更主流的结构:
- 只有 decoder
- 没有 encoder
- 输入就是一串 token
- 输出也是继续往后生成 token
这就是 decoder-only Transformer。
它并不是说“只保留了原 Transformer 一半”,更准确地说,它保留的是:
- token embedding
- positional information
- 多层 masked self-attention
- 多层前馈网络
- 最后输出 next-token logits
它去掉的是:
- encoder 栈
- encoder-decoder attention
于是模型的核心任务就变成:
给定前缀 token,预测下一个 token。
自回归生成
“自回归”这个词可以理解成:
- 当前时刻的输出
- 依赖于之前已经出现的输出
对于语言模型来说,就是:
这里:
表示第 个 token 之前的所有 token - 模型在每一步只负责预测“下一个 token 的概率分布”
更直观一点:
- 你输入一段前缀
- 模型给出“下一个 token 最可能是什么”
- 你把这个新 token 接回前缀
- 然后继续预测下一个 token
这就是自回归生成。
为什么 decoder-only 一定要用 mask
假设当前正在预测第
如果模型能直接看到:
- 第
个 token - 第
个 token - 甚至整个后面的真实答案
那这个预测任务就失真了。
所以 decoder-only 模型必须满足一个严格约束:
位置
只能访问 的信息,不能访问未来位置。
这就是 causal mask 或 autoregressive mask 的意义。
在注意力矩阵里,它意味着:
- 当前位置不能 attend 到未来 token
- softmax 前,未来位置对应的分数会被屏蔽
因此 decoder-only 模型虽然使用的是 self-attention,但它不是“全可见”的 self-attention,而是:
- masked self-attention
- causal self-attention
训练时的 decoder-only 是怎么工作的
虽然我们说模型是“逐 token 生成”的,但训练时通常并不是:
- 先跑第 1 个 token
- 再跑第 2 个 token
- 再跑第 3 个 token
训练时更常见的是:
- 把整段 token 一次性送进模型
- 用 mask 保证每个位置只能看见历史
- 并行地计算每个位置对下一个 token 的预测
举个例子。
句子是:
The capital of France is Paris训练时可以把它构造成:
输入:
The capital of France is目标:
capital of France is Paris更准确地说,是对序列中每个位置都做 next-token prediction:
- 看见
The,预测capital - 看见
The capital,预测of - 看见
The capital of,预测France - 看见
The capital of France,预测is - 看见
The capital of France is,预测Paris
由于有 causal mask,这些位置可以在训练时并行算出来。
这就是:
- 训练时是整段并行
- 约束仍然是自回归
训练时没有 encoder,为什么还能训练出预测能力
很多人第一次接触 decoder-only 时会下意识觉得:
- 没有
encoder - 那是不是就没有一个模块专门“读懂输入”
- 这样模型怎么还能根据输入做预测
关键在于:
decoder-only不是“不建模输入”,而是“用同一个 masked self-attention stack 同时承担读上下文和预测下一个 token 的工作”。
也就是说,虽然没有单独的 encoder 模块,但输入 token 仍然会被认真处理:
- token 先经过 embedding
- 加入位置信息
- 进入多层 masked self-attention
- 每一层都在“基于左侧上下文更新当前位置表示”
- 最后当前位置表示被用来预测下一个 token
所以在 decoder-only 里,并不是:
- 一边是“输入编码器”
- 另一边是“输出解码器”
而是:
- 同一个网络既负责理解已有前缀,也负责给出下一个 token 的分布
假设训练文本是:
The capital of France is Paris在位置 is 之后,模型需要预测 Paris。
为了做到这一点,它必须利用左侧上下文:
The capital of France is这段左侧上下文并不是“直接原样送到 softmax 就结束”,而是经过多层 masked self-attention 之后,形成当前位置可用的上下文表示。
于是模型虽然没有 encoder,但它仍然在做一件本质上等价的事:
- 读取已有前缀
- 建立上下文表示
- 基于这个表示预测下一项
为什么不需要单独 encoder
因为语言建模目标本身就是:
这里需要的不是“双向读完整输入,再输出另一段序列”,而是:
- 给定左侧前缀
- 继续往后补全
这和传统翻译中的 encoder-decoder 任务形态不一样。
在机器翻译里,常常是:
- 整个源语言句子先被 encoder 编码
- decoder 再在这个编码上生成目标语言
而在 decoder-only 里,任务被统一改写成了:
- “给定一串前缀,预测它后面最可能出现什么”
因此它天然不要求必须存在一个独立的 encoder。
为什么只做 next-token prediction,最后却能学出问答、总结、翻译这些能力
表面上看,模型训练时做的事情非常朴素:
- 只预测下一个 token
那为什么最后却能表现出:
- 问答
- 总结
- 翻译
- 改写
- 代码补全
- 一定程度的推理能力
核心原因可以拆成四层。
- 很多任务本来就可以写成“续写”
从形式上说,很多语言任务都可以改写成:
- 给定一个前缀
- 让模型把后面的内容续出来
例如问答可以写成:
Question: What is the capital of France?
Answer:模型只需要继续补全:
Paris翻译可以写成:
Translate to Chinese:
Hello, world!模型继续补全中文结果即可。
总结可以写成:
Article:
...
Summary:模型继续补全摘要即可。
所以从接口层面看,很多任务本质上都能被包装成:next-token continuation
- 为了预测下一个 token,模型必须学到大量隐含结构
next-token prediction 看起来简单,但要长期做对,其实模型必须掌握很多能力。
例如它必须逐渐学会:
- 语法结构
- 搭配关系
- 指代关系
- 常识与事实模式
- 文本中的任务格式
- 某些推理链条和程序性模式
否则它就无法在真实文本分布中持续正确预测“接下来最可能出现什么”。
也就是说:
虽然训练目标只写成了“预测下一个 token”,但为了优化这个目标,模型会被迫学习很多更高层的语言结构。
- 预训练语料里本身就包含大量“任务样例”
互联网文本和高质量语料里,并不只有普通叙述句。
它们还包含了大量结构化任务痕迹,例如:
- 问答页面
- 教材与解释性文本
- 翻译对照
- 标题与摘要
- 代码与注释
- 列表、定义、证明、步骤说明
因此从统计学习角度看,模型其实在预训练中反复看到:
- 某种输入形式后面通常接什么输出
例如:
Question: ...
Answer: ...English: ...
Chinese: ...TL;DR: ...这些模式在训练中会不断出现。
于是模型不仅学到自然语言本身,也学到了很多“任务格式 -> 续写形式”的映射。
- 推理时我们又把任务重新写回这种格式
为什么 prompt 有效?
因为推理时我们会故意把任务写成模型熟悉的 continuation 形式。
例如:
请总结下面这段文字:
...
总结:这实际上就是在构造一个前缀,让模型进入它在训练中见过很多次的分布区域。
于是模型做的仍然不是“显式切换到一个新算法”,而是:
- 按照训练中学到的模式,继续补全接下来的 token
所以从模型内部视角看,它始终在做同一件事:
- next-token prediction
而从人类视角看,就像它在执行:
- 问答
- 翻译
- 总结
Teacher Forcing 在这里扮演什么角色
训练时模型并不是拿自己刚生成的 token 再喂给自己,而是始终使用真实历史 token 作为前缀。
这意味着:
- 每个位置都在学习“在正确上下文下,下一 token 应该是什么”
- 模型因此能稳定、大规模地从文本分布中学习 continuation 规律
如果没有 teacher forcing,训练会困难得多,因为:
- 错误会不断累积
- 上下文分布会迅速漂移
所以 decoder-only 虽然在推理时是一 token 一 token 生成,但训练时之所以还能高效学出强能力,一个关键原因就是:它用 teacher forcing 把自回归目标变成了可并行、可稳定优化的问题
推理时的 decoder-only 是怎么工作的
推理和训练最大的区别在于:
- 训练时后面的真实 token 已知
- 推理时后面的 token 不存在,只能靠模型自己生成
所以推理过程必须真的一 token 一 token 地走。
假设 prompt 是:
The capital of France is推理时的流程大致是:
- 把这段 prompt 编码成 token
- 输入模型
- 模型输出下一个 token 的概率分布
- 选出一个 token,例如
Paris - 把
Paris拼回输入序列 - 再次输入模型,预测它之后的 token
于是序列会变成:
The capital of France is Paris接着再预测下一个 token,比如句号:
The capital of France is Paris .然后继续。
这说明一件很关键的事:
推理时的输入序列长度会随着生成过程不断变长。
这也是为什么推理时的 attention 计算会越来越重,以及为什么后来需要 KV Cache。