Batch Normalization
按通道跨 batch/空间统计并维护运行均值方差。
学习目标
- 两样本展示训练与推理方差差异
- BN 的 momentum 越大,历史保留越多吗?
- 说明:小批或非代表性批次可能让统计不稳;冻结 affine 不等于冻结运行状态。
为什么需要这个概念
BatchNorm 按通道标准化激活,训练时通常使用当前批统计,并更新 running_mean 和 running_var;推理时默认使用运行统计,再执行可学习的缩放与平移。
学习前需要掌握
背景与问题
BatchNorm 不仅有可训练参数,还有随训练更新的运行统计。若只冻结权重却忽略模式切换,微调或推理结果仍可能变化。
概念定义
BatchNorm 按通道标准化激活,训练时通常使用当前批统计,并更新 running_mean 和 running_var;推理时默认使用运行统计,再执行可学习的缩放与平移。
直观理解
训练时用这一批样本估计参照线,推理时用累计参照线。两条线可能不同,因此同一输入在两种模式下不一定相同。
核心原理
BatchNorm2d 接受 ,对每个通道跨 N、H、W 计算统计量,缩放和偏移各有 C 个参数。训练前向使用有偏方差估计;PyTorch 更新 running_var 时采用无偏估计,这使小构造批次的数值尤其值得区分。
momentum 控制运行统计的指数更新比例,与优化器动量含义不同。track_running_stats=False 时不会维护这组运行统计,评估也使用输入批统计,因此不能把“eval 总用固定均值”当成所有配置的规则。
requires_grad=False 只冻结 affine 参数,不阻止训练模式更新 buffer。做冻结骨干微调时,需要明确是否让 BatchNorm 继续适应新域;每次 model.train 后也要按配方重新设置这些层。
数学表达
核心公式
BatchNorm 按通道标准化激活,训练时通常使用当前批统计,并更新 running_mean 和 running_var;推理时默认使用运行统计,再执行可学习的缩放与平移。
变量含义
γ,β可学习缩放和平移running_mean评估使用的 buffer
计算步骤
- 1训练均值为 2,有偏方差为 1,输出近似 ±1。
- 2运行方差记录无偏估计 2。
- 3评估除以 sqrt(2),输出近似 ±0.7071。
代码对应位置
示例 1两样本展示训练与推理方差差异的最小验证:使用完整构造输入核对两样本展示训练与推理方差差异,输出只表示本例计算。
变量解释
| 变量 | 含义 |
|---|---|
γ,β | 可学习缩放和平移 |
running_mean | 评估使用的 buffer |
完整数值示例
两样本展示训练与推理方差差异
已知条件
- 单通道输入为 1、3
- affine=False,momentum=1
- 先训练前向,再对同一批评估前向
计算步骤
- 训练均值为 2,有偏方差为 1,输出近似 ±1。
- 运行方差记录无偏估计 2。
- 评估除以 sqrt(2),输出近似 ±0.7071。
计算结果
running_mean=2,running_var=2;相同输入在两种模式下数值不同。
处理前后对比
- 小批或非代表性批次可能让统计不稳;冻结 affine 不等于冻结运行状态。
两样本展示训练与推理方差差异
这个差异来自明确的统计约定,不是模型随机了。真实大批量时两种方差更接近,小批次则更明显;默认 momentum 也会让运行统计逐步混合,而不是完全替换。
如果评估结果随同批其他样本变化,应先查看配置是否禁用了 running stats,以及是否真的调用 eval。不要只重复加载 affine 权重。
计算与实现步骤
- 训练均值为 2,有偏方差为 1,输出近似 ±1。
- 运行方差记录无偏估计 2。
- 评估除以 sqrt(2),输出近似 ±0.7071。
代码实现
示例 1
两样本展示训练与推理方差差异的最小验证
example_01.py用途:使用完整构造输入核对两样本展示训练与推理方差差异,输出只表示本例计算。
import torch
from torch import nn
bn = nn.BatchNorm1d(1, affine=False, momentum=1.)
x = torch.tensor([[1.], [3.]])
bn.train()
a = bn(x)
bn.eval()
b = bn(x)
print("train:", [round(v, 4) for v in a.flatten().tolist()])
print(f"running mean={bn.running_mean.item():.1f} var={bn.running_var.item():.1f}")
print("eval:", [round(v, 4) for v in b.flatten().tolist()])代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
使用完整构造输入核对两样本展示训练与推理方差差异,输出只表示本例计算。
mean- 训练特征逐列均值。
b- 偏置项。
Step 1 · 1–11 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
import torch
from torch import nn
bn = nn.BatchNorm1d(1, affine=False, momentum=1.)
x = torch.tensor([[1.], [3.]])
bn.train()
a = bn(x)
bn.eval()
b = bn(x)
print("train:", [round(v, 4) for v in a.flatten().tolist()])
print(f"running mean={bn.running_mean.item():.1f} var={bn.running_var.item():.1f}")
print("eval:", [round(v, 4) for v in b.flatten().tolist()])代码与数学原理
减去训练均值并除以训练标准差,对应代码中的 mean/std 或 StandardScaler。
预期输出或运行结果
train: [-1.0, 1.0] running mean=2.0 var=2.0 eval: [-0.7071, 0.7071]
常见错误 · 5 条
- 不要在测试集上调用 fit 或 fit_transform;测试集只能复用训练参数。
- 验证忘 eval
- num_features 填 H
- 梯度累积当大 BN batch
- 只冻参数
实际应用
- CNN 训练与部署模式管理
- 冻结骨干网络时处理运行统计
常见错误
- 验证忘 eval
- num_features 填 H
- 梯度累积当大 BN batch
- 只冻参数
常见问题
BN 的 momentum 越大,历史保留越多吗?
在 PyTorch 的运行统计更新中,新统计的权重是 momentum,值越大越快跟随当前批;这与某些动量直觉相反。
这个示例能说明什么边界?
小批或非代表性批次可能让统计不稳;冻结 affine 不等于冻结运行状态。
推荐学习资料
参考库不会生成虚假资源或无效外部链接。