BN究竟起了什么作用?一个闭门造车的分析
By 苏剑林 | 2019-10-11 | 133155位读者 |BN,也就是Batch Normalization,是当前深度学习模型(尤其是视觉相关模型)的一个相当重要的技巧,它能加速训练,甚至有一定的抗过拟合作用,还允许我们用更大的学习率,总的来说颇多好处(前提是你跑得起较大的batch size)。
那BN究竟是怎么起作用呢?早期的解释主要是基于概率分布的,大概意思是将每一层的输入分布都归一化到N(0,1)上,减少了所谓的Internal Covariate Shift,从而稳定乃至加速了训练。这种解释看上去没什么毛病,但细思之下其实有问题的:不管哪一层的输入都不可能严格满足正态分布,从而单纯地将均值方差标准化无法实现标准分布N(0,1);其次,就算能做到N(0,1),这种诠释也无法进一步解释其他归一化手段(如Instance Normalization、Layer Normalization)起作用的原因。
在去年的论文《How Does Batch Normalization Help Optimization?》里边,作者明确地提出了上述质疑,否定了原来的一些观点,并提出了自己关于BN的新理解:他们认为BN主要作用是使得整个损失函数的landscape更为平滑,从而使得我们可以更平稳地进行训练。
本博文主要也是分享这篇论文的结论,但论述方法是笔者“闭门造车”地构思的。窃认为原论文的论述过于晦涩了,尤其是数学部分太不好理解,所以本文试图尽可能直观地表达同样观点。
(注:阅读本文之前,请确保你已经清楚知道BN是什么,本文不再重复介绍BN的概念和流程。)
一些基础结论 #
在这部分内容中我们先给出一个核心的不等式,继而推导梯度下降,并得到一些关于模型训练的基本结论,为后面BN的分析铺垫。
核心不等式 #
假设函数f(θ)的梯度满足Lipschitz约束(L约束),即存在常数L使得下述恒成立
‖∇θf(θ+Δθ)−∇θf(θ)‖2≤L‖Δθ‖2
那么我们有如下不等式
f(θ+Δθ)≤f(θ)+⟨∇θf(θ),Δθ⟩+12L‖Δθ‖22
证明并不难,定义辅助函数f(θ+tΔθ),t∈[0,1],然后直接得到f(θ+Δθ)−f(θ)=∫10∂f(θ+tΔθ)∂tdt=∫10⟨∇θf(θ+tΔθ),Δθ⟩dt=⟨∇θf(θ),Δθ⟩+∫10⟨∇θf(θ+tΔθ)−∇θf(θ),Δθ⟩dt≤⟨∇θf(θ),Δθ⟩+∫10‖∇θf(θ+tΔθ)−∇θf(θ)‖2⋅‖Δθ‖2dt≤⟨∇θf(θ),Δθ⟩+∫10L‖Δθ‖22tdt=⟨∇θf(θ),Δθ⟩+12L‖Δθ‖22
梯度下降 #
假设f(θ)是损失函数,而我们的目标是最小化f(θ),那么这个不等式告诉我们很多信息。首先,既然是最小化,自然是希望每一步都在下降,即f(θ+Δθ)<f(θ),而12L‖Δθ‖22必然是非负的,所以要想下降的唯一选择就是⟨∇θf(θ),Δθ⟩<0,这样一个自然的选择就是
Δθ=−η∇θf(θ)
这里η>0是一个标量,即学习率。
可以发现,式(4)就是梯度下降的更新公式,所以这也就是关于梯度下降的一种推导了,而且这个推导过程所包含的信息量更为丰富,因为它是一个严格的不等式,所以它还可以告诉我们关于训练的一些结论。
Lipschitz约束 #
将梯度下降公式代入到不等式(2),我们得到
f(θ+Δθ)≤f(θ)+(12Lη2−η)‖∇θf(θ)‖22
注意到,保证损失函数下降的一个充分条件是12Lη2−η<0,为了做到这一点,要不就要η足够小,要不就要L足够小。但是η足够小意味着学习速度会相当慢,所以更理想的情况是L能足够小,降低了L就可以用更大的学习率了,能加快学习速度,这也是它的好处之一。
但L是f(θ)的内在属性,因此只能通过调整f本身来降低L。
BN是怎样炼成的 #
本节将会表明:以降低神经网络的梯度的L常数为目的,可以很自然地导出BN。也就是说,BN降低了神经网络的梯度的L常数,从而使得神经网络的学习更加容易,比如可以使用更大的学习率。而降低梯度的L常数,直观来看就是让损失函数没那么“跌宕起伏”,也就是使得landscape更光滑的意思了。
注:我们之前就讨论过L约束,之前我们讨论的是神经网络关于“输入”满足L约束,这导致了权重的谱正则和谱归一化(请参考《深度学习中的Lipschitz约束:泛化与生成模型》),本文则是要讨论神经网络(的梯度)关于“参数”满足L约束,这导致了对输入的各种归一化手段,而BN是其中最自然的一种。
梯度分析 #
以监督学习为例,假设神经网络表示为ˆy=h(x;θ),损失函数取l(y,ˆy),那么我们要做的事情是
θ=argminθE(x,y)∼p(x,y)[l(y,h(x;θ))]
也就是f(θ)=E(x,y)∼p(x,y)[l(y,h(x;θ))],所以
∇θf(θ)=E(x,y)∼p(x,y)[∇θl(y,h(x;θ))]=E(x,y)∼p(x,y)[∇hl(y,h(x;θ))∇θh(x;θ)]
顺便说明一下,本文的每个记号均没有加粗,但是根据实际情况不同它既有可能表示标量,也有可能表示向量。
非线性假设 #
显然,f(θ)是一个非线性函数,它的非线性来源有两个:
1、损失函数l(y,ˆy)一般是非线性的;
2、神经网络h(x;θ)中的激活函数是非线性的。
关于激活函数,当前主流的激活函数基本上都满足一个特性:导数的绝对值不超过某个常数。我们现在来考虑这个特性能否推广到损失函数中去,即(在整个训练过程中)损失函数的梯度∇hl(y,h(x;θ))是否会被局限在某个范围内?
看上去,这个假设通常都是不成立的,比如交叉熵是−logp,而它的导数是−1/p,显然不可能被约束在某个有限范围。但是,损失函数联通最后一层的激活函数一起考虑时,则通常是满足这个约束的。比如二分类是最后一层通常用sigmoid激活,这时候配合交叉熵就是
−logsigmoid(h(x;θ))=log(1+e−h(x;θ))
这时候它关于h的的梯度在-1到1之间。当然,确实存在一些情况是不成立的,比如回归问题通常用mse做损失函数,并且最后一层通常不加激活函数,这时候它的梯度是一个线性函数,不会局限在一个有限范围内。这种情况下,我们只能寄望于模型有良好的初始化以及良好的优化器,使得在整个训练过程中∇hl(y,h(x;θ))都比较稳定了。这个“寄望”看似比较强,但其实能训练成功的神经网络基本上都满足这个“寄望”。
柯西不等式 #
我们的目的是探讨∇θf(θ)满足L约束的程度,并且探讨降低这个L的方法。为此,我们先考虑最简单的单层神经网络(输入向量,输出标量)h(x;w,b)=g(⟨x,w⟩+b),这里的g是激活函数。这时候
E(x,y)∼p(x,y)[∇bf(w,b)]=E(x,y)∼p(x,y)[∂lw,b∂g˙g(⟨x,w⟩+b)]E(x,y)∼p(x,y)[∇wf(w,b)]=E(x,y)∼p(x,y)[∂lw,b∂g˙g(⟨x,w⟩+b)x]
基于我们的假设,∂lw,b∂g和˙g(⟨x,w⟩+b)都被限制在某个范围之内,所以可以看到偏置项b的梯度是很平稳的,它的更新也应当会是很平稳的。但是w的梯度不一样,它跟输入x直接相关。
关于w的梯度差,我们有
‖E(x,y)∼p(x,y)[∇wf(w+Δw,b)]−E(x,y)∼p(x,y)[∇wf(w,b)]‖2=‖E(x,y)∼p(x,y)[(∂lw+Δw,b∂g˙g(⟨x,w+Δw⟩+b)−∂lw,b∂g˙g(⟨x,w⟩+b))x]‖2
将圆括号部分记为λ(x,y;w,b,Δw),根据前面的讨论,它被约束在某个范围之内,这部分依然是平稳项,既然如此,我们不妨假设它天然满足L约束,即
‖λ(x,y;w,b,Δw)‖2=O(‖Δw‖2)
这时候我们只需要关心好额外的x。根据柯西不等式,我们有
‖E(x,y)∼p(x,y)[λ(x,y;w,b,Δw)x]‖2≤√E(x,y)∼p(x,y)[λ(x,y;w,b,Δw)2]×√|Ex∼p(x)[x⊗x]|1
这样一来,我们得到了与(当前层)参数无关的|Ex∼p(x)[x⊗x]|1,如果我们希望降低L常数,最直接的方法是降低这一项。
减均值除标准差 #
要注意,虽然我们很希望降低梯度的L常数,但这是有前提的——必须在不会明显降低原来神经网络拟合能力的前提下,否则只需要简单乘个0就可以让L降低到0了,但这并没有意义。
式(12)的结果告诉我们,想办法降低|Ex∼p(x)[x⊗x]|1是个直接的做法,这意味着我们要对输入x进行变换。然后根据刚才的“不降低拟合能力”的前提,最简单并且可能有效的方法就是平移变换了,即我们考虑x→x−μ,换言之,考虑适当的μ使得
|Ex∼p(x)[(x−μ)⊗(x−μ)]|1
最小化。这只不过是一个二次函数的最小值问题,不难解得最优的μ是
μ=Ex∼p(x)[x]
这正好是所有样本的均值。于是,我们得到:
结论1: 将输入减去所有样本的均值,能降低梯度的L常数,是一个有利于优化又不降低神经网络拟合能力的操作。
接着,我们考虑缩放变换,即x−μ→x−μσ,这里的σ是一个跟x大小一样的向量,而除法则是逐位相除。这导致
|Ex∼p(x)[(x−μ)⊗(x−μ)]|1→|Ex∼p(x)[(x−μ)⊗(x−μ)]σ⊗σ|1
σ是对L的一个最直接的缩放因子,但问题是缩放到哪里比较好?如果一味追求更小的L,那直接σ→∞就好了,但这样的神经网络已经完全没有拟合能力了;但如果σ太小导致L过大,那又不利于优化。所以我们需要一个标准。
以什么为标准好呢?再次回去看梯度的表达式(9),前面已经说了,偏置项的梯度不会被x明显地影响,所以它似乎会是一个靠谱的标准。如果是这样的话,那相当于将输入x的这一项权重直接缩放为1,那也就是说,Ex∼p(x)[(x−μ)⊗(x−μ)]σ⊗σ变成了一个全1向量,再换言之:
σ=√Ex∼p(x)[(x−μ)⊗(x−μ)]
这样一来,一个相对自然的选择是将σ取为输入的标准差。这时候,我们能感觉到除以标准差这一项,更像是一个自适应的学习率校正项,它一定程度上消除了不同层级的输入对参数优化的差异性,使得整个网络的优化更为“同步”,或者说使得神经网络的每一层更为“平权”,从而更充分地利用好了整个神经网络,减少了在某一层过拟合的可能性。当然,如果输入的量级过大时,除以标准差这一项也有助于降低梯度的L常数。
于是有结论:
结论2: 将输入(减去所有样本的均值后)除以所有样本的标准差,有类似自适应学习率的作用,使得每一层的更新更为同步,减少了在某一层过拟合的可能性,是一个提升神经网络性能的操作。
推导穷,BN现 #
前面的推导,虽然表明上仅以单层神经网络(输入向量,输出标量)为例子,但是结论已经有足够的代表性了,因为多层神经网络本质上也就是单层神经网络的复合而已(关于这个论点,可以参考笔者旧作《从Boosting学习到神经网络:看山是山?》)。
所以有了前面的两个结论,那么BN基本就可以落实了:训练的时候,每一层的输入都减去均值除以标准差即可,不过由于每个batch的只是整体的近似,而期望(14),(16)是全体样本的均值和标准差,所以BN避免不了的是batch size大点效果才好,这对算力提出了要求。此外,这个分析过程的一个结论是:BN应当放在全连接/卷积前面。
此外,我们还要维护一组变量,把训练过程中的均值方差存起来,供预测时使用,这就是BN中通过滑动平均来统计的均值方差变量了。至于BN的标准设计中,减均值除标准差后还补充上的β,γ项,我认为仅是锦上添花作用,不是最必要的,所以也没法多做解释了。
简单的总结 #
本文从优化角度分析了BN其作用的原理,所持的观点跟《How Does Batch Normalization Help Optimization?》基本一致,但是所用的数学论证和描述方式个人认为会更简单易懂写。最终的结论是减去均值那一项,有助于降低神经网络梯度的L常数,而除以标准差的那一项,更多的是起到类似自适应学习率的作用,使得每个参数的更新更加同步,而不至于对某一层、某个参数过拟合。
当然,上述诠释只是一些粗糙的引导,完整地解释BN是一件很难的事情,BN的作用更像是多种因素的复合结果,比如对于我们主流的激活函数来说,[−1,1]基本上都是非线性较强的区间,所以将输入弄成均值为0、方差为1,也能更充分地发挥激活函数的非线性能力,不至于过于浪费神经网络的拟合能力。
总之,神经网络的理论分析都是很艰难的事情,远不是笔者能胜任的,也就只能在这里写写博客,讲讲可有可无的故事来贻笑大方罢了~
转载到请包括本文地址:https://spaces.ac.cn/archives/6992
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (Oct. 11, 2019). 《BN究竟起了什么作用?一个闭门造车的分析 》[Blog post]. Retrieved from https://spaces.ac.cn/archives/6992
@online{kexuefm-6992,
title={BN究竟起了什么作用?一个闭门造车的分析},
author={苏剑林},
year={2019},
month={Oct},
url={\url{https://spaces.ac.cn/archives/6992}},
}
April 3rd, 2022
请问苏神|Ex∼p(x)[x⊗x]|1中的⊗表示的是向量外积还是张量积呢?
July 20th, 2022
stylegan第一版生成的人脸图中总是有个圆斑,后来第二版作者去掉了BN就好了.可见BN也有局限性.感觉有点像photoshop里的图像自动对比度处理,让图像的细节能看得更清晰,但也破坏了数据的先验分布信息.
March 26th, 2024
请问苏神,为什么要先考虑平移,再考虑缩放?如果单从结果的角度分析,直接考虑缩放,缩放因子为 均值,不也能将其变成等式(9)吗?
均值有可能为0,缩放因子怎么可以用均值?当然RMS是有可能的,对应(Batch) RMS Norm了
之所以先考虑平移,是因为平移对应加减,它对模型表达能力的影响最小~
July 11th, 2024
请问苏神,这里的推论“BN应当放在全连接/卷积前面”好像和大家普遍采用的不太一样?我理解BN必须放在激活函数之前,但是想不明白BN在全连接/卷积的前后有什么影响QAQ
参考: https://stackoverflow.com/questions/39691902/ordering-of-batch-normalization-and-dropout
不同的假设有不同的结论吧,当前Transformer中主流的Pre Norm就是把Norm放到Attention/MLP前面的。
事实上本文的结论,更准确应该是将BN加在输入之后,至于输入之后是什么,取决于我们怎么看待一个Block。本文的视角是Activation(Dense(x))这样一个运算视为一个Block,所以输入之后就是全连接之前;早期的ResNet-v2,是将Dense(Activation(x))视为一个Block,所以输入之后就是激活函数之前,同样可以借用本文的分析得出相近的结论。
July 29th, 2024
1,https://kexue.fm/archives/6051 对于“输入”满足L约束,需要对W进行谱约束
2,此文描述对于“梯度”满足L约束,需要对X进行BN归一化。请问这里是否也可以写成对X进行谱归一化?会不会更有效果?
在中间,是否也可以对X进行截断操作?
怎么截断法?
clipping:裁剪。不叫截断,我翻译错了
weight clipping
由 Wasserstein GAN 提出。在利用 gradient descent 进行参数更新后,再对所有参数进行裁剪操作:
if w < -threshold:
w = -threshold
elif w > threshold:
w = threshold
else:
w = identity(w)
或许在输入和输入变换后进行裁剪,或者在中间,或者后半段。如果输入不可以裁剪,就网络中间层或者靠近尾部层进行裁剪。因为尾部十分靠近loss func给的梯度,他们往往相对前面层较大(梯度消失往往说的是网络的前面层),而它们太大也会影响结果的输出。或许L2正则只用正则后面层的参数,前面层某些值较大根本没法有太大的影响到结果。我想到droupout也是只把后面的丢掉,它前面不丢掉;如果这样可以行,这样就把droupout为什么只丢掉后面层的原因,就给串起来了,说不定可以得到一些有用的结果。
clip输入的话会丢信息啊,你不能为normalize而normalize。
理论上可以,问题是更复杂了。