难度
进阶
把 LayerNorm、残差连接、多头注意力、FFN 和堆叠逻辑放到一个统一框架里,理解一个 block 为什么能成为现代大模型的基础积木。
难度
进阶
阅读时长
约 105 分钟
更新日期
2026/03/24
主题
Transformer / Transformer Block / LayerNorm / 基础原理
这篇教程的目标,是让你把一个 Transformer block 真正看成“可解释、可拆解、可实现”的积木,而不是一张结构图上的黑盒。读完后你应该能:
这篇文章和 Transformer 注意力机制入门 的关系是:前者讲“注意力怎么工作”,这篇讲“注意力在整个 block 里扮演什么角色”。
很多人第一次看 Transformer,会记住一句话:
就是 Attention 加 FFN 再堆很多层。
这句话不算错,但太粗。真正决定 Transformer 能否稳定扩展的,不只是注意力本身,还有:
如果把 block 级别理解透了,你再看 GPT、BERT、LLaMA、MoE、FlashAttention 等工作时,就会很清楚:它们到底是在改哪个积木,而不是被一堆术语带着跑。
一个典型 block 可以抽象成两大段:
并且每一段都会配上:
把它写得更接近流程图,就是:
x今天很多主流模型采用的是 pre-norm 版本,也就是先归一化再进子层。早期原始 Transformer 更接近 post-norm。这个差异虽然只是顺序变化,却会显著影响深层训练稳定性。
注意力子层的本质工作,是让当前每个 token 决定要从整段上下文里读取哪些信息。
你可以把它理解成:
在这一层里,每个位置都会生成 Q/K/V,然后通过注意力权重聚合其他位置的信息。多头机制让不同子空间里的关系可以并行建模。
因此,注意力更像这个 block 的“信息交换中心”。
很多初学者会把 FFN 当成注意力之后随便接的一层 MLP,但这其实是个误解。FFN 的作用至少有三层:
标准 FFN 常写成:
FFN(x) = W2 * σ(W1 * x + b1) + b2
其中中间维度通常会先升高再压回去,例如从 d_model 扩到 4 * d_model。这不是随便设计的,而是给模型足够的表示扩张空间。
从某种意义上说:
没有残差连接,深层 Transformer 很难稳定训练。原因很简单:
残差连接允许每个子层学的是“增量修改”,而不是“从零重写”。这会带来两个重要收益:
这也是为什么残差不是一个小技巧,而是 Transformer 能堆得很深的重要条件。
LayerNorm 的作用,是让每个 token 的特征维度保持更稳定的尺度,减少训练过程中的数值波动。
在深层网络里,如果表示分布层层漂移,优化会非常困难。LayerNorm 相当于不断把表示拉回一个更可控的区间。
它的重要性可以从两个角度理解:
这也是为什么你看几乎所有现代大模型,都会在归一化位置上做大量精细设计。
这是 block 理解里非常关键的一点。
原始 Transformer 更接近:
x -> sublayer -> residual add -> LayerNorm
现代很多 LLM 更接近:
x -> LayerNorm -> sublayer -> residual add
为什么后来越来越多模型偏向 pre-norm?核心原因是它在深层训练中通常更稳。因为归一化先发生,进入子层的输入更容易处在健康数值范围内,梯度路径也更顺畅。
所以如果你看 LLaMA、GPT-NeoX 一类实现,看到和论文图不完全一样,不要慌,很多差异都来自这里。
从功能上说,一个 block 不是只干一件事,而是在做两类交替操作:
如果你把多层堆叠起来,可以这样理解整个网络:
虽然不同模型具体分工不完全相同,但“混合信息 -> 非线性加工 -> 再混合 -> 再加工”的节奏,正是 block 堆叠的本质。
如果你只看 block 内核,两者非常相似,但 decoder 需要额外解决“不能偷看未来 token”这个问题。
因此 decoder block 通常会在 self-attention 上加 causal mask,确保当前位置只能看见过去。若是 encoder-decoder 架构,还会额外加入 cross-attention:
现代通用 LLM 多为 decoder-only,因此很多人现在说“Transformer block”时,脑子里默认其实是 decoder block。
block 不是纯理论积木,它直接影响工程成本:
很多后续论文本质上都是在 block 级别做改造,例如:
所以理解 block,实际上是在理解后来大量论文的共同接口。
下面这段代码不是完整工业实现,但足够帮助你建立 block 结构感:
import torch
import torch.nn as nn
class TransformerBlock(nn.Module):
def __init__(self, d_model, ff_hidden):
super().__init__()
self.ln1 = nn.LayerNorm(d_model)
self.attn = nn.MultiheadAttention(d_model, num_heads=8, batch_first=True)
self.ln2 = nn.LayerNorm(d_model)
self.ffn = nn.Sequential(
nn.Linear(d_model, ff_hidden),
nn.GELU(),
nn.Linear(ff_hidden, d_model),
)
def forward(self, x):
attn_input = self.ln1(x)
attn_out, _ = self.attn(attn_input, attn_input, attn_input)
x = x + attn_out
ffn_input = self.ln2(x)
ffn_out = self.ffn(ffn_input)
x = x + ffn_out
return x
如果你能把这段代码和前面的结构解释一一对应起来,说明你已经真正开始“读懂 block”了。
没有 FFN、残差和归一化,Transformer 不会成为今天这样可扩展的架构。
FFN 往往占据大量参数和算力,是 block 中非常重要的表达容量来源。
真实模型常会改动归一化位置、激活函数、FFN 结构、注意力头设计等细节。
Transformer 的力量来自 block 可重复堆叠。单层理解只是起点,多层如何协同才是真正关键。
先看原理,再到模拟器里调参验证,学习效果更稳定。
从相近主题继续深入,建立连续学习链路。