BN:
反向传播时经过该层的梯度是要乘以该层的参数的,即前向有:
反向传播时便有:
那么考虑从l层传到k层的情况,有:
其中这个
便是问题所在。如果Wi小于1,就会发生提督弥散
而如果Wi大于1,那么传到这里的时候又会有梯度爆炸问题
BN所做的就是解决这个梯度传播的问题,因为BN作用抹去了w的scale影响。
BN为了保证非线性的获得,对变换后的满足均值为0方差为1的x又进行了scale加上shift操作(y=scale*x+shift),每个神经元增加了两个参数scale和shift参数,这两个参数是通过训练学习到的,意思是通过scale和shift把这个值从标准正态分布左移或者右移一点并长胖一点或者变瘦一点,每个实例挪动的程度不一样,这样等价于非线性函数的值从正中心周围的线性区往非线性区移动。
在测试中使用BN:
在训练中使用BN是要计算均值和方差的,而这两个统计量是随着样本不同而变化的。如果在测试中依然遵循这样的方式,那么无疑同一个样本在不同的batch中预测会得到不一样的概率值,这显然是不对的。
在测试中,BN根据训练过程中计算的均值和方差,使用滑动平均去记录这些值。在测试的时候统一使用记录下来的滑动平均值,这一点可以从源码中看出来。所以在TensorFlow或者Pytorch中,BN的代码分别有is_training 和 self.training字段,就是为了区别使用行为的。
举个例子。
在训练过程的第t次迭代中,我们得到了均值u和方差sigma。那么u和sigma将使用如下方式记录下来。
最后得到的μ,σ作为最终的值保存下来。供测试环节使用。
CBN:
batch比较小时候,BN在batch维度统计不准确,导致准确率下降。在无法扩大batch训练的前提下,通过收集最近几次迭代信息来更新当前迭代时刻的均值和方差,这样就变向实现了扩大batch目的。由于梯度下降机制,模型训练过程中相近的几个iter所对应的模型参数的变化是平滑的(smoothly),其权重变化可以用泰勒级数拟合出来,因此通过基于泰勒多项式的拟合来补偿网络权重的变化,从而可以准确地估计统计量,并可以有效地应用批次归一化。
BN就是仅仅利用当前迭代时刻信息进行norm,而CBN在计算当前时刻统计量时候会考虑前k个时刻统计量,从而实现扩大batch size操作。同时作者指出CBN操作不会引入比较大的内存开销,训练速度不会影响很多,但是训练时候会慢一些,比GN还慢。
CmBN 是CBN的修改版
CmBN的做法和前面两个都不一样,其把大batch内部的4个mini batch当做一个整体,对外隔离。CBN在第t时刻,也会考虑前3个时刻的统计量进行汇合,而CmBN操作不会,不再滑动cross,其仅仅在mini batch内部进行汇合操作,保持BN一个batch更新一次可训练参数。