CNN经典算法之BN-Inception(附论文详细解读)

标签:#inception##卷积神经网络##深度学习# 时间:2019/06/03 21:41:08 作者:小木

本文是深度学习经典算法解读的一部分:https://www.datalearner.com/blog/1051558603213207

来源论文:Ioffe, Sergey, and Christian Szegedy. “Batch normalization: Accelerating deep network training by reducing internal covariate shift.” arXiv preprint arXiv:1502.03167 (2015).

由于网络输入分布的变化,网络学习的参数也不同。深度网络内部节点的分布差异问题会导致某些梯度失效,收敛速度变慢等问题。为此,Sergey等人提出Batch Normalization来使得网络层输入的均值和方差保持固定,来加快训练速度。

Batch Normalization(BN)是深度学习中非常重要的技巧,它是由Google的Sergey等人首次提出,并运用在卷积神经网络上。2015年2月6日,微软发布PReLU-Net网络,其图像识别的错误率首次低于人类。仅仅五天后,Google的Sergey就发布了BN-Inception,取得了更低的错误率,是历史上第二个超越人类识别的算法。BN可以大大降低训练速度,并提高深度学习的准确率。本文将解读其论文中的Batch Normalization的出发点以及解决的问题。

[TOC]

一、背景介绍

深度学习极大地促进了计算机视觉等领域的发展。随机梯度下降(Stochastic Gradient Descent,SGD)及其变种求解算法如动量(momentum)、Adagrad等取得了很好的性能。SGD的优化目标是求解参数\Theta,以最小化如下的损失函数:

\Theta = \arg \min_{\Theta}\frac{1}{N} \sum_{i=1}^Nl(x_i,\Theta)

这里的x_{1,\cdots,N}是训练数据。一般情况下,我们使用mini-batch进行训练,也就是说一次只会处理x_{1,\cdots,m}个数据,其中m< n使用mini-batches训练的主要优点包括:1)mini-batch上损失函数的梯度是基于训练集估计的,它的质量随着batch大小的增加而增加。2)基于批次的处理要比基于单个训练集的计算更加高效。尤其是现有的并行计算平台非常适合这种处理。

尽管SGD很简单有效,但是它需要我们仔细挑选优化的学习速率以及模型的初始值。由于每一层的结果都受到了前面层的参数的影响,因此,当网络很深的时候,每一层参数的改变都会放大很多,导致其训练是比较复杂的。

Covariate Shift问题

当训练集的样本分布与测试集分布不同或者与真实世界不同的时候就会出现Covariate Shift问题。例如,你做一个猫的识别任务。假设你的训练集中的猫都是黑猫,但是测试集中出现了白猫。这个时候你的算法在识别白猫的时候就不一定好用了,这个现象就是Covariate Shift。关于这个问题可以参考:

https://www.analyticsvidhya.com/blog/2017/07/covariate-shift-the-hidden-problem-of-real-world-data-science/

https://www.quora.com/What-is-Covariate-shift

Shimodaira, Hidetoshi. “Improving predictive inference under covariate shift by weighting the log-likelihood function.” Journal of statistical planning and inference 90.2 (2000): 227-244.

一般来说,传统机器学习领域都是用领域自适应(domain adaptation)来解决这样的问题。这是迁移学习中一个重要的概念。这里不展开解释了额,可以去看看后续的博客。在这篇论文中,作者认为Covariate Shift可以推广一下概念,也就是说不一定整个学习系统会遇到这个问题,在一个子网络的学习中也可能会出现这个现象。假设考虑如下的网络:

l = F_2(F_1(u,\Theta_1),\Theta_2)

其中,F_1F_2是任意的转换,参数\Theta_1\Theta_2需要学习的参数,目标是l的最小化。学习\Theta_2可以当做是当x=F_1(u,\Theta_1)输入到子网络:

l = F_2(x,\Theta_2)

的情况。也就是需要计算如下的梯度下降过程:

\Theta_2 \leftarrow \Theta_2 - \frac{\alpha}{m}\sum_{i=1}^m\frac{\partial F_2(x_i,\Theta_2)}{\partial\Theta_2}

显然,这个学习的过程和给定一个单独的网络F_2,输入为x是等价的。因此,使训练更有效的输入分布的属性应当也适用于子网络的学习(例如训练集和测试集拥有相同的分布)。也就是说,x随着时间变化保持不变是很有利的。因此,\Theta_2并不需要重新调整以适应x的变化。

对于子网络也固定分布的情况对于子网络之外的层也有利。考虑一个带有sigmoid激活函数的层:

z = g(Wu + b)

这里的u是输入,权重Wb是学习的参数。当|x|增长的时候,g(x)的导数趋向于0。这意味着,除了那些绝对值很小的输入,x=Wu+b的大多数维度都会逐渐消失并导致训练缓慢。但是,由于x受到了Wb以及所有下面层的参数的影响,在训练的过程中改变这些参数会导致x很多的维度都落入了非线性的饱和区域,使得收敛变慢。当网络的深度变深的时候,这个影响会放大。在实际中,饱和问题一般会通过使用ReLU激活函数、精心设计的初始化参数以及较低的学习速率来解决。然而,如果我们可以在训练的过程中让非线性的输入分布保持稳定,那么优化器就不容易落入饱和区域,那么训练的过程就会加速。

作者把这种深度网络内部节点的分布改变称为“Internel Covariate Shift”。如果能消除这种变化,可以加速训练过程。因此,作者提出了一种新的机制,称为“Batch Normalization”,来解决这个问题。它通过一个正规化(normalization)步骤来固定网络层输入的均值和方差。同时,通过降低对初始值和参数尺度变化导致的梯度变化的依赖,对网络中梯度的流动有益。这允许我们可以使用更大的学习速率。此外,batch normalization也对模型有正则的作用进而减少Dropout的作用。最终,BN通过阻止网络陷入饱和模式使我们可以使用饱和的非线性激活函数。

二、降低内部协方差变化(Internel Covariate Shift)

很早之前的研究就发现如果网络的输入是whitened(输入whitened的意思是指其均值为0,方差为1),分类的效果比较好。因为如果输入是whitened,意味着特征之间相对独立。这不仅仅是针对深度学习来说的,任意有监督的学习任务中,特征whitened都是一种有效的方法。如下图所示:


关于这个可以参考:Why does whitening the inputs of a neural network lead to faster convergence?

那么如何将网络层的输入变成whitened,来降低内部协方差呢?我们先看两种基本方法。

2.1、直接修改训练过程中的输入

我们可以考虑在每个训练步骤中或者是内部某一步中,直接修改网络或者是根据网络激活函数的值修改优化算法的参数。但是,如果这些修改在优化中穿插的话,那么梯度下降步骤可能尝试以需要更新标准化的方式更新参数,最后会降低梯度的影响。举个例子,假设某一层的输入是u加上学习到的偏移b,即x=u + b,那么正规化的结果就是\hat{x}=x-E[x],其中E[x]是均值。如果某次梯度下降的步骤中忽略E(x)b的依赖,我们来更新一下b,那么有:

b \leftarrow b + \Delta b

其中

\Delta b = \frac{\partial l}{\partial \hat{x}}

那么我们会发现:

\begin{aligned} u + (b+\Delta b) - E(u+(b+\Delta b)) & = \\ u + b - E(u+b) \end{aligned}

可以看到当更新了b之后,再正规化,发现输入并没有任何变化,因此,其损失函数也不会有变化。继续循环迭代,b会无限增长,但是损失函数保持不变。如果将正规化还扩大的激活函数上,那么这个问题更加严重。当正规化参数在梯度下降之外计算的时候,作者发现实验就会使得模型爆炸。

这里是作者举的例子。其实我们想一下也很简单,我们举个更直观的例子,假设我们某一层的输入是x,那么正规化一下会变成\hat{x}=x-E(x)。如果我们输入经过梯度的更新变成了x+\Delta x,那么再继续正规化之后会发现\hat{x}=x+\Delta x - E(x+\Delta x) = x-E(x),也就是即便输入经过梯度下降变化了,但是其正规化的结果没变。

上面这个问题就是梯度下降的优化没有考虑正规化发生的问题。为了解决这个问题,我们需要确保网络的激活函数总是可以产生期望的分布。这样会使得损失函数的梯度会考虑正规化。

2.2、另一种方法

为了达到上述目的,假设x是某一层的输入,X是训练集,那么x的正规化可以写成:

\hat{x} = \text{Norm}(x,X)

也就是说,这个正规化不仅依赖于当前的输入,还依赖于整个训练集。这里如果x是某一层产生的,那么xX中的每一个值都是与\Theta有关的变量。

那么,反向传播的时候,我们需要计算Jacobians:

\frac{\partial \text{Norm}(x,X)}{\partial x}

\frac{\partial \text{Norm}(x,X)}{\partial X}

忽略后面的一项,这会导致前面说的爆炸现象。在这种情况下,对输入层做whitening是很昂贵的操作,因为它需要计算协方差矩阵\text{Cov}(x)以及它的逆方差的跟,以产生whitened激活函数,以及其导数。

这些促使作者寻找一个替代的方案,既是可微也不需要分析总的数据。

已经有一些研究使用基于单个训练集样本的统计结果来计算正规化,或者在图像识别中基于同一个位置不同的feature map计算正规化。然而,这是通过放弃激活函数的绝对规模来改变网络的表示能力。而作者希望保留这样的信息。

3、基于Mini-Batch的Normalization

由于对每一层做full whitening成本很高,而且而不是每一处都可微。作者做了两个简化:第一个是不再对层的输入和输出一起whitening,而是对每一个特征的值单独whitening。例如,对于一个层的输入是d维的x=(x^{(1)}\cdots x^{(d)}),针对每一维度单独正规化:

\hat{x}^{(k)} = \frac{x^{(k)-E[x^{(k)}]}}{\sqrt{\text{Var}[x^{(k)}]}}

这里的期望和方差计算的是训练及数据。这样的正规化可以加速收敛,即使特征没有去相关化。

但是注意,仅仅这样正规化会改变层的表示。例如,如果对sigmoid激活函数的输入做正规化,会导致其输入在0-1之间,那么其输出是一个接近线性的结果,也就是失去了非线性的表示能力。为了解决这个问题,作者需要网络中插入的转换可以表征身份转换(the transformation inserted in the network
can represent the identity transform)。为了完成这样的操作,作者对每一个激活的结果都引入了一对参数\gamma^{(k)}\beta^{(k)}来对正规化的值做尺度变换和平移转换:

y^{(k)} = \gamma^{(k)}\hat{x}^{(k)} + \beta^{(k)}

这两个参数也随着原始的模型参数一起学习,但是他们保存着网络的表示能力。实际上,如果我们设置\gamma^{(k)}=\sqrt{\text{Var}[x^{(k)}]},以及\beta^{(k)}=E[x^{(k)}],那么我们就可以还原原始的激活函数了。

在批处理设定下,每一次迭代的步骤中都可以基于整个训练集,那么我们可以使用这个训练集来正规化激活函数。但是在使用随机优化的时候并不实际。因此,作者做了第二个简化:由于在随机训练中使用batch方式,每一个mini-batch都禅是一个激活函数的均值和方差。那么这个正规化的统计就可以参与整个梯度反向传播了。

欢迎大家关注DataLearner官方微信,接受最新的AI技术推送