昨天同事们突然讨论起了Batch Normalization的问题,大家从internal covariate shift的角度讨论了半天,结果突然间懵逼了,陷入了“道理我都懂,但是为什么会有效的?”的状态,这个问题不弄明白感觉彻夜难眠了。于是下班后赶紧又第N遍的研究了一下bn这个操作,得到了一些有解释性的答案,在这里记录和分享一下。
关于Internal Covariate Shift
相信很多关于bn的讲解应该都是来自于“internal covariat shift”的理论,那么到底什么是internal covariat shift,理论点讲:对于层间的信号,源空间和目标空间的条件概率一致,但边缘概率不同。通俗一点说,就是对于神经网络的每一层来讲,输入和输出经过了层内的计算,他们的分布发生了变化,但是特征所指示的样本标记是一样。(来自:知乎)并且这个变化会随着网络深度的增大而增大,这就是internal covariat shift 。这样不利于网络的收敛,于是batch normalization就是通过mini-batch来规范层的输入,固定每层的均值和方差。
Bach Normalization的操作
流程如下:
大概就是:
1. 对某个神经元求mini-batch的均值和方差
2. 用均值和方差对神经元在当前batch的分布做归一化到[0,1]
3. 学习参数γ和β对分布再做scale和shift操作
理论上讲这样子能够将分布的输入归一化到一个比较一致的空间内,避免“internal covariate shift”。
这样带来的好处:
1. 减轻了网络对参数初始化的敏感度
2. 可以使用较高的学习率,模型收敛更快,更加稳定
3. 一定程度上增加了模型的泛化能力
然而bn和internal covariate shift并没啥子关系?
然而如果强行这样子解释,我感觉非常别扭,尤其是我们先归一化到了[0,1]分布,有通过shift和scale操作把分布拉到另一个分布下,这样子不是很矛盾吗?!一些文章里给的解释是:
“scale and shift”操作则是为了让因训练所需而“刻意”加入的BN能够有可能还原最初的输入,从而保证整个网络的capacity不变。
就是分布可以变,也可以不变,excuse me?
甚至有些资料指出了bn和internal covariate shift并没有啥子关系:我是资料。
所以我觉得这样子解释还是蛮牵强的。
BN的真正作用
看过很多资料后,我觉得这样子的解释更合理:BN解决了反向传播过程中的梯度问题(梯度消失和爆炸),同时使得不同scale的参数整体更新步调更一致。
我们都知道batch normalization是用在激活之前的,最早时候的说法是,归一化后能够让参数都在激活函数的非饱和区域内,比如在sigmoid的下面这个区域(绿色框,红色虚线):
但是我觉得在激活函数普遍用relu的今天,用这个说法仿佛也不是那么有说服性。这个问题用前向、反向传播可能更好解释:
不使用batch normalization的前向/反向传播是这个样子的:
1. 前向
2. 反向
3. 如果做连续多层的反向传播,就会有:
在这个过程中,有权重wi的连乘,当每个权重w的值都较小,那反向传播过程中就会出现梯度消失;如果每个权重w的值都很大,则会产生梯度爆炸。所以BN操作的合理解释应该是:通过归一化操作将权重参数限制在比较合理的范围,这样不会产生梯度消失或者爆炸的问题。
使用batch normalization的前向/反向传播:
1. 前向
2. 反向
3. 连续多层反向传播:
通过增加了一个标准差矩阵对权重
进行缩放,并且可以感受到,当权重比较大的时候,标准差
会更大,
则会更小,这样就达到了使得权重较大的参数反向传播时乘上一个更小的系数从而获得较小的梯度,防止梯度爆炸,反之亦然。或者也可以说,这样网络的参数不会过于敏感,参数更新更加的稳健。这才是BN的真正作用所在。
感谢参考资料:
http://www.itsiwei.com/22671.html