2、BatchNorm原理剖析:数学公式、训练与推理阶段的差异、对batch size的依赖

好,咱们接着聊BatchNorm。

说实话,我刚入行那会儿,对BatchNorm的理解就停留在「加一层能加速训练」的层面。直到有一次,我在做一个文本分类项目,模型怎么都训不上去,loss像心电图一样上下乱跳。后来一查,原来是BatchNorm的参数没调对。嗯,从那以后,我才真正沉下心来把它的原理啃了一遍。

今天我就把这块掰开了讲。你跟着我走一遍,保证以后面试、调参都不慌。

2.1 数学公式:到底在做什么?

BatchNorm的核心思想,说白了就是:把每一层的输入拉回到一个稳定的分布上。你想想看,网络一层层往前传,每层的分布都在变,这叫Internal Covariate Shift。模型学起来当然费劲。

那BatchNorm怎么做的?看公式:

输入:小批量 B = {x₁, x₂, ..., xₘ}

第一步:计算均值
μ_B = (1/m) * Σ xᵢ

第二步:计算方差
σ²_B = (1/m) * Σ (xᵢ - μ_B)²

第三步:归一化
x̂ᵢ = (xᵢ - μ_B) / √(σ²_B + ε)

第四步:缩放和平移
yᵢ = γ * x̂ᵢ + β

这里有个细节我要强调一下:ε是一个很小的常数,比如1e-5。为什么加它?防止方差为0时除零错误。我在项目中遇到过,有次忘了加ε,结果训练到一半直接NaN了,排查了半天才发现是这个问题。

γ和β是可学习的参数。很多人以为归一化完就结束了,其实不是。你想想,如果模型觉得原始分布更好怎么办?所以BatchNorm给了模型一个「反悔」的机会——通过γ和β,它可以学习恢复到原来的分布,或者学到一个更合适的分布。

核心理解:BatchNorm不是死板地把数据拉到0均值1方差,而是让模型自己决定「拉到什么程度最合适」。γ和β就是干这个的。

2.2 训练与推理阶段的差异:这个坑我踩过

好,这里我要重点讲一下。很多人把训练和推理的BatchNorm混为一谈,结果模型上线后效果崩了。我当初就犯过这个错。

训练阶段:

训练时,我们用的是当前batch的均值和方差。每个batch都不一样,所以每次前向传播算出来的μ和σ²都在变。这其实是一种随机性,某种程度上起到了正则化的作用。

推理阶段:

推理时,你只有一个样本,或者batch size很小。这时候再用当前batch的统计量就不靠谱了。怎么办?

答案是:使用全局统计量

具体来说,训练过程中我们会维护两个滑动平均:

running_mean = momentum * running_mean + (1 - momentum) * μ_B
running_var = momentum * running_var + (1 - momentum) * σ²_B

推理时,直接用running_mean和running_var来归一化:

y = γ * (x - running_mean) / √(running_var + ε) + β

注意:推理时γ和β用的是训练好的参数,但均值和方差必须用全局的。我曾经见过有人把训练时的batch统计量直接用到推理上,结果模型输出完全不对。这个坑,你千万别踩。

还有一个细节:momentum的取值。我一般习惯设0.9或0.99。如果数据集很大,可以设大一点,让全局统计量更稳定。如果数据集小,设小一点,让统计量更新更快。

2.3 对batch size的依赖:为什么NLP里不好用?

这个问题,可以说是BatchNorm在NLP领域的「阿喀琉斯之踵」。

batch size越大,统计量越准。这是直觉。但NLP任务里,受限于显存,batch size往往很小。比如你做个BERT微调,batch size可能就8、16。这时候算出来的均值和方差,噪声很大。

我举个例子你就明白了:

batch size 均值估计误差 方差估计误差 训练稳定性
4
16 一般
64
256 很低 很低 很好

你看,batch size从4到256,稳定性天差地别。但NLP里,尤其是大模型,batch size能到64就算不错了。

那为什么CV里BatchNorm用得风生水起?

因为CV的batch size可以很大啊。一张图224x224x3,显存占用相对可控。你开个256的batch size,ResNet照样跑得动。但NLP里,一个句子长度128、256,加上embedding层,显存一下子就上去了。

我的经验:如果你做NLP任务,batch size小于32,我建议你慎重使用BatchNorm。要么换LayerNorm,要么用Ghost BatchNorm(把大batch拆成小group分别归一化)。我曾在序列标注任务上试过,batch size=8时,加了BatchNorm反而比不加还差。

还有一个问题:推理时的不一致性。训练时用batch统计量,推理时用全局统计量,这两者之间如果有差异,模型表现就会波动。batch size越小,这个差异越大。

说白了,BatchNorm的设计初衷是给CV大batch场景用的。拿到NLP小batch场景下,它就像一辆法拉利开进了泥泞小路——不是不能开,但真的不舒服。

2.4 小结:什么时候该用BatchNorm?

我个人的建议是这样的:

  • CV任务,batch size ≥ 32:放心用BatchNorm,效果很好
  • NLP任务,batch size ≥ 64:可以考虑用,但LayerNorm通常是更好的选择
  • NLP任务,batch size 很小:别折腾了,直接用LayerNorm
  • 序列长度变化很大的任务:BatchNorm对变长序列的处理很麻烦,LayerNorm天然支持

嗯,BatchNorm的原理就讲到这里。下一节我们聊聊LayerNorm,看看它为什么在NLP里更受欢迎。到时候我会拿Transformer里的具体实现来拆解,保证让你看得明明白白。