从零开始实现一个深度学习框架 | 一文读懂Normalization (1)

语言: CN / TW / HK

往期回顾

导语

上期我们带大家用神经网络+遗传算法训练了一个自动玩小游戏的程序:

从零开始实现一个深度学习框架 | 当神经网络遇上遗传算法

主要是为了避免本系列文章过于枯燥,所以中间会穿插一些有趣的神经网络应用。本期我们回归正题,带大家深入理解一下神经网络中的Normalization到底是咋回事。

废话不多说,让我们愉快地开始吧~

Normalization的起源

众所周知,满足独立同分布条件的数据往往更受深度学习炼丹师们的喜爱,即:

independent  and  identically  distributed (i.i.d.)

大家经常在论文里看到的满足 i.i.d. 一般指的 就是数据满足独立同分布了。例如,脍炙人口的朴素贝叶斯算法就必须要求数据满足独立同分布。当然,神经网络并不强制要求输入数据独立同分布,但炼丹师的无数经验告诉我们,满足独立同分布的数据往往是更有助于模型训练的。一个直观的解释就是如果神经网络每层的输入分布变化很大,那么网络就要不断地去调整适应不同分布的数据,增加了模型学习的难度。一般而言,神经网络每层输入数据不满足独立同分布的问题又被称为:

Internal Covariate Shift (ICS)

更加专业一点地描述,就是统计机器学习中一般会假设“源空间和目标空间的数据分布是一致的”,而covariate shift的含义就是源空间和目标空间的条件概率一致:

但是其边缘概率不同:

具体而言, 对于没有加独立同分布约束的神经网络,由于神经网络层内的运算,其各层的输入信号分布和输出信号的分布是不同的,但是他们所对应的样本标签是一样的。顺便提一句,叫 internal covariate shift是 因为具体到神经网络,我们是对层间信号进行分析,所以在 c o variate shift前面加了个 in terna l

因此,在把数据喂给神经网络之前,我们往往会对数据进行一些预处理:

  • 独立:去除相关性;

  • 同分布:保证具有相同的均值和方差。

这个预处理一般也叫“白化”,其中最经典的方法就是PCA白化,简单而言,就是进行和PCA降维一样的操作,但是选择的特征向量个数和数据维度相同。对于不知道PCA降维是什么的同学,可以参考如下链接进行学习:

https: //zhuanlan.zhihu.com/p/77151308

参考文献

[1]. https://zhuanlan.zhihu.com/p/33173246

[2 ].  http://ufldl.stanford.edu/tutorial/unsupervised/PCAWhitening/

[3]. https://www.zhihu.com/question/38102762/answer/85238569

Normalization算法详解

前面我们说到,对于神经网络中的某个神经元:

由于存在ICS问题,输入数据  的分布可能会有很大的变化,这是不利于  进行学习的。因此,最"标准"的解决方案就是对所有的输入数据都进行白化操作,但是这个操作是不可微,而且需要的计算量过大,因此,以BN为代表的Normalization方法就成了目前主流的解决ICS问题的一个退而求其次的解决方案。

具体而言,该方案的基本思想就是对输入数据进行平移和伸缩变换,公式化的表达如下所示:

公式中的参数  是平移参数,  是缩放参数,  经过这两个参数处理之后,就变成了均值为0、方差为1的标准分布了:

接下来的  则是再平移参数,  是再缩放参数,最终,经过normalization层后的输出就是均值为  ,方差为  的分布了:

其中,第一步很好理解,就是为了保证输入数据同分布,那么第二步又是为了什么呢?一般地,我们认为这是为了保证模型的表达能力不会因为规范化操作而下降。如果对self-attention有了解的朋友可以回忆一下(这个我们以后的章节会聊到),现在用的最多的self-attention方式是不是key, value, query都是其实不一样的呢?在我看来,其实这些处理的功能在某种意义上都是类似的,即为了加强模型的表征能力。

写到这里,可能很多人会有疑惑,加上再平移和再缩放参数,不就变成和之前一样了吗?其实不是的,因为在引入normalization之前,输入  的均值是由该层神经网络之前的所有神经网络的参数决定的,但是在引入normalization之后,输入  的均值仅由  来决定,这显然是不同的,后者去除了分布和前面神经网络参数的关联,让模型训练变得更加简单了。

我们可以举几个简单的例子来看看引入normalization后给网络训练到底带来了哪些好处:

1. 权重伸缩不变性

即当网络权重  按照常量  进行伸缩时,得到的规范化后的值保持不变:

推导如下:

因此,我们有:

即权重的伸缩变化不会影响反向传播的梯度的雅可比矩阵,避免了反向传播过程中因为权重过大或过小导致的梯度消失和梯度爆炸问题。

另外,由于:

即网络的权重较大时,其对应的梯度会比较小,起到了参数正则化的效果,避免了网络的大幅震荡。

2. 数据伸缩不变性

即当输入数据   按照常量   进行伸缩时,得到的规范化后的值保持不变:

因此,我们有:

换句话说,数据的伸缩变换不会影响对该层的权重参数的更新,有利于保证训练的稳定性。

接下来,我们来学习一些现有的normalization方法。

1. Batch Normalization

BN可以看作一种纵向规范化方法,套入到我们前面提到的Normalization公式:

参数  和  在BN中的计算方式如下:

其中,  代表网络进行一次梯度学习输入的数据数量(即batch size)。

放个图更加直观地展示一下BN的计算方式:

2. Layer Normalization

LN可以看作一种横向规范化方法,套入到我们前面提到的Normalization公式:

参数  和  在LN中的计算方式如下:

即LN是对单个训练样本进行的。

放个图更加直观地展示一下LN的计算方式:

3. Instance Normalization

IN同样可以套入到我们前面提到的Normalization公式:

参数  和  在IN中的计算方式如下:

即IN是对 单个训练样本的单个特征图进行的。

放个图更加直观地展示一下IN的计算方式:

4. Group Normalization

GN其实就是IN和LN的结合, 套入到我们前面提到的Normalization公式:

参数  和  在GN中的计算方式如下:

其中G代表单个Group里的特征图数量,即GN是对单个训练样本的某几个特征图进行的。

放个图 更加直观地展示一下GN的计算方式:

5. Weight Normalization

前面四种normalization方法均将规范化应用于输入的特征数据  ,而WN则另辟蹊径,将规范化应用到了网络权重 

具体而言,WN会将网络权重  分解为向量方向  和向量模  两个部分:

于是,我们只需要固定  就可以达到我们想要的效果,即 我们有:

套入到我们前面总结的公式:

可知在WN中,  和  被固定为了0,  则为  换句话说,WN等价于利用神经元的权重的欧式范数对输入数据进行伸缩变换。

6. Cosine Normalization

搞完数据和权重,研究者们又盯上了数据和权重之前的运算符,于是CN便横空出世了。具体而言,他们将原来的线性变换  修改成了(即计算权重  和输入  的夹角):

于是所有的数据都被规范化到了区间  。简单来说,CN本质上就是在WN的基础上把  定义成了  ,还是可以套入到我们最开始总结的normalization的公式中的。

总而言之,尽管到目前为止,不同的研究者提出了各种各样的normalization,他们的适用场景虽然不同,例如LN一般用于NLP领域,而BN适用于mini-batch之间以及mini-batch和整体数据分布近似同分布的场景,但是他们都 万变不离其宗,可以套用到同一个统一的公式中。

参考文献

[1]. https://arxiv.org/abs/1803.08494

[2]. https://zhuanlan.zhihu.com/p/33173246

下期预告:

下一篇文章我们将用numpy在我们自己搭建的深度学习框架pytoydl中实现几种常见的normalization方法:

https://github.com/CharlesPikachu/pytoydl

并详细介绍他们的优点与不足。