一、备注
最近我在研究深度学习和神经网络,看了一些比较经典的神经网络论文,有些地方不是很懂,于是简单地记录下来,一方面是供小伙伴们学习和讨论,另一方面也是通过写博客来激励自己学习。
神经网络的训练是一个玄学问题,参数调的不好的话训练速度会很慢。Batch Normalization是2015年提出的,主要是用于加快神经网络的训练,提高模型的泛化能力,而且实际测试的效果不错。我看完以后还是有很多不懂的地方,看了网上很多大佬的分析,才慢慢有所领悟,也想将我的一些想法记录下来。
关于深度学习这一块,初学者还是应该多读论文,多写代码多实践,至少目前来看,我觉得深度学习还是比较依赖个人经验的,很多想法都是在大量实践中得出来的。
二、原理
1.数据分布问题
Batch Normalization是针对mini-batch sgd设计的,文章开头提到了数据的分布问题。原始训练数据通过输入层以后会被激活,在这个过程中数据的分布会发生变化,而且这种变化会随着神经网络层数的增加而加剧。当输入层的分布发生变化时,训练速度会减慢,因为模型需要适应这种分布的变化,由一种数据分布迁移到另一种数据分布,这不是DNN考虑的问题。数据分布的变化,文章将其称为covariate shift(应该翻译为协变吧)。
对于多层神经网络来说,上一层的输出可以看作下一层的输入,于是,数据的分布在经过上一层的激活后,分布会发生变化,也就是说,数据的分布在神经网络内部发生了变化,作者把这称为Internal Covariate Shift(内部协变),这个内部,指的是神经网络内部。
两层的神经网络可以这样表示,
令, 则, 的输出是的输入,利用梯度下降更新,
m是batch size, 是学习率。
作者将看成子网络,而该网络的输入是上一层的输出,这样便于分析。
当训练数据的分布和测试数据相同的时候,训练效率会更高,这个很容易理解,不用再去适应另一个分布了。
分布的变化还有另外一个问题,那就是梯度的消失,当激活函数为sigmoid是,输入数据经过激活后可能分布可能会变换到sigmoid梯度弥散的部分,导致模型的收敛减慢。
sigmoid函数图像如图,当较大时,函数的导数会趋于0,导致模型训练速度会减慢,解决办法是通过变换,将x的分布尽量变换到0附近,此处的导数值较大,有利于模型的训练。
2.Batch normalization
为了解决上述问题,作者提出了Batch Normalization操作。
之前的研究表明,白化操作可以加快模型的训练。白化就是利用线性变换将x的均值变为0,方差变为1.
在更新的过程中还要考虑激活的过程,否则会出现问题,文章举了一个例子。
假设有一个网络层,对于输入, 输出, 对x进行归一化,有, 对b进行更新,则
, , 于是,, 更新以后,, 按照白化操作更新,
标准化以后与一样,也就是说,激活后的x与激活前一样,这样,下一层的输入就没有变化,训练的误差也不会有变化,这个原因是因为x的期望与参数b有关。
为了解决这个问题,在标准化的过程中还要考虑训练集。
假设模型参数为, 为输入,为训练集,那么标准化应该是 ,反向传播的过程中,需要计算一下两个雅可比矩阵
和
如果不考虑后者的话就会出现上文提到的损失不更新的问题。
但是上述操作代价比较大,于是作者寻找了一种替代方案,首先,并不对输入和输出同时尽行标准化,而是对输入向量中的每一个特征进行标准化,操作如下:
, .
其次,标准化以后,隐藏层的表示会发生变化,为了解决这个问题,作者又加入了一个仿射变化,可以将激活后的数据恢复出来,具体操作如下:
, 和 都是需要学习的。
利用仿射变换,能够恢复出原隐藏层的表示。
网上关于这个讨论挺多的,目前说法不一,我也不太懂,目前的操作流程是这样的:1.标准化,2.激活,3.仿射恢复。
我们先标准化,激活以后利用仿射变换恢复出原来的分布,这样看起来好像是做了无用功,因为分布最后还是会恢复成原来的分布,那为什么还要多此一举呢?网上的解释是这种操作增强了模型的表示能力,看了很多博客以后我想谈谈自己的看法:
1.我们标准化的目的是为了加快模型的训练,因为分布不一致会减慢模型的训练,降低泛化能力,标准化以后数据的分布处于激活函数的导数绝对值大的地方,这样反向传播的时候浅层神经网络可以得到训练,避免梯度消失。
2.标准化的副作用是隐藏层的表示发生了变化,会影响到下一层的训练,所以我们需要恢复出原来的分布,这样就不会对神经网络的下一层产生影响。
总结起来就是,利用标准化和仿射变换,使得当前层的训练加快,又不会影响下一层的训练,于是,模型的训练被加快,模型的表示能力得到强化。
标准化的过程依赖于整个训练集,但是当使用随机梯度优化的时候不会用到整个训练集,于是,利用每次训练的小批样本来进行标准化,具体操纵如下:
, B为mini-batch, 大小为m。
是一个常量,用来弥补 过小而带来的影响。
利用反向传播算法推导损失,如图
3.利用Batch Normalization来进行训练和测试
训练的过程中,先利用标准化操作得到的新数据训练BN网络,同时还要优化BN层中的scale和shift参数,然后将训练好的BN网络用于inference, inference的时候利用mini-batch中的数据的方差和期望代替测试数据的方差与期望。
BN还可以用于卷积神经网络,只不过原先mini-batch(大小为m)会加入大小为p*q的feature map, 所以,新的mini-batch变为m*p*q,每一组feature map都会有新的和参数。
BN的好处:
1.加快训练。BN层可以使用更高的学习率。
2.防止过拟合。BN层可以避免网络模型的过拟合问题。
三、效果
我用简单的三层神经网络测试了一下,效果还是很不错的。
无BN层时,
有BN层时,
优化方式都是sgd,采用的是简单的三层神经网络模型。不添加BN层时优化的很慢,难以收敛,加入BN层以后优化得更稳定,而且准确率更高。