神经网络 BN

在学习Batch Normalization之前,我们来看一道某知名互联网公司算法题。

以下关于batch normalization说法正确的是()

     A. normalization的均值⽅差计算是基于全部训练数据的

     B. normalization的均值方差只基于当前的mini-batch

     C. normalization对输入层的每一维单独计算均值方差

     D. normalization的输出分布服从均值为0,方差为1的高斯分布

对于这道题一下就知道 Batch Normalization,这篇博客就基本可以跳过去了,但对于还有疑惑的同学,我们可以带着问题来进一步探索。

Batch Normalization

Batch Normalization是优化深度神经网络中最激动人心的最新创新之一。实际上它并不是一个优化算法,而是一个自适应的重新参数化的方法,试图克服神经网络层数加深导致模型难以训练。目前最常用的深度学习基础模型包括前向神经网络(MLP),CNN 和 RNN。 Batch Normalization 在这些基础网络结构中均有得到应用,大量数据表明,Batch Normalization 在 MLP 和 CNN 上效果很显著的,但在 RNN 上效果不明显。

Batch Normalization中文一般称为 “批标准化/规范化”,是一种对数值的特殊函数变换方法,也就是说假设原始的某个数值是 x,套上一个起到规范化作用的函数,对规范化之前的数值 x 进行转换,形成一个规范化后的数值,即:

神经网络 BN

所谓规范化,是希望转换后的数值 x ̂满足一定的特性,至于对数值具体如何变换,跟规范化目标有关, f() 函数的具体形式,不同的规范化目标导致具体方法中函数所采用的形式不同。

在介绍深度学习 Normalization 前,我们先普及下神经元的活动过程。深度学习是由神经网络来体现对输入数据的函数变换的,而神经网络的基础单元就是网络神经元,一个典型的神经元对数据进行处理时包含两个步骤的操作(参考图 1):

神经网络 BN

  1. 对输入数据进行线性变换,产生净**值:

         神经网络 BN

          其中,Xi 是输入,Wi 是权重参数,b 是偏置,Wi 和 b 是需要进行训练学习的网络参数

      2. 加入非线性**函数,神经网络的非线性能力来自于此,目前深度学习最常用的**函数是 Relu 函数 x=Relu(a)

这样一个神经元就完成了对输入数据的非线性函数变换。这里需要强调下,步骤1 中的输出一般称为净**(Net Activation),步骤2 经过**函数后得到的值为**值。为了描述简洁,本文后续文字中使用**的地方,其实指的是未经**函数的净**值,而非一般意义上的**,这点还请注意。

Normalization 操作方法

神经网络里主要有两类实体:神经元连接神经元的边,所以深度学习中的 Normalization,按照规范化操作涉及对象的不同可以分为两大类:

  • 一类是对第 L 层每个神经元的**值或者说对于第 L+1 层网络神经元的输入值进行 Normalization 操作,比如 BatchNorm/LayerNorm/InstanceNorm/GroupNorm 等方法都属于这一类;
  • 另外一类是对神经网络中连接相邻隐层神经元之间的边上的权重进行规范化操作,比如 Weight Norm 就属于这一类。广义上讲,一般机器学习里看到的损失函数里面加入的对参数的 L1/L2 等正则项,本质上也属于这第二类规范化操作。L1 正则的规范化目标是造成参数的稀疏化,就是争取达到让大量参数值取得 0 值的效果,而 L2 正则的规范化目标是有效减小原始参数值的大小。有了这些规范目标,通过具体的规范化手段来改变参数值,以达到避免模型过拟合的目的。

那么对于第一类的 Normalization 操作,其在什么位置发挥作用呢?

目前有两种在神经元中插入 Normalization 操作的地方(参考图 2):

  • 第一种是最早由Google研究员在其论文中提出的Batch Normalization,放在**函数之前
  • 另外一种是后续研究提出的,放在**函数之后,不少研究表明将 BN 放在**函数之后效果更好。本文在理解时仍然遵循 BN 原始论文,后续讲解都可以看成是将 Normalization 操作放在**函数之前进行

神经网络 BN

                                 图 2. Normalization 加入的位置

对于神经元的**值来说,不论哪种 Normalization 方法,其规范化目标都是一样的,就是将其**值规整为 均值为 0,方差为 1 的正态分布(本文开头问题答案的既视感)。即规范化函数统一都是如下形式:

神经网络 BN                         (1)

其中,ai 为某个神经元原始**值,ai^norm 为经过规范化操作后的规范后值

整个规范化过程可以分解为两步,第一步参考公式(2),是将**值规整到均值为 0,方差为 1 的正态分布范围内。

神经网络 BN      (2)                 

神经网络 BN       (3)

神经网络 BN神经网络 BN神经元在训练过程中学习到对应的两个调节因子,对规范到均值为 0 ,方差为1 的值进行微调。因为经过第一步操作后,Normalization 有可能降低神经网络的非线性表达能力,所以会以此方式来补偿 Normalization 操作后神经网络的表达能力。

其中,μ 是通过神经元集合 S(至于 S 如何选取读者可以先不用关注,后文有述)中包含的 m 个神经元各自的**值求出的均值,即:

神经网络 BN

σi 为根据均值 μ 和神经元集合 S 中神经元各自**值求出的**值标准差:

     神经网络 BN神经网络 BN

其中,ε 是为了增加训练稳定性而加入的小的常量数据。

不论是早期提出的提出的 Batch Normalization,还是 Batch Normalization 的改进版本。其基本计算步骤都如上所述,大同小异,最主要的区别在于神经元集合 S 的范围怎么定,不同的方法采用了不同的神经元集合定义方法。

神经元集合 S 的范围如何确定

为什么这些 Normalization 需要确定一个神经元集合 S 呢?原因很简单,前面讲过,这类深度学习的规范化目标是将神经元的**值限定在均值为 0 方差为 1 的正态分布中。而为了能够对网络中某个神经元的**值 a_i 规范到均值为 0 和方差为 1 的范围,必须有一定的手段求出均值和方差,而均值和方差是个统计指标,要计算均值和方差这两个指标一定要在一个集合范围内才可行,所以这就要求必须指定一个神经元组成的集合,利用这个集合里每个神经元的**来统计出所需的均值和方差,这样才能达到预定的规范化目标。

神经网络 BN

                                   图 3 Normalization 的一个计算过程

(参考图 3) 给出了这类 Normalization 的一个计算过程的具体例子,例子中假设网络结构是前向反馈网络,对于隐层的三个节点来说,其原初的**值为 [0.4, -0.6, 0.7],为了可以计算均值为 0 方差为 1 的正态分布,划定集合 S 中包含了这个网络中的 6 个神经元,至于如何划定集合 S 读者可以先不用关心,此时其对应的**值如图中所示,根据这 6 个**值,可以算出对应的均值和方差。有了均值和方差,可以利用公式(1)对原初**值进行变换,设定神经网络 BN神经网络 BN两个调节因子为 1,那么可以得到转换后的**值 [0.21,-0.75, 0.50],对于新的**值经过非线性变换函数比如 RELU,则形成这个隐层的输出值 [0.21, 0, 0.50]。这个例子中隐层的三个神经元在某刻进行 Normalization 计算的时候共用了同一个集合 S,在实际的计算中,隐层中的神经元可能共用同一个集合,也可能每个神经元采用不同的神经元集合 S,并非一成不变,这点还请留心与注意。

针对神经元的所有 Normalization 方法都遵循上述计算过程,唯一的不同在于如何划定计算统计量所需的神经元集合 S

 前向神经网络中的 Batch Normalization

神经网络 BN

图 4  前向神经网络 Batch Normalization

对于前向神经网络来说,Batch Normalization 在计算隐层某个神经元 k **的规范值的时候,对应的神经元集合 S 范围是如何划定呢?(参考图 4) 给出了示意,因为对于 Mini-Batch 训练方法来说,根据 Loss 更新梯度使用 Batch 中所有实例来做,所以对于神经元 k 来说,假设某个 Batch 包含 n 个训练实例,那么每个训练实例在神经元 k 都会产生一个**值,也就是说 Batch 中 n 个训练实例分别通过同一个神经元 k 的时候产生了 n 个**值,Batch Normalization的集合 S 选择入围的神经元就是这 n 个同一个神经元被 Batch 不同训练实例激发的**值。划定集合 S 的范围后,Normalization 的具体计算过程与前文所述计算过程一样,采用公式(1) 即可完成规范化操作。

CNN 网络中的 Batch Normalization

常规的 CNN 一般由卷积层、下采样层及全连接层构成。全连接层形式上与前向神经网络是一样的,所以可以采取前向神经网络中的 BatchNorm 方式,而下采样层本身不带参数所以可以忽略,所以 CNN 中主要关注卷积层如何计算 Batch Normalization。

神经网络 BN

图 7  CNN 的卷积核

CNN 中的某个卷积层由 m 个卷积核构成,每个卷积核对三维的输入(通道数*长*宽)进行计算,**及输出值是个二维平面(长*宽),对应一个输出通道(参考图 7),由于存在 m 个卷积核,所以输出仍然是三维的,由 m 个通道及每个通道的二维平面构成。

神经网络 BN

图8 CNN 中的 BatchNorm 过程

在CNN卷积层中,如果要对通道**二维平面中某个**值进行 Normalization 操作,怎么确定集合 S 的范围呢?

图 8 给出了示意图。类似于前向神经网络中的 BatchNorm 计算过程,对于 Mini-Batch 训练方法来说,反向传播更新梯度使用 Batch 中所有实例的梯度方向来进行,所以对于 CNN 某个卷积层对应的输出通道 k 来说,假设某个 Batch 包含 n 个训练实例,那么每个训练实例在这个通道 k 都会产生一个二维**平面,也就是说 Batch 中 n 个训练实例分别通过同一个卷积核的输出通道 k 的时候产生了 n 个**平面

假设**平面长为 5,宽为 4,则**平面包含 20 个**值,n 个不同实例的**平面共包含 20*n 个**值。那么 BatchNorm 的集合 S 的范围就是由这 20*n 个同一个通道被 Batch 不同训练实例激发的**平面中包含的所有**值构成(对应图 8 中所有标为蓝色的**值。划定集合 S 的范围后,**平面中任意一个**值都需进行 Normalization 操作,其 Normalization 的具体计算过程与前文所述计算过程一样,采用公式(1) 即可完成规范化操作。这样即完成 CNN 卷积层的 BatchNorm 转换过程。

神经网络 BN

描述起来似乎有些复杂,但是从概念上,其实可以把 CNN 中的 卷积层 想象成前向神经网络中的一个 隐层,然后把对应的某个卷积核 想象成 MLP 隐层中的一个神经元节点,两者不同之处是:

  • CNN 输出是个二维**平面而 MLP 的神经元输出是一个**值
  • 另外一个不同是这个神经元覆盖的输入部分不同,CNN 的卷积核是局部覆盖输入,通过滑动窗口来实现输入的全覆盖,   而 MLP 的神经元则是一步到位全局覆盖输入 。如果从这个角度思考 CNN 和 MLP 中的 BatchNorm 的话,其实两者的做法是一致的。

Batch Normalization 优点

  1. 可以加快模型 收敛速度 ,不再依赖精细的参数初始化过程,
  2. 可以调大 学习率 等,
  3. 同时引入的 随机噪声 能够起到对模型参数进行 正则化 的作用,有利于增强模型泛化能力。

Batch Normalization 不足

  1. 如果 Batch Size 太小,则 BN 效果明显下降。因为在小的 BatchSize 意味着数据样本少,因而得不到有效统计量,也就是说噪音太大。
  2. 对于有些像素级图片生成任务来说,BN 效果不佳;对于图片分类等任务,只要能够找出关键特征,就能正确分类,这算是一种粗粒度的任务,因为在 Mini-Batch 内多张无关的图片之间计算统计量,弱化了单张图片本身特有的一些细节信息。
  3. RNN 等动态网络使用 BN 效果不佳且使用起来不方便
  4. 训练时和推理时统计量不一致

参考:

1. Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift

2. 深度学习中的Normalization模型