原文链接

    简介
    Batch Normalization 简称 BN,是 2015 年提出的一种方法《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》,已经广泛被证明其有效性和重要性。虽然有些细节处理还解释不清其理论原因,但是实践证明好用才是真的好。
    原论文地址:https://arxiv.org/abs/1502.03167

    机器学习领域有个很重要的假设:IID 独立同分布假设,就是假设训练数据和测试数据是满足相同分布的,这是通过训练数据获得的模型能够在测试集获得好的效果的一个基本保障。而 BN 就是在深度神经网络训练过程中使得每一层神经网络的输入保持相同分布的。
    为什么深度神经网络随着网络深度加深,训练起来越困难,收敛越来越慢?这是个在 DL 领域很接近本质的好问题。很多论文都是解决这个问题的,比如 ReLU 激活函数,再比如 ResNet 等,BN 本质上也是解释并从某个不同的角度来解决这个问题的。

    一、Internal Covariate Shift 现象:
    从论文名字可以看出,BN 是用来解决 “Internal Covariate Shift” 问题的。首先来解释一下什么叫做 covariate shift 现象,这个指的是训练集的数据分布和预测集的数据分布不一致,这样的情况下如果我们在训练集上训练出一个分类器,肯定在预测集上不会取得比较好的效果。这种训练集和预测集样本分布不一致的问题就叫做 “covariate shift” 现象。
    对于深度学习这种包含很多隐层的网络结构,在训练过程中,因为各层参数不停在变化,所以每个隐层都会面临 covariate shift 的问题。也就是在训练过程中,隐层的输入分布老是变来变去,导致网络模型很难稳定的学规律,这就是所谓的 “Internal Covariate Shift”,Internal 指的是深层网络的隐层,是发生在网络内部的事情,而不是 covariate shift 问题只发生在输入层。

    二、Batch Normalization 由来:
    针对上述问题,于是提出了 BatchNorm 的基本思想:能不能让每个隐层节点的激活输入分布固定下来呢?这样就避免了 “Internal Covariate Shift” 问题了。
    启发来源:之前的研究表明如果在图像处理中对输入图像进行白化(Whiten)操作的话(所谓白化,就是对输入数据分布变换到 0 均值,单位方差的正态分布)那么神经网络会较快收敛。
    那么 BN 作者就开始推论:图像是深度神经网络的输入层,做白化能加快收敛,那么其实对于深度网络来说,其中某个隐层的神经元是下一层的输入,意思是其实深度神经网络的每一个隐层都是输入层,不过是相对下一层来说而已,那么能不能对每个隐层都做白化呢?所以 BN 可以理解为对深层神经网络每个隐层神经元的激活值做简化版本的白化操作。

    三、Batch Normalization 原理:
    BN 的基本思想其实相当直观:因为深层神经网络在做非线性变换前的激活输入值 x 随着网络深度加深或者在训练过程中,其分布逐渐发生偏移或者变动,之所以训练收敛慢,一般是整体分布逐渐往非线性函数的取值区间的上下限两端靠近,所以这导致反向传播时低层神经网络的梯度消失,这是训练深层神经网络收敛越来越慢的本质原因。
    而 BN 就是通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到均值为 0 方差为 1 的标准正态分布,其实就是把越来越偏的分布强制拉回比较标准的分布,这样使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,意思是这样让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。
    上面说得还是显得抽象,下面更形象地表达下这种调整到底代表什么含义:
    Batch Normalization详解 - 图1

    假设某个隐层神经元原先的激活输入 x 取值符合正态分布,正态分布均值是 - 2,方差是 0.5,对应上图中最左端的浅蓝色曲线,通过 BN 后转换为均值为 0,方差是 1 的正态分布(对应上图中的深蓝色图形)。这意味着输入 x 的取值正态分布整体右移 2(均值的变化),图形曲线更平缓了(方差增大的变化)。那么把激活输入 x 调整到这个正态分布有什么用?首先我们看下均值为 0,方差为 1 的标准正态分布代表什么含义:
    Batch Normalization详解 - 图2

    这意味着在一个标准差范围内,也就是说 64% 的概率 x 其值落在[-1,1]的范围内,在两个标准差范围内,也就是说 95% 的概率 x 其值落在了[-2,2]的范围内。那么这又意味着什么?我们知道,激活值 x=WU+B,U 是真正的输入,x 是某个神经元的激活值,假设非线性函数是 sigmoid,那么看下 sigmoid(x) 函数及其导数:
    Batch Normalization详解 - 图3

    Batch Normalization详解 - 图4

    所以经过 BN 后,均值是 0,方差是 1,那么意味着 95% 的 x 值落在了[-2,2]区间内,很明显这一段是 sigmoid(x) 函数接近于线性变换的区域,意味着 x 的小变化会导致非线性函数值较大的变化,也即是梯度变化较大,对应导数函数图中明显大于 0 的区域,就是梯度非饱和区。
    也就是说经过 BN 后,目前大部分 Activation 的值落入非线性函数的线性区内,其对应的导数远离导数饱和区,这样来加速训练收敛过程。

    到了这里,又会发现一个问题:如果都通过 BN,那么不就跟把非线性函数替换成线性函数效果相同了?我们知道,如果是多层的线性函数变换其实这个深层是没有意义的,因为多层线性网络跟一层线性网络是等价的。这意味着网络的表达能力下降了,这也意味着深度的意义就没有了。所以 BN 为了保证非线性的获得,对变换后的满足均值为 0 方差为 1 的 x 又进行了 scale 加上 shift 操作 (y=scale*x+shift),每个神经元增加了两个参数 scale 和 shift 参数,这两个参数是通过训练学习到的,意思是通过 scale 和 shift 把这个值从标准正态分布左移或者右移一点并长胖一点或者变瘦一点,每个实例挪动的程度不一样,这样等价于非线性函数的值从正中心周围的线性区往非线性区动了动。核心思想应该是想找到一个线性和非线性的较好平衡点,既能享受非线性的较强表达能力的好处,又避免太靠非线性区两头使得网络收敛速度太慢。当然,论文作者并未明确这样说。

    四、Batch Normalization 算法流程:
    上面是对 BN 的抽象分析和解释,具体在 Mini-Batch SGD 下做 BN 怎么做?其实论文里面这块写得很清楚也容易理解。
    在多层 CNN 里,BN 放在卷积层之后,激活和池化之前,以 LeNet5 为例:
    Batch Normalization详解 - 图5

    对于 Mini-Batch SGD 来说,一次训练过程里面包含 m 个训练实例,其具体 BN 操作就是对于隐层内每个神经元的激活值来说,进行如下变换:
    Batch Normalization详解 - 图6

    变换的意思是:某个神经元对应的原始的激活 x 通过减去 mini-Batch 内 m 个实例获得的 m 个激活 x 求得的均值 E(x) 并除以求得的方差 Var(x) 来进行转换。

    上文说过经过这个变换后会导致网络表达能力下降,为了防止这一点,每个神经元增加两个调节参数(scale 和 shift),这两个参数是通过训练来学习到的,用来对变换后的激活反变换,使得网络表达能力增强,即对变换后的激活进行如下的 scale 和 shift 操作,这其实是变换的反操作:
    Batch Normalization详解 - 图7

    这就是算法的关键之处了,每一个神经元 x 都会有这样的一对参数,当:
    Batch Normalization详解 - 图8

    这样的时候可以恢复出原始的某一层学习到的特征的,因此我们引入这个可以学习的参数使得我们的网络可以恢复出原始网络所要学习的特征分布,最后 BN 层的前向传导公式为:
    Batch Normalization详解 - 图9

    上面公式中的 m 指的是 mini-batch size。也就是每一个 batch 来做一个这样的 BN。代码对应也是四句话:
    Batch Normalization详解 - 图10

    五、BN 带来的好处:

    1. 没有它之前,需要小心的调整学习率和权重初始化,但是有了 BN 可以放心的使用大学习率;
    2. 极大提升了训练速度,收敛过程大大加快;
    3. Batch Normalization 本身上也是一种正则的方式,可以代替其他正则方式如 Dropout 等。

    六、BN 的缺陷:
    Batch Normalization 中的 batch 就是批量数据,即每一次优化时的样本数目,通常 BN 网络层用在卷积层后,用于重新调整数据分布。假设神经网络某层一个 batch 的输入为 X=[x1,x2,…,xn],其中 xi 代表一个样本,n 为 batch size。
    当 batch 值很小时,计算的均值和方差不稳定。研究表明对于 ResNet 类模型在 ImageNet 数据集上,batch 从 16 降低到 8 时开始有非常明显的性能下降。所以 BN 不适应于当训练资源有限而无法应用较大的 batch 的场景。

    七、BN的具体实施和变种:

    对于CNN,BN的操作是在各个特征维度之间单独进行,也就是说各个通道是分别进行Batch Normalization操作的。
    如果输出的blob大小为(N,C,H,W),那么在每一层normalization就是基于
    NHW个数值进行求平均以及方差的操作**,记住这里我们后面会进行比较。

    变种:
    Normalization思想非常简单,为深层网络的训练做出了很大贡献。因为有依赖于样本数目的缺陷,所以也被研究人员盯上进行改进。说的比较多的就是Layer Normalization与Instance Normalization,Group Normalization了。
    前面说了Batch Normalization各个通道之间是独立进行计算,如果抛弃对batch的依赖,也就是每一个样本都单独进行normalization,同时各个通道都要用到,就得到了Layer Normalization
    跟Batch Normalization仅针对单个神经元不同,Layer Normalization考虑了神经网络中一层的神经元。如果输出的blob大小为(N,C,H,W),那么在每一层Layer Normalization就是基于CHW个数值进行求平均以及方差的操作
    Layer Normalization把每一层的特征通道一起用于归一化,如果每一个特征层单独进行归一化呢?也就是限制在某一个特征通道内,那就是instance normalization了
    如果输出的blob大小为(N,C,H,W),那么在每一层Instance Normalization就是基于H*W个数值进行求平均以及方差的操作。对于风格化类的图像应用,Instance Normalization通常能取得更好的结果,它的使用本来就是风格迁移应用中提出。
    Group Normalization是Layer Normalization和Instance Normalization 的中间体, Group Normalization将channel方向分group,然后对每个Group内做归一化,算其均值与方差。
    如果输出的blob大小为(N,C,H,W),将通道C分为G个组,那么Group Normalization就是基于GHW个数值进行求平均以及方差的操作。我只想说,你们真会玩,要榨干所有可能性。
    在Batch Normalization之外,有人提出了通用版本Generalized Batch Normalization,有人提出了硬件更加友好的L1-Norm Batch Normalization等,不再一一讲述。
    另一方面,以上的Batch Normalization,Layer Normalization,Instance Normalization都是将规范化应用于输入数据x,Weight normalization则是对权重进行规范化,感兴趣的可以自行了解,使用比较少,也不在我们的讨论范围。
    这么多的Normalization怎么使用呢?有一些基本的建议吧,不一定是正确答案。
    (1) 正常的处理图片的CNN模型都应该使用Batch Normalization。只要保证batch size较大(不低于32),并且打乱了输入样本的顺序。如果batch太小,则优先用Group Normalization替代。
    (2)对于RNN等时序模型,有时候同一个batch内部的训练实例长度不一(不同长度的句子),则不同的时态下需要保存不同的统计量,无法正确使用BN层,只能使用Layer Normalization。
    (3) 对于图像生成以及风格迁移类应用,使用Instance Normalization更加合适。

    注:参考知乎各位大佬深度学习中 Batch Normalization 为什么效果好?和郭耀华大神【深度学习】深入理解 Batch Normalization 批标准化
    https://blog.csdn.net/qq_42823043/article/details/89765194