引言
本文探讨了BN和LN,BN适合于CNN;而LN适合于RNN。虽然我们现在还不知道BN为什么有效,但是重点是它有效,我们就使用它。
Batch Normalization
Batch Normalization(批归一化,以下简称BN)是由Sergey Ioffe1等人提出来的,是一个广泛使用的深度神经网络训练的技巧,它不仅可以加快了模型的收敛速度,还可以简化初始化要求,即可以使用较大的学习率。
概念
原文提出了一些概念,用于解释为什么BN有用,但是
covariate shift与 internal covariate shift
在原文 1中,以分布稳定性角度,covariate shift描述的是模型输入分布变化的现象。
internal covariate shift 说的是在深度神经网络隐藏层之间输入分布变化的现象。
从模型的角度看,训练数据和测试数据分布相差较大,也是一种covariate shift。
算法描述
原文中算法描述如下:

其中是训练批次
中的所有样本,该算法可学习的参数是
和
;输出是每个样本经过BN后的结果。
共四部,前三步分别是计算批次内样本的均值、方差、进行标准化。
最后一步是反标准化操作,将标准化后的数据再扩展和平移。为了让模型自己去学习是否需要标准化,以及多大程度。其中是一个很小的常数,防止分母为零。
上面说的都是针对训练数据的,对于测试数据,或者说线上数据应该怎么做呢?
因为线上数据可能一次只输入一条,因此无法计算均值和方差。原文的做法是保存训练数据每个批次的均值和方差,主要思想是求所有批次得到的均值和方差的期望,使用的是指数移动平均值(EMA),着重考虑最近迭代的均值和方差。
算法实现
下面我们用一个回归任务来看一下批归一化的效果。
以下示例参考了莫凡Python2

以函数画图,增加了一些噪音。
然后我们构造一个深层的网络来拟合这些数据,用到了上面自定义的批归一化实现。
打印网络结构:
我们构建了两个网络实例,一个使用了批归一化,另一个没有使用。作为对比。
训练,并画图。

L0是输入层,L1到L8是隐藏层,绘画的是每次迭代各个层输入值的分布情况。
红色是无BN的网络,蓝色的有BN的网络。
PreAct是激活之前的值,Act是激活之后的值。可以看到,无BN的网络,激活函数为ReLU的情况话,所有网络的输出基本不变,看上去像是死掉了。
而使用了BN的网络,每层的分布较为分散,没有集中在某处,经过BN激活之后的值也存在很多大于零的部分。
下面画出两个网络拟合曲线和损失曲线。


为什么BN有用
BN使得深层神经网络更易于训练,但是具体为什么,现在还没有定论,不过存在一些假设。
- 假设1:原文1的作者猜测是因为BN减少了 internal covariate shift(ICS),使得神经网络更易于训练。
❌ Shibani Santurkar3等人通过实验证明,这种表现和ICS无关。 - 假设2:BN通过2个可学习的参数调整隐藏层的输入分布来使优化器更好地工作。
❓ 这个假设强调是因为参数之间的相互依赖性,让优化任务更加困难,但是没有确凿的证据。 - 假设3:BN重新定制了底层的优化问题,使之更加平滑且稳定。
❓ 这是最新的研究,并且还未有人提出异议。他们提供了一部分理论支持,但是一些基本问题仍然未得到解答,比如BN是如何帮助泛化的。
Layer Normalization
Jimmy4基于Batch Normalization提出了Layer Normalization(层归一化,以下简称LN)。
原文指出,如果将BN应用到RNN中会出现一些问题,由于NLP任务中句子的长度是不固定的,如果使用BN,会导致每个时间步的统计量不同。可能某个时间步,某个句子没有输入了;更糟糕的是,BN无法适应于在线学习(每个批次只有一个样本)和批次数量过小的情况。
如果说BN是针对整个批次计算的,那么LN就是针对一个样本所有特征计算的。

或者说BN是对一个隐藏层的所有神经元进行归一化。
算法描述
类似BN,但是是对每个样本自身进行计算,因此训练时和测试时是一样的,不需要计算EMA。
令是某个时间步LN层的H大小的输入向量表示,LN通过下面的公式将
进行归一化:
其中就是LN层的输出,
是点乘操作,
和
是输入各个维度的均值和方差,
和
是两个可学习的参数,和
的维度相同。
在标准的RNN中,在每个时间步中,RNN单元的总输入的平均值要么增加,要么减小,导致梯度爆炸或消失。应用LN后,归一化操作重新缩放所有的总输入到某个层中,从而保证更稳定的隐藏层到隐藏层的传递。
算法实现
参考
- Batch Normalization: Accelerating Deep Network Training b y Reducing Internal Covariate Shift ↩︎ ↩︎ ↩︎
- 莫凡Python ↩︎
- How Does Batch Normalization Help Optimization? ↩︎
- Layer Normalization ↩︎
















