本文主要介绍深度学习里的一个常用的trick,主要用于加速收敛算法,这篇主要介绍一下怎么做的(How),下篇再介绍Why和该算法的一些好处,本来想着根据自己的理解写一下,看了大神写的之后我就决定”抄袭了”,(大神就是大神啊…)。原文使用MXNet实现的算法(原文查看文末的原文链接),这里改成使用TensorFlow实现一下这个例子。

批量归一化

这一节我们介绍批量归一化(batch normalization)层,它能让较深的神经网络的训练变得更加容易。在“实战 Kaggle 比赛:预测房价”一节里,我们对输入数据做了标准化处理:处理后的任意一个特征在数据集中所有样本上的均值为 0、标准差为 1。标准化处理输入数据使各个特征的分布相近:这往往更容易训练出有效的模型。

通常来说,数据标准化预处理对于浅层模型就足够有效了。随着模型训练的进行,当每层中参数更新时,靠近输出层的输出较难出现剧烈变化。但对于深层神经网络来说,即使输入数据已做标准化,训练中模型参数的更新依然很容易造成靠近输出层输出的剧烈变化。这种计算数值的不稳定性通常令我们难以训练出有效的深度模型。

批量归一化的提出正是为了应对深度模型训练的挑战。在模型训练时,批量归一化利用小批量上的均值和标准差,不断调整神经网络中间输出,从而使得整个神经网络在各层的中间输出的数值更稳定。批量归一化和下一节将要介绍的残差网络为训练和设计深度模型提供了两类重要思路。

批量归一化层

对全连接层和卷积层做批量归一化的方法稍有不同。下面我们将分别介绍这两种情况下的批量归一化。

对全连接层做批量归一化

我们先考虑如何对全连接层做批量归一化。通常,我们将批量归一化层置于全连接层中的仿射变换和激活函数之间。设全连接层的输入为$\boldsymbol{u}$,权重参数和偏差参数分别为 ,激活函数为 。设批量归一化的操作符为 。那么,使用批量归一化的全连接层的输出为

其中批量归一化输入 由仿射变换

得到。考虑一个由 个样本组成的小批量,仿射变换的输出为一个新的小批量 。它们正是批量归一化层的输入。对于小批量 中任意样本 ,批量归一化层的输出同样是 维向量

并由以下几步求得。首先,对小批量 求均值和方差:

其中的平方计算是按元素求平方。接下来,我们使用按元素开方和按元素除法对 标准化:

这里 是一个很小的常数,保证分母大于 0。在上面标准化的基础上,批量归一化层引入了两个可以学习的模型参数,拉伸(scale)参数 和偏移(shift)参数 。这两个参数和 形状相同,皆为 维向量。它们与 分别做按元素乘法(符号 )和加法计算:

至此,我们得到了 的批量归一化的输出
值得注意的是,可学习的拉伸和偏移参数保留了不对 做批量归一化的可能:此时只需学出 。我们可以对此这样理解:如果批量归一化无益,理论上学出的模型可以不使用批量归一化。

对卷积层做批量归一化

对卷积层来说,批量归一化发生在卷积计算之后、应用激活函数之前。如果卷积计算输出多个通道,我们需要对这些通道的输出分别做批量归一化,且每个通道都拥有独立的拉伸和偏移参数,且均为标量。设小批量中有 个样本。在单个通道上,假设卷积计算输出的高和宽分别为 。我们需要对该通道中 个元素同时做批量归一化。对这些元素做标准化计算时,我们使用相同的均值和方差,即该通道中 个元素的均值和方差。

测试/预测时的批量归一化

使用批量归一化训练时,我们可以将批量大小设的大一点,从而使批量内样本的均值和方差的计算都较为准确。将训练好的模型用来预测/测试时,我们希望模型对于任意输入都有确定的输出。因此,单个样本的输出不应取决于批量归一化所需要的随机小批量中的均值和方差。一种常用的方法是通过移动平均估算整个训练数据集的样本均值和方差,并在预测时使用它们得到确定的输出。可见,和丢弃层一样,批量归一化层在训练模式和预测模式下的计算结果也是不一样的。

tensorflow调用

根据上面的讲解,运算流程应该是,输入神经元(neural)的数据先做得到,再按照上面的公式对一个batch内的进行normalization并接着scale和shift,之后再对其进行激活得到

下面,使用mnist手写数字识别为例,按照这个流程走一遍吧,在tensorflow中调用使用的是tf.layers.batch_normalization,完整代码请看这里(使用jupter-notebook查看):

1
2
3
4
5
epsilon = 0.001
Wx_plus_b = tf.layers.batch_normalization(Wx_plus_b, mean, var, shift, scale, epsilon)
# similar with this two steps:
# Wx_plus_b = (Wx_plus_b - fc_mean) / tf.sqrt(fc_var + 0.001)
# Wx_plus_b = Wx_plus_b * scale + shift

转载自:动手学深度学习
原文网址:https://zh.gluon.ai/chapter_convolutional-neural-networks/batch-norm.html
作者:阿斯顿·张、李沐、扎卡里 C. 立顿、亚历山大 J. 斯莫拉