从一条直线到大模型输出一个token(五):Transformer Block 全景与层归一化
建议先看:从一条直线到大模型输出一个token(四):位置编码 RoPE
上一篇末尾留了个悬念:「苹果」在"我吃了一个苹果"里是水果,在"苹果发布新手机"里是公司------同一个 token,含义要靠旁边的词决定。从这一篇开始,我们正式走进 Transformer 大厦,看词和词怎么"发生关系"。
从一条直线到大模型输出一个token(五):Transformer Block 全景与层归一化
- [从一条直线到大模型输出一个token(五):Transformer Block 全景与层归一化](#从一条直线到大模型输出一个token(五):Transformer Block 全景与层归一化)
-
- [1. 先看全景:一个 Block 长什么样](#1. 先看全景:一个 Block 长什么样)
-
- [1.1 Block 是大模型的"标准层"](#1.1 Block 是大模型的"标准层")
- [1.2 数据怎么流过 Block](#1.2 数据怎么流过 Block)
- [1.3 N 个 Block 堆叠成完整模型](#1.3 N 个 Block 堆叠成完整模型)
- [2. 层归一化 LayerNorm](#2. 层归一化 LayerNorm)
-
- [2.1 它解决什么问题:数值会爆炸](#2.1 它解决什么问题:数值会爆炸)
- [2.2 定义:一行的"体检"](#2.2 定义:一行的"体检")
- [2.3 贯穿案例:「西安」行的完整手算](#2.3 贯穿案例:「西安」行的完整手算)
- [2.4 完整矩阵:全部 6 行的 LayerNorm 结果](#2.4 完整矩阵:全部 6 行的 LayerNorm 结果)
- [3. LayerNorm 与 BatchNorm:两种归一化的对比](#3. LayerNorm 与 BatchNorm:两种归一化的对比)
- 小结
- 下一篇预告
1. 先看全景:一个 Block 长什么样
1.1 Block 是大模型的"标准层"
把大模型想成一栋楼,Block 就是标准楼层------整栋楼就是把同一个 Block 重复盖 N 遍。LLaMA-3-8B 盖了 32 层,Qwen2.5-7B 盖了 28 层,DeepSeek-V3 盖了 61 层。
一个 Block 内部只有两种核心部件,结构如图 5-1 所示:
- 多头自注意力:负责"词和词之间交换信息"(第 6、7 篇拆解)
- 前馈网络 FFN:负责"每个词自己做深度加工"(第 8 篇拆解)
外加两个配角:层归一化(LayerNorm,本篇主角)和残差连接(第 8 篇讲)。

图5-1 一个 Block 的完整流程(Pre-Norm 结构)
1.2 数据怎么流过 Block
矩阵进,矩阵出,形状始终是 6×4096。这六步是严格串行的------第②步注意力的输出是第③步归一化的输入,一步都不能跳、不能换序(图 5-1 的垂直流程就是这个意思):
- ① 层归一化:把矩阵的数值"拉回稳定区间"
- ② 多头自注意力:每个词环顾四周,吸收其他词的信息
- 加残差:注意力加工的结果,加上"未经加工的原始输入"(快车道直通)
- ③ 再层归一化:再拉一次
- ④ 前馈网络 FFN:每个词独立深度加工
- 再加残差:又一条快车道
注意图 5-1 中绕在主流程外侧的两条蓝色旁路------这是残差连接:不管中间的加工多复杂,原始信息永远保留一条高速通道。它的作用第 8 篇细讲。
1.3 N 个 Block 堆叠成完整模型
嵌入层 + RoPE 之后,矩阵依次流过 Block 1、Block 2......Block N,最后进输出层,如图 5-2 所示。

图5-2 N 个 Block 堆叠:矩阵 6×4096 从头流到尾,逐层加深语义
矩阵的形状从头到尾不变,变的是数字里编码的语义:浅层 Block 加工语法,中层加工语义,深层加工到任务级别(哪些层负责什么,第 9 篇展开)。
顺带一提结构细节:图 5-1 画的是 Pre-Norm(先归一化再进子层)------2017 年原始论文是 Post-Norm(先算子层再归一化),但深层模型训练时 Post-Norm 容易梯度不稳,现代主流大模型(LLaMA 系及之后)全部改用 Pre-Norm。这也是"原始论文 ≠ 现代实现"的一个典型例子。
这里展开说下"梯度不稳"。训练时,误差信号要从输出层往输入层逐层回传(反向传播),每经过一层,梯度都要乘一次该层的系数:
- Post-Norm :归一化在残差相加之后,等于主干上每一层都插了一个"除以 σ"的关卡。梯度回传时连乘几十次这种系数,要么越乘越小(梯度消失,浅层学不到东西),要么突然放大(梯度爆炸,训练发散)------32 层以上就很难训
- Pre-Norm :归一化挪到子层入口 ,主干变成干净的直通加法线( x + f ( L N ( x ) ) x + f(\mathrm{LN}(x)) x+f(LN(x)))。梯度沿主干回传时不受归一化干扰,多深都稳
一句话:Post-Norm 把关卡设在主干上,梯度每层都被"过安检";Pre-Norm 把关卡挪进支路,主干一路绿灯。这就是现代大模型全部选 Pre-Norm 的原因。
2. 层归一化 LayerNorm
2.1 它解决什么问题:数值会爆炸
Block 里的每一步都是矩阵运算,数字会一层层被放大。做个实验:设每层让数值扩大 1.5 倍再加一点偏移(真实模型里的放大系数远不止 1.5),不加归一化连续过 10 层,结果如图 5-3 所示。

图5-3 为什么必须归一化:无 LayerNorm 时数值指数爆炸
初始 1.0 的数值,10 层后变成 114.3------放大了 114 倍。真实模型 60 层起步、数值跨度更大,不控制的后果是:前向传播数值溢出(变成 ∞ \infty ∞ 或 N a N \mathrm{NaN} NaN,浮点数表示不了这么大的数),反向传播梯度爆炸,模型根本训不动。
LayerNorm 的作用就是每层入口都做一次"数值体检":不管进来的是 1 还是 114,都拉回均值 0、方差 1 的标准状态。红色爆炸曲线 vs 绿色稳定曲线,就是"有没有归一化"的天壤之别。
2.2 定义:一行的"体检"
LayerNorm 只对矩阵的每一行独立做:「今天」这一行的 4096 个数算一个均值一个方差,「西安」那一行自己算自己的,行与行互不干扰。
LayerNorm ( x ) = x − μ σ ⊙ γ + β \text{LayerNorm}(\mathbf{x}) = \frac{\mathbf{x} - \mu}{\sigma} \odot \boldsymbol{\gamma} + \boldsymbol{\beta} LayerNorm(x)=σx−μ⊙γ+β
- x \mathbf{x} x:某一行向量(一个 token 的 4096 维)
- μ \mu μ、 σ \sigma σ:这一行自己的均值和标准差
- γ \boldsymbol{\gamma} γ、 β \boldsymbol{\beta} β:可学习的缩放和平移参数(下面专门解释)
γ 和 β 到底是什么,掰开说:
-
它们是两个长度 4096 的数字列表 (和输入向量一样长),不是单个数。第 1 维有第 1 维的 γ 1 , β 1 \gamma_1, \beta_1 γ1,β1,第 2 维有第 2 维的 γ 2 , β 2 \gamma_2, \beta_2 γ2,β2......每个维度配自己的一对。一个 LayerNorm 层总共 2×4096 = 8192 个参数。
-
"可学习"的意思 :这 8192 个数字不是人定的,是训练出来的。训练开始前初始化为 γ \gamma γ 全 1、 β \beta β 全 0(等于"先不干预");训练过程中,每次预测错了,误差会反传回来告诉每个 γ i \gamma_i γi、 β i \beta_i βi 该调大还是调小------和嵌入表的 5.3 亿参数一样,靠梯度下降一点点学。
-
γ 管"拉多宽"(缩放) :乘法系数。 γ i > 1 \gamma_i > 1 γi>1 把第 i 维放大, < 1 < 1 <1 压缩。比如归一化后某维的值是 1.2,乘 γ = 1.5 \gamma=1.5 γ=1.5 变成 1.8(更突出),乘 γ = 0.5 \gamma=0.5 γ=0.5 变成 0.6(更淡化)。
-
β 管"往哪挪"(平移) :加法偏移。 β i > 0 \beta_i > 0 βi>0 整体右移, < 0 < 0 <0 左移。比如 1.2 加 β = 0.3 \beta=0.3 β=0.3 变成 1.5。
-
为什么需要它们 :第 3 步的"减 μ 除 σ"把每行都强制拉成均值 0、方差 1------数值是稳了,但也把维度之间的差异抹平了。可实际上不是每个维度同等重要:语义空间里"是不是地名"这个维度可能很关键,"语气强弱"可能次要。γ 和 β 就是给模型留的"后悔药":标准化之后,再让模型自己决定每个维度恢复多大的幅度、往哪个方向偏。
用「西安」行的真实数字走一遍( γ = 1.2 , 0.8 , 1.0 , 1.1 \gamma = 1.2, 0.8, 1.0, 1.1 γ=1.2,0.8,1.0,1.1, β = 0.1 , − 0.1 , 0.05 , 0.2 \beta = 0.1, -0.1, 0.05, 0.2 β=0.1,−0.1,0.05,0.2):
| 维度 | 归一化后(第 3 步结果) | γ(缩放) | β(平移) | 输出 |
|---|---|---|---|---|
| d₁ | -1.289 | ×1.2 | +0.1 | -1.446 |
| d₂ | 0.704 | ×0.8 | -0.1 | 0.463 |
| d₃ | 1.207 | ×1.0 | +0.05 | 1.257 |
| d₄ | -0.622 | ×1.1 | +0.2 | -0.485 |
表5-1 γ缩放与β平移的逐维效果(「西安」行)
d₁ 被放大并微移(-1.289 → -1.446),d₂ 被压缩(0.704 → 0.463)------同一行里不同维度受到的"待遇"各不相同,全由训练学出来的 γ、β 决定。
用代码描述(大模型实现细节,跳过不影响理解):
python
class LayerNorm:
def __init__(self, d_model=4096):
self.gamma = np.ones(d_model) # 初始化为 1
self.beta = np.zeros(d_model) # 初始化为 0
def forward(self, x): # x: (6, 4096)
mu = x.mean(axis=-1, keepdims=True) # 每行各自的均值
sigma = x.std(axis=-1, keepdims=True) # 每行各自的标准差
return (x - mu) / sigma * self.gamma + self.beta
2.3 贯穿案例:「西安」行的完整手算
拿 RoPE 后的「西安」向量 − 1.079 , 0.004 , 0.277 , − 0.717 -1.079,\\ 0.004,\\ 0.277,\\ -0.717 −1.079, 0.004, 0.277, −0.717,四步手算如图 5-4 所示。

图5-4 LayerNorm 手算:「西安」行的完整四步
第 1 步:取「西安」这一行 − 1.079 , 0.004 , 0.277 , − 0.717 -1.079,\\ 0.004,\\ 0.277,\\ -0.717 −1.079, 0.004, 0.277, −0.717。
第 2 步:算这行的均值和标准差:
μ = − 1.079 + 0.004 + 0.277 − 0.717 4 = − 0.379 \mu = \frac{-1.079 + 0.004 + 0.277 - 0.717}{4} = -0.379 μ=4−1.079+0.004+0.277−0.717=−0.379
σ 2 = ( − 0.700 ) 2 + ( 0.383 ) 2 + ( 0.656 ) 2 + ( − 0.338 ) 2 4 = 0.295 , σ = 0.543 \sigma^2 = \frac{(-0.700)^2 + (0.383)^2 + (0.656)^2 + (-0.338)^2}{4} = 0.295, \quad \sigma = 0.543 σ2=4(−0.700)2+(0.383)2+(0.656)2+(−0.338)2=0.295,σ=0.543
第 3 步:每个数减 μ、除以 σ:
x ^ 1 = − 1.079 − ( − 0.379 ) 0.543 = − 1.289 \hat{x}_1 = \frac{-1.079 - (-0.379)}{0.543} = -1.289 x^1=0.543−1.079−(−0.379)=−1.289
四个数依次得到 − 1.289 , 0.704 , 1.207 , − 0.622 -1.289,\\ 0.704,\\ 1.207,\\ -0.622 −1.289, 0.704, 1.207, −0.622------现在这行的均值是 0、方差是 1。
第 4 步:乘可学习的 γ \gamma γ、加可学习的 β \beta β( γ \gamma γ、 β \beta β 的完整解释见 2.2 节和表 5-1;本例取 γ = 1.2 , 0.8 , 1.0 , 1.1 \gamma = 1.2, 0.8, 1.0, 1.1 γ=1.2,0.8,1.0,1.1, β = 0.1 , − 0.1 , 0.05 , 0.2 \beta = 0.1, -0.1, 0.05, 0.2 β=0.1,−0.1,0.05,0.2):
1.2 × ( − 1.289 ) + 0.1 = − 1.446 1.2 \times (-1.289) + 0.1 = -1.446 1.2×(−1.289)+0.1=−1.446
最终输出 − 1.446 , 0.463 , 1.257 , − 0.485 -1.446,\\ 0.463,\\ 1.257,\\ -0.485 −1.446, 0.463, 1.257, −0.485------正是表 5-1 最右列。每个数都可手算验证。
2.4 完整矩阵:全部 6 行的 LayerNorm 结果
「西安」只是其中一行。整张矩阵每一行独立做一遍同样的四步(各算各的 μ 和 σ),结果如下(γ、β 取同一组演示值):
X L N = 0.565 − 1.356 1.226 0.208 − 1.446 0.463 1.257 − 0.485 − 1.218 0.026 1.599 − 0.469 0.740 − 1.353 − 0.038 1.433 0.133 − 0.539 − 1.025 1.955 1.265 0.170 0.417 − 1.643 \mathbf{X}_{LN} = \begin{bmatrix} 0.565 & -1.356 & 1.226 & 0.208 \\ -1.446 & 0.463 & 1.257 & -0.485 \\ -1.218 & 0.026 & 1.599 & -0.469 \\ 0.740 & -1.353 & -0.038 & 1.433 \\ 0.133 & -0.539 & -1.025 & 1.955 \\ 1.265 & 0.170 & 0.417 & -1.643 \end{bmatrix} XLN= 0.565−1.446−1.2180.7400.1331.265−1.3560.4630.026−1.353−0.5390.1701.2261.2571.599−0.038−1.0250.4170.208−0.485−0.4691.4331.955−1.643
各行自己的 μ 和 σ(体现"每行独立"):
| token | μ(这行的均值) | σ(这行的标准差) |
|---|---|---|
| 今天 | 0.045 | 0.710 |
| 西安 | -0.379 | 0.543 |
| 的 | 0.410 | 0.346 |
| 天气 | -0.147 | 0.715 |
| 怎么样 | -0.404 | 0.505 |
| ? | 0.128 | 0.692 |
表5-2 六行各自的均值与标准差(每行独立统计)
注意「西安」行的 − 1.446 , 0.463 , 1.257 , − 0.485 -1.446,\\ 0.463,\\ 1.257,\\ -0.485 −1.446, 0.463, 1.257, −0.485 正是上节手算的结果------第 2 行。这就是矩阵进 Block 前的第一次"数值体检":形状不变(还是 6×4096),但每一行都被拉回了各自的稳定区间。
3. LayerNorm 与 BatchNorm:两种归一化的对比
有机器学习基础的读者会问:归一化不是有现成的 BatchNorm 吗?图像领域用得好好的,为什么 NLP 要另起炉灶?
先把两者的定义摆出来。归一化的对象是一个"数据组",区别在于怎么分组:
- BatchNorm (批量归一化,2015 年提出,CV 领域标配):把同一个批次里、不同样本的同一个维度 分成一组。比如一个批次 32 张图片,把 32 张图的"红色通道第一行像素"拿在一起,算这 32 个数的均值方差来归一化------跨样本、按维度
- LayerNorm (层归一化,2016 年提出):把同一个样本自己的全部维度 分成一组。比如「西安」这个 token 的 4096 维,算它自己 4096 个数的均值方差------单样本、按层内全部维度
放进我们的矩阵里看(矩阵一行是一个 token、一列是一个维度),分组方式如图 5-5 所示。

图5-5 为什么 NLP 选 LayerNorm 而不是 BatchNorm
矩阵的每一行是一个 token,每一列是一个维度:
- BatchNorm 按列归一化:把「今天」「西安」「的」「天气」的第 1 维拿在一起比------跨 token 统计。问题来了:句子有长有短(这次 6 个 token,下次 600 个),每批的统计量乱跳;更致命的是生成场景是逐 token 出结果的,根本没有"一批句子"可比
- LayerNorm 按行归一化:每个 token 自己的 4096 维内部统计------句长变化不影响,来一个 token 归一化一个,完全稳定
表5-3 LayerNorm vs BatchNorm 对比
| 维度 | BatchNorm | LayerNorm |
|---|---|---|
| 归一化方向 | 按列(跨样本同一维度) | 按行(单个样本全部维度) |
| 依赖批大小 | 强依赖(batch 太小统计不稳) | 完全无关 |
| 变长序列 | 每次统计量不同,不稳 | 每行独立,天然适配 |
| 逐 token 生成 | 无法用(没有完整批次) | 完美支持 |
| 适用场景 | CV(固定尺寸图像) | NLP / 大模型(变长文本) |
一句话总结:文本是变长的、生成是逐个的,只有"按行独立"的 LayerNorm 能同时扛住这两点。
小结
这一篇,我们拿下了 Transformer 大厦的结构图和第一块砖:
- Block = 标准楼层:层归一化 → 多头自注意力 → 残差 → 层归一化 → FFN → 残差,Pre-Norm 是现代主流
- N 个 Block 堆叠,矩阵形状 6×4096 从头流到尾,语义逐层加深
- LayerNorm 解决数值爆炸:不归一化 10 层放大 114 倍,模型根本训不动
- LayerNorm 按行独立:减 μ 除 σ 再乘 γ 加 β,「西安」行四步手算全程可验证
- 不用 BatchNorm 的原因:文本变长 + 逐 token 生成,只有按行归一化扛得住
下一篇预告
Block 结构里,注意力排第一个位置------它是"词和词交换信息"的唯一通道,也是整个 Transformer 名字里 Attention 的由来。
下一篇拆注意力的第一步:Q、K、V 三剑客。「西安」想知道自己是"城市名",它得先发出一张"查询单"(Q:我要找地名相关信息);其他词得亮出自己的"名片"(K:我有什么信息)和"干货"(V:我的具体内容)。三张单子怎么从同一个矩阵变出来?这是第 6 篇的故事。
系列目录:
- 从一条直线到高维空间
- 分词与 token 表
- 隐藏层与嵌入
- 位置编码 RoPE
- Transformer Block 全景与层归一化(当前篇)
- QKV 三剑客
- 注意力权重与多头机制
- 残差连接与前馈网络
- 输出矩阵与多层堆叠
- 首 token 诞生与 KV-Cache
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。