BN和conv pooling一样是一个含有参数的层,其解决的问题是样本间在隐含层的特征数据分布不均,提升训练效率。
基本算法如下,首先对每一层的数据,都会计算其均值和方差,再将特征数据分布归一化到均值为1,标准差为0。仅仅是这样操作后会有一个硬伤:原本一些数据分布可能都是大于0的,现在你归一化到均值为1,一般情况下,神经元在ReLu都不会被激活!
因而BN层又构造了一个
y
i
=
γ
x
i
+
β
y_i=\gamma x_i+\beta
yi=γxi+β的线性变换,且
γ
\gamma
γ、
β
\beta
β两个参数都是可学习的,让神经网络自己凭经验选择,对于某一类数据在特定层,需要将数据变换到什么参数下的分布
其优点有:
- 让SGD变得简单而高效,可以使用更高的学习率也不必过于小心参数初始化(BN同时解决了梯度消失/爆炸??限制了权重,避免爆炸,把激活值拉到一个合理区间,避免消失?)
- BN提高了泛化性能。AlexNet中的LRN、dropout可以退出历史舞台了,也可以选择更小的L2正则约束参数
关于BN层的使用,有两种方式,一是在conv/FC之前使用,二是在conv/FC之后,在ReLu激活之前使用BN层,作者论证了后者更合理,而且由于BN的归一化作用,神经网络中的bias没啥影响了:
随便找了个代码,确实BN是夹在conv和ReLu之间:
if batch_norm:
layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]