批量规范化

介绍 BatchNorm 的原理、训练与推理两种行为,以及在卷积层与全连接层的差异。

知识课 · 约 30 分钟 · 更新于 2026-06-08

中间层"分布漂移"的问题

上节课我们看到,深层网络梯度消失/爆炸的根本原因之一是 层间连乘的乘数尺度不稳定 。 而"乘数"的尺度,又与 中间层数据的分布 直接相关—— 如果某一层的输入均值漂移到很大或方差变得极小, 激活值就会落入饱和区或被压扁,导致梯度大幅放大或收缩。

更糟糕的是:随着前面所有层的参数都在 持续更新 , 后面每一层的输入分布也跟着 持续变化 —— 每一层都需要不停适应前一层送来的新分布,训练自然变慢。 这个现象在文献中称为 "内部协变量偏移" (Internal Covariate Shift)。

为了直观地观察这种分布漂移,下面以一个深层网络中的 某一中间层 为例, 记录它的激活值在训练过程中的统计量变化——对比不使用 BN 与使用 BN 两种情况, 看这一层送往下一层的分布是否稳定。

该中间层激活值的均值与方差随训练步数的变化

实线 为未加 BN 的网络:均值持续向上漂移、方差不断扩大, 每一层送给下一层的分布始终在变; 虚线 为加入 BN 后的对照:均值稳定在 0 附近、方差稳定在 1 附近。 鼠标悬浮可查看某一步的具体数值。

既然问题出在"中间层数据的分布漂移", 一个直接的想法就是—— 主动把每层中间数据的分布拉回到标准化 。 这就是 Batch Normalization(批量规范化,简称 BN) 的出发点。

BatchNorm 的两步操作

BN 对每一层的输入做 两步 处理:先把分布 标准化 到均值 0、方差 1, 再在标准化的结果上做一次 可学习的缩放与平移 ,才得到这一层的输出。 第一步负责把分布拉稳,第二步决定这层最终要呈现什么分布。

第一步:规范化(Normalize)

把当前 mini-batch 内的数据变换为 均值 0、方差 1 :

  • :当前 batch 的均值;
  • :当前 batch 的方差;
  • :极小的常数(如 ),防止分母为 0。

第二步:可学习的线性变换(Scale & Shift)

第一步得到的 还只是中间结果。 BN 紧接着对它 逐元素 地缩放、平移,才得到这一层真正的输出 :

缩放与平移作用在 标准化后的 上,而不是原始的 ; 表示逐元素相乘。 、 是 与特征维(卷积层为通道数)同长度 的可学习向量, 每个特征 / 通道各有一对、独立作用,与权重 W 一起被反向传播更新。

三步分布变换:原始 → 规范化 → 缩放平移

拖动滑块调节 与 , 观察第三张直方图(γβ 变换后)的位置与宽度如何随之改变—— 它的均值约等于 、标准差约等于 。

训练 vs 推理:BN 行为不同

BN 是 少数训练时和推理时行为不同 的层。 理解这个差异对实际使用 BN 非常关键:

全连接层与卷积层中的 BN

BN 在全连接层和卷积层中"统计的对象"略有差异—— 它对应着两个 PyTorch 类: BatchNorm1d / BatchNorm2d 。

BN 在训练中的三个实际作用

实战:给 SimpleCNN 加 BN

在「CNN 实战:MNIST」一课的 SimpleCNN 中加入 BN, 采用一种 非常常见的搭配方式 :

改动很小:在两层卷积之后各加一个 nn.BatchNorm2d(out_channels) , 在 FC1 之后加一个 nn.BatchNorm1d(128) 。

有 BN vs 无 BN:训练曲线对比

训练损失(train loss)

测试精度(test accuracy)

加入 BN 后收敛明显更快:BN 版本在第 2 个 epoch 的损失与精度, 已接近无 BN 版本第 4 个 epoch 的水平,最终精度也略高一些。 鼠标悬浮可查看每个 epoch 的数值。

使用注意事项

为下一章 Transformer 埋一个伏笔:LayerNorm

BatchNorm 的成功,启发了一整套 "归一化层" 家族。 虽然 BN 在视觉任务中至今仍是主流, 但 Transformer 时代主要使用的是另一种归一化——LayerNorm 。

  • BatchNorm :在 batch 维度上统计 μ/σ,跨样本共享统计量;
  • LayerNorm :在 单个样本 的特征维度上统计 μ/σ, 不依赖 batch 。

LayerNorm 解决了 BN 在 小 batch、变长序列、单样本推理 等场景的局限—— 而这些正是 Transformer 的典型应用场景。 两者思路相近、各有所长, 后续 Transformer 章节会再次涉及 。