Transformer Block 完整拆解

把 LayerNorm、残差连接、多头注意力、FFN 和堆叠逻辑放到一个统一框架里,理解一个 block 为什么能成为现代大模型的基础积木。

难度

进阶

阅读时长

约 105 分钟

更新日期

2026/03/24

主题

Transformer / Transformer Block / LayerNorm / 基础原理

先修知识

Transformer 注意力机制基础矩阵与张量维度概念位置编码基础

学习目标

这篇教程的目标,是让你把一个 Transformer block 真正看成“可解释、可拆解、可实现”的积木,而不是一张结构图上的黑盒。读完后你应该能:

  1. 说清一个 Transformer block 里每个模块分别做什么。
  2. 理解残差连接和 LayerNorm 为什么对深层训练至关重要。
  3. 理解 FFN 为什么看起来简单,却占了大量参数和计算。
  4. 把单层 block、层间堆叠和 encoder / decoder 差异串成完整认知。

这篇文章和 Transformer 注意力机制入门 的关系是:前者讲“注意力怎么工作”,这篇讲“注意力在整个 block 里扮演什么角色”。

为什么要把 Transformer 拆到 block 级别来理解

很多人第一次看 Transformer,会记住一句话:

就是 Attention 加 FFN 再堆很多层。

这句话不算错,但太粗。真正决定 Transformer 能否稳定扩展的,不只是注意力本身,还有:

  • 残差路径是否顺畅
  • 归一化放在什么位置
  • 前馈层如何扩张表示
  • 多层堆叠后信息怎样逐步被重写

如果把 block 级别理解透了,你再看 GPT、BERT、LLaMA、MoE、FlashAttention 等工作时,就会很清楚:它们到底是在改哪个积木,而不是被一堆术语带着跑。

一个标准 Transformer block 长什么样

一个典型 block 可以抽象成两大段:

  1. 注意力子层
  2. 前馈网络子层

并且每一段都会配上:

  • 残差连接
  • LayerNorm

把它写得更接近流程图,就是:

  1. 输入 x
  2. 经过 LayerNorm
  3. 进入 Multi-Head Attention
  4. 与原输入做残差相加
  5. 再经过 LayerNorm
  6. 进入 FFN
  7. 再做一次残差相加

今天很多主流模型采用的是 pre-norm 版本,也就是先归一化再进子层。早期原始 Transformer 更接近 post-norm。这个差异虽然只是顺序变化,却会显著影响深层训练稳定性。

模块一:Multi-Head Self-Attention 负责信息路由

注意力子层的本质工作,是让当前每个 token 决定要从整段上下文里读取哪些信息。

你可以把它理解成:

  • block 的第一大功能不是“创造新知识”
  • 而是“重新组织上下文里的信息流”

在这一层里,每个位置都会生成 Q/K/V,然后通过注意力权重聚合其他位置的信息。多头机制让不同子空间里的关系可以并行建模。

因此,注意力更像这个 block 的“信息交换中心”。

模块二:FFN 为什么看起来普通却如此重要

很多初学者会把 FFN 当成注意力之后随便接的一层 MLP,但这其实是个误解。FFN 的作用至少有三层:

  1. 对每个 token 的表示做更强的非线性变换。
  2. 把注意力聚合回来的信息进一步加工。
  3. 提供大量参数容量,是 block 中参数最密集的部分之一。

标准 FFN 常写成:

FFN(x) = W2 * σ(W1 * x + b1) + b2

其中中间维度通常会先升高再压回去,例如从 d_model 扩到 4 * d_model。这不是随便设计的,而是给模型足够的表示扩张空间。

从某种意义上说:

  • 注意力负责“看哪里”
  • FFN 负责“看完之后怎么重新想一遍”

模块三:残差连接为什么是深层网络的生命线

没有残差连接,深层 Transformer 很难稳定训练。原因很简单:

  • 每层都在改写表示
  • 如果所有层都只能“完全推翻上一层结果”,梯度传播和信息保留都很困难

残差连接允许每个子层学的是“增量修改”,而不是“从零重写”。这会带来两个重要收益:

  1. 梯度更容易跨层传播。
  2. 如果某层暂时学不到有用变换,至少不会把已有表示彻底毁掉。

这也是为什么残差不是一个小技巧,而是 Transformer 能堆得很深的重要条件。

模块四:LayerNorm 为什么要放在每层里

LayerNorm 的作用,是让每个 token 的特征维度保持更稳定的尺度,减少训练过程中的数值波动。

在深层网络里,如果表示分布层层漂移,优化会非常困难。LayerNorm 相当于不断把表示拉回一个更可控的区间。

它的重要性可以从两个角度理解:

  • 优化角度:减少梯度爆炸 / 消失和分布漂移。
  • 工程角度:让更深网络和更大学习率更有机会稳定工作。

这也是为什么你看几乎所有现代大模型,都会在归一化位置上做大量精细设计。

Pre-Norm 和 Post-Norm 的区别

这是 block 理解里非常关键的一点。

Post-Norm

原始 Transformer 更接近:

x -> sublayer -> residual add -> LayerNorm

Pre-Norm

现代很多 LLM 更接近:

x -> LayerNorm -> sublayer -> residual add

为什么后来越来越多模型偏向 pre-norm?核心原因是它在深层训练中通常更稳。因为归一化先发生,进入子层的输入更容易处在健康数值范围内,梯度路径也更顺畅。

所以如果你看 LLaMA、GPT-NeoX 一类实现,看到和论文图不完全一样,不要慌,很多差异都来自这里。

一个 block 到底学到了什么

从功能上说,一个 block 不是只干一件事,而是在做两类交替操作:

  1. 横向信息混合:通过注意力把不同位置连接起来。
  2. 纵向特征变换:通过 FFN 把单个位置的表示变得更抽象、更适合下一层。

如果你把多层堆叠起来,可以这样理解整个网络:

  • 前面几层更像在建立局部模式和基础关系。
  • 中间层逐步形成更高阶依赖。
  • 后面层更接近任务相关的抽象决策。

虽然不同模型具体分工不完全相同,但“混合信息 -> 非线性加工 -> 再混合 -> 再加工”的节奏,正是 block 堆叠的本质。

Encoder block 和 Decoder block 有什么不同

如果你只看 block 内核,两者非常相似,但 decoder 需要额外解决“不能偷看未来 token”这个问题。

因此 decoder block 通常会在 self-attention 上加 causal mask,确保当前位置只能看见过去。若是 encoder-decoder 架构,还会额外加入 cross-attention:

  • encoder block:主要做双向上下文编码。
  • decoder block:主要做自回归生成,并可读取 encoder 输出。

现代通用 LLM 多为 decoder-only,因此很多人现在说“Transformer block”时,脑子里默认其实是 decoder block。

为什么 block 设计会影响训练成本和推理成本

block 不是纯理论积木,它直接影响工程成本:

  • 注意力部分决定长序列的显存和计算压力。
  • FFN 部分决定大量参数和 dense matmul 成本。
  • LayerNorm 与残差路径影响训练稳定性。
  • 头数、隐藏维度、FFN 扩展倍数影响整体吞吐。

很多后续论文本质上都是在 block 级别做改造,例如:

  • FlashAttention 优化注意力执行
  • MoE 把 FFN 变成专家路由
  • LoRA 常插在线性投影层
  • RoPE 改造注意力中的位置注入方式

所以理解 block,实际上是在理解后来大量论文的共同接口。

一个最小 PyTorch 风格伪代码

下面这段代码不是完整工业实现,但足够帮助你建立 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”了。

常见误区

1. 认为注意力就是全部

没有 FFN、残差和归一化,Transformer 不会成为今天这样可扩展的架构。

2. 认为 FFN 只是配角

FFN 往往占据大量参数和算力,是 block 中非常重要的表达容量来源。

3. 认为论文图上的 block 就是工业实现原样

真实模型常会改动归一化位置、激活函数、FFN 结构、注意力头设计等细节。

4. 只看单层,不看堆叠逻辑

Transformer 的力量来自 block 可重复堆叠。单层理解只是起点,多层如何协同才是真正关键。

练习与思考题

  1. 为什么残差连接可以被理解成“让子层学习增量更新”?
  2. 为什么现代 LLM 普遍更偏向 pre-norm,而不是原始 Transformer 风格的 post-norm?
  3. 如果去掉 FFN,只保留注意力,模型表达能力会受什么影响?
  4. 站在系统角度,block 的哪些部分最容易成为训练或推理瓶颈?

延伸阅读

配套模拟器

先看原理,再到模拟器里调参验证,学习效果更稳定。

相关阅读

从相近主题继续深入,建立连续学习链路。