BatchNorm

前言

独立同分布i.i.d.

百度百科中解释为:在概率统计理论中,指随机过程中,任何时刻的取值都为随机变量,如果这些随机变量服从同一分布,并且互相独立,那么这些随机变量是独立同分布。如果随机变量X1和X2独立,是指X1的取值不影响X2的取值,X2的取值也不影响X1的取值且随机变量X1和X2服从同一分布,这意味着X1和X2具有相同的分布形状和相同的分布参数,对离随机变量具有相同的分布律,对连续随机变量具有相同的概率密度函数,有着相同的分布函数,相同的期望、方差。如实验条件保持不变,一系列的抛硬币的正反面结果是独立同分布。

关于独立同分布,西瓜书这样解释道:输入空间$X$中的所有样本服从一个隐含未知的分布,训练数据所有样本都是独立地从这个分布上采样而得。

好了,那为啥非要有这个假设呢?

我们知道,机器学习就是利用当前获取到的信息(或数据)进行训练学习,用以对未来的数据进行预测、模拟。所以都是建立在历史数据之上,采用模型去拟合未来的数据。因此需要我们使用的历史数据具有总体的代表性。

为什么要有总体代表性?我们要从已有的数据(经验) 中总结出规律来对未知数据做决策,如果获取训练数据是不具有总体代表性的,就是特例的情况,那规律就会总结得不好或是错误,因为这些规律是由个例推算的,不具有推广的效果。而通过独立同分布的假设,就可以大大减小训练样本中个例的情形。

由于现在的机器学习方向的内容已经变得比较广,存在不少机器学习问题并不要求样本同分布,比如一些发表在机器学习方向上的online算法就对数据分布没啥要求,关心的性质也非泛化性。另外,比如 Naive Bayes 模型就建立在特征彼此独立的基础之上,而Logistic Regression 和 神经网络 则在非独立的特征数据上依然可以训练出很好的模型。在不少问题中要求样本(数据)采样自同一个分布是因为希望用训练数据集训练得到的模型可以合理用于测试集,使用同分布假设能够使得这个做法解释得通。但独立同分布的数据可以简化常规机器学习模型的训练、提升机器学习模型的预测能力,已经是一个共识。

因此,在把数据喂给机器学习模型之前,“白化(whitening)”是一个重要的数据预处理步骤。白化一般包含两个目的:
(1)去除特征之间的相关性 —> 独立;
(2)使得所有特征具有相同的均值和方差 —> 同分布。

白化最典型的方法就是PCA,可以参考阅读 PCAWhitening

问题

机器学习领域有个很重要的假设:IID独立同分布假设,就是假设训练数据和测试数据是满足相同分布的,这是通过训练数据获得的模型能够在测试集获得好的效果的一个基本保障。

那BatchNorm的作用是什么呢?BatchNorm就是在深度神经网络训练过程中使得每一层神经网络的输入保持相同分布的。

思考一个问题:为什么传统的神经网络在训练开始之前,要对输入的数据做Normalization?原因在于神经网络学习过程本质上是为了学习数据的分布,一旦训练数据与测试数据的分布不同,那么网络的泛化能力也大大降低;另一方面,一旦在mini-batch梯度下降训练的时候,每批训练数据的分布不相同,那么网络就要在每次迭代的时候去学习以适应不同的分布,这样将会大大降低网络的训练速度,这也正是为什么我们需要对所有训练数据做一个Normalization预处理的原因。

为什么深度神经网络随着网络深度加深,训练起来越困难,收敛越来越慢?这是个在DL领域很接近本质的好问题。很多论文都是解决这个问题的,比如ReLU激活函数,再比如Residual Network,BN本质上也是解释并从某个不同的角度来解决这个问题的。

“Internal Covariate Shift”问题

《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》论文名字可以看出,BN是用来解决“Internal Covariate Shift”问题的,那么首先得理解什么是“Internal Covariate Shift”?

论文首先说明Mini-Batch SGD相对于One Example SGD的两个优势:梯度更新方向更准确;并行计算速度快;(为什么要说这些?因为BatchNorm是基于Mini-Batch SGD的,所以先夸下Mini-Batch SGD,当然也是大实话);然后吐槽下SGD训练的缺点:超参数调起来很麻烦。(作者隐含意思是用BN就能解决很多SGD的缺点)

第一种理解方式为:这篇博客引入covariate shift的概念:如果ML系统实例集合$(X,Y)$中的输入值$X$的分布老是变,这不符合IID假设,网络模型很难学到稳定的规律,这不得引入迁移学习才能搞定吗,我们的ML系统还得去学习怎么迎合这种分布变化啊。对于深度学习这种包含很多隐层的网络结构,在训练过程中,因为各层参数不停在变化,所以每个隐层都会面临covariate shift的问题,也就是在训练过程中,隐层的输入分布老是变来变去,这就是所谓的“Internal Covariate Shift”,Internal指的是深层网络的隐层,是发生在网络内部的事情,而不是covariate shift问题只发生在输入层。

第二种理解方式:知乎上的回答为:大家都知道在统计机器学习中的一个经典假设是“源空间(source domain)和目标空间(target domain)的数据分布(distribution)是一致的”。如果不一致,那么就出现了新的机器学习问题,如,transfer learning/domain adaptation等。而covariate shift就是分布不一致假设之下的一个分支问题,它是指源空间和目标空间的条件概率是一致的,但是其边缘概率不同,即:即对所有的$x \in \scr X$,$P_s(Y|X=x)=P_t(Y|X=x)$,但是$P_s(X)\not= P_t(X)$。大家细想便会发现,的确,对于神经网络的各层输出,由于它们经过了层内操作作用,其分布显然与各层对应的输入信号分布不同,而且差异会随着网络深度增大而增大,可是它们所能“指示”的样本标记(label)仍然是不变的,这便符合了covariate shift的定义。由于是对层间信号的分析,也即是“internal”的来由。

同上面的第二种理解方式一样,这篇博客提到,对于covariate shift的定义我们讲的规范一点:假设$q_1(x)$是测试集中一个样本点的概率密度,$q_0(x)$是是训练集中一个样本点的概率密度。最终我们估计一个条件概率密度$p(y|x,\theta)$,它由$x$和一组参数$\theta=(\theta_1,\theta_2,…..,\theta_m)$所决定。对于一组参数来说,对应$loss(\theta)$函数评估性能的好坏。综上,当我们找出在$q_0(x)$分布上最优的一组$\theta’$时,能否保证$q_1(x)$上测试时也最好呢?传统机器学习假设训练集和测试集是独立同分布的,即$q_1(x)=q_1(x)$,所以可以推出最优$\theta’$依然可以保证$q_1(x)$最优。但现实当中这个假设往往不成立,伴随新数据产生,老数据会过时,当$q_0(x)$不再等于$q_1(x)$时,就被称作covariate shift。

综上,我对“Internal Covariate Shift”问题的理解为:

  • 输入值$x$不满足独立同分布而一直处于变化状态,在网络训练过程中,随着不同$x$的输入,隐层单元要学习到的特征一直变来变去。因此收敛速度很慢,甚至可能低层输入的变化一直趋向于变大或者变小,导致高层落入饱和区,使得学习过早停止,导致无法收敛。BatchNorm就是在深度神经网络训练过程中使得每一层神经网络的输入保持相同分布的。
  • 神经网络的本质是学习数据的分布。当源空间与目标空间的数据分布不一致的时候。网络学习到的数据分布不适用于目标空间的数据分布(在迁移学习中把源空间理解为已有的标记数据(训练集),目标空间理解为未标记数据(测试集))。也就是说,经过层间相互作用,网络学习到的分布(可以粗略理解为输出层前一层的输出)不同于原始训练集的分布,但是给定了$x$之后,他们的类标是一致的。这样的后果是对于训练样本可能结果很好,但是对于测试集泛化能力很差(可以理解为此时学习到的特征只是对训练集的分布进行了特殊映射,使得其条件概率一致,但是由于源空间和目标空间的数据分布不一致,无法用来表征测试集)。

Normalization 的通用框架与基本思想

我们以神经网络中的一个普通神经元为例。神经元接收一组输入向量$x=(x_1, x_2, \cdots, x_d)$ 通过某种运算后,输出一个标量值:

由于 ICS 问题的存在, $x$的分布可能相差很大。要解决独立同分布的问题,“理论正确”的方法就是对每一层的数据都进行白化操作。然而标准的白化操作代价高昂,特别是我们还希望白化操作是可微的,保证白化操作可以通过反向传播来更新梯度。

因此,以 BN 为代表的 Normalization 方法退而求其次,进行了简化的白化操作。基本思想是:在将$x$送给神经元之前,先对其做平移和伸缩变换, 将$x$的分布规范化成在固定区间范围的标准分布。

通用变换框架就如下所示:

我们来看看这个公式中的各个参数。

(1)$\mu$是平移参数(shift parameter), $\sigma$是缩放参数(scale parameter)。通过这两个参数进行 shift 和 scale 变换:$\hat x=\frac{x-\mu}{\sigma}$得到的数据符合均值为 0、方差为 1 的标准分布。

(2)$b$是再平移参数(re-shift parameter),$g$是再缩放参数(re-scale parameter)。将 上一步得到的$\hat x$进一步变换为:

最终得到的数据符合均值为$b$、方差为$g^2$的分布。

第一步得到标准分布,可以使得对于每个隐层神经元,把逐渐向非线性函数映射后向取值区间极限饱和区靠拢的输入分布强制拉回到均值为0方差为1的比较标准的正态分布,使得非线性变换函数的输入值落入对输入比较敏感的区域,以此避免梯度消失问题。因为梯度一直都能保持比较大的状态,所以很明显对神经网络的参数调整效率比较高,就是变动大,就是说向损失函数最优值迈动的步子大,也就是说收敛地快。BN说到底就是这么个机制,方法很简单,道理很深刻。

说好的处理 ICS,第一步都已经得到了标准分布,第二步怎么又给变走了?

答案是——为了保证模型的表达能力不因为规范化而下降。

我们可以看到,第一步的变换将输入数据限制到了一个全局统一的确定范围(均值为 0、方差为 1)。低层神经元可能很努力地在学习,但不论其如何变化,其输出的结果在交给高层神经元进行处理之前,将被粗暴地重新调整到这一固定范围。

难道我们底层神经元人民就在做无用功吗?

所以,为了尊重底层神经网络的学习结果,我们将规范化后的数据进行再平移和再缩放,使得每个神经元对应的输入范围是针对该神经元量身定制的一个确定范围(均值为$b$、方差为$g^2$)。rescale 和 reshift 的参数都是可学习的。这就使得 Normalization 层可以学习如何去尊重底层的学习结果。

均值$b$、方差$g^2$的学习过程,可以看成是神经网络中$w$和$b$的学习过程,使用的都是链式法则。

Normalization再平移和再缩放除了充分利用底层学习的能力,另一方面的重要意义在于保证获得非线性的表达能力。Sigmoid 等激活函数在神经网络中有着重要作用,通过区分饱和区和非饱和区,使得神经网络的数据变换具有了非线性计算能力。而第一步的规范化会将几乎所有数据映射到激活函数的非饱和区(线性区),仅利用到了线性变化能力,从而降低了神经网络的表达能力。而进行再变换,则可以将数据从线性区变换到非线性区,恢复模型的表达能力。

sigmoid 两侧都有饱和区,relu 系列的饱和区在左侧,使用 relu 函数代替 sigmoid 函数只能缓解,不能避免。非线性是一个提升模型表达能力的很好的性质,但过早的落入饱和区使得学习不充分。

那么问题又来了——经过这么的变回来再变过去,会不会跟没变一样?

不会。因为,再变换引入的两个新参数 $g$ 和 $b$,可以表示旧参数$x$作为输入的同一族函数,但是新参数有不同的学习动态。在旧参数中,$x$的均值取决于下层神经网络的复杂关联;但在新参数中,$y=g \cdot \hat x + b$的均值仅由$b$来确定,去除了与下层计算的密切耦合。新参数很容易通过梯度下降来学习,简化了神经网络的训练。

总结:Normalization核心思想应该是想找到一个线性和非线性的较好平衡点,既能享受非线性的较强表达能力的好处,充分利用底层学习的能力,又避免太靠非线性区两头使得网络收敛速度太慢。

那么还有一个问题——这样的 Normalization 离标准的白化还有多远?

标准白化操作的目的是“独立同分布”。独立就不说了,暂不考虑。变换为均值为$b$、方差为$g^2$的分布,也并不是严格的同分布,只是映射到了一个确定的区间范围而已。(所以,这个坑还有得研究呢!)

BatchNorm的前向计算

训练过程

假设对于一个深层神经网络来说,其中两层结构如下:

对每个隐层神经元的激活值做BN,可以想象成每个隐层又加上了一层BN操作层,它位于$z^l=Wa^{l-1}+b$激活值获得之后,非线性函数变换之前,其图示如下:

BN的具体操作流程,如论文中描述的一样,如下图所示。

下面对图中的公式进行详细说明

首先,对于Mini-Batch SGD来说,一次训练过程里面包含$m$个训练实例,也就是说这里的$m$指的是batshsize等于$m$,这里的$B$指的是某一个batch,$x_i$并不是该层的输入,而是$t$层的$z^l=Wa^{l-1}+b$。

对于公式$\mu_B=\frac{1}{m}\sum_{i=1}^m x_i$。若该层是DNN层,该公式的含义是将一个batch之内所有输入$x_i$求和(这个时候$x_i$是一个列向量),也就是说一个batch之内所有输入的相同位置对应同一个均值,$m$的大小也恰好等于batchsize的大小。若该层是CNN层,该公式的含义是将一个batch中所有输入$x_i$相同位置的矩阵中所有分量分别求和(这个时候$x_i$是一个三维张量),也就是在一个batch之内相同位置的特征图对应同一个均值,$m$的大小为$batchsize \times out_w \times out_h$,其中$out_w \times out_h$为一个输出特征图大小。对于$\sigma_B^2$公式的解释相同,这里不再赘述。

对于公式$\hat{x}_i = \frac{x_i-\mu_B}{\sqrt{\sigma_B^2 + \varepsilon}}$,若该层是DNN,则将每一个输入$x_i$向量中每一个分量减去其对应的平均值除以其对应的方差;若该层是CNN,则是每一个输入$x_i$张量中每一个分量都减该输入的对应的平均值除以其对应的方差。其中$\varepsilon$的作用是防止分母等于0。

上文说过经过这个变换后某个神经元的激活x形成了均值为0,方差为1的正态分布,目的是把值往后续要进行的非线性变换的线性区拉动,增大导数值,增强反向传播信息流动性,加快训练收敛速度。但是这样会导致网络表达能力下降,为了防止这一点,每个神经元增加两个调节参数(scale和shift),这两个参数是通过训练来学习到的,用来对变换后的激活反变换,使得网络表达能力增强,即对变换后的激活进行如下的scale和shift操作,这其实是变换的反操作:$y_i=\gamma\hat{x}_i + \beta$,其中$\hat{x}_i$的含义与上个公式的解释相同,这里不在赘述。

上面的文字可能这里描述的很不清晰,因此下面分别用文字和公式的形式进行详细说明。

对于DNN,$x_i$与求均值、方差的示意图如下:

对于CNN,$x_i$与求均值、方差的示意图如下:

DNN

对于DNN:图中的公式可以写成下面的形式,假设$l$为第$l$个神经元的输出,则

CNN

对于CNN:图中的公式可以写成下面的公式,假设$l$为第$l$个卷积核输出,则

推理(Inference)过程

BN在训练的时候可以根据Mini-Batch里的若干训练实例进行激活数值调整,但是在推理(inference)的过程中,很明显输入就只有一个实例,看不到Mini-Batch其它实例,那么这时候怎么对输入做BN呢?因为很明显一个实例是没法算实例集合求出的均值和方差的。这可如何是好?

既然没有从Mini-Batch数据里可以得到的统计量,那就想其它办法来获得这个统计量,就是均值和方差。可以用从所有训练实例中获得的统计量来代替Mini-Batch里面$m$个训练实例获得的均值和方差统计量,因为本来就打算用全局的统计量,只是因为计算量等太大所以才会用Mini-Batch这种简化方式的,那么在推理的时候直接用从所有训练实例中获得的统计量即可。

决定了获得统计量的数据范围,那么接下来的问题是如何获得均值和方差的问题。很简单,因为每次做Mini-Batch训练时,都会有那个Mini-Batch里m个训练实例获得的均值和方差,现在要全局统计量,只要把每个Mini-Batch的均值和方差统计量记住,然后对这些均值和方差求其对应的数学期望即可得出全局统计量,即:

有了均值和方差,每个隐层神经元也已经有对应训练好的Scaling参数和Shift参数,就可以在推导的时候对每个神经元的激活数据计算NB进行变换了,在推理过程中进行BN采取如下方式:

这个公式其实和训练时$y_i=\gamma^{(k)}\hat{x}_i + \beta$是等价的,通过简单的合并计算推导就可以得出这个结论。那么为啥要写成这个变换形式呢?我猜作者这么写的意思是:在实际运行的时候,按照这种变体形式可以减少计算量,为啥呢?因为对于每个隐层节点来说,$\frac{\gamma}{\sqrt{Var[x]+\varepsilon}}$与$\frac{\gamma E[x]}{\sqrt{Var[x]+\varepsilon}}$都是固定值,这样这两个值可以事先算好存起来,在推理的时候直接用就行了,这样比原始的公式每一步骤都现算少了除法的运算过程,乍一看也没少多少计算量,但是如果隐层节点个数多的话节省的计算量就比较多了。

但是在darknet中,还是使用的$y_i=\gamma^{(k)}\hat{x}_i + \beta$,并没有采用简化的形式。

滑动平均

这里的$\bar x_m$表示前$m$个数据的平均值。

在darknet中,为了运算的的方便,直接将$\frac{1}{m}=0.01$。若不简化的话,需要从$\bar x_1、\bar x_2$一直迭代到$\bar x_m$,迭代过程中$m$的值不同,运算繁琐。

反向传播

由之前的反向传播公式已知,现在已知的是损失函数对$y_i$的偏导数$\dfrac{\partial J}{\partial y_i}$,我们要求的是$\dfrac {\partial J} {\partial\gamma}$和$\dfrac {\partial J} {\partial\beta}$,另外为了保证反向传播可以继续回传,我们还要求$\dfrac {\partial L} {\partial x_{i}}$。

$\gamma$与$\beta$偏导

在推导公式之前,需要说明的是,为了推导方便,我们把一个batch内的第$i$个输入记为$x_i$。$B$表示不同的batch,对于DNN而言,$x_i$、$\widehat {x}_{i}$与$y_i$均为向量,对于CNN而言,均是三维张量。

首先,我们求$\dfrac {\partial J} {\partial\gamma}$

上面两个式子都涉及到batch中的$m$个样本的累加,因为$m$个样本的$y_i$对$β、γ$都有影响。不好理解的话,如下图所示,根据复合函数求导的法则,$J$对$\gamma$求导要对这$m$个支路分别求偏导再相加。

DNN

对于DNN,设$i$代表一个batch内的第$i$个样本,$l$为第$l$个神经元的输出

CNN

对于CNN,设$i$代表一个batch内的第$i$个样本,$l$为第$l$卷积核,$out_h,out_w$分别为一个卷积核输出的长和宽。$\delta$为损失函数关于$y$的导数,则有下式

总结:对比这几个式子,以darknet源代码为例,为了保证代码通用性,使用了sum_array函数对一个神经元输出求和,在DNN中设置输出的大小为1,在CNN中设置输出的大小为$out_w \times out_h$。

$x_i$偏导

直接求$\dfrac {\partial J} {\partial x_{i}}$的步骤比较长,不直观,且这是一个复合函数,其中$\mu_B(x)、\sigma_B^2(x)、\widehat {x}_i(x)$均与$x$有关,因此我们首先求$\dfrac {\partial J} {\partial \widehat {x}_i}、\dfrac {\partial J} {\partial \mu}、\dfrac {\partial J} {\partial \sigma_B^2}$。如果不好理解,那么根据链式法则,可以画出下图,需要注意的是$\mu_B、\sigma_B^2$和所有的$x_i$均有关,且当求$\widehat x_i$的时候,所有的$\mu_B、\sigma_B^2$均是同一个值,在画图的时候,将这些相同的值画到一个节点上。

注意:在对$\sigma_B^2$求导的时候,式子中除了$\sigma_B^2$,其余的变量如$x_i、\mu_B$均看成是常数。并且这个时候只是对$\sigma_B^2$求导,不需要考虑$\mu_B、\sigma_B^2$是关于$x_i$的函数。

注意:在darknet中,对于这个式子的求解省略了第二项。猜测是因为第二项比较小。

下面,就可以求$\dfrac {\partial L} {\partial x_{i}}$,在求导过程中,需要用到复合函数求导的方法,如下图

也就得到了论文中的结果:

DNN

对于DNN,反向传播推导过程如下,$B$为某个batch,$l$为第$l$个神经元的输出,因为本人矩阵求导法则记得不是清楚,所以下面所有的公式中的分量均是标量。

下面,就可以求$\dfrac {\partial L} {\partial x_{i,l}}$

CNN

对于CNN,反向传播推导过程如下,$B$为某个batch,$l$为第$l$个卷积核的输出,$j,k$分别代表一个卷积核输出的特征图的长和宽的下标。

下面,就可以求$\dfrac {\partial L} {\partial x_{i,l,j,k}}$

总结:从上面的式子可以看出,不管是对于CNN还是DNN,一个batch之内同一个神经元或者卷积核对应同一个均值、方差、$\gamma、\beta$。访问$delta$的时候如果对于CNN令$size = out_w \times out_h$,对于DNN,令$size=1$,可以保证batchnorm代码的统一性。具体可以看darknet源代码。

BatchNorm的优点

BatchNorm为什么NB呢,关键还是效果好。

  • 不仅仅极大提升了训练速度,收敛过程大大加快;即解决了“Internal Covariate Shift”问题的第一种理解中出现的问题。
  • 还能增加分类效果,一种解释是这是类似于Dropout的一种防止过拟合的正则化表达方式,所以不用Dropout也能达到相当的效果;即解决了“Internal Covariate Shift”问题的第二种理解中出现的问题。
  • 另外调参过程也简单多了,对于初始化要求没那么高,而且可以使用大的学习率等。
  • BN说到底还是为了防止“梯度弥散”。关于梯度弥散,大家都知道一个简单的例子:$0.9^{30}\approx 0.04$。在BN中,是通过将activation规范为均值和方差一致的手段使得原本会减小的activation的scale变大。可以说是一种更有效的local response normalization方法

总而言之,经过这么简单的变换,带来的好处多得很,这也是为何现在BN这么快流行起来的原因。

Bacthnormal优化办法

1) 增大学习率
BN能减少每层的梯度变化幅度,使梯度稳定在理想的变化范围内,所以大学习率一般不会导致梯度消失。

另外大学习率,训练一次,一般会导致参数,如权重变大,假设变大了$n$倍,即$W’=nW$,其中$W’$为目前权重,$W$为上次权重

设上一次训练,均值为:

方差为:

则本次均值:

本次方差:

所以

可以看出,当因上一次训练的大学习率导致权重$W$变大$n$倍后,只会让本次训练的梯度更小,这样一点程度上,便避免了过大学习率导致的梯度爆炸.

2) 去掉Dropout

3) 减少L2正则项,这里不是很理解,难道两者冲突了?

4) 提高学习率衰减速度.由于BN收敛速度快,在相同迭代次数,使用BN算法的网络,比未使用相同BN算法的网络,会更快到达相应的衰减点

5) 更彻底随机化训练数据

6) 减少图片扭曲

主流 Normalization 方法梳理

在上一节中,我们提炼了 Normalization 的通用公式:

对照于这一公式,我们来梳理主流的四种规范化方法。

Batch Normalization —— 纵向规范化

Batch Normalization 于2015年由 Google 提出,开 Normalization 之先河。其规范化针对单个神经元进行,利用网络训练时一个 mini-batch 的数据来计算该神经元 $x_i$ 的均值和方差,因而称为 Batch Normalization。

其中 $M$ 是 mini-batch 的大小。$\epsilon$是为了避免除数为0时所使用的微小正数。从图中可以看出,每个神经元(卷积核)都有一个$\mu$和$\sigma$,而不是一个BN层中所有神经元共享$\mu$和$\sigma$

需要注意的是,上述的计算方法用于在训练过程中。在测试时,所使用的$\mu$和$\sigma$是整个训练集的均值$\mu_p$和标准差$\sigma_p$. 整个训练集的均值$\mu_p$和标准差$\sigma_p$值通常是在训练的同时用移动平均法来计算的.

按上图所示,相对于一层神经元的水平排列,BN 可以看做一种纵向的规范化。由于 BN 是针对单个维度定义的,因此标准公式中的计算均为 element-wise(每个元素对应相乘)的。

BN 独立地规范化每一个输入维度$x_i$ ,但规范化的参数是一个 mini-batch 的一阶统计量和二阶统计量。这就要求 每一个 mini-batch 的统计量是整体统计量的近似估计,或者说每一个 mini-batch 彼此之间,以及和整体数据,都应该是近似同分布的。分布差距较小的 mini-batch 可以看做是为规范化操作和模型训练引入了噪声,可以增加模型的鲁棒性;但如果每个 mini-batch的原始分布差别很大,那么不同 mini-batch 的数据将会进行不一样的数据变换,这就增加了模型训练的难度。

因此,BN 比较适用的场景是:每个 mini-batch 比较大,数据分布比较接近。在进行训练之前,要做好充分的 shuffle. 否则效果会差很多。

另外,由于 BN 需要在运行过程中统计每个 mini-batch 的一阶统计量和二阶统计量,因此不适用于 动态的网络结构 和 RNN 网络。不过,也有研究者专门提出了适用于 RNN 的 BN 使用方法,这里先不展开了。

简单来说,一阶统计量就是期望,中位数等,二阶统计量就是方差。对于动态网络,无法求出来。

Layer Normalization —— 横向规范化

层规范化就是针对 BN 的上述不足而提出的。与 BN 不同,LN 是一种横向的规范化,如图所示。它综合考虑一层所有维度的输入,计算该层的平均输入值和输入方差,然后用同一个规范化操作来转换各个维度的输入。

其中 $i$ 枚举了该层所有的输入神经元。对应到标准公式中,四大参数 $\mu,\sigma,g,b$ 均为标量(BN中是向量),所有输入共享一个规范化变换。

LN 针对单个训练样本进行,不依赖于其他数据,因此可以避免 BN 中受 mini-batch 数据分布影响的问题,可以用于 小mini-batch场景、动态网络场景和 RNN,特别是自然语言处理领域。此外,LN 不需要保存 mini-batch 的均值和方差,节省了额外的存储空间。

但是,BN 的转换是针对单个神经元可训练的——不同神经元的输入经过再平移和再缩放后分布在不同的区间,而 LN 对于一整层的神经元训练得到同一个转换——所有的输入都在同一个区间范围内。如果不同输入特征不属于相似的类别(比如颜色和大小),那么 LN 的处理可能会降低模型的表达能力。

Weight Normalization —— 参数规范化

前面我们讲的模型框架 $h=f\left(g\cdot\frac{x-\mu}{\sigma}+b\right)$中,经过规范化之后的$y$作为输入送到下一个神经元,应用以$w$为参数的$f_w(\cdot)$函数定义的变换。最普遍的变换是线性变换,即$f_w(x)=w \cdot x$.

BN 和 LN 均将规范化应用于输入的特征数据$x$,而 WN 则另辟蹊径,将规范化应用于线性变换函数的权重$w$ ,这就是 WN 名称的来源。

具体而言,WN 提出的方案是,将权重向量 $w$分解为向量方向$ \hat v$ 和向量模$ g$ 两部分:

其中 $v$是与$w$同维度的向量,$||v||$是欧氏范数,因此$\hat v$是单位向量,决定了$w$的方向;$g$ 是标量,决定了 $w$ 的长度。由于 $||w|| \equiv |g|$ ,因此这一权重分解的方式将权重向量的欧氏范数进行了固定,从而实现了正则化的效果。

乍一看,这一方法似乎脱离了我们前文所讲的通用框架?

并没有。其实从最终实现的效果来看,异曲同工。我们来推导一下看。

对照一下前述框架:

我们只需令:

就完美地对号入座了!

回忆一下,BN 和 LN 是用输入的特征数据的方差对输入数据进行 scale,而 WN 则是用 神经元的权重的欧氏范式对输入数据进行 scale。虽然在原始方法中分别进行的是特征数据规范化和参数的规范化,但本质上都实现了对数据的规范化,只是用于 scale 的参数来源不同。

另外,我们看到这里的规范化只是对数据进行了 scale,而没有进行 shift,因为我们简单地令 $\mu=0$. 但事实上,这里留下了与 BN 或者 LN 相结合的余地——那就是利用 BN 或者 LN 的方法来计算输入数据的均值$\mu$。

WN 的规范化不直接使用输入数据的统计量,因此避免了 BN 过于依赖 mini-batch 的不足,以及 LN 每层唯一转换器的限制,同时也可以用于动态网络结构。

Cosine Normalization —— 余弦规范化

Normalization 还能怎么做?

我们再来看看神经元的经典变换$ f_w(x)=w\cdot x$.

对输入数据 $x$的变换已经做过了,横着来是 LN,纵着来是 BN。

对模型参数 $w$ 的变换也已经做过了,就是 WN。

好像没啥可做的了。

然而天才的研究员们盯上了中间的那个点,对,就是$\cdot$

他们说,我们要对数据进行规范化的原因,是数据经过神经网络的计算之后可能会变得很大,导致数据分布的方差爆炸,而这一问题的根源就是我们的计算方式——点积,权重向量 $w$ 和 特征数据向量$x$的点积。向量点积是无界(unbounded)的啊!

那怎么办呢?我们知道向量点积是衡量两个向量相似度的方法之一。哪还有没有其他的相似度衡量方法呢?有啊,很多啊!夹角余弦就是其中之一啊!而且关键的是,夹角余弦是有确定界的啊,[-1, 1] 的取值范围,多么的美好!仿佛看到了新的世界!

于是,Cosine Normalization 就出世了。他们不处理权重向量 $w$ ,也不处理特征数据向量 $x$ ,就改了一下线性变换的函数:

其中 $\theta$ 是 $w$ 和 $x$ 的夹角。然后就没有然后了,所有的数据就都是 [-1, 1] 区间范围之内的了!

不过,回过头来看,CN 与 WN 还是很相似的。我们看到上式中,分子还是$w$ 和$x$ 的内积,而分母则可以看做用 $w$ 和 $x$ 二者的模之积进行规范化。对比一下 WN 的公式:

一定程度上可以理解为,WN 用 权重的模 $||v||$ 对输入向量进行 scale,而 CN 在此基础上用输入向量的模 $||x||$对输入向量进行了进一步的 scale.

CN 通过用余弦计算代替内积计算实现了规范化,但成也萧何败萧何。原始的内积计算,其几何意义是 输入向量在权重向量上的投影,既包含 二者的夹角信息,也包含 两个向量的scale信息。去掉scale信息,可能导致表达能力的下降,因此也引起了一些争议和讨论。具体效果如何,可能需要在特定的场景下深入实验。

现在,BN, LN, WN 和 CN 之间的来龙去脉是不是清楚多了?

附件

文章中的visio图的附件在这里

参考

详解深度学习中的Normalization,BN/LN/WN
【深度学习】深入理解Batch Normalization批标准化
深度学习(二十九)Batch Normalization 学习笔记
深度学习中 Batch Normalization为什么效果好?
Batch Normalization原理及其TensorFlow实现——为了减少深度神经网络中的internal covariate shift,论文中提出了Batch Normalization算法,首先是对”每一层“的输入做一个Batch Normalization 变换
《Batch Normalization Accelerating Deep Network Training by Reducing Internal Covariate Shift》阅读笔记与实现
深度学习中的Batch Normalization
BatchNormal推导和yolo源码解析
Batch Normalize的几点说明
Understanding the backward pass through Batch Normalization Layer

------ 本文结束------
坚持原创技术分享,您的支持将鼓励我继续创作!

欢迎关注我的其它发布渠道