【深度理解】Batch Normalization(批归一化)

这几天正在看BN的论文,最近也经常看到关于BN理解的文章,在目前研究的课题中BN也是极其重要的,所以就抽出一段时间认真地研究了一下Batch Normalization的原理,以下为参考网上的几篇文章总结得出的。

Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift - 原文

Batch Normalization的论文翻译

论文解读

一、初识BN

我们今天的主角:批归一化,或者说是批标准化,英文名字 “Batch Normalization”,出自一篇非常值得学习的文献————Sergey Ioffe,Christian Szegedy在2015年发表的论文《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》也就是GoogLenet - Inception v2网络中使用的一种Normalization,常用缩写为BN。

近年来深度学习异常火爆,并且在视觉、语音和其他诸多领域屡创佳绩,随机梯度下降(SGD)成了训练深度神经网络的主流方法。虽然SGD对于训练深度神经网络来说是简单高效的,但它被人诟病的地方是,需要对模型的超参数进行仔细地选择,比如:权重衰减系数、Dropout比例、特别是优化中使用的学习率以及模型的参数初始化。由于每个层的输入都受到前面所有层的参数影响,因此,当网络变得更深时,网络参数的微小变化也会被逐渐放大,这使得训练变得越来越复杂,收敛越来越慢。这是一个深度学习领域的接近本质的问题,已经有很多论文提出了解决方法,比如:RELU激活函数,Residual Network残差网络等等。BN本子上也是其中一种目前被大量使用的解决方法。

BN是一个深度神经网络的训练技巧,它不仅可以加快了模型的收敛速度,而且更重要的是在一定程度缓解了深层网络中“梯度弥散”的问题,从而使得深层网络模型的训练更加容易和稳定。

在开始讲解算法之前,我们先来思考几个问题:

我们都知道在神经网络训练开始之前,都需要对输入数据做一个归一化处理,那么为什么要归一化呢?BN的作用到底是什么?
  • 深度神经网络的学习过程的本质是什么呢,这个问题现阶段没办法给出准确的答案,知乎上曾经有人讨论过这个问题,《关于深度学习的本质和优缺点大家说下自己的理解?》,有兴趣的童鞋可以去看一看,个人比较赞成这位仁兄的看法。
    在这里插入图片描述
    在我目前的水平看来,深度学习的本质上就是刻画问题的内部复杂结构特征,进行任意的非线性变换,简单来说可以看成是学习数据的分布(个人看法,勿喷)。机器学习领域有个很重要的假设:IID独立同分布假设【数据的独立同分布(Independent Identically Distributed)】————假设训练数据和测试数据是满足相同分布的,这是通过训练数据获得的模型能够在测试集获得好的效果的一个基本保障。如果训练数据与测试数据的分布不同,那么网络的泛化能力就会大大降低。另一方面,如果每批训练数据的分布各不相同,网络就要在每次迭代时都去学习适应不同的分布,那么网络的训练速度就会大大降低,这就是为什么我们需要对输入数据做一个归一化处理。

  • 那BN的作用到底是什么呢?根据刚才提到的机器学习领域的IID独立同分布假设,我们可以发现BN的作用就是在深度神经网络训练过程中使得每一层神经网络的输入均保持相同分布。

二、与BN相知

1、“Internal Covariate Shift”问题

从论文的名字《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》中我们可以看出BN是提出的一种解决“Internal Covariate Shift”问题的算法,那么什么是“Internal Covariate Shift”?

我们在最开始的时候提到过SGD,论文也是首先提到了Mini-Batch SGD相对于One Example SGD的两个优点:梯度更新方向更准确;并行计算速度快。为什么要说SGD,因为我们的BN是基于Mini-Batch SGD的一种解决方法,SGD的训练缺点是:超参数调试困难。(那是不是说如果BN和SGD结合就perfect了(✧◡✧))

我们知道如果深度神经网络开始训练,那么各个参数就都要发生更新,除了输入层的数据外(因为我们已经人为地为输入层数据的每个样本都进行了归一化),后面网络每一层的输入数据的分布是不停地在发生变化的,因为在训练的时候,前面层训练参数的更新将导致后面层输入数据的分布产生变化。对于深度神经网络这种包含许多隐层的网络结构来说,在训练过程中,由于各层参数在不停地变化,所以每个隐层都会面临covariate shift的问题,也就是说在训练过程中,隐层的输入分布老是变来变去,这就是所谓的“Internal Covariate Shift”

2、BN的基本思想

BN算法的基本思想其实相当地直观:因为深层神经网络在做非线性变换前的激活输入值(就是那个x=WU+B,U是输入),随着网络结构深度的增加,在训练过程中其分布逐渐发生偏移或者变动。训练速度变慢的原因,一般是整体分布逐渐往非线性函数的取值区间的上下限两端靠近(对于sigmoid函数来说,意味着激活输入值WU+B是|x|绝对值大的正值或负值,如下图两个红色剪头的指向),所以这导致反向传播时低层神经网络的梯度消失(数学导数),这是训练深层神经网络收敛越来越慢的本质原因
在这里插入图片描述
而BN就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到均值为0方差为1的标准正态分布,其实就是把越来越偏的分布强制拉回比较标准的分布,这样使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,意思是这样让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。

简单来说就是说,对于每个隐层神经元,把逐渐向非线性函数映射后向取值区间极限饱和区靠拢的输入分布强制拉回到均值为0方差为1的比较标准的正态分布,使得非线性变换函数的输入值落入对输入比较敏感的区域,以此避免梯度消失问题。保持梯度在一直比较大的位置,很明显这样的参数调整效率更高,也就是损失函数最优化的步子更大,速度更快。(这也是在很多情况下为什么RELU比sigmoid好一些的原因,因为RELU大于0时的梯度一直是1)

下面我们通过数学方法来分析这种调整有什么意义。
在这里插入图片描述
上图对应几个正态分布。

假设某个隐层神经元原先的激活输入x,符合均值是-2,方差是0.5的正态分布(在上图中对应最左端的浅绿色曲线),通过BN后转换为均值为0,方差是1的正态分布(在上图中对应的深红色图形)。

这意味着什么?意味着输入x的正态分布整体向右平移2个单位(对应正态分布中均值平移的变化),图形曲线更扁平了(对应正态分布中方差增大的变化)。通过这个图我们可以看出,BN其实就是把每个隐层神经元的激活输入分布从非【均值为0方差为1的正态分布】通过平移(增大/减小均值)、压缩/拉伸(增大/减小方差)曲线尖锐程度,调整为【均值为0方差为1的正态分布】。

那么把激活输入x调整到这个【均值为0方差为1的正态分布】有什么用嘛?首先我们看下均值为0,方差为1的标准正态分布代表什么含义:
在这里插入图片描述
上图对应均值为0方差为1的标准正态分布图。

这意味着68%概率分布在[-1,1]的范围内,95%概率分布在[-2,2]的范围。假设非线性函数是sigmoid,那么看下sigmoid(x)其函数图像:
在这里插入图片描述
sigmoid导数具体的推导过程如下:
在这里插入图片描述
因为f(x)=sigmoid(x)在0到1之间,所以sigmoid(x)的导数f′(x)在0到0.25之间,其对应的函数图像如下:
在这里插入图片描述
现在我们假设没有经过BN调整前x的原先正态分布均值是6,方差是1,在[均值 - 方差2,均值 + 方差2]范围内的概率是95%,那么也就意味着落在[4,8]之间概率是95%,那么对应的sigmoid(x)函数的值明显接近于1,在上面我们说过这个位置是典型的梯度饱和区,所以在这个区域里梯度变化很慢。

为什么这个位置是梯度饱和区?请看下sigmoid(x)函数图像,如果横坐标(sigmoid(x)函数值)取值接近0或者接近于1的时候对应纵坐标(sigmoid(x)导数函数值)取值,接近于0,意味着梯度变化很小甚至消失。而假设经过BN后,均值是0,方差是1,那么意味着95%的x值落在了[-2,2]区间内,很明显这一段是sigmoid(x)函数接近于线性变换的区域,意味着x的小变化会导致非线性函数值产生较大的变化,也即是梯度变化较大,对应导数函数图中明显大于0的区域,就是梯度非饱和区。

从上面提到的过程中学到了什么呢?BN的作用其实简单来说就是把隐层神经元激活输入从各种奇怪的非【均值为0方差为1的正态分布】拉回到【均值为0方差为1的正态分布】。

但是又出现了一个问题,如果都通过BN实现归一化的话,不就是把非线性函数替换成线性函数了?这意味着什么呢?这就要说到我们深度学习的学习过程是怎么实现的了,即通过多层非线性实现一个泛化的过程。如果是多层的线性函数其实这个深层就没有任何的意义,因为多层线性网络和一层线性网络是等价的。这意味着网络的表达能力下降了,也就是意味着深度的意义就没有了。所以BN为了保证非线性的获得,对变换后的满足【均值为0方差为1的正态分布】的x又进行了scale + shift操作。每个神经元增加了两个参数scale和shift,这两个参数通过训练学习到的,关键就是在线性和非线性之间找到一个比较好的平衡点,既能享受非线性的较强表达能力的好处,又避免太靠非线性区两头使得网络收敛速度太慢。最不济的情况,这两个参数可以等效成最开始的状态,也就是训练数据集本来的特征,这只是需要简单的计算就可以实现。

3、预处理操作

论文中提到了需要对神经网络输入数据进行预处理操作,众所周知最好的算法莫过于白化预处理。如果对网络的输入进行白化预处理,网络的训练将会收敛地更快——即输入线性变换为具有零均值和单位方差,并且去除了相关性。然而白化计算量太大了,代价昂贵,还有就是白化不是处处可微的,所以在深度学习中,其实很少用到白化,因此使用了下面的公式进行预处理,可以理解为对深层神经网络每个隐层神经元的激活值做简化版本的白化操作。
在这里插入图片描述
要注意,这里某一层的某个神经元的x(k)不是指该层的原始输入,即不是上一层每个神经元的输出,而是该层这个神经元的线性激活x=WU+B,这里的U才是上一层神经元的输出。变换的意思是:某个神经元对应的原始的激活x通过减去mini-Batch内m个实例获得的m个激活x求得的均值E(x)并除以开方求得的方差Var(x)来进行转换。

上文说过经过这个变换后某个神经元的激活x形成了均值为0,方差为1的正态分布,目的是把值往后续要进行的非线性变换的线性区拉动,增大导数值,增强反向传播信息流动性,加快训练收敛速度。

4、BN算法的实现

这个时候你可能会觉得真是好简单,不就是在网络中间对数据做一个归一化处理?然而其实并不是那么简单的。如果是仅仅使用上面的归一化公式,对网络某一层A的输出数据做归一化,然后送入网络下一层B,这样是会影响到本层网络A所学习到的特征的,这样会导致网络表达能力下降。比如:网络中间某一层A学习到特征数据本身就分布在S型激活函数的两侧,你强制把它给归一化处理了、标准差也限制在了1,把数据变换成分布于s函数的中间部分,这样就相当于搞坏了这一层网络所学习到的特征分布。为了防止这一点,论文提出了一个解决方法,在每个神经元上增加两个调节参数(scale和shift),这两个参数是通过训练来学习到的,用来对变换后的激活反变换,使得网络表达能力增强,即对变换后的激活进行如下的scale和shift操作,这其实是变换的反操作:
在这里插入图片描述
每一个神经元都会有这么一对这样的参数:
在这里插入图片描述
在这里插入图片描述
Batch Normalization网络层的前向传导过程公式就是:
在这里插入图片描述
上面的公式中的ϵ是一个为了数值稳定,加到小批量数据方差上的常量,m指的是mini-batch size。

在训练过程中我们需要通过这个变换反向传播损失 ℓ 的梯度,以及计算关于BN变换参数的梯度。我们使用的链式法则如下(简化之前):
在这里插入图片描述

5、BN的推理过程

BN算法在训练时的操作就如我们上面所说,首先提取每次迭代时的每个mini-batch的平均值和方差进行归一化,再通过两个可学习的变量恢复要学习的特征。 但是在实际应用时就没有mini-batch了,那么BN算法怎样进行归一化呢?实际上在测试的过程中,BN算法的参数就已经固定好了,首先进行归一化时的平均值和方差分别为:
在这里插入图片描述
有了均值和方差,每个隐层神经元也已经有对应训练好的Scaling参数和Shift参数,就可以在推导的时候对每个神经元的激活数据计算NB进行变换了,在推理过程中进行BN采取如下方式:
在这里插入图片描述
可以看的出这个公式其实和训练时
在这里插入图片描述
是等价的。

三、BN的相惜

BN优点:

  • 神经网络本质是学习数据分布,如果寻来你数据与测试数据分布不同,网络的泛化能力将降低,batchnorm就是通过对每一层的计算做scale和shift的方法,通过规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到正太分布,减小其影响,让模型更加健壮。

  • 可以使用更高的学习率。如果每层的scale不一致,实际上每层需要的学习率是不一样的,同一层不同维度的scale往往也需要不同大小的学习率,通常需要使用最小的那个学习率才能保证损失函数有效下降,Batch Normalization将每层、每维的scale保持一致,那么我们就可以直接使用较高的学习率进行优化。

  • 移除或使用较低的dropout。 dropout是常用的防止overfitting的方法,而导致overfit的位置往往在数据边界处,如果初始化权重就已经落在数据内部,overfit现象就可以得到一定的缓解。论文中最后的模型分别使用10%、5%和0%的dropout训练模型,与之前的40%-50%相比,可以大大提高训练速度。

  • 取消Local Response Normalization层。 由于使用了一种Normalization,再使用LRN就显得没那么必要了。而且LRN实际上也没那么work。

  • 减少图像扭曲的使用。 由于现在训练epoch数降低,所以要对输入数据少做一些扭曲,让神经网络多看看真实的数据。

参考文章:

深度学习(二十九)Batch Normalization 学习笔记
【深度学习】深入理解Batch Normalization批标准化

猜你喜欢

转载自blog.csdn.net/TeFuirnever/article/details/88845299