前言

Github:本文代码放在该项目中:NLP相关Paper笔记和代码复现
说明:讲解时会对相关文章资料进行思想、结构、优缺点,内容进行提炼和记录,相关引用会标明出处,引用之处如有侵权,烦请告知删除。
转载请注明:DengBoCong

对于深度学习而言,正则化方法就是“通过把一部分不重要的复杂信息损失掉,以此来降低拟合难度以及过拟合的风险,从而加速了模型的收敛”,而本篇文章我们要讲的Normalization方法的目的就是让分布稳定下来(降低各维度数据的方差),不同的正则化方法的区别只是操作的信息维度不同,即选择损失信息的维度不同。

本篇文章将结合TensorFlow和Pytorch计算框架,阐述几种归一化算法:Batch Normalization(BN)、Layer Normalization(LN)、Weight Normalization(WN)、Instance Normalization(IN)、Group Normalization(GN)、Cosine Normalization(CN)。

相关知识

“Covariate Shift: A Review and Analysis on Classifiers”论文中对Covariate Shift的描述:

In real world, the joint distribution of inputs to the model and outputs of the model differs between training and test data, which is called dataset shift

关于Covariate Shift的一篇方法综述性论文,可参考我的另一篇论文阅读笔记

下面我用白话简单的阐述一下Covariate Shift和Internal Covariate Shift

  • 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_0(x)=q_1(x)$,所以可以推出最优 $\theta^{‘}$ 依然可以保证 $q_1(x)$ 最优。但现实当中这个假设往往不成立,伴随新数据产生,老数据会过时,当 $q_0(x)$ 不再等于 $q_1(x)$ 时,就被称作Covariate Shift。
  • Internal Covariate Shift:深度神经网络模型的训练为什么会很困难?其中一个重要的原因是,深度神经网络涉及到很多层的叠加,而每一层的参数更新会导致上层的输入数据分布发生变化,通过层层叠加,高层的输入分布变化会非常剧烈,这就使得高层需要不断去重新适应底层的参数更新。为了训好模型,我们需要非常谨慎地去设定学习率、初始化权重、以及尽可能细致的参数更新策略,Google 将这一现象总结为Internal Covariate Shift,简称 ICS。

ICS会导致什么问题?简而言之,每个神经元的输入数据不再是“独立同分布”。

  • 上层参数需要不断适应新的输入数据分布,降低学习速度。
  • 下层输入的变化可能趋向于变大或者变小,导致上层落入饱和区,使得学习过早停止。
  • 每层的更新都会影响到其它层,因此每层的参数更新策略需要尽可能的谨慎。

我们以神经网络中的一个普通神经元为例,神经元接收一组输入向量$x=(x_1,x_2,…,x_d)$,通过某种运算后,输出一个标量值:$y=f(x)$。由于 ICS 问题的存在,$x$ 的分布可能相差很大。要解决独立同分布的问题,“理论正确”的方法就是对每一层的数据都进行白化操作。然而标准的白化操作代价高昂,特别是我们还希望白化操作是可微的,保证白化操作可以通过反向传播来更新梯度。因此,以 BN 为代表的 Normalization 方法退而求其次,进行了简化的白化操作。基本思想是:在将 $x$ 喂给神经元之前,先对其做平移和伸缩变换, 将 $x$ 的分布规范化成在固定区间范围的标准分布。通用变换框架就如下所示:
$$h=f(g\cdot \frac{x-\mu}{\sigma}+b)$$
其中,$\mu$ 是平移参数,$\sigma$ 是缩放参数,通过这两个参数进行 shift 和 scale 变换:$\hat{x}=\frac{x-\mu}{\sigma}$得到的数据符合均值为 0、方差为 1 的标准分布。$b$ 是再平移参数,$g$ 是再缩放参数。将上一步得到的 $\hat{x}$ 进一步变换为:$y=g\cdot \hat{x}+b$,最终得到的数据符合均值为 $b$ 、方差为 $g^2$ 的分布。

Batch Normalization(BN)

针对Batch Normalization的详细介绍,可以参考这一篇文章:论文阅读笔记:看完也许能进一步了解Batch Normalization

Batch Normalization 于2015年由 Google 提出,开 Normalization 之先河。其规范化针对单个神经元进行,利用网络训练时一个 mini-batch 的数据来计算该神经元 $x_i$ 的均值和方差,因而称为 Batch Normalization。
$$\mu_i=\frac{1}{M}\sum x_i \\ \ \sigma_i=\sqrt{\frac{1}{M}\sum(x_i-\mu_i)^2+\epsilon}$$
其中$M$是mini-batch 的大小。按上图所示,相对于一层神经元的水平排列,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 使用方法,这里先不展开了,附一张Batch Normalization的结构图如下:
在这里插入图片描述

Layer Normalization(LN)

Layer Normalization就是针对 BN 的上述不足而提出的。与 BN 不同,LN 是一种横向的规范化。它综合考虑一层所有维度的输入,计算该层的平均输入值和输入方差,然后用同一个规范化操作来转换各个维度的输入。
$$\mu=\sum_ix_i,\quad \sigma=\sqrt{\sum_i(x_i-\mu)^2+\epsilon}$$

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

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

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

在NLP任务中,对于不同的训练案例,通常有不同的句子长度。这在RNN中很容易处理,因为每个时间步使用相同的权重。但是,当我们以明显的方式将批归一化应用于RNN时,我们需要为序列中的每个时间步计算并存储单独的统计信息。如果测试序列比任何训练序列都要长,这是有问题的。层归一化不存在此类问题,因为其归一化项仅取决于当前时间步对层的求和输入。 在所有时间步中,它也只有一组增益和偏置参数共享。

这里附一张Batch Normalization和Layer Normalization之间计算差异的图:
在这里插入图片描述
LN用于RNN进行Normalization时,取得了比BN更好的效果。但用于CNN时,效果并不如BN明显。

Weight Normalization(WN)

在前面列的变换框架中:
$$h=f(g\cdot \frac{x-\mu}{\sigma}+b)$$
中,经过规范化之后的 $y$ 作为输入送到下一个神经元,应用以 $w$ 为参数的 $f_w(\cdot)$ 函数定义的变换。最普遍的变换是线性变换,即 $f_w(x)=w\cdot x$。BN 和 LN 均将规范化应用于输入的特征数据 $x$ ,而 WN 则另辟蹊径,将规范化应用于线性变换函数的权重 $w$ ,这就是 WN 名称的来源。具体而言,WN 提出的方案是,将权重向量 $w$ 分解为向量方向 $\hat{v}$ 和向量模 $g$ 两部分:
$$w=g\cdot \hat{v}=g\cdot \frac{v}{||v||}$$
其中 $v$ 是与 $w$ 同维度的向量, $||v||$ 是欧氏范数,因此 $\hat{v}$ 是单位向量,决定了 $w$ 的方向。$g$ 是标量,决定了 $w$ 的长度。由于 $||w||\equiv |g|$ ,因此这一权重分解的方式将权重向量的欧氏范数进行了固定,从而实现了正则化的效果。通过推导(如下),我们会发现WN其实只是在前述框架上令 $\sigma=||v||,\quad \mu=0, \quad b=0$。
$$f_w(WN(x))=w\cdot WN(x)=g\cdot \frac{v}{||v||}\cdot x=v\cdot g\cdot \frac{x}{||v||}=f_v(g\cdot \frac{x}{||v||})$$

BN 和 LN 是用输入的特征数据的方差对输入数据进行 scale,而 WN 则是用 神经元的权重的欧氏范式对输入数据进行 scale。虽然在原始方法中分别进行的是特征数据规范化和参数的规范化,但本质上都实现了对数据的规范化,只是用于 scale 的参数来源不同。另外,我们看到这里的规范化只是对数据进行了 scale,而没有进行 shift,因为我们简单地令 $\mu=0$。 但事实上,这里留下了与 BN 或者 LN 相结合的余地——那就是利用 BN 或者 LN 的方法来计算输入数据的均值 $\mu$ 。WN 的规范化不直接使用输入数据的统计量,因此避免了 BN 过于依赖 mini-batch 的不足,以及 LN 每层唯一转换器的限制,同时也可以用于动态网络结构。

和目前主流归一化方法不同的是,WN的归一化操作作用在了权值矩阵之上。从其计算方法上来看,WN完全不像是一个归一化方法,更像是基于矩阵分解的一种优化策略,它带来了四点好处:

  • 更快的收敛速度;
  • 更强的学习率鲁棒性;
  • 可以应用在RNN等动态网络中;
  • 对噪声更不敏感,更适用在GAN,RL等场景中。

说WN不像归一化的原因是它并没有对得到的特征范围进行约束的功能,所以WN依旧对参数的初始值非常敏感,这也是WN一个比较严重的问题。所以针对这个问题,论文中作者实验采用WN+Mean-Only BN的方法。在每一层的layer的激活函数之前,我们发现$t=w\cdot x=\frac{g}{||v||}v\cdot x$,我们发现虽然我们将权重 $w$ 进行分离,但是每一层的激活函数之前的输出的均值仍然与 $v$ 有关。因此作者将WN与BN进行结合,采用移动平均去计算每个mini-batch上的均值 $\mu [t]$,因此:
$$t=wx$$ $$\hat{t}=t-\mu [t] + b$$ $$y=\phi (\hat{t})$$
对激活函数之前的t的反向传播的损失函数为:
$$\bigtriangledown_tL=\bigtriangledown_{\hat{t}}L-\mu [\bigtriangledown_{\hat{t}}L]$$
对损失函数来说,mean-only batch normalization 可以有效的在反向传播中centering梯度。并且对于mean-only的BN来说,其计算量要小于full-BN的方法。另外,这个方法比Full-BN引入更轻微的噪声。

Cosine Normalization(CN)

我们要对数据进行规范化的原因,是数据经过神经网络的计算之后可能会变得很大,导致数据分布的方差爆炸,而这一问题的根源就是我们的计算方式——点积,权重向量 $w$ 和 特征数据向量 $x$ 的点积,向量点积是无界(unbounded)的啊!那怎么办呢?我们知道向量点积是衡量两个向量相似度的方法之一。哪还有没有其他的相似度衡量方法呢?有啊,很多啊!夹角余弦就是其中之一啊!而且关键的是,夹角余弦是有确定界的啊,[-1, 1] 的取值范围。于是,Cosine Normalization 就出世了。他们不处理权重向量 $w$ ,也不处理特征数据向量 $x$ ,就改了一下线性变换的函数:
$$f_w(x)=cos\theta=\frac{w\cdot x}{||w||\cdot ||x||}$$
其中 $\theta$ 是 $w$ 和 $x$ 的夹角。不过,回过头来看,CN 与 WN 还是很相似的。我们看到上式中,分子还是 $w$ 和 $x$ 的内积,而分母则可以看做用 $w$ 和 $x$ 二者的模之积进行规范化。对比一下 WN 的公式:
$$f_w(WN(x))=f_v(g\cdot \frac{x}{||v||})$$
一定程度上可以理解为,WN 用 权重的模 $||v||$ 对输入向量进行 scale,而 CN 在此基础上用输入向量的模 $||x||$ 对输入向量进行了进一步的 scale。CN 通过用余弦计算代替内积计算实现了规范化,但成也萧何败萧何。原始的内积计算,其几何意义是 输入向量在权重向量上的投影,既包含 二者的夹角信息,也包含 两个向量的scale信息。去掉scale信息,可能导致表达能力的下降,因此也引起了一些争议和讨论。具体效果如何,可能需要在特定的场景下深入实验。

Instance Normalization

在这里插入图片描述

IN在计算归一化统计量时并没有像BN那样跨样本、单通道,也没有像LN那样单样本、跨通道。它是取的单通道,单样本上的数据进行计算,如图1最右侧所示。所以对比BN的公式,它只需要它只需要去掉批量维的求和即可:
$$u_{ti}=\frac{1}{HW}\sum_{l=1}^W\sum_{m=1}^Hx_{tilm}\quad \sigma_{ti}^2=\frac{1}{HW}\sum_{l=1}^W\sum_{m=1}^H(x_{tilm}-u_{ti})^2 \quad y_{tijk}=\frac{x_{tilm}-u_{ti}}{\sqrt{\sigma_{ti}^2+\epsilon}}$$
在TensorFlow实现中,对于是否使用BN中的可学习参数 $\beta$ 和 $\gamma$ ,从LN的TensorFlow中源码中我们可以看出这两个参数是要使用的。但是我们也可以通过将其值置为False来停用它们,这一点和其它归一化方法在TensorFlow中的实现是相同的。

Group Normalization(GN)

组归一化 (GN) 将输入的通道分成较小的子组,并根据其均值和方差归一化这些值。由于 GN 只对单一样本起作用,因此该技术与batch大小无关。在图像分类任务中,GN 的实验得分与BN十分接近。如果整体batch大小很小,则使用 GN 而不是BN可能更为有利,因为较小的batch大小会导致BN的性能不佳,下面附一张原论文中的图:
在这里插入图片描述

从左到右一次是BN,LN,IN,GN。众所周知,深度网络中的数据维度一般是[N, C, H, W]或者[N, H, W,C]格式,N是batch size,H/W是feature的高/宽,C是feature的channel,压缩H/W至一个维度,其三维的表示如上图,假设单个方格的长度是1,那么其表示的是[6, 6,*, * ]

  • BN在batch的维度上norm,归一化维度为[N,H,W],对batch中对应的channel归一化;
  • LN避开了batch维度,归一化的维度为[C,H,W];
  • IN 归一化的维度为[H,W];
  • 而GN介于LN和IN之间,其首先将channel分为许多组(group),对每一组做归一化,及先将feature的维度由[N, C, H, W]reshape为[N, G,C//G , H, W],归一化的维度为[C//G , H, W]

传统角度来讲,在深度学习没有火起来之前,提取特征通常是使用SIFT,HOG和GIST特征,这些特征有一个共性,都具有按group表示的特性,每一个group由相同种类直方图的构建而成,这些特征通常是对在每个直方图(histogram)或每个方向(orientation)上进行组归一化(group-wise norm)而得到。而更高维的特征比如VLAD和Fisher Vectors(FV)也可以看作是group-wise feature,此处的group可以被认为是每个聚类(cluster)下的子向量sub-vector。

从深度学习上来讲,完全可以认为卷积提取的特征是一种非结构化的特征或者向量,拿网络的第一层卷积为例,卷积层中的的卷积核filter1和此卷积核的其他经过transform过的版本filter2(transform可以是horizontal flipping等),在同一张图像上学习到的特征应该是具有相同的分布,那么,具有相同的特征可以被分到同一个group中,按照个人理解,每一层有很多的卷积核,这些核学习到的特征并不完全是独立的,某些特征具有相同的分布,因此可以被group。

导致分组(group)的因素有很多,比如频率、形状、亮度和纹理等,HOG特征根据orientation分组,而对神经网络来讲,其提取特征的机制更加复杂,也更加难以描述,变得不那么直观。另在神经科学领域,一种被广泛接受的计算模型是对cell的响应做归一化,此现象存在于浅层视觉皮层和整个视觉系统。作者基于此,提出了组归一化(Group Normalization)的方式,且效果表明,显著优于BN、LN、IN等。

Normalization的不变性

  • 权重伸缩不变性(weight scale invariance)指的是,当权重 $W$ 按照常量 $\lambda$ 进行伸缩时,得到的规范化后的值保持不变,即:
    $$Norm(W^{‘}x)=Norm(Wx)$$
    其中,$W^{‘}=\lambda W$。上述规范化方法均有这一性质,这是因为,当权重 $W$ 伸缩时,对应的均值和标准差均等比例伸缩,分子分母相抵:
    $$Norm(W^{‘}x)=Norm(g\cdot \frac{W^{‘}x-\mu^{‘}}{\sigma^{‘}}+b)=Norm(g\cdot \frac{\lambda Wx-\lambda\mu}{\lambda \sigma}+b)=Norm(g\cdot \frac{Wx-\mu}{\sigma}+b)=Norm(Wx)$$
    权重伸缩不变性可以有效地提高反向传播的效率,由于:
    $$\frac{\partial Norm(W^{‘}x)}{\partial x}=\cdot\frac{\partial Norm(Wx)}{\partial x}$$
    因此,权重的伸缩变化不会影响反向梯度的 Jacobian 矩阵,因此也就对反向传播没有影响,避免了反向传播时因为权重过大或过小导致的梯度消失或梯度爆炸问题,从而加速了神经网络的训练。权重伸缩不变性还具有参数正则化的效果,可以使用更高的学习率。由于:
    $$\frac{\partial Norm(W^{‘}x)}{\partial W^{‘}}=\frac{1}{\lambda}\cdot\frac{\partial Norm(Wx)}{\partial W}$$
    因此,下层的权重值越大,其梯度就越小。这样,参数的变化就越稳定,相当于实现了参数正则化的效果,避免参数的大幅震荡,提高网络的泛化性能。
  • 数据伸缩不变性:数据伸缩不变性(data scale invariance)指的是,当数据 $x$ 按照常量 $\lambda$ 进行伸缩时,得到的规范化后的值保持不变,即:
    $$Norm(Wx^{‘})=Norm(Wx)$$
    其中,$x^{‘}=\lambda x$。数据伸缩不变性仅对 BN、LN 和 CN 成立。因为这三者对输入数据进行规范化,因此当数据进行常量伸缩时,其均值和方差都会相应变化,分子分母互相抵消。而 WN 不具有这一性质。数据伸缩不变性可以有效地减少梯度弥散,简化对学习率的选择。对于某一层神经元 $h_l=f_{W_l}(x_l)$ 而言,展开可得:
    $$h_l=f_{W_l}(x_l)=f_{W_l}(f_{W_{l\ 1}}(x_l\ 1))=…=x_0 \coprod_{k=0}^{l}W_k$$
    每一层神经元的输出依赖于底下各层的计算结果。如果没有正则化,当下层输入发生伸缩变化时,经过层层传递,可能会导致数据发生剧烈的膨胀或者弥散,从而也导致了反向计算时的梯度爆炸或梯度弥散。加入 Normalization 之后,不论底层的数据如何变化,对于某一层神经元 $h_l=f_{W_l}(x_l)$ 而言,其输入 $x_l$ 永远保持标准的分布,这就使得高层的训练更加简单。从梯度的计算公式来看:
    $$\frac{\partial Norm(Wx^{‘})}{\partial W}=\cdot\frac{\partial Norm(Wx)}{\partial W}$$
    数据的伸缩变化也不会影响到对该层的权重参数更新,使得训练过程更加鲁棒,简化了对学习率的选择。

    总结

    选择什么样的归一化方式,取决于你关注数据的哪部分信息,如果某个维度信息的差异性很重要,需要被拟合,那就别在那个维度进行归一化。

参考资料: