神经网络之BN层

 

背景

BN,全称Batch Normalization,是2015年提出的一种方法,在进行深度网络训练时,大都会采取这种算法。
原文链接:Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift

尽管梯度下降法训练神经网络很简单高效,但是需要人为地去选择参数,比如学习率,参数初始化,权重衰减系数,Dropout比例等,而且这些参数的选择对于训练结果至关重要,以至于我们很多时间都浪费到这些调参上。BN算法的强大之处在下面几个方面:

  1. 可以选择较大的学习率,使得训练速度增长很快,具有快速收敛性。
  2. 可以不去理会Dropout,L2正则项参数的选择,如果选择使用BN,甚至可以去掉这两项。
  3. 去掉局部响应归一化层。(AlexNet中使用的方法,BN层出来之后这个就不再用了)
  4. 可以把训练数据打乱,防止每批训练的时候,某一个样本被经常挑选到。(不是很理解啊)

首先来说归一化的问题,神经网络训练开始前,都要对数据做一个归一化处理,归一化有很多好处,原因是网络学习的过程的本质就是学习数据分布,一旦训练数据和测试数据的分布不同,那么网络的泛化能力就会大大降低,另外一方面,每一批次的数据分布如果不相同的话,那么网络就要在每次迭代的时候都去适应不同的分布,这样会大大降低网络的训练速度,这也就是为什么要对数据做一个归一化预处理的原因。另外对图片进行归一化处理还可以处理光照,对比度等影响。
另外,为什么要进行归一化还有一些原因,可以参考这里 网络一旦训练起来,参数就要发生更新,出了输入层的数据外,其它层的数据分布是一直发生变化的,因为在训练的时候,网络参数的变化就会导致后面输入数据的分布变化,比如第二层输入,是由输入数据和第一层参数得到的,而第一层的参数随着训练一直变化,势必会引起第二层输入分布的改变,把这种改变称之为:Internal Covariate Shift,BN就是为了解决这个问题的。

BN

和卷积层,激活层,全连接层一样,BN层也是属于网络中的一层。我们前面提到了,前面的层引起了数据分布的变化,这时候可能有一种思路是说:在每一层输入的时候,在加一个预处理多好。比如归一化到均值为0,方差为1,然后再送入输入进行学习。基本思路是这样的,然而实际上没有这么简单,如果我们只是使用简单的归一化方式:

 

对某一层的输入数据做归一化,然后送入网络的下一层,这样是会影响到本层网络所学习的特征的,比如网络中学习到的数据本来大部分分布在0的右边,经过RELU激活函数以后大部分会被激活,如果直接强制归一化,那么就会有大多数的数据无法激活了,这样学习到的特征不就被破坏掉了么?论文中对上面的方法做了一些改进:变换重构,引入了可以学习的参数,这就是算法的关键之处:这两个希腊字母就是要学习的。

每一个神经元x_k都会有这样的一对参数,当:

这样的时候可以恢复出原始的某一层学习到的特征的,因此我们引入这个可以学习的参数使得我们的网络可以恢复出原始网络所要学习的特征分布,最后BN层的前向传导公式为:

上面公式中的m指的是mini-batch size。也就是每一个batch来做一个这样的BN。代码对应也是四句话。

m = K.mean(X, axis=-1, keepdims=True)        #计算均值  
std = K.std(X, axis=-1, keepdims=True)           #计算标准差  
X_normed = (X - m) / (std + self.epsilon)         #归一化  
out = self.gamma * X_normed + self.beta           #重构变换

上面的x是一个二维矩阵,对于源码的实现就是上面几行了。

使用

一旦网络训练结束,就没有了batch这个概念了,测试阶段的时候我们一般只输入一个样本来看一下预测结果。因此测试样本前向传导的时候,上面式子里的均值和标准差从哪里来?其实网络一旦训练完毕,参数都是固定的,这个时候即便是训练数据进来一个batch,BN层计算的均值和标准差都是基本不变的(网络趋于稳定),我们可以采用这些数值作为测试样本所需要的均值和标准差,于是最后测试阶段的均值和标准差为:

上面简单理解就是:对于均值来说直接计算所有batch u值的平均值;然后对于标准偏差采用每个batch σB的无偏估计。最后测试阶段,BN的使用公式就是

BN可以用于一个神经网络的任何一个神经元上,文献中主要是把BN变换放在激活函数层的前面,所以前向传导的计算公式应该是:z=g(BN(Wu+b)),因为偏置参数经过BN层其实是不起作用的,因为也会被均值归一化(平移),所以这个参数就可以不要了,可以写成:z=g(BN(Wu))

BN在CNN上的使用。

上面所说的是BN对于每一个神经元都做处理,对于卷积神经网络来说呢?比如某一层卷积层的维度是:1001006,如果对每一个神经元都进行BN的话,那就需要600万*2的参数,这是相当恐怖的,所以其实卷积神经网络使用BN的时候,也做了权重共享的策略,把一张特征图当做一个神经元来处理。
比如某层的特征维度是[m,f,p,q],分别是batch_num:m,维度: f,特征尺寸p,q。CNN中可把每个特征图看成是一个特征处理(神经元),因此在使用BN的时候,Mini-batch size的大小就是mpq,对于每一个特征图只有一对科学系的参数。说白了,就是相当于求所有样本(batch_num:m个)所对应的的一个特征图的所有神经元的平均值和方差,然后对这一个神经元做归一化,假设特征维度只有一维的话,就相当于一个batch的所有图片像素的均值和方差来对每一张图片来做归一化,也是容易理解的。