论文阅读 Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift

本次阅读的论文是发表《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》,这是一篇经典文章。前段时间我自己手写resnet50网络的时候,其中采用了Batch Normalization(BN),我自己当时就不太理解,踩了一些坑。关于Batch Normaliation,这个初学者不太好懂,虽然网上已经有不少人对这个方法写过总结,但是我还是认为每一个学习深度学习的人都应该抽点时间好好看一下这篇论文,之后一定会对BN有一个更加深刻的理解。

一、为什么会出现BN。

训练深度神经网络的时候,在训练过程中,每一层的输入的分布一直在改变。这是因为前一层的参数一直在改变,而前一层的输出又作为后面一层的输入,如此一来,每一层的输入的分布就处于一个变化的状态。在这种情况下,需要以一个非常小的学习率进行训练,而且对参数的初始化也要很小心,这将减慢训练速度。此外,对存在非线性饱和的模(modelswithsaturating nonlinearities),训练将非常的难。作者称这种现象叫“内部协变量转移(internal covariate shift)”。

比如说使用sigmoid激活寒素的模型,当输入比较大或者比较小的时候,激活函数的导数约为0,那么得到的梯度将也约为0,那么训练的时候,参数更新会变得非常慢,甚至几乎不更新,也就时说训练不起作用了。(如下面两图可以看出)

                                                               

 那么解决的策略是什么呢?把输入标准化。在本文中,将标准化输入这件事变成了模型的一部分,并且对每一个训练的mini-batch进行标准化操作。使用Batch Normalization操作,将允许我们在训练的时候采用更大的学习率,不用太关注参数初始化,而Batch Normalization有正则化的作用,使得模型对Dropout的需求降低,这也是一件好事(因为使用Dropout,训练的时候,loss波动会大一些,训练速度也会需要多一点)。在达到相同准确率的情况下,使用Batch Normalization比不采Batch Normalization要快14倍。

我的理解:

为什么BN可以使得训练的时候采用更大的学习率呢,而且可以处理非线性饱和问题?

当输入的分布比较乱时,数据一会大一会小,那么模型中参数的变化会比较大,想要训练出一个模型能够在整个训练集上都有较好的表现时相对困难的。而且会出现非线性饱和的现象,这个时候训练就会变得很慢。不止是sigmoid激活函数,tanh(x)也是一样的,只不过比sigmoid好一点。

使用BN的作用,就是把整个数据的分布归一化到均值为0,方差为1的分布上。这意味着强行把数据调整到激活函数的敏感区,这样,无论是什么样的数据,都将会得到一个比较大的梯度,训练时收敛的自然就会快。

二、Batch Normalization原理

作者在文中写了SGD(s'tochastic gradient descent)随机梯度下降法情况下的batch normalization和mini batch normalization(

批梯度下降)下的batch normalization。我们平常使用的大都是批梯度下降法。这里就直接分析这种情况。

全部一起对所有层的输入输入代价时很高昂的,而且并不是所有地方都是可以可微的,所以作者做了两个简化。第一,让每一个标量特征单独标准化,使其具有0均值,方差为1。(The first is that instead of whitening the features in layer inputs and outputs jointly, we will normalize each scalar feature independently, by making it have the mean of zero and the variance of 1)。

对于一个输入时d维的层,x = (x(1) . . . x(d)),

但是这样的简单标准化时有问题的,因为这将改变网络中层信息所能表示的信息。例如,对一个使用sigmoid激活函数的层,使用这样的标准化将会把输入限制在sigmoid函数的线性区,这就直接丧失了sigmoid函数可以产生的非线性。为了解决这个问题,Batch Normalization使用了下面的方法来解决这个问题。

引入一对参数γ(k), β(k),对直接标准化的结果进行一个放缩变换和一个平移变换。

这两个参数 γ(k), β(k)通过神经网络自己学习,这可以让神经网络自己找到最有的参数。对于使用Batch Size=m的数据集,使用的算法如下所示。

反向传播的过程:

这一点没有太多可以解释的,就是高等数学中的微分,链式求导。

 注意:在推测(或者说预测)的时候,和训练是不同的。

在训练的时候,我们在每一个batch-size的数据上进行BN,但是预测的时候,应该是基于真个数据集所得到的模型才是合理的,这样的模型才可以尽可能做到全局最优。那么就有一个问题了,每一批数据的均值和方差是不一样的,所以应该通过所有的这些均值和方差来得到一个最终用于预测的方差和均值。

在训练过程中,因该是保存了一系列的均值,和一系列的方差(每一批数据都保存了)。那么具体的做法如上述公式可以看出,通过对这些均值再次求一次均值来作为最终模型的均值,最终模型的方差是通过这一系列方差求一个无偏估计得到。 

注:在使用tensorflow时,如果使用过tf.layers.batch_normalization的时候要特别小心。

我在写resnet的时候,一开始出现了训练集上准确率接近100%,但是验证集上准确率只有40%左右,不会超过50%。我一直没有找到原因,最后发现问题出在了BN上,tensorflow中,使用BN应该要添加如下语句。这就是因为训练的时候要保持那一系列的均值和方差,添加如下语句才可以实现。

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
  with tf.control_dependencies(update_ops):
    train_op = optimizer.minimize(loss)

三、充分发挥Batch Normalization的优势

作者通过实验验证了BN的作用,只是简单的对在模型中使用Batch Normalization不能充分发挥Batch Normalization的作用。作者各处了一下几点,充分发挥BN的作用:

(1)增大学习率(Increase learning rate)

(2)去掉Dropout(Remove Dropout)

(3)去掉L2正则化(Reduce the L2 weight regularization)

(4)加速学习率的衰减(Accelerate the learning rate decay)

(5)删除局部响应归一化(Remove Local Response Normalization)

(6)将训练集充分打乱(Shuffle training examples more thoroughly),这一点有助于提升准确率。

(7)减少图像的拉伸形变,更多的专注于真是图像(Reduce the photometric distortions)

以上这些方法都是很实用的,在我们使用了BN的网络中,可以通过这些方法大幅提升训练速度,增加训练的准确率。

四、结论

使用Batch Normalization的网络本身就可以提升训练的速度,同时这种网络用于含有饱和非线性的网络中,对增大的学习率也有更大的容忍度。BN正则化的作用,降低了模型中对Dropout的需求,使得模型通常可以不使用Dropout来避免过拟合。


论文地址:

https://arxiv.org/pdf/1502.03167.pdf

如果发现问题欢迎指正。如果这对你有用,可以顶一下,或者评论一下,你们的支持对我是极大的鼓舞。

猜你喜欢

转载自blog.csdn.net/yuanliang861/article/details/83446471