第 6 章:Transformer 架构¶
1. 本章要解决的问题¶
第 5 章里,我们已经理解了 Attention 的核心直觉:
模型会根据当前 token 的需求,去上下文里有选择地读取信息。
这一步非常关键,但它还不是一个完整的大模型架构。
因为当我们真的想把语言模型做出来时,很快会遇到几个更具体的问题:
- 只有 Attention,模型怎么知道 token 的先后顺序?
- 只有上下文交互,没有额外非线性变换,表达能力够吗?
- 如果把网络堆得很深,训练为什么还能稳定?
- 为什么后来会分化出 BERT、GPT、T5 这些不同结构?
所以这一章要解决的,不再是:
Attention 是什么。
而是:
Attention 是怎样被组织进一个完整的 Transformer,并进一步演化成现代 LLM 主流架构的。
从全书结构上看,这一章有三个作用:
- 它承接第 5 章,把 Attention 从“单个机制”升级成“完整系统”
- 它为第 7 章的 Mini-GPT 提供结构层面的蓝图
- 它也为后面预训练、微调、RAG、Agent 等章节建立统一模型视角
如果第 5 章回答的是:
模型怎样动态关注上下文。
那么第 6 章回答的就是:
这些能力怎样被拼装成一个真正可训练、可扩展、可用于不同任务的神经网络架构。
2. 你学完后应该会什么¶
- 能用自己的话解释 Transformer 为什么不只是 Attention
- 能说明 token embedding、position、attention、FFN、残差连接、LayerNorm 分别做什么
- 能画出一个最小 Transformer block 的数据流
- 能区分 encoder-only、decoder-only、encoder-decoder 三类架构
- 能解释 GPT 为什么采用 decoder-only
- 能把这一章的结构理解直接映射到第 7 章的 Mini-GPT 代码里
3. 为什么只有 Attention 还不够¶
很多人第一次学 Transformer 时,容易把它理解成一句话:
Transformer = Attention
这不算完全错,但不完整。
更准确地说,Transformer 是:
以 Attention 为核心,再配上一组让深层网络可以表达、训练和扩展的辅助模块。
如果只有 Attention,而没有其他配套设计,会出现几个明显问题。
3.1 没有位置信息,模型不知道顺序¶
Attention 本身并不天然理解顺序。
假设输入两个序列:
dog bites manman bites dog
如果我们只把 token 向量丢进 self-attention,而不给任何位置相关信息,那么模型看到的更像是一个“词袋集合”,而不是一个有先后顺序的序列。
但语言的意义高度依赖顺序。
所以 Transformer 必须额外引入:
- positional encoding
- 或 positional embedding
来告诉模型:
这个 token 不只是“是什么”,还要知道“它在第几个位置”。
3.2 只有信息交互还不够,还需要更强表达能力¶
Attention 擅长做的是:
让每个位置从其他位置读取相关信息。
但如果整个网络只反复做“加权读取”,而没有额外的非线性变换,那么模型的表达能力会受限。
这就像一个团队里所有人都在互相交换信息,但没有人对信息做进一步加工、抽象和重组。
所以 Transformer 在 attention 之后,通常还会接一个逐位置的前馈网络(Feed-Forward Network, FFN)。
它的作用可以先粗略理解成:
- attention 负责“信息路由”
- FFN 负责“特征变换”
两者组合起来,模型才能既会看上下文,也会处理上下文。
3.3 网络变深之后,训练会更困难¶
现代大模型不是一两层,而是很多层 block 堆起来的。
一旦网络变深,就会遇到经典问题:
- 梯度传播困难
- 训练不稳定
- 前面学到的表示容易被后面破坏
所以 Transformer 借鉴了残差连接(Residual Connection)的思想。
也就是每个子层都不是只输出新结果,而是把输入保留下来,再和新结果相加。
直觉上可以理解成:
模型不是每一层都推翻前一层,而是在原有表示上做增量修正。
这会让深层网络更容易训练。
3.4 激活分布不稳定,需要规范化¶
深层神经网络训练时,一个常见问题是不同层输入分布会不断变化,导致训练不稳定。
Transformer 里广泛使用 LayerNorm,作用可以先简单理解成:
把每个位置上的表示拉回一个更稳定的数值范围。
这样做的好处是:
- 梯度更稳定
- 训练更容易收敛
- 深层堆叠时更可靠
所以到这里我们就能看出:
Transformer 不是把 Attention 单独拿出来直接堆很多层,而是围绕它补齐了一整套工程化和训练稳定性设计。
4. Transformer 的核心组成模块¶
现在我们把完整 Transformer 先拆成几个最重要的零件。
4.1 Token Embedding¶
模型拿到的原始输入并不是单词本身,而是 token id。
例如一句话:
I love NLP
经过 tokenizer 之后,可能变成:
[314, 892, 10577]
但这些整数本身没有语义。
所以第一步通常要做 embedding lookup,把每个 token id 映射成一个稠密向量:
其中:
- \( x_i \) 是第 \( i \) 个 token id
E是 embedding matrix- \( e_i \) 是该 token 的向量表示
可以把它理解成:
token embedding 负责回答“这个 token 是谁”。
4.2 Positional Encoding / Positional Embedding¶
有了 token embedding 之后,模型还缺一件事:
这个 token 在序列中的位置。
最早的 Transformer 论文里使用的是 sinusoidal positional encoding; 而 GPT、BERT 等很多现代模型更常用可学习的 positional embedding。
无论具体实现是什么,本质上都是要把“位置信息”注入表示中。
最常见的做法是直接相加:
其中 \( p_i \) 表示第 \( i \) 个位置的向量。
这一层负责回答:
这个 token 不只是“谁”,还要知道“它在哪”。
4.3 Multi-Head Self-Attention¶
这部分是 Transformer 的核心。
第 5 章里我们已经见过单头 attention 的基本形式:
而在 Transformer 里,通常不会只用一个 attention head,而是使用 multi-head attention。
它的直觉是:
让模型从多个子空间、多个关系视角同时观察上下文。
例如有的 head 可能更关注:
- 主谓关系
- 代词指代
- 局部搭配
- 长距离依赖
严格说,head 不一定会自动学成这么清晰的人类语法功能,但这个直觉足够帮助我们理解它为什么比单头更强。
multi-head 的常见写法是:
其中每个 head 都有自己的一组 \( W_Q, W_K, W_V \)。
4.4 Feed-Forward Network¶
attention 之后,Transformer 还会接一个 position-wise FFN。
所谓 position-wise,意思是:
每个位置都经过同一套两层 MLP,但不同位置之间在这一步不直接交互。
常见形式是:
这里的激活函数 \( \sigma \) 可能是 ReLU、GELU 等。
它的主要作用不是建模序列关系,而是:
- 提升非线性表达能力
- 对 attention 汇总后的特征做进一步加工
所以可以把它理解成:
- attention 决定“看谁”
- FFN 决定“怎么处理看到的内容”
4.5 Residual Connection¶
Transformer 的每个核心子层外面,通常都会包一层残差连接。
例如:
这意味着子层不是完全替换旧表示,而是在旧表示基础上叠加一个修正项。
它的价值在深层网络里非常大:
- 缓解梯度消失
- 保留原始信息通路
- 让训练更稳定
很多时候你会发现,真正让深层模型能“堆起来”的,不只是核心模块有多聪明,还有这些看起来很朴素的训练技巧。
4.6 LayerNorm¶
Transformer 中另一个关键零件是 LayerNorm。
它通常放在子层附近,用于稳定训练。
你可以先把它理解成:
对每个样本、每个位置的隐藏表示做标准化,让不同层之间的数值分布更可控。
从直觉上说,它像是在提醒网络:
“不要让某一层的激活值突然爆得太大,也不要让尺度飘得太厉害。”
现代很多实现里,还会区分:
- Post-LN:先子层,再残差,再 LayerNorm
- Pre-LN:先 LayerNorm,再进子层,再做残差
工程上 Pre-LN 在深层训练里通常更稳定,所以很多现代 LLM 实现更偏向这种写法。
5. 一个 Transformer Block 是怎么串起来的¶
理解完零件之后,接下来最重要的问题是:
这些零件到底按什么顺序工作?
先看最经典的 Transformer block 思路。
5.1 输入表示¶
设输入序列长度为 \( T \),隐藏维度为 \( d_{model} \)。
输入 token ids 先经过 embedding,得到:
再加上位置向量:
这时每个位置已经同时携带了:
- token 语义信息
- 位置信息
5.2 进入 self-attention 子层¶
然后每个位置通过 self-attention 与整段上下文交互。
如果是普通 Transformer encoder,一个位置可以看所有 token; 如果是 GPT 这样的生成模型,则要加 causal mask,禁止当前位置偷看未来。
这一层的作用是:
让每个 token 根据当前任务,从整段上下文中读取自己需要的信息。
5.3 残差连接和 LayerNorm¶
attention 子层之后,通常会接:
- residual
- LayerNorm
写成简化形式可以是:
或者在 Pre-LN 结构里写成:
两种写法都很常见,核心思想不变:
attention 负责信息交互,残差和规范化负责让训练稳定。
5.4 进入 FFN 子层¶
接下来每个位置再单独进入 FFN:
或对应的 Pre-LN 版本。
这一步不直接建模位置之间的关系,而是对当前表示做更强的非线性变换。
5.5 多层堆叠¶
一个 block 还不够。
Transformer 的能力很大程度上来自:
把这样的 block 反复堆叠很多层。
随着层数加深,模型可以逐步形成:
- 更复杂的上下文表示
- 更抽象的语义特征
- 更强的生成或理解能力
所以 Transformer 的一个核心思想其实很朴素:
同一种高质量 block,稳定地重复很多次。
6. 三类主流 Transformer 架构¶
理解 block 之后,下一步就能看懂为什么后来会出现不同“家族”。
虽然大家底层都来自 Transformer,但根据任务目标不同,主流架构大致分成三类。
6.1 Encoder-only¶
代表模型:BERT、RoBERTa
这类模型主要由 encoder stack 构成。
它的特点是:
- 每个位置通常可以看到左右两边上下文
- 更适合做表示学习和理解任务
- 常见于分类、抽取、匹配、判别任务
为什么它擅长理解?
因为对于一句完整输入,encoder-only 模型在编码时可以双向整合上下文。
例如句子里一个词的表示,不仅能参考左边,也能参考右边。
这对下面这些任务很有帮助:
- 句子分类
- 命名实体识别
- 文本匹配
- 检索编码
但它天然不是最直接的生成架构,因为生成任务要求模型在第 t 步只能依赖前 t-1 步。
6.2 Decoder-only¶
代表模型:GPT 系列、LLaMA、Qwen 等大多数现代自回归 LLM
这类模型只保留 decoder stack,但在语言建模场景里,通常只用到:
- masked self-attention
- FFN
- 残差连接
- LayerNorm
而不一定使用原始 seq2seq Transformer decoder 里的 cross-attention。
它的核心特点是:
- 使用 causal mask
- 每个位置只能看见自己和左边上下文
- 天然适配 next-token prediction
例如训练时:
输入:
I love deep
目标:
让模型预测下一个 token 更可能是 learning
这个目标和 decoder-only 结构是完全对齐的。
所以它特别适合:
- 文本续写
- 对话生成
- 代码生成
- 通用自回归语言建模
6.3 Encoder-decoder¶
代表模型:T5、BART
这类模型同时保留 encoder 和 decoder 两部分。
它的典型工作方式是:
- encoder 先把输入序列编码成上下文表示
- decoder 再基于这些表示一步步生成输出
这里 decoder 除了有 masked self-attention,还会多一个:
- cross-attention
也就是 decoder 在生成时,不仅看自己前面已经生成的 token,还会去读取 encoder 输出。
这种结构非常适合输入和输出都比较明确的 seq2seq 任务,例如:
- 机器翻译
- 摘要
- 改写
- 问答
因为它天然支持:
先理解输入,再条件生成输出。
6.4 三类架构的直观对比¶
可以先把它们粗略记成下面这样:
| 架构类型 | 代表模型 | 上下文可见性 | 更适合什么 |
|---|---|---|---|
| encoder-only | BERT | 双向 | 理解、表示、判别 |
| decoder-only | GPT | 仅左侧可见 | 自回归生成 |
| encoder-decoder | T5 | encoder 双向,decoder 左侧可见 | 条件生成、seq2seq |
这张表不是为了背诵,而是帮助你建立一个特别重要的意识:
架构不是凭空选的,而是和训练目标、任务形式强相关。
7. GPT 为什么采用 decoder-only¶
这一节是本章最重要的落点之一。
很多人会问:
既然 encoder-decoder 看起来更完整,为什么 GPT 不走那条路,而是选择 decoder-only?
原因可以从四个角度理解。
7.1 它和 next-token prediction 完全对齐¶
GPT 的核心训练目标是:
给定前文,预测下一个 token。
这要求模型在第 \( t \) 个位置只能看:
- \( x_1 \)
- \( x_2 \)
- ...
- \( x_{t-1} \)
而 decoder-only + causal mask 恰好就是为这种约束设计的。
所以它在结构上和训练目标天然一致。
7.2 它和生成过程完全一致¶
推理时,GPT 的工作方式也是:
- 读入当前上下文
- 预测下一个 token 概率分布
- 采样或选出一个 token
- 把它拼回上下文
- 继续下一步
这本质上就是 decoder-only 的自回归生成过程。
所以它的训练和推理在形式上非常统一。
7.3 架构更简洁,更容易做大规模预训练¶
相较于 encoder-decoder,decoder-only 在通用语言建模场景下通常更直接:
- 输入输出统一成一条 token 序列
- 训练目标简单清晰
- 模型设计更容易标准化
这对于大规模预训练很重要。
因为一旦训练范式足够统一,数据组织、并行训练、推理部署都会更顺。
7.4 它特别适合“通用生成器”这个产品形态¶
ChatGPT、代码补全、写作助手、Agent 背后的大模型,本质上都强依赖一种能力:
给定已有上下文,持续生成后续 token。
而 decoder-only 恰好天然擅长这件事。
所以从研究目标到产品形态,GPT 选择 decoder-only 都很自然。
这并不意味着 encoder-only 或 encoder-decoder 不重要,而是说明:
对于通用自回归生成,decoder-only 是最顺手的架构。
8. 从结构图到代码骨架¶
到这里,我们已经可以把 Transformer block 映射成代码里的模块关系。
先看一个极简伪代码版本:
class TransformerBlock(nn.Module):
def __init__(self):
self.ln1 = LayerNorm(d_model)
self.attn = CausalSelfAttention(d_model, n_heads)
self.ln2 = LayerNorm(d_model)
self.ffn = MLP(d_model)
def forward(self, x):
x = x + self.attn(self.ln1(x))
x = x + self.ffn(self.ln2(x))
return x
如果继续向上封装成一个最小 GPT,大致会是:
class GPT(nn.Module):
def __init__(self):
self.token_emb = Embedding(vocab_size, d_model)
self.pos_emb = Embedding(block_size, d_model)
self.blocks = nn.ModuleList([
TransformerBlock() for _ in range(n_layers)
])
self.ln_f = LayerNorm(d_model)
self.lm_head = Linear(d_model, vocab_size)
def forward(self, idx):
tok = self.token_emb(idx)
pos = self.pos_emb(position_ids)
x = tok + pos
for block in self.blocks:
x = block(x)
x = self.ln_f(x)
logits = self.lm_head(x)
return logits
这里最重要的不是记代码,而是建立对应关系:
token_emb:token embeddingpos_emb:位置表示blocks:重复堆叠的 Transformer blockslm_head:把隐藏状态映射回词表 logits
这也正是第 7 章 Mini-GPT 要真正实现的内容。
所以你可以把这一章当成:
第 7 章代码实现前的结构蓝图。
9. 常见误区¶
误区 1:Transformer 就是 Attention¶
不对。
更准确地说,Attention 是 Transformer 的核心模块,但完整 Transformer 还包括:
- 位置表示
- FFN
- 残差连接
- LayerNorm
- 多层堆叠
真正可训练、可扩展的大模型,是这些模块共同作用的结果。
误区 2:有了 self-attention 就天然知道顺序¶
不对。
self-attention 本身只是在 token 间计算相关性,并不自带“第几个位置”的概念。
所以如果没有位置编码或位置嵌入,模型无法可靠地区分不同顺序。
误区 3:FFN 只是一个可有可无的小 MLP¶
不对。
FFN 不是装饰件,它承担了重要的非线性变换功能。
如果只有 attention 而没有 FFN,模型的信息交互有了,但表示加工能力不够强。
误区 4:BERT 和 GPT 的区别只是一个双向一个单向¶
这句话只说对了一半。
两者的差别不只是可见性不同,还包括:
- 训练目标不同
- 更适合的任务类型不同
- 输出使用方式不同
所以它们不是同一个模型换个 mask 那么简单,而是面向不同任务偏好的两条路线。
误区 5:decoder-only 比 encoder-decoder 更“低级”¶
不对。
架构没有绝对高级和低级,只有任务匹配不匹配。
对于通用自回归生成,decoder-only 往往更直接、更高效、更容易规模化; 对于翻译、摘要等条件生成任务,encoder-decoder 往往更自然。
10. 面试问题¶
Q1:一个标准 Transformer block 通常由哪些部分组成?¶
通常包括:
- multi-head attention
- FFN
- residual connection
- LayerNorm
在进入 block 之前,还会有 token embedding 和 position embedding。
Q2:为什么 Transformer 需要位置编码?¶
因为 self-attention 本身不天然感知顺序。
如果不显式注入位置信息,模型就很难区分:
A B CC B A
这样的序列差异。
Q3:FFN 在 Transformer 里起什么作用?¶
attention 负责从上下文中聚合信息,FFN 负责对每个位置的表示做进一步非线性变换,提升表达能力。
Q4:encoder-only、decoder-only、encoder-decoder 的区别是什么?¶
- encoder-only 更偏理解和表示学习
- decoder-only 更偏自回归生成
- encoder-decoder 更偏条件生成和 seq2seq
Q5:GPT 为什么采用 decoder-only?¶
因为 GPT 的训练目标是 next-token prediction,而 decoder-only 配合 causal mask 与这一目标天然对齐,训练和推理形式也保持一致。
11. 本章小结¶
这一章最重要的结论可以浓缩成三句话:
第一,Transformer 不只是 Attention,而是:
Attention + position + FFN + residual + LayerNorm + 多层堆叠。
第二,不同 Transformer 架构并不是随便分叉出来的,而是和任务形式强相关:
- BERT 偏理解
- GPT 偏生成
- T5 偏条件生成
第三,GPT 之所以成为现代通用大模型的主流路线之一,一个关键原因就在于:
decoder-only 与 next-token prediction 和自回归生成天然匹配。
理解了这一层,下一章再去从零实现一个 Mini-GPT,就不会只是“照着代码搭积木”,而是会知道每个模块为什么存在、为什么这样连接、为什么最终会长成 GPT 这种样子。