Batch Normalization的正确打开方式

Batch Normalization在TensorFlow中有三个接口调用 (不包括slim、Keras模块中的),分别是:

  • tf.layers.batch_normalization
  • tf.nn.batch_normalization
  • tf.contrib.layers.batch_norm

通过观察这三个接口的参数列表可以得到一个初步的结论,tf.layers.batch_normalizationtf.contrib.layers.batch_norm可以用来构建待训练的神经网络模型,而tf.nn.batch_normalization一般只用来构建推理模型。简洁起见,本文把神经网络模型分为训练模式和推理模式(包括推理、测试和评估等)。由于tf.contrib包的不稳定性,本文将主要介绍如何使用tf.layers.batch_normalization这个方法在模型中添加BN layer

tf.layers.batch_normalization()方法

方法接口如下:

tf.layers.batch_normalization(
    inputs,
    axis=-1,
    momentum=0.99,
    epsilon=0.001,
    center=True,
    scale=True,
    beta_initializer=tf.zeros_initializer(),
    gamma_initializer=tf.ones_initializer(),
    moving_mean_initializer=tf.zeros_initializer(),
    moving_variance_initializer=tf.ones_initializer(),
    beta_regularizer=None,
    gamma_regularizer=None,
    beta_constraint=None,
    gamma_constraint=None,
    training=False,
    trainable=True,
    name=None,
    reuse=None,
    renorm=False,
    renorm_clipping=None,
    renorm_momentum=0.99,
    fused=None,
    virtual_batch_size=None,
    adjustment=None
)

这里有几个重要参数需要注意:

  • axis的值取决于按照input的哪一个维度进行BN,例如输入为channel_last format,即[batch_size, height, width, channel],则axis应该设定为4,如果为channel_first format,则axis应该设定为1.
  • momentum的值用在训练时,滑动平均的方式计算滑动平均值moving_mean和滑动方差moving_variance。 后面做更详细的说明。
  • centerTrue时,添加位移因子beta到该BN层,否则不添加。添加beta是对BN层的变换加入位移操作。注意,beta一般设定为可训练参数,即trainable=True
  • scaleTrue是,添加缩放因子gamma到该BN层,否则不添加。添加gamma是对BN层的变化加入缩放操作。注意,gamma一般设定为可训练参数,即trainable=True
  • training表示模型当前的模式,如果为True,则模型在训练模式,否则为推理模式。要非常注意这个模式的设定,这个参数默认值为False。如果在训练时采用了默认值False,则滑动均值moving_mean和滑动方差moving_variance都不会根据当前batch的数据更新,这就意味着在推理模式下,均值和方差都是其初始值,因为这两个值并没有在训练迭代过程中滑动更新。

TensorFlow的api文档中对该方法标星出了Note警示如下:

Batch Normalization的正确打开方式_第1张图片
Note and code example of tf.layers.batch_normalization

TensorFlow中模型训练时的梯度计算、参数优化等 train_op并没有依赖滑动均值 moving_mean和滑动方差 moving_variance,则 moving_meanmoving_variance不会自动更新,所以必须加入负责更新这些参数的 update_ops到依赖中,且应该在执行前向计算结束后、后向计算开始前执行 update_ops,所以添加依赖的位置不能出错。实际中, 只需要在构建模型代码中,添加完所有BN层之后获取update_ops就不会出错,切记!切记!这是TensorFlow的图计算模式造成的编程影响,在其他深度学习框架中可能会有差别。

Batch Normalization的作用

  1. 效果
    该方法出自Sergey Ioffe和Christian Szegedy的《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》一文,BN方法到底能否减少Internal Covariate Shift可能还无法下最终结论 (参见《How Does Batch Normalization Help Optimization?》),但的确可以加速训练平稳收敛!所以,BatchNorm成为了居家旅行、训练模型之必备layer。
  2. 计算
    BatchNorm的具体计算/变换如图 (见论文):
    Batch Normalization的正确打开方式_第2张图片
    Batch Normalizing Transform, applied to activation x over a mini-batch.
    用大白话描述就是,计算出当前batch的每个channel的均值mean,计算出当前batch的每个channel的方差variance,令输入减去均值再除以标准差delta,得到normalized输出x-hat,最后乘以scale参数gamma,加上shift参数beta,得到最终变换后的输出y
  3. BN层在train与inference时的差别
    在训练时,我们可以计算出batch的均值和方差,迭代训练过程中,均值和方差一直在发生变化。但是在推理时,均值和方差是固定的,它们在训练过程中就被确定下来。《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》中给出的确定方式和TensorFlow中存在不同,这里我们介绍TensorFlow中的方式,即采用滑动平均MovingAverage的方法,公式为: moving_average_value * momentum + value * (1 - momentum),其中value为当前batch的平均值或方差,moving_average_value为滑动均值或滑动方差。
    最终,模型训练完毕后,在推理时使用滑动平均值moving_mean和滑动方差moving_variance对feature maps进行变换。
  4. 在模型中的哪些位置插入BN层
    推荐在Conv层或FC层之后,非线性变换激活层之前插入BN层。原因见论文:
    Batch Normalization的正确打开方式_第3张图片
    where to insert BN layers

TensorFlow中的BatchNorm实现链

tf.layers.batch_normalization -->
tf.layers.BatchNormalization -->
tf.python.keras.layers.BatchNormalization -->
keras.backend.normalize_batch_in_training -->
keras.backend._fused_normalize_batch_in_training -->
tf.python.ops.nn.fused_batch_norm

tf.python.keras.layers.BatchNormalization -->
keras.backend.moving_average_update -->
tf.python.training import moving_averages.moving_averages

前半部分主要是对batch_norm的变换,后半部分是对滑动均值的更新。

后记

写这篇文章是为了介绍BatchNorm在TensorFlow中的正确使用方法。作者曾因为没有正确传递training参数给tf.layers.batch_normalization,导致模型在训练完成后所有moving_mean都是0,所有moving_variance都是1.0,在读取并量化模型进行batch norm fold时,无法读入这两个参数,提示NoneType错误。经过研究一番才发现是调用tf.layers.batch_normalization方法是必须pass正确的模式。

你可能感兴趣的:(Batch Normalization的正确打开方式)