Batch&Layer Normalization, 网络低层输出数据的正规化

一. 简介

神经网络训练中, 低层参数更新后, 其输出也会有相应变化, 高层参数会疲于适应这些剧烈的变化, 难以有效收敛, 所以需要 normalization.
有了它, 可以使用更大的学习率,初值可以更随意。它起到了正则项的作用,在某些情况下,有它就不需要使用 dropout 了。

二. 原理

因为低层参数的更新, 高层网络要接收的 x 的分布可能在不同 batch 上相差很大, 不再是独立同分布. 要解决独立同分布的问题,“理论正确” 的方法就是对每一层的数据都进行白化操作。然而标准的白化操作代价高昂,特别是我们还希望白化操作是可微的,保证白化操作可以通过反向传播来更新梯度。
因此,以 BN 为代表的 Normalization 方法退而求其次, 将 x \bold x x 的分布规范化成在固定区间范围的标准分布。
h = f ( γ ⋅ x − μ σ + β ) (1) h=f(\bold \gamma\cdot\frac{\bold x-\mu}{\sigma}+\bold \beta) \tag 1 h=f(γσxμ+β)(1)
注意式1中的参数均为黑体向量, 维度与低层神经元个数一致.

  1. μ =E[x], 是平移参数(moving_mean),变换后的数据均值为0.
  2. σ= ( v a r ( x ) ) \sqrt{(var(x))} (var(x)) , 是缩放参数(scale parameter), 变换后的数据方差为1. 以上两个参数不用学习, 是统计出来的.
  3. beta , 再平移参数(re-shift parameter),变换后的数据均值为 beta.
  4. gamma, 再缩放参数(re-scale parameter)。变换后的数据方差为 gamma. 以上两个参数是 trainable的.

Q: 为啥要有再平移和再缩放?
A: 强制限定 x 的分布范围会削弱低层网络的表达效果, 所以引入可学习参数 gama,beta, 保证模型的表达能力不因为规范化而下降。

Q:经过这么的变回来再变过去,会不会跟没变一样?
A: 不会。因为,再变换引入的两个新参数 gama,beta, 可以表示旧参数作为输入的同一族函数,但是新参数有不同的学习动态。在旧参数中,x 的均值取决于下层神经网络的复杂关联;但在新参数中,仅由 b 来确定,去除了与下层计算的密切耦合。新参数很容易通过梯度下降来学习,简化了神经网络的训练。

2.1 Normalization 的权重伸缩不变性

权重伸缩不变性(weight scale invariance)指的是,当权重 W 按照常量 λ 进行伸缩时,得到的规范化后的值保持不变.
所以, 在 低层输出与Norm层之间认为插入乘法op是不起作用的.

三. BatchNormalization

Batch Normalization 于 2015 年由 Google 提出,开 Normalization 之先河。其规范化针对单个神经元进行,利用网络训练时一个 mini-batch 的数据来计算该神经元的均值和方差, 因而称为 Batch Normalization。
以输入shape=[N,T,d] 为例, 计算均值 μ \mu μ.shape=[1,T,d]
BN 需要在运行过程中统计每个 mini-batch 的一阶统计量和二阶统计量,因此不适用于 动态的网络结构 和 RNN 网络。

3.1 keras api

  • calss BatchNormalization(Layer)
  • BatchNormalization.__init__(self,
    axis=-1,
    momentum=0.99,
    epsilon=1e-3,
    center=True,
    scale=True,
    beta_initializer=‘zeros’,
    gamma_initializer=‘ones’,
    moving_mean_initializer=‘zeros’,
    moving_variance_initializer=‘ones’,
    beta_regularizer=None,
    gamma_regularizer=None,
    beta_constraint=None,
    gamma_constraint=None,
    renorm=False,
    renorm_clipping=None,
    renorm_momentum=0.99,
    fused=None,
    trainable=True,
    virtual_batch_size=None,
    adjustment=None,
    name=None,
    **kwargs)
    • momentum, Momentum for the moving average.
    • center, scale. 两个 bool 参数, 分别对应 beta, gamma 是否生效.

3.2 tf api

位于 tensorflow.contrib.layers.python.layers.layers.batch_norm(). 一个 case 见下: 调用
layers.fully_connected(inputs, num_outputs=256, normalizer_fn=layers.batch_norm, scope=‘Deep/Deep_Network/Dnn_HiddenLayer_1’,…) api, 会

对于一个 [512, 256] 的 variable tensor, 叠加 BN 后新增的 var 为:

Deep/Deep_Network/Dnn_HiddenLayer_1/BatchNorm/beta, [256],<dtype: 'float32'>
Deep/Deep_Network/Dnn_HiddenLayer_1/BatchNorm/gamma, [256],<dtype: 'float32'>
Deep/Deep_Network/Dnn_HiddenLayer_1/BatchNorm/moving_mean, [256],<dtype: 'float32'>
Deep/Deep_Network/Dnn_HiddenLayer_1/BatchNorm/moving_variance, [256],<dtype: 'float32'>

3.3 training:bool 的计算差异

  • 训练时,均值、方差只基于该批次内数据做统计, 记为 mean, variance;
  • 推理时,均值、方差是基于所有批次(整个数据集)的期望, 记为 moving_mean, moving_variance.

Q: moving_mean, moving_variance 怎么算呢?
A: 严格统计所有数据的均值不现实(内存限制及样本总数不确定), 所以退而采用 滑动平均的迭代方法, 见下:
m o v i n g _ m e a n ( t ) = m o v i n g _ m e a n ( t − 1 ) ∗ d e c a y + m e a n _ t h i s _ b a t c h ∗ ( 1 − d e c a y ) (2) moving\_mean^{(t)} = \\ moving\_mean^{(t-1)} * decay + mean\_this\_batch * (1 - decay) \tag 2 moving_mean(t)=moving_mean(t1)decay+mean_this_batch(1decay)(2)
mean_this_batch 与 variance_this_batch 通过 tf.nn.moments(x) 同时算出.
式(2)的迭代通过 tensorflow.python.keras.layers.normalization.BatchNormalization._assign_moving_average(self, variable, value, momentum) 调用.

3.4 moving_mean 的更新机制

moving_mean 在训练时不参与 loss 计算, 那么按照最小拓扑子图策略, 它相应的计算 op 也就得不到执行, 但为了 predict 阶段用, 却仍要更新, 那如何保障执行呢?
以 keras.BatchNormalization 为例:

  1. _fused_batch_norm() 方法中有
    mean_update = self._assign_moving_average(self.moving_mean, mean,
    momentum)
    self.add_update(mean_update, inputs=True)
    语句.
  2. add_update() 方法是父类 Layer 的方法, 它会添加入参中的 op 到 self._updates 字段中, 可通过 updates() 方法返回, 同时该方法具有 @property 注解, 所以也可当字段用.
  3. 后续 optimize 阶段, 需要手动指定在计算 loss 前先执行这些 update op.

在这里插入图片描述
图. 清晰地看到两个相应的 update_op. 名字含 cond_ 是因为区分 training 的 true/false, 用到了 tf.condition.

注意 tf/keras update_op 的差异

  • tf.layers.Layer.call() 中有 _add_elements_to_collection(self.updates, ops.GraphKeys.UPDATE_OPS) 语句, 添加到了 graph_obj 的 相应 dict 中.
  • 但 keras 并没有做这件事, 所以需要手动明确地作维护.

四. LayerNormalization

以输入shape=[N,T,d] 为例, 计算均值 μ \mu μ.shape=[N,T,1]

4.1 对比

在输入x上计算均值的时候, BN在axis=0上计算, LN在axis=-1上计算.
可以类比一个N*d的矩阵, BN竖着算, LN 横着算.

4.2 keras / layer_norm

4.3 tf / layer_norm

def layer_norm(inputs, epsilon=1e-8, scope="layer_norm", params_shape=None):
    '''Applies layer normalization. See https://arxiv.org/abs/1607.06450.
    inputs: A tensor with 2 or more dimensions, where the first dimension has `batch_size`.
    epsilon: A floating number. A very small number for preventing ZeroDivision Error.
    scope: Optional scope for `variable_scope`.
      
    Returns:
      A tensor with the same shape and data dtype as `inputs`.
    '''
    with tf.variable_scope(scope, reuse=tf.AUTO_REUSE):
        # inputs    [N,T,d]
        inputs_shape = inputs.get_shape()
        if params_shape == None:
            params_shape = inputs_shape[-1:]  # [d]

        # [N,T,1]
        mean, variance = tf.nn.moments(inputs, [-1], keep_dims=True)
        # [d,]
        beta = tf.get_variable("beta", params_shape, initializer=tf.zeros_initializer())
        gamma = tf.get_variable("gamma", params_shape, initializer=tf.ones_initializer())
        utils.add_variable_for_rtp([beta, gamma])
        # inputs - mean, shape is [N,T,d] - [N,T,1]
        normalized = (inputs - mean) / ((variance + epsilon) ** 0.5)
        # [d,] * [N,T,d] + [d,]
        outputs = gamma * normalized + beta

    return outputs

参考

  1. 他人博客, 论文笔记-Batch Normalization
  2. sohu blog. 详解深度学习中的 Normalization,不只是 BN
  3. paper, Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
  4. 知乎, 透彻理解 BatchNorm
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值