Skip to content

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。

自回归生成

“自回归”这个词可以理解成:

  • 当前时刻的输出
  • 依赖于之前已经出现的输出

对于语言模型来说,就是:

p(x1,x2,,xT)=t=1Tp(xtx<t)

这里:

  • x<t 表示第 t 个 token 之前的所有 token
  • 模型在每一步只负责预测“下一个 token 的概率分布”

更直观一点:

  • 你输入一段前缀
  • 模型给出“下一个 token 最可能是什么”
  • 你把这个新 token 接回前缀
  • 然后继续预测下一个 token

这就是自回归生成。

为什么 decoder-only 一定要用 mask

假设当前正在预测第 t 个 token。

如果模型能直接看到:

  • t+1 个 token
  • t+2 个 token
  • 甚至整个后面的真实答案

那这个预测任务就失真了。

所以 decoder-only 模型必须满足一个严格约束:

位置 t 只能访问 1t 的信息,不能访问未来位置。

这就是 causal maskautoregressive 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 的预测

举个例子。

句子是:

text
The capital of France is Paris

训练时可以把它构造成:

输入:

text
The capital of France is

目标:

text
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 仍然会被认真处理:

  1. token 先经过 embedding
  2. 加入位置信息
  3. 进入多层 masked self-attention
  4. 每一层都在“基于左侧上下文更新当前位置表示”
  5. 最后当前位置表示被用来预测下一个 token

所以在 decoder-only 里,并不是:

  • 一边是“输入编码器”
  • 另一边是“输出解码器”

而是:

  • 同一个网络既负责理解已有前缀,也负责给出下一个 token 的分布

假设训练文本是:

text
The capital of France is Paris

在位置 is 之后,模型需要预测 Paris

为了做到这一点,它必须利用左侧上下文:

text
The capital of France is

这段左侧上下文并不是“直接原样送到 softmax 就结束”,而是经过多层 masked self-attention 之后,形成当前位置可用的上下文表示。

于是模型虽然没有 encoder,但它仍然在做一件本质上等价的事:

  • 读取已有前缀
  • 建立上下文表示
  • 基于这个表示预测下一项

为什么不需要单独 encoder

因为语言建模目标本身就是:

p(xtx<t)

这里需要的不是“双向读完整输入,再输出另一段序列”,而是:

  • 给定左侧前缀
  • 继续往后补全

这和传统翻译中的 encoder-decoder 任务形态不一样。

在机器翻译里,常常是:

  • 整个源语言句子先被 encoder 编码
  • decoder 再在这个编码上生成目标语言

而在 decoder-only 里,任务被统一改写成了:

  • “给定一串前缀,预测它后面最可能出现什么”

因此它天然不要求必须存在一个独立的 encoder。

为什么只做 next-token prediction,最后却能学出问答、总结、翻译这些能力

表面上看,模型训练时做的事情非常朴素:

  • 只预测下一个 token

那为什么最后却能表现出:

  • 问答
  • 总结
  • 翻译
  • 改写
  • 代码补全
  • 一定程度的推理能力

核心原因可以拆成四层。

  1. 很多任务本来就可以写成“续写”

从形式上说,很多语言任务都可以改写成:

  • 给定一个前缀
  • 让模型把后面的内容续出来

例如问答可以写成:

text
Question: What is the capital of France?
Answer:

模型只需要继续补全:

text
Paris

翻译可以写成:

text
Translate to Chinese:
Hello, world!

模型继续补全中文结果即可。

总结可以写成:

text
Article:
...

Summary:

模型继续补全摘要即可。

所以从接口层面看,很多任务本质上都能被包装成:next-token continuation

  1. 为了预测下一个 token,模型必须学到大量隐含结构

next-token prediction 看起来简单,但要长期做对,其实模型必须掌握很多能力。

例如它必须逐渐学会:

  • 语法结构
  • 搭配关系
  • 指代关系
  • 常识与事实模式
  • 文本中的任务格式
  • 某些推理链条和程序性模式

否则它就无法在真实文本分布中持续正确预测“接下来最可能出现什么”。

也就是说:

虽然训练目标只写成了“预测下一个 token”,但为了优化这个目标,模型会被迫学习很多更高层的语言结构。

  1. 预训练语料里本身就包含大量“任务样例”

互联网文本和高质量语料里,并不只有普通叙述句。

它们还包含了大量结构化任务痕迹,例如:

  • 问答页面
  • 教材与解释性文本
  • 翻译对照
  • 标题与摘要
  • 代码与注释
  • 列表、定义、证明、步骤说明

因此从统计学习角度看,模型其实在预训练中反复看到:

  • 某种输入形式后面通常接什么输出

例如:

text
Question: ...
Answer: ...
text
English: ...
Chinese: ...
text
TL;DR: ...

这些模式在训练中会不断出现。

于是模型不仅学到自然语言本身,也学到了很多“任务格式 -> 续写形式”的映射。

  1. 推理时我们又把任务重新写回这种格式

为什么 prompt 有效?

因为推理时我们会故意把任务写成模型熟悉的 continuation 形式。

例如:

text
请总结下面这段文字:
...

总结:

这实际上就是在构造一个前缀,让模型进入它在训练中见过很多次的分布区域。

于是模型做的仍然不是“显式切换到一个新算法”,而是:

  • 按照训练中学到的模式,继续补全接下来的 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 是:

text
The capital of France is

推理时的流程大致是:

  1. 把这段 prompt 编码成 token
  2. 输入模型
  3. 模型输出下一个 token 的概率分布
  4. 选出一个 token,例如 Paris
  5. Paris 拼回输入序列
  6. 再次输入模型,预测它之后的 token

于是序列会变成:

text
The capital of France is Paris

接着再预测下一个 token,比如句号:

text
The capital of France is Paris .

然后继续。

这说明一件很关键的事:

推理时的输入序列长度会随着生成过程不断变长。

这也是为什么推理时的 attention 计算会越来越重,以及为什么后来需要 KV Cache