【八股文-机器学习】BN的原理和计算过程

BN 原理

训练深层网络时,层内神经元间、层间神经元间激活值的量级差别较大,不满足独立同分布时,模型不稳定不容易收敛(直观来看解决方案要么自适应地调节每一层甚至每一个神经元的学习率,要么把神经元激活值规范化一下)。

批规范化(Batch Normalization,BN):在minibatch维度上在每次训练iteration时对隐藏层进行归一化
标准化(Standardization):对输入数据进行归一化处理
正则化(Regularization):通常是指对参数在量级和尺度上做约束,缓和过拟合情况,L1 L2正则化,通常是加在loss函数中的正则项,又或者dropout。

隐藏层是指位于输入层和输出层之间的部分。

在训练的每次iteration,BN会对隐藏层神经元的激活值做规范化(减均值,除标准差,这个均值和标准差是对当前的minibatch求解得到的).自然地,如果minibatch的尺寸是1的话,训练的时候学习不到任何东西,因为均值是它本身,方差是1,规范化之后神经元的值会变成0.但是,如果使用大规模的minibatch,BN是非常有效的.

BN的思想就是将激活前隐层的值x变为BN(x),x减去均值除以标准差,这样隐层状态不再发散,之后的激活值也更规范.
图片说明

但有时候处理完之后的分布不一定是我们想要的(这样的规范反而会使网络表达能力下降),所以乘上缩放系数γ,加上偏移β。

BN 的差异

全连接层和卷积层的差异

  1. 全连接层BN
  • 全连接层BN通常会在线性变换之后激活之前进行
  • 各个神经元间的均值和方差不共享,需要在mini-batch中计算各自的均值方差
  • γ和β是当前层所有神经元共享的标量。
  1. 卷积层BN
  • 卷积层BN通常会在卷积之后,激活之前进行
  • 多个卷积核卷积生成多通道的特征图,每个通道都要单独处理,各通道有自己的均值方差,γ,β,每个通道所有神经元共享均值方差(mini-batch数据卷积后m×w×h个神经元求均值方差)

训练和测试的差异

  1. 训练
  • 每次iteration都要根据隐层值计算新的均值方差,以当前的mini-batch为一个单位
  1. 测试
  • BN用的均值和方差是固定的常量(这个常量是在模型训练时每次iteration通过移动平均法更新的全局量,模型训练结束,这个全局量就是考虑了全量训练数据的常量了)。
  1. 为什么训练的时候不用全量训练数据的均值和方差常量呢?
  • 训练的时候为了模型稳定,需要在当前batch数据中维持隐藏层激活值的稳定,因此不用考虑别的数据,而且不同batch数据间的均值和方差可能差别较大,这个差别实际上能够增加模型鲁棒性,一定程度上减少过拟合,如果在训练的时候就用全量训练数据的均值和方差可能会加剧过拟合。

多卡的差异

因为BN层的归一化操作一般是以单块GPU为单位进行计算的,所以对于大batch,我们使用多卡时,BN的mini-batch需要扩充到多个GPU,也就是SyncBN的作用。同步BN帮助我们同步多卡的信息。

  1. 什么时候会比较需要同步?
    单GPU上的batch size比较小的时候,比如像分割这种任务,大分辨率图输入从而非常消耗显存,单卡上的batch很小,因此需要用多卡来同步BN。

  2. 同步的过程是怎样的?
    首先我们对于每张卡计算出均值方差的统计量,然后收集所有卡的统计量计算出一个统一的mini-batch的均值方差然后再让每张卡根据计算出来的均值方差进行BN操作。

  3. 同步需要几步?
    正常来说,先同步均值,再同步方差,但其实是可以同时同步的。
    图片说明

BN 代码实现

  1. 代码仿照pytorch

    # 以 BatchNorm2d 为例
    # mean_val, var_val 不为None时,不对输入进行统计,而直接用传进来的均值、方差
    def dummy_bn_forward(x, bn_weight, bn_bias, eps, mean_val=None, var_val=None):
     if mean_val is None:
         mean_val = x.mean([0, 2, 3])
     if var_val is None:
         # 这里需要注意,torch.var 默认算无偏估计,因此需要手动设置unbiased=False
         var_val = x.var([0, 2, 3], unbiased=False)
    
     x = x - mean_val[None, ..., None, None]
     x = x / torch.sqrt(var_val[None, ..., None, None] + eps)
     x = x * bn_weight[..., None, None] + bn_bias[..., None, None]
     return mean_val, var_val, x
    inputs_mean, inputs_var, _ = dummy_bn_forward(
         inputs, bn_layer.weight, bn_layer.bias, bn_layer.eps
     )
    n = inputs.numel() / inputs.size(1)
    # 更新 running_var 和 running_mean 计算移动平均值,这个是用于测试的
    running_var = running_var * (1 - momentum) + momentum * inputs_var * n / (n - 1)
    running_mean = running_mean * (1 - momentum) + momentum * inputs_mean

值得注意的是,当track_running_stats=True时, 才会使用移动平均值来进行eval,否则也会手动自己计算方差和均值。

  1. 如何更新系数图片说明

这实际上就是bn weights和bias两个参数,一般通道多少个就会是多少维,因为每个通道共享。

BN 的改进

图片说明

  1. layer normalization
  • 层规范化LayerNormalization,LN是对当前隐藏层整层的神经元进行规范化
  • 对于[B,C,W,H]这样的训练数据而言,BN是在B,W,H维度求均值方差进行规范化,而LN是对C,W,H维度求均值方差进行规范化(当前层一共会求batchsize个均值和方差,每个batchsize分别规范化),这样LN就与batchsize无关了,小的batchsize也可以进行归一化训练,LN也可以很轻松地用到RNN中。
  • LN与batchsize无关,在小batchsize上效果可能会比BN好,但是大batchsize的话还是BN效果好。
  1. instance normalization
  • BN注重对batchsize数据归一化,但是在图像风格化任务中,生成的风格结果主要依赖于某个图像实例,所以对整个batchsize数据进行归一化是不合适的,因而提出了IN只对HW维度进行归一化。
  • 在图像风格化任务中,更合适使用IN来做规范化。IN只对W,H维度求均值方差进行归一化。
  1. group normalization
    图片说明
  • BN是最传统的,如果batchsize允许够大的话,用在CNN中的效果依然是最好的;LN适合RNN;IN适合图像风格化任务;GN更适合小batchsize的CNN训练
  1. cross-iteration batch normalization
  • 作者认为连续几次训练iteration中模型参数的变化是平滑的
  • 作者将前几次iteration的BN参数保存起来,当前iteration的BN参数由当前batch数据求出的BN参数和保存的前几次的BN参数共同推算得出(顾名思义 Cross-Interation BN)
  • 训练前期BN参数记忆长度短一些,后期训练稳定了可以保存更长时间的BN参数来参与推算,效果更好
  • 可以将CBN粗糙地总结为 “前几次训练的BN(LN/GN应该都可以)参数” + 当前batch数据计算的BN(LN/GN)参数 来计算得出当前次训练iteration真正的CBN参数。
全部评论

相关推荐

你背过凌晨4点的八股文么:简历挂了的话会是流程终止,像我一样
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客企业服务