Layer Normalization
对每个样本最后若干特征维统计,不依赖其他 batch 样本。
学习目标
- 两个 token 各自标准化
- LayerNorm(D) 为什么适合变长序列?
- 说明:LayerNorm 不会自动屏蔽 padding,也不保证保存所有绝对幅度信息。
为什么需要这个概念
LayerNorm 对输入指定的尾部维度计算均值与有偏方差,再用可选的逐元素缩放和偏移变换。LayerNorm(D) 对每个位置的 D 个特征独立计算。
学习前需要掌握
背景与问题
序列长度和 batch 大小会变化,在线推理甚至只有一个样本。LayerNorm 不依赖同批样本的统计,因而常用于序列与 Transformer 隐藏表示。
概念定义
LayerNorm 对输入指定的尾部维度计算均值与有偏方差,再用可选的逐元素缩放和偏移变换。LayerNorm(D) 对每个位置的 D 个特征独立计算。
直观理解
每个 token 自己建立一把特征刻度尺。同批换了另一句话,当前 token 的标准化基准不会因此改变。
核心原理
若输入为 且 normalized_shape=D,统计轴只有最后一维,均值形状可理解为 。若指定 (L,D),则同时跨两个尾轴统计,语义和参数形状都改变,不能看名字相同就混用。
LayerNorm 默认有与 normalized_shape 一致的 affine 参数,因而标准化输出不保证训练后仍为零均值单位方差。默认不维护 BatchNorm 那样的运行均值与方差,所以单独的 LayerNorm 在 train 与 eval 下计算相同。
在残差块中,Pre-LN 和 Post-LN 的归一化位置不同,会影响梯度路径和训练配方。LayerNorm 并不会识别 padding,若随后对序列求平均,仍需用有效位置 mask 排除填充。
数学表达
核心公式
LayerNorm 对输入指定的尾部维度计算均值与有偏方差,再用可选的逐元素缩放和偏移变换。LayerNorm(D) 对每个位置的 D 个特征独立计算。
变量含义
D隐藏维μ_nl单 token 均值
计算步骤
- 1第一个 token 均值为 2,标准差近似 1。
- 2第二个 token 均值为 12,标准差近似 2。
- 3各自标准化后都近似为 (-1,1)。
代码对应位置
示例 1两个 token 各自标准化的最小验证:使用完整构造输入核对两个 token 各自标准化,输出只表示本例计算。
变量解释
| 变量 | 含义 |
|---|---|
D | 隐藏维 |
μ_nl | 单 token 均值 |
完整数值示例
两个 token 各自标准化
已知条件
- 输入 shape 为 (1,2,2)
- 两个 token 分别为 (1,3)、(10,14)
- 不使用 affine 参数
计算步骤
- 第一个 token 均值为 2,标准差近似 1。
- 第二个 token 均值为 12,标准差近似 2。
- 各自标准化后都近似为 (-1,1)。
计算结果
输出 shape 保持 (1,2,2),训练与评估模式的最大差为 0。
处理前后对比
- LayerNorm 不会自动屏蔽 padding,也不保证保存所有绝对幅度信息。
两个 token 各自标准化
虽然第二个 token 的绝对值大很多,LayerNorm 主要保留其内部相对结构。若任务必须使用原始幅度作为信号,需要考虑归一化位置和残差是否保留了相关信息。
如果写成 LayerNorm((2,2)),就会把两个 token 合在一起求统计,并且学习 2×2 的 affine 参数。这不是对原操作的等价写法。
计算与实现步骤
- 第一个 token 均值为 2,标准差近似 1。
- 第二个 token 均值为 12,标准差近似 2。
- 各自标准化后都近似为 (-1,1)。
代码实现
示例 1
两个 token 各自标准化的最小验证
example_01.py用途:使用完整构造输入核对两个 token 各自标准化,输出只表示本例计算。
import torch
from torch import nn
x = torch.tensor([[[1., 3.], [10., 14.]]])
ln = nn.LayerNorm(2, elementwise_affine=False)
ln.train()
a = ln(x)
ln.eval()
b = ln(x)
print([[round(v, 4) for v in row] for row in a[0].tolist()])
print("mode max diff:", (a - b).abs().max().item())代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
使用完整构造输入核对两个 token 各自标准化,输出只表示本例计算。
b- 偏置项。
Step 1 · 1–10 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
import torch
from torch import nn
x = torch.tensor([[[1., 3.], [10., 14.]]])
ln = nn.LayerNorm(2, elementwise_affine=False)
ln.train()
a = ln(x)
ln.eval()
b = ln(x)
print([[round(v, 4) for v in row] for row in a[0].tolist()])
print("mode max diff:", (a - b).abs().max().item())预期输出或运行结果
[[-1.0, 1.0], [-1.0, 1.0]] mode max diff: 0.0
常见错误 · 3 条
- NCHW 直接 LN(C)
- normalized_shape 错
- 以为无参数
实际应用
- Transformer 子层归一化
- 小批量序列隐藏状态处理
常见错误
- NCHW 直接 LN(C)
- normalized_shape 错
- 以为无参数
常见问题
LayerNorm(D) 为什么适合变长序列?
统计和参数只依赖末维 D,长度 L 可以变化;若把 L 也放进 normalized_shape,就失去这一性质。
这个示例能说明什么边界?
LayerNorm 不会自动屏蔽 padding,也不保证保存所有绝对幅度信息。
推荐学习资料
参考库不会生成虚假资源或无效外部链接。