深入理解 BatchNormalization
经典论文**《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》**提出了Batch Normalization(BN) 批标准化的概念,在模型中运用 BN 不仅可以加快了模型的收敛速度,而且更重要的是在一定程度缓解了深层网络中“梯度弥散”的问题,从而使得深层网络模型的训练更加容易和稳定。
下面来说说这两个优点背后的原理。
1 加快收敛的速度。
先假设模型没有用上BatchNorm层,优化器为 SGD。
在第一次反向传播后,基于正向传播时每个隐藏层传入的数据分布,每层的权重(W)和偏置(b)参数都进行调整,以达到减小 loss 的目的。在第二次正向传播时,由于参数的调整,每个隐藏层输入数据的分布都和第一次的输入数据不一样。所以,在第二次反向传播后,又基于新的数据分布来调整参数。第三次,第四次…同样会发生这样的情况。这直接导致训练的速度下降。这种隐层输入数据分布老是变来变去的现象,我们叫做“Internal Covariate Shift”。同样,类似于蝴蝶效应,即使前面几层参数的微调,都可能导致后面几层的输入数据分布发生明显的改变。BN的设计直觉就是在隐藏层强行改变输入数据的分布。
那怎么改变数据的分布呢?------------我们先复习下归一化处理。
E(xk)指的是每一批训练数据神经元xk的平均值;然后分母就是每一批数据神经元xk的一个标准差了。
例如我们在 layer 3运用归一化:
(这里的ϵ为一个极小的数值,目的是防止出现除以0的情况出现)
这种归一化操作使数据处于标准正态分布。即,均值为0,标准差为1。但,这样强行改变数据的分布就破坏了前面层学习到的特征结构了。
如何在改变数据分布的情况下,保留前层学习的结果呢?
------变换重构,引入了可学习参数γ、β,这就是算法关键之处:
可以理解为将前面层学习到的成果转移给γ,β。
当满足上图取值时,就可以恢复没有BN层的分布情况了。说明引入γ、β可以恢复没有BN层时学习到的特征结构,这正是BN得以成功的关键之处。
这里,总结一下:
一般我们初始化,γ=1、β=0。
γ、β同样可以通过反向传播来调整其参数,达到学习的目的。
可以想象BN就是个中转站,经过BN的数据又可以重新调整好位置。
值得注意的是:BN层一般用在线性层和卷积层后面,而不是放在非线性单元后。即,A[l-1]->Z[l]->BN->A[l]
这里有个小细节:因为β充当该层的偏置了,所以该层的偏置(b)显得不那么重要了。
Z
~
\tilde{Z}
Z~=g(BN(WZ+b)) ==
Z
~
\tilde{Z}
Z~=g(BN(WZ))
那改变数据为什么能学习地更快呢?
要强调的一点是:机器学习的本质就是学习数据的分布。
运用BN层使迭代时的输入数据分布相同(更准确地说应该是相近),每层学习的精力都在基于此数据分布的优化调整,更加独立的学习(不受其他层的干扰),所以训练地更快。而且运用BN层会缓解之前提到的“蝴蝶效应”,所以可以使用更高的学习率。
2 缓解了深层网络中“梯度弥散”的问题
https://blog.csdn.net/TeFuirnever/article/details/88845299#BN_30
这位博主讲的很细致,但我觉得BN的亮点不是解决梯度弥散,因为将隐藏层的激活函数改为 RELU 就可以解决这个问题了。
3 BN在CNN中的运用
我觉得文字解释不如伪代码来的直接。
这里直接附上正向传播的伪代码
m == batch_size
值得注意的是,iteration = train_size / batch_size
以上代码是一次iteration的参数,在实际操作中,不可能保留每个轮次的参数,这样占用的内存太多了,在keras中的BN层有个参数momentum就是解决这个问题的。
采取的是:new_params = momentum * prev_params + (1 - momentum) * this_params 的机制,一般momentum选取在 0.99,0.999…