目录
第一课里,我们把 Transformer 当成一个黑盒:Token 向量进去,带有上下文的信息出来。现在把黑盒打开一层。
大语言模型并不是只有一个巨大的 Transformer。它会把结构相同的 Transformer Block 堆叠很多次。每个 Block 都做两件核心工作:让 Token 之间交换信息,再分别加工每个 Token 的表示。
Attention 负责“彼此交流”,FFN 负责“各自加工”;Residual 和 Norm 让这两步能够稳定地重复很多层。
1、Block 是模型的基本积木
假设输入隐藏状态是:
\[x\in\mathbb{R}^{B\times T\times d_{model}}\] 一个 Block 接收 x,输出形状相同的新隐藏状态。然后,这个输出会成为下一个 Block 的输入。
Embedding → Block 1 → Block 2 → ... → Block N → LM Head
层数越多,Token 表示经历的交流和加工次数越多。但所有 Block 不共享参数:结构看起来相同,每一层学到的权重却不同。
2、先看完整数据流
以 Llama 一类模型常见的 Pre-Norm 结构为例,一个 Block 可以写成两行:
\[h=x+Attention(RMSNorm(x))\] \[y=h+FFN(RMSNorm(h))\]第一行是 Attention 子层,第二行是 FFN 子层。每个子层前先做 Norm,子层输出再与原输入相加。
def forward(x):
x = x + attention(rms_norm_1(x))
x = x + ffn(rms_norm_2(x))
return x
真实代码还会处理位置编码、Attention Mask、Dropout 或缓存,但骨架就是这两次“Norm → 子层 → Add”。
3、Attention:负责 Token 之间交流
Attention 是 Block 中唯一让不同位置直接交换信息的部分。
例如句子“苹果发布了新手机,它很受欢迎”中,“它”的表示可以从“苹果”和“新手机”等 Token 获取信息。经过 Attention 后,每个位置仍然对应一个 Token,但向量已经融入了其他位置的上下文。
| 输入 | Attention 做的事 | 输出 |
|---|---|---|
[B, T, d_model] |
不同 Token 按相关性汇总信息 | [B, T, d_model] |
Q、K、V、RoPE、GQA 等细节并没有消失,只是都包含在 Attention 这个子层内部。
4、FFN:负责逐个 Token 加工
Attention 完成交流后,FFN 会对每个 Token 的向量单独做非线性变换。它不会在 Token 之间传递信息,同一套参数会应用在所有位置上。
经典 FFN 可以理解为先升维、激活,再降回原维度:
\[[B,T,d_{model}]\rightarrow[B,T,d_{ff}]\rightarrow[B,T,d_{model}]\]$d_{ff}$ 通常大于 $d_{model}$,像是先把每个 Token 放到更宽的工作空间里加工,再压回原来的宽度。现代模型常使用 SwiGLU,但它仍属于“逐 Token 加工”的 FFN。
5、Residual:保留原始信息
如果每个子层都完全覆盖输入,几十甚至上百层之后,早期信息和梯度都更难保留。残差连接直接把输入加回来:
\[output=input+sublayer(input)\]可以把子层理解为只学习“这一次需要补充或修正什么”,而不是从头重写整个表示。
图中的弧形旁路就是残差路径。它绕过 Attention 或 FFN,在末端执行逐元素相加,因此两边的形状必须相同。
6、Norm:让数值保持稳定
Block 重复很多层时,隐藏状态的数值尺度可能不断变化。Norm 会把输入调整到更稳定的尺度,让后续子层更容易训练。
现代 LLM 常用 RMSNorm,并把 Norm 放在 Attention 和 FFN 之前,因此叫 Pre-Norm。Norm 不负责 Token 交流,也不会改变张量形状。
| 组件 | 主要作用 | 会混合 Token 吗 | 改变最终形状吗 |
|---|---|---|---|
| RMSNorm | 稳定数值尺度 | 否 | 否 |
| Attention | 汇总其他 Token 的信息 | 是 | 否 |
| FFN | 逐 Token 非线性加工 | 否 | 否 |
| Residual | 保留输入、帮助梯度传播 | 否 | 否 |
7、形状为什么始终不变
Block 内部可以暂时升维、拆成多个 Head,但入口和出口都保持 [B, T, d_model]。这样做有两个直接好处:
- 残差连接能够逐元素相加。
- 相同结构可以直接堆叠,不需要为每一层设计新的接口。
输入 x [B, T, d_model]
Attention 输出 [B, T, d_model]
第一次相加 h [B, T, d_model]
FFN 输出 [B, T, d_model]
Block 输出 y [B, T, d_model]
“形状没变”不代表内容没变。每经过一个 Block,同一个 Token 的向量都包含了新的上下文和新的特征。
堆叠很多层之后发生什么
早期层往往处理更局部、更表面的模式;更深层可以组合更复杂的关系。这里不必把每层机械地分配成某种固定功能,重要的是:每一层都在已有表示上继续交流和加工。
第 0 层:初始 Token 表示
第 1 层:交流一次、加工一次
第 2 层:在新表示上再次交流、加工
...
第 N 层:得到送给 LM Head 的最终隐藏状态
容易混淆的 4 件事
- 一个 Block 不等于整个 Transformer。 模型通常会堆叠很多个 Block。
- Attention 与 FFN 分工不同。 前者混合 Token,后者逐 Token 处理。
- Residual 不是拼接。 它要求形状相同,并执行逐元素相加。
- Block 输入输出形状相同,不代表向量内容相同。 表示已经被上下文化和加工。
记住这 5 件事
- Transformer Block 是大模型反复堆叠的基本单元。
- 一个现代 Pre-Norm Block 通常有 Attention 和 FFN 两个子层。
- Attention 让 Token 交流,FFN 单独加工每个 Token。
- 每个子层前做 Norm,子层后通过 Residual 加回输入。
- Block 的输入输出都是
[B, T, d_model],因此可以连续堆叠。
第九课复习总图
下一课继续追问:Residual、LayerNorm 和 RMSNorm 为什么能让深层模型更容易训练?