想象你是一家高级餐厅后厨流水线的总厨:几十位厨师一字排开,第一位切菜,第二位调味,第三位过油……每道菜要经过七八位厨师的手。可问题是,新招的厨师手都不稳,第一位切出的土豆块今天 3 厘米见方、明天 5 厘米见方,第二位师傅刚练熟 3 厘米的刀法,食材规格又变了。整条流水线永远在“重新适应”,而不是在精进手艺——这就是深层网络训练的真实困境。2015 年提出的 Batch Normalization(BN,批归一化)就是在流水线的每个工位之间加装一台“标准切配台”:把每一批送来的食材统一成标准分量(均值 0、方差 1)再往下传,下游厨师不必再猜食材大小,只管按自己的菜谱发挥。更妙的是,切配台旁还配两瓶“秘制调料”——缩放参数 γ 和平移参数 β——允许每道菜保留自己的风味。本文就围绕这台“标准切配台”,带你逐层拆解 BN 的公式、训练与推理的差异、在 CNN 中的用法,以及它为什么能让训练又快又稳。

岗位关联

对 AI 从业者而言,BN 是训练深层网络的“基础设施”:理解它,你才能正确地设计网络、调学习率、排查训练不收敛的问题。它是深度学习工程师的必修课,也是面试中最高频的考点之一。

目录
  1. 可视化演示
  2. 内部协变量偏移
  3. 批内统计量
  4. 归一化与仿射变换
  5. 训练与推理
  6. CNN 通道归一化
  7. 梯度传播改善
  8. BN 实战技巧
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示BN归一化原理、mini-batch统计量计算过程、以及训练与推理模式差异,理解深度网络中分布稳定化的核心机制。

本节配有交互动效(进入视口后自动加载,约 3KB)。

BN归一化核心原理 对mini-batch数据按特征维度归一化 可学习参数γ和β恢复表达能力 y = γ·(x-μ)/√(σ²+ε) + β 稳定各层输入分布

内部协变量偏移

把这套深层网络想象成一个高档餐厅的后厨流水线:卷积层负责“切菜”,全连接层负责“摆盘”,每一层都是一位厨师,而前一位厨师做出来的半成品,就是后一位厨师的食材。问题在于,训练初期的厨师手法全在变:第一位师傅今天切 3 厘米见方,明天切 5 厘米见方,第二位师傅刚练熟 3 厘米的刀法,食材规格又变了。整条流水线永远在“重新适应”,而不是在精进手艺。

深度学习把这个现象叫内部协变量偏移(Internal Covariate Shift):第 $l$ 层看到的输入,是前面所有层参数共同作用的结果。只要前 $l-1$ 层参数一更新,第 $l$ 层面对的输入分布就换了一副面孔,层数越深,这种“连锁漂移”越剧烈。要描述相邻两层的关系,需要下面这个基本式:

病灶找到了:不是某位厨师水平差,而是整条线上“食材规格”一直在变。BN 的登场,就是在每个工位之间加装一台标准切配台。

xl=Wlhl−1+bl\displaystyle x_l = W_l h_{l-1} + b_l
这就像下游厨师每天面对不同规格的食材,刚摸清规律就换了新标准,手艺始终无法精进。
  1. 上一层输出$h_{l-1}$ 表示第 $l-1$ 层的输出,也就是第 $l$ 层的输入“食材”,其分布由前 $l-1$ 层的所有参数共同决定。
    hl−1h_{l-1}
  2. 权重与偏置$W_l$ 和 $b_l$ 是本层要学习的参数,每次梯度更新后它们的取值都会变化。
    Wl,blW_l,\quad b_l
  3. 线性组合$W_l h_{l-1} + b_l$ 把上游输出做一次线性变换,得到本层尚未经过激活的原始值 $x_l$。
    Wlhl−1+blW_l h_{l-1} + b_l
  4. 漂移根源$W_l$ 或 $h_{l-1}$ 的分布一旦改变,$x_l$ 的分布就会跟着漂移,下游每一层看到的样本范围持续变化,网络被迫不断“重新适应”。
    dist(xl) 随训练持续变动\text{dist}(x_l) \text{ 随训练持续变动}

批内统计量

要给食材定标准,切配台的第一件事是“现称现切”:把当前送来的这一批食材(一个 mini-batch)全部过秤,算出“平均分量”和“分量波动”。在 BN 中,这两个数就是批均值和批方差。注意,这里的“一批”不是所有训练数据,而是当前这一次前向传播拿到的 $m$ 个样本——切配台只根据手头这批原料来定标准。

先看批均值的公式:

有了均值,还要知道这批食材“均匀不均匀”,这由批方差刻画:

特别提醒:BN 不是把所有特征混在一起统计,而是按特征维度分别统计——就像切配台把番茄归番茄、土豆归土豆,各自称重、各自定标准。这样每个维度都能独立地被“切配”到统一规模。

μB=1m∑i=1mxi\displaystyle \mu_{\mathcal{B}} = \frac{1}{m}\sum_{i=1}^{m} x_i
均值像“标准分量”,方差像“大小不齐的程度”——两个数合在一起,就完整描述了这批食材的整体规格。
  1. 离差$x_i - \mu_{\mathcal{B}}$ 表示每个样本偏离批均值的程度,差分可正可负。
    xi−μBx_i - \mu_{\mathcal{B}}
  2. 平方$(x_i - \mu_{\mathcal{B}})^2$ 将偏离量平方,去掉正负号,只保留偏离幅度的大小。
    (xi−μB)2(x_i - \mu_{\mathcal{B}})^2
  3. 求平均$\frac{1}{m}\sum_{i=1}^{m}$ 对全体样本的平方偏离取平均,得到批方差 $\sigma_{\mathcal{B}}^2$,波动越大方差越大。
    1m∑i=1m(xi−μB)2\frac{1}{m}\sum_{i=1}^{m} (x_i - \mu_{\mathcal{B}})^2

归一化与仿射变换

有了批均值 $\mu_{\mathcal{B}}$ 和批方差 $\sigma_{\mathcal{B}}^2$,切配台正式开工:第一步,把每份食材按统一规格重新切配,也就是归一化;第二步,厨师再按自己的菜谱撒上“秘制调料”γ 和 β,让标准食材仍能做出自己的风味。这两步对应的正是 BN 最核心的两个公式。

首先是归一化:

然后是仿射变换:

归一化负责“统一规格”,γ 和 β 负责“保留风味”,两者缺一不可。如果只有归一化而没有仿射变换,每层都被钉死在零均值一成不变,网络的表达能力会被严重削弱——这就好比所有菜都做成同一个味道,再好的厨师也无用武之地。

x^i=xi−μBσB2+ϵ\displaystyle \hat{x}_i = \frac{x_i - \mu_{\mathcal{B}}}{\sqrt{\sigma_{\mathcal{B}}^2 + \epsilon}}
γ 决定“加量还是减量”,β 决定“调咸还是调淡”——两瓶调料让网络在标准食材上也保留完整的表达能力。
  1. 学习参数$\gamma$ 和 $\beta$ 是可学习的向量参数,和网络权重一起通过反向传播更新。
    γ, β\gamma,\ \beta
  2. 缩放$\gamma \hat{x}_i$ 把标准化的结果按比例缩放,相当于厨师决定这道菜的分量。
    γx^i\gamma \hat{x}_i
  3. 平移$+\beta$ 整体平移数值,相当于调整口味的基准线,让输出范围由网络自己决定。
    γx^i+β\gamma \hat{x}_i + \beta

训练与推理

切配台在训练时是“现称现切”:每次前向传播都用当前 batch 现算的均值和方差。可到了部署上线(推理)阶段,情况变了——线上可能一次只来一盘菜(batch=1),根本没有“一批”可以称。怎么办?答案是:老师傅的记忆。训练过程中,切配台一边工作一边积累长期经验,把“平均规格”记成两份账本:全局均值和全局方差。

这份账本用滑动平均(moving average)的方式维护:每处理一批数据,就把旧账本和新批次的统计量按比例融合。公式如下:

推理时,BN 直接使用这份“标准菜谱”里的全局均值和全局方差做归一化,输出与当前 batch 无关,稳定且高效。这套“训练现切、推理定型”的双轨机制是 BN 最容易踩坑的地方,很多新手忘记切换模型模式,导致推理结果异常。

μ^run←λμ^run+(1−λ)μB\displaystyle \hat{\mu}_{\text{run}} \leftarrow \lambda \hat{\mu}_{\text{run}} + (1-\lambda) \mu_{\mathcal{B}}
训练时“每批现切”,推理时“按菜谱标准切”——全局统计量是训练期间对大量批次统计量做滑动平均得到的历史经验。
  1. 历史经验值$\hat{\mu}_{\text{run}}$ 是训练至今累积的全局均值,相当于账本上记着的“标准分量”。
    μ^run\hat{\mu}_{\text{run}}
  2. 本批实测值$\mu_{\mathcal{B}}$ 是当前 batch 刚算出来的均值,代表今天这批食材的实际情况。
    μB\mu_{\mathcal{B}}
  3. 加权融合$\lambda$ 是动量系数(通常取 0.9 左右),$1-\lambda$ 是当前 batch 的贡献比重,新账本 = 旧账本 × 动量 + 本批实测 × 补充权重。
    λμ^run+(1−λ)μB\lambda \hat{\mu}_{\text{run}} + (1-\lambda) \mu_{\mathcal{B}}

CNN 通道归一化

在卷积网络里,切配台不能把整张特征图一锅烩,而要按“食材类别”分别处理:每个通道(channel)就是一类食材——有的通道负责检测边缘,有的负责响应纹理。CNN 中一个 batch 的特征图形状是 $(N, C, H, W)$(样本数、通道数、高、宽)。BN 的做法是:对每个通道 $c$,把批内所有样本、所有空间位置的像素值收集在一起,算该通道的均值 $\mu_c$ 和方差 $\sigma_c^2$,然后对该通道的每个位置做归一化。

每个通道还各配一套“秘制调料” $\gamma_c$、$\beta_c$。公式写出来是这样:

这种“分门别类”的切配方式,让 CNN 的每一层都能在稳定的像素强度范围内工作,同时保留不同通道的信息分工。正因为 BN 依赖批统计量,CNN 训练时 batch size 不能太小,否则每个通道的均值方差都会失真。

yc=γcxc−μcσc2+ϵ+βc\displaystyle y_{c} = \gamma_{c}\frac{x_{c} - \mu_{c}}{\sqrt{\sigma_{c}^{2} + \epsilon}} + \beta_{c}
在 CNN 中,BN 是按通道做的“分类切配”:番茄按番茄的标准、土豆按土豆的标准,整张特征图不会被混在一起称重。
  1. 通道标记$c$ 表示第 $c$ 个特征通道,类比为一类食材,取值范围 $1$ 到 $C$。
    c∈{1,2,…,C}c \in \{1, 2, \dots, C\}
  2. 通道内统计$\mu_c$ 和 $\sigma_c^2$ 在第 $c$ 个通道覆盖的所有样本与所有空间位置上计算,即跨 $N \times H \times W$ 个数值。
    μc, σc2\mu_c,\ \sigma_c^2
  3. 通道级仿射$\gamma_c$ 和 $\beta_c$ 每个通道一套,切配后按通道分别微调,保留各通道的独特响应。
    γcx^c+βc\gamma_c \hat{x}_c + \beta_c

梯度传播改善

BN 为什么能让训练变快?因为切配台让每层看到的数据分布稳定了,梯度也跟着“稳”了。可以把梯度想象成流水线上传递的“进度暗号”:如果暗号忽大忽小,下游厨师总是瞎忙;如果暗号稳定清晰,整条线的配合就顺畅。深度学习里,梯度靠链式法则从后向前传播,中间的激活值一旦落入饱和区,暗号就传不过去了。

没有 BN 时,输入数值一大,经过 Sigmoid 等激活函数时就容易进入两端饱和区,梯度趋近于 0,参数几乎停更;有 BN 后,输入被拉回 0 附近,激活值大概率落在梯度较大的区域,反向传播的信号可以顺畅地传回每一层。从公式上看,BN 对输入 $x_i$ 的偏导有一个直接的尺度因子:

梯度尺度稳定了,学习率就能调大,训练就像给流水线工人“打了鸡血”但又不会乱套——这正是 BN 能显著加速收敛的原因。此外,batch 统计量的随机波动还给训练注入了一点轻微的正则化效应,让模型泛化能力略有提升。

∂yi∂xi=γσB2+ϵ\displaystyle \frac{\partial y_i}{\partial x_i} = \frac{\gamma}{\sqrt{\sigma_{\mathcal{B}}^2 + \epsilon}}
这相当于给梯度装了一个“稳压器”:无论输入幅值多大,梯度都被固定在一个可控的尺度上,不再爆炸或消失。
  1. 链式起点$\frac{\partial y_i}{\partial x_i}$ 是反向传播时输出 $y_i$ 对输入 $x_i$ 的偏导,是梯度继续向前传的第一站。
    ∂yi∂xi\frac{\partial y_i}{\partial x_i}
  2. 尺度因子$\frac{\gamma}{\sqrt{\sigma_{\mathcal{B}}^2 + \epsilon}}$ 把梯度幅度除以标准差,再乘上可学习的 $\gamma$,相当于给梯度定了一个“标准量程”。
    1σB2+ϵ\frac{1}{\sqrt{\sigma_{\mathcal{B}}^2 + \epsilon}}
  3. 稳定收益分子分母都被标准化后,梯度量级保持在 $O(1)$ 附近,训练可以使用更大的学习率而不担心数值发散。
    梯度量级∼O(1)\text{梯度量级} \sim O(1)

BN 实战技巧

有了这台切配台,还得会用。实战中第一个问题是“放在哪”:BN 通常放在卷积层/全连接层之后、激活函数之前,也就是先做 $BN(Wx+b)$,再接 ReLU。为什么?因为 ReLU 会把负值直接截成 0,如果把 BN 放后面,统计出来的分布已经被截断,不再对称,切配效果会打折扣。原论文推荐的正是“先 BN 后激活”,主流框架的 BN 层也默认这样使用。

第二个问题是 batch size 怎么选。BN 的统计量来自当前 batch,batch 越小,均值方差估计越不准,相当于往每一层都注入大量噪声。工程上一般要求 batch size 不小于 16,再用 BN 才有稳定收益。第三个问题是训练和推理模式的切换:训练时用批统计量,验证/推理时用全局滑动平均统计量,PyTorch 的 model.train() / model.eval() 正是为这个切换准备的。

最后介绍一个实用的部署优化:推理参数折叠。推理时 BN 使用固定的全局统计量,对每个输入来说只是一个固定的线性变换,因此可以把 γ、β 连同全局均值、方差一起,折进前一个卷积层或全连接层的权重里:

到这里,这台“标准切配台”的原理与用法就全部讲完了:它把漂移的食材统一成标准分量,用 γ、β 保留风味,训练时现称现切、推理时按菜谱定型,在 CNN 里按通道分类处理,还顺手稳住了梯度、支持更大的学习率。

y=γσrun2+ϵx+(β−γ μrunσrun2+ϵ)\displaystyle y = \frac{\gamma}{\sqrt{\sigma_{\text{run}}^2 + \epsilon}} x + \left(\beta - \frac{\gamma\, \mu_{\text{run}}}{\sqrt{\sigma_{\text{run}}^2 + \epsilon}}\right)
切配台磨合成熟后,标准分量成了常量,直接写进菜谱,连称重都省了——推理时 BN 不再需要逐层统计,计算量明显下降。
  1. 展开仿射把仿射公式 $y = \gamma \hat{x} + \beta$ 与归一化公式 $\hat{x} = (x-\mu)/\sqrt{\sigma^2+\epsilon}$ 合并成一个式子。
    y=γx−μσ2+ϵ+βy = \gamma\frac{x-\mu}{\sqrt{\sigma^2+\epsilon}} + \beta
  2. 合并斜率$\frac{\gamma}{\sqrt{\sigma^2+\epsilon}}$ 成为新的线性系数 $A$,相当于把“切配比例”固定进权重。
    A=γσ2+ϵA = \frac{\gamma}{\sqrt{\sigma^2+\epsilon}}
  3. 合并截距$\beta - \frac{\gamma\mu}{\sqrt{\sigma^2+\epsilon}}$ 成为新的偏置 $B$,把平移量固定下来。
    B=β−γμσ2+ϵB = \beta - \frac{\gamma\mu}{\sqrt{\sigma^2+\epsilon}}
  4. 折叠结果$y = A x + B$,推理时 BN 层退化为一个纯线性运算,可以直接融入前一层。
    y=Ax+By = A x + B

AI 应用场景

CNN 图像分类训练加速

阶段:模型训练与优化

解决的问题:训练深层 ResNet、VGG 时,传统方法动辄遇到梯度消失或爆炸,必须小心翼翼地做参数初始化和学习率调度;BN 稳定每层输入分布后,梯度尺度被“稳压”,可以直接用更大的学习率,收敛速度快数倍。

具体案例:在 ImageNet 上训练 ResNet-50 时,卷积层后紧跟 BN 层是标配做法;在分布式训练中,每个 GPU 上的 batch 统计量让梯度更新更平稳,模型在同样的 epoch 数内精度更高,很多开源训练框架的默认配置就是“卷积 + BN + ReLU”。

推荐系统 CTR 预估模型的稳定训练

阶段:特征工程与训练保障

解决的问题:CTR 模型的稀疏特征经过 embedding 后,数值尺度波动大,MLP 深层部分训练震荡;传统做法要靠精细的特征缩放和很小的学习率。BN 在隐藏层之间做归一化,让每一层的输入都保持稳定,模型更容易收敛。

具体案例:某广告推荐团队在点击率预估模型的 3 层 MLP 之间插入 BN 层后,训练 loss 曲线明显变平滑,相同迭代次数下 AUC 提升约 0.3%,线上推理时再通过参数折叠把 BN 并入前一层,几乎不增加耗时。

GAN 生成对抗训练

阶段:模型训练与调优

解决的问题:GAN 训练以不稳定著称,生成器和判别器互为“上游厨师”:一方的参数更新总在改变另一方的输入分布,双方很难达到平衡。BN 分别稳定两个网络的层输入,是 DCGAN、StyleGAN 等经典生成模型的标准组件。

具体案例:训练人脸生成模型时,在判别器卷积层后加 BN,并在生成器反卷积层后加 BN,显著减少了训练早期的模式崩塌,让生成图像的质量随迭代稳定上升。

Python 演示

python56 行
import numpy as np  def batch_norm_forward(x, gamma, beta, eps=1e-5):    mu = x.mean(axis=0, keepdims=True)    var = x.var(axis=0, keepdims=True)    x_hat = (x - mu) / np.sqrt(var + eps)    return gamma * x_hat + beta  class BatchNorm:    def __init__(self, dim, momentum=0.9, eps=1e-5):        self.gamma = np.ones(dim)        self.beta = np.zeros(dim)        self.momentum = momentum        self.eps = eps        self.running_mu = np.zeros(dim)        self.running_var = np.ones(dim)     def __call__(self, x, training=True):        if training:            mu = x.mean(axis=0, keepdims=True)            var = x.var(axis=0, keepdims=True)            self.running_mu = (self.momentum * self.running_mu                               + (1 - self.momentum) * mu.ravel())            self.running_var = (self.momentum * self.running_var                                + (1 - self.momentum) * var.ravel())            x_hat = (x - mu) / np.sqrt(var + self.eps)        else:            x_hat = (x - self.running_mu) / np.sqrt(self.running_var + self.eps)        return self.gamma * x_hat + self.beta  def main():    np.random.seed(42)    dim = 4    bn = BatchNorm(dim)     print("第 1 批输入:上游尺度偏大")    x1 = np.random.randn(16, dim) * 5 + 10    y1 = bn(x1, training=True)    print("  原始均值 %.2f -> BN 后均值 %.3f" % (x1.mean(), y1.mean()))     print("第 2 批输入:上游尺度偏小")    x2 = np.random.randn(16, dim) * 0.5 - 3    y2 = bn(x2, training=True)    print("  原始均值 %.2f -> BN 后均值 %.3f" % (x2.mean(), y2.mean()))     print("推理模式:使用全局滑动平均统计量")    x3 = np.random.randn(8, dim) * 2 + 1    y3 = bn(x3, training=False)    print("  输出均值 %.3f,输出标准差 %.3f" % (y3.mean(), y3.std()))  if __name__ == "__main__":    main()
目的:用 NumPy 从零实现 BN 的四个核心公式,演示训练时“现称现切”、推理时“按标准菜谱”两种统计方式的差异。
  1. mu = x.mean(axis=0, keepdims=True)按特征维度(列)计算本批均值,“现称”本批食材的平均分量。
  2. var = x.var(axis=0, keepdims=True)按特征维度计算本批方差,衡量本批食材的整齐程度。
  3. x_hat = (x - mu) / np.sqrt(var + eps)执行归一化:中心化后除以标准差,eps 防止方差为 0。
  4. return gamma * x_hat + beta仿射变换:用可学习参数 γ、β 恢复网络的表达能力。
  5. self.running_mu = (self.momentum * self.running_mu滑动平均更新全局均值,把本批经验“记入账本”。
  6. x_hat = (x - self.running_mu) / np.sqrt(self.running_var + self.eps)推理路径使用全局统计量,输出与当前 batch 无关。
  7. if __name__ == "__main__":可执行入口,运行后可直接观察两种模式下输出的稳定性差异。

常见误区

误区“很多教程画网络图时把 BN 画在 ReLU 后面,我也照着放,效果好像也没差多少,是不是放前放后都一样?”

正解原始论文明确提出 BN 应放在线性变换之后、激活函数之前,即 $BN(Wx+b)$ 再接 ReLU。原因是 ReLU 会把负值截断,若先激活再 BN,统计出来的分布已被截断、不再对称,“切配”效果会打折。主流框架(PyTorch、TensorFlow)的 BN 层也默认按“先 BN 后激活”的语义使用。

为何常见:部分早期教程习惯于把“卷积 → ReLU → BN”画在一行,视觉上更顺,且浅层网络中两者差异不大,容易让人误以为顺序无关紧要。

误区“推理时我把一批数据一起送进模型,BN 当然用这批数据的均值和方差,这样不是更贴合实际吗?”

正解BN 在推理阶段必须切换到训练期间保存的全局滑动平均统计量,而不能用当前 batch 的统计量。原因有二:一是推理输出不应依赖“和谁一批”这种偶然因素;二是线上推理往往 batch=1,此时方差为 0,直接除零或产生极端结果。PyTorch 中 model.eval() 会自动完成这个切换。

为何常见:训练和推理用的同一套前向代码,差异藏在框架内部,新手没有切换 eval() 模式时,模型表现时好时坏,很难定位到 BN 头上。

误区“为了省显存,我把 batch 从 64 减到 4。反正有 BN 在,分布都被归一化了,训练应该差不多吧?”

正解BN 的统计量来自当前 batch,batch 越小,均值方差的估计噪声越大,相当于在每一层注入大量随机扰动;极端时 batch=1 甚至无法计算方差。工程经验上要保证 batch size 足够大(通常 ≥16),BN 才能发挥“稳定切配”的作用。

为何常见:显存不够时,最直接的念头就是减小 batch,而 BN 的“标准化”名头容易让人误以为它不依赖 batch 大小,忽略了统计量本身需要足够样本才能准确。

误区“BN 把每层输入都拉到零均值一方差,那参数初始化随便设,反正会被它救回来,dropout 也不用加了。”

正解BN 只是降低了对初始化的敏感度,并不能完全替代合理的初始化;例如全零权重会让所有样本输出相同,BN 统计量也失去意义。此外 BN 的“轻微正则化”来自 batch 统计量的随机波动,幅度有限,不能无条件替代 dropout,在数据增强充分的大模型上更应保留必要的正则化手段。

为何常见:BN 在各类博客中被宣传得过于万能,仿佛“加了 BN 一切搞定”,忽略了它只是稳定分布的工具,而非包治百病的神药。

面试题

Q1. 关于 Batch Normalization 对层输入做的核心运算,下列说法正确的是?

单选题 · easy

  • A.对整批数据做白化去相关
  • B.按批求均值方差并标准化← 正确答案
  • C.对每个样本单独做归一化
  • D.把输入整体缩放到 0 到 1

答案:B。BN 的核心是先算 mini-batch 的均值和方差,再对每个样本做标准化 $(x-\mu)/\sqrt{\sigma^2+\epsilon}$。白化还要做去相关和旋转,BN 并不涉及;BN 依赖批统计量,不是对单样本独立操作;缩放到 [0,1] 是 min-max 归一化,也不是 BN。

Q2. BN 中可学习参数 γ 和 β 的主要作用是?

单选题 · easy

  • A.决定均值与方差的大小
  • B.让标准化作用彻底失效
  • C.恢复网络的表达能力← 正确答案
  • D.替代全局统计量

答案:C。γ 和 β 对标准化结果做仿射变换 $y=\gamma\hat{x}+\beta$,让网络在“标准食材”上仍能保留任意缩放和平移,即保持完整的表达力。均值和方差来自数据统计而非 γβ,γβ 也不能让标准化失效,更不能替代统计量。

Q3. 推理阶段 BN 层应使用什么统计量?

单选题 · easy

  • A.当前 batch 的均值方差
  • B.训练期滑动平均全局统计量← 正确答案
  • C.随机初始化的均值方差
  • D.推理样本自身最大值

答案:B。推理时 BN 使用训练期间用滑动平均维护的全局统计量,输出稳定且与当前 batch 无关;如果还用当前 batch 的统计量,输出会随“和谁一批”波动,batch=1 时方差甚至为 0。

Q4. 在典型 CNN 结构中,BN 层通常放置在?

单选题 · mid

  • A.在卷积层之前单独使用
  • B.卷积之后激活之前← 正确答案
  • C.放在池化层之前
  • D.放在 Dropout 之后

答案:B。原论文和主流框架都习惯把 BN 放在线性变换(卷积或全连接)之后、激活函数之前,先标准化再非线性;放在卷积之前、池化前等属于特殊设计,不是常规用法。

Q5. 关于训练时 BN 的统计量与作用,下列说法正确的是?

多选题 · mid

  • A.对批内每个特征维度分别统计← 正确答案
  • B.训练时直接使用全局统计量
  • C.能支撑更大的学习率← 正确答案
  • D.统计量与批大小无关

答案:AC。BN 按特征(通道)维度分别计算 μ、σ²,训练阶段用的是当前 batch 的统计量,因此 batch 越小估计噪声越大。分布稳定后梯度尺度稳定,网络便能承受更大的学习率。

Q6. BN 在 CNN 中对特征图归一化时,统计范围是什么?

单选题 · mid

  • A.对单张图的所有通道混合
  • B.单个通道内全部位置和样本← 正确答案
  • C.整个 batch 所有通道混在一起
  • D.每个像素的局部邻域窗口

答案:B。CNN 中 BN 对每个通道,跨 batch 样本和空间位置做统计,即收集 $N \times H \times W$ 个数值求 μ 和 σ²;不是按图混通道,也不是局部邻域窗口统计(那是 Layer/Instance Normalization 或局部响应归一化的做法)。

Q7. “内部协变量偏移”的含义包括?

多选题 · mid

  • A.训练数据标注存在系统性噪声
  • B.上游参数更新导致层输入分布变化← 正确答案
  • C.训练中每层输入分布持续漂移← 正确答案
  • D.测试集与训练集分布不一致

答案:BC。内部协变量偏移特指训练过程中,因上游层参数更新而导致的下游层输入分布变化。它与标注噪声、测试集和训练集的分布差异(那叫数据集偏移)无关,是深层网络特有的“连锁漂移”现象。

Q8. 使用很小的 batch(如 batch=2)训练时 BN 效果会变差,最主要原因是?

单选题 · hard

  • A.均值方差估计噪声过大← 正确答案
  • B.γ 和 β 无法反向传播
  • C.滑动平均不再更新
  • D.归一化变成恒等映射

答案:A。batch 太小,样本不足以代表真实分布,μ 和 σ² 的估计充满随机波动,相当于在每一层注入大噪声。γβ 仍能正常训练,滑动平均也在更新,归一化更不会变成恒等映射。

Q9. BN 能改善梯度传播的根本原因是?

单选题 · hard

  • A.显著增大网络的参数量
  • B.让激活值避开梯度饱和区← 正确答案
  • C.直接修改损失函数表达式
  • D.使得激活值强制为正数

答案:B。BN 把输入拉回 0 附近,激活值大概率落在梯度较大的线性/非饱和区域,反向传播的梯度信号不衰减。BN 并不增加参数量(γβ 只是原有量级的少量参数),也不改损失函数,更不强制激活值为正。

Q10. 关于推理阶段 BN 折叠(folding)优化,正确的是?

多选题 · extreme

  • A.BN 可合并为一次线性运算← 正确答案
  • B.折叠公式包含 γ、β 与全局统计量← 正确答案
  • C.折叠后推理计算量明显降低← 正确答案
  • D.折叠必须依赖当前 batch 统计量

答案:ABC。推理时用全局 μ、σ²,BN 可展开为 $y = (\gamma/\sqrt{\sigma^2+\epsilon})x + (\beta - \gamma\mu/\sqrt{\sigma^2+\epsilon})$,即一次线性运算,可折进前一层权重,从而减少推理计算量。折叠依赖的是全局统计量,与当前 batch 无关。