BatchNorm 的训练模式和推理模式

原视频:BatchNorm 的训练模式和推理模式:批统计、running mean/var 是怎么记账的,三个坑一个个数 UP 主:古希腊掌管代码的神 | 时长:0:59 | tag:经典八股 链接:https://www.bilibili.com/video/BV1nCJQ6eEgE

一句话结论

BatchNorm 训练时用当前 batch 的均值/方差做归一化,同时用滑动平均把统计量攒进 running mean/var;推理时不再看当前 batch,直接用攒好的 running 统计。同一张图单独预测和成批预测结果不同,基本都是这两种模式没分清。

面试答法

30 秒版:训练模式下,BN 对每个通道用当前 batch 的均值和方差归一化,并以动量滑动更新 running mean 和 running var;推理模式下,改用训练期攒下的 running 统计,所以单个样本的输出不依赖同批的其他样本。工程上三个要点:推理前记得切 eval();batch 太小时批统计噪声大、甚至不可靠;这也是 Transformer 改用 LayerNorm 的原因之一——LN 只在单个样本内部归一化,训练和推理行为天然一致。

展开版:见下方「核心原理」与「三个坑」;被追问实现细节时,补「易错点与常见追问」里的 running var 无偏修正与 momentum 约定。

核心原理

1. 训练时:用这一批的统计量

对某个特征(通道),取当前 batch 的均值 $\mu_B$ 和方差 $\sigma_B^2$,先标准化再做可学习的缩放平移:

$$\hat{x} = \frac{x - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}, \qquad y = \gamma\hat{x} + \beta$$

其中 $\gamma$、$\beta$ 是逐通道学出来的参数,训练和推理都一样地使用;$\epsilon$ 是防止除零的小常数。关键在于:$\mu_B$、$\sigma_B$ 是这一批样本一起算出来的,所以同一个样本的输出天然依赖它和谁分在一批——训练时这种抖动还有正则效果,推理时则会变成 bug。

BN 公式与归一化前后对比(视频截图,0:17)

2. 训练时一直在"记账":running 统计

推理时可能只有一个样本,没有"一批"可算。BN 的解法是训练时顺手记账:每一步把当前批统计按动量 $m$(PyTorch 默认 0.1)滑动平均进 running mean / running var:

$$\mu_{run} \leftarrow (1-m)\,\mu_{run} + m\,\mu_B$$

训练步数足够多后,running 统计就近似整个数据集的全局均值/方差。推理时冻结这本账,直接用它归一化,输出因此与同批样本无关、对单个样本确定。

running mean 随训练步数收敛(视频截图,0:32)

三个坑

  1. 忘了切 eval():train 模式下推理,同一个样本放进不同的 batch,输出会跟着"邻居"变。下图里同一个 $x=5$ 在三个 batch 中的 train 输出是 1.52 / -1.34 / -0.45,而 eval 模式恒为 1.00。
  2. Batch 太小:批统计本身噪声大,训练不稳、running 账也记不准;极端情况(如每通道只有 1 个值)时训练模式的方差无从定义,框架会直接报错。
  3. 由此引出 LayerNorm:LN 只在单个样本内部(特征维)算统计量,不维护 running 账本,训练/推理完全一致,也与 batch size 无关,更适合 Transformer 和小 batch 场景。

忘切 eval 的后果:同一输入、三个答案(视频截图,0:42)

易错点与常见追问

修订说明