Transformer:把零件拼成一个能跑的模型
上一节学了注意力。但 attention 并不是一整个模型 — 它是 Transformer Block 里的一个子层。 这一节我们把 attention、FFN、残差、LayerNorm 这几样拼起来,看一个完整的 Transformer 长什么样。
① 直觉:Transformer = 「乐高积木」
最终的 GPT 模型在视觉上其实非常简洁:
- 输入:一串 token IDs
- 查 embedding 表 + 加位置编码 → 张量
- 过 N 个结构完全相同的 Transformer Block
- 过一个 LayerNorm 收尾
- 用一个线性层投影到词表大小 → 输出每个位置上"下一个 token"的 logits
中间的 N 个 Block 是同一个结构反复堆叠 —— 像同一种乐高积木堆 96 层。 GPT-2 small 是 12 层,GPT-3 是 96 层,LLaMA-65B 是 80 层。 模型变"大",绝大多数时候是层数变多或维度变大,结构不变。
② 互动:拆开一个 Transformer Block 看看
点击下面流程图里的任何一个阶段,看它具体做什么、为什么需要它:
Multi-Head Attention
这是什么上一节讲过的注意力。让每个 token "回头看"前面所有 token,按需聚合信息。
为什么有这是 Transformer 的灵魂:让 token 之间能"对话"。
张量形状:(L, d)
这是一个 Transformer Block 的内部流程。整个 GPT 就是把这种 block 堆叠 N 次 (N = 12 / 24 / 96 / ... 看模型大小)。点击左边任意一个阶段,右边会显示它做什么、为什么需要它。
重点关注 4 个零件:Attention(让 token 之间换信息)、FFN(在单个 token 内部加工信息)、残差连接(让 梯度顺畅)、LayerNorm(让分布稳定)。 理解了这 4 件,Transformer 没有别的秘密。
③ Attention 和 FFN 的"分工"
一个 Block 里有两个子层。它们的分工非常清楚:
| 子层 | 作用 | token 间是否互动 | 参数占比 |
|---|---|---|---|
| Attention | 让每个 token 看"该看的"其他 token,聚合上下文 | 是 | 约 1/3 |
| FFN | 在每个 token 上独立做非线性变换(先升维到 4d 再降回 d) | 否 | 约 2/3 |
一个普通的比喻:Attention 是会议室里同事互相讨论,FFN 是回到工位上独立深加工。 缺了 attention,token 互相看不到对方;缺了 FFN,token 只能"传话"不能"思考"。两者缺一不可。
④ 残差连接:让 96 层也能训得动的秘密
如果你简单地把 96 个 attention 串起来,会发现训练时梯度消失:损失传不回前面的层,前几层就学不到东西。 2015 年 ResNet 提出的残差连接(skip connection)一举解决了这个问题:
看起来只是加了一个 x +,但效果是颠覆性的:
- 子层只需要学"对输入做什么修改"(residual),不需要学"完整的输出"
- 反向传播时,梯度可以直接通过
+流回前一层,不会因为深而衰减 - 信息有"高速公路"穿过整个网络 — 哪怕某些层学得不好,原始信息还能被后面的层用上
⑤ LayerNorm:让每一层的"输入分布"保持稳定
训练神经网络最头疼的事情之一叫"内部协变量漂移"(internal covariate shift): 前面层的参数稍微变一下,中间层的输入分布就跟着剧烈变化,导致训练不稳定。
LayerNorm 干一件简单的事:把每个 token 的 d 维向量归一化成均值 0、方差 1,再用可学习的 γ/β 把分布恢复成有用的样子。
和 BatchNorm 的关键差别:LayerNorm 沿"特征维"归一化(每个 token 内部), 和序列里别的位置、batch 里别的样本无关。这对变长序列特别合适。
现在的 LLaMA、PaLM 把 LayerNorm 进一步简化成 RMSNorm(只除以 RMS,不减均值),效果一样还更省。
⑥ Pre-norm vs Post-norm:一个看起来很小但影响巨大的选择
原始 Transformer 论文用的是 post-norm(norm 放在子层之后):
x = LayerNorm(x + Sublayer(x))
但后来大家发现这样深层不好训。现在 GPT-3 / LLaMA 都改成了 pre-norm(norm 放在子层之前):
x = x + Sublayer(LayerNorm(x))
差异看起来微妙,但 pre-norm 让残差路径是干净的恒等映射,梯度能从顶层一路顺畅地流回底层。 这是后来大模型能叠到 80、96、120 层的关键之一。
⑦ 代码:完整的 Transformer Block
下面这段把所有零件拼起来。运行能看到输入和输出形状相同 — 所以可以无限叠:
np. 看自动提示,⌘/Ctrl + Enter运行。⑧ 完整的 GPT 长什么样
把上面的 block 包在 embedding 和输出投影之间,就是一个完整的 GPT:
np. 看自动提示,⌘/Ctrl + Enter运行。Karpathy 的 nanoGPT 完整实现(含训练)一共也就 300 行 Python 左右。 你看完这门课就能读懂它的每一行。
⑨ 模型容量的三个旋钮
Transformer 架构定了,模型"做大"实际上只有三个旋钮:
- 层数 N —— Block 堆几层。GPT-3 = 96 层,LLaMA-70B = 80 层。
- 维度 d —— 每个 token 多少维。GPT-3 d=12288, LLaMA-70B d=8192。
- 头数 h —— MHA 拆几个头。通常 d 越大 h 越多,d_k = d/h 一般 64–128。
参数量 ≈ 12 × N × d²。GPT-3:12 × 96 × 12288² ≈ 175B。 这条公式可以让你看到任意一个新模型的尺寸,就估算出它有多少参数。
⑩ 小测验
⑪ 延伸阅读
- karpathy/nanoGPT:一个完整的、能在单卡跑起来的 GPT 实现。读完本课后强烈推荐对照看一遍
model.py。 - Attention is All You Need (PyTorch 实现):原论文 post-norm 的标准实现,跟现代 pre-norm 做对比。