深度学习中的归一化方法总结(BN、LN、IN、GN)

一般在神经网络中会用到数据的归一化,比如在卷积层后进行归一化然后再下采样然后再激活等。目前比较受欢迎的数据归一化层有:BN(BatchNormalization),LN(LayerNormalization),IN(InstanceNormalization),GN(GroupNormalization)这4种。本篇文章主要是对比一下它们各自是怎么计算的。
先看对数据的归一化是这么操作的。其实就是先计算均值和方差然后再标准化即可。具体的对一个标量数据(x i ∈ R x_i∈RxiR)在给定的数据集X = x 1 , x 2 , . . . , x m X=x_1,x_2,...,x_mX=x1,x2,...,xm中进行标准化是按如下进行计算的:
先计算给定数据集的均值和方差:μ = 1 m ∑ i = 1 m x i \mu=\frac1m\sum_{i=1}^{m}x_iμ=m1i=1mxiσ 2 = 1 m ∑ i = 1 m ( x i − μ ) 2 \sigma^2=\frac1m\sum_{i=1}^{m}(x_i-\mu)^2σ2=m1i=1m(xiμ)2然后对这个数据集中的每个数进行标准化(归一化):x ^ = x i − μ σ 2 + ϵ \hat{x}=\frac{x_i-\mu}{\sqrt{\sigma^2+\epsilon}}x^=σ2+ϵxiμ
BN、LN、IN、GN这4种归一化方法的区别就是用于计算均值和方差的数据集不同。后面我以卷积层后跟归一化来举例,我叫需要进行标准化的值为一个像素点,那么数据集叫像素集。我们来看一下这4种方法它们计算均值和方差的像素集有啥区别。(蓝色区域即为该方法对应的计算一次均值和方差的像素集,当然最终是要将整个方块按区域划分分别进行一次归一化)
在这里插入图片描述
假如现在图像先进行了卷积运算得到如上图所示的激活状态(N,C,H,W),其中N是样本数,C为通道数即特征图数。现在我对以上的激活状态进行归一化操作。
对于BN,一个要计算均值和方差的像素集为:所有样本(一个batch的所有样本)中有相同索引的特征图像素点集合为一个计算均值和方差的像素集。如图所示蓝色区域为一个像素集,在每一个像素集中先计算方差和均值然后对每一个像素进行归一化即可完成这个像素集的归一化。那么要将整个输入都BN完则需要对C个像素集分别进行归一化。BN有点像在多个样本的某一特征上进行归一化这样的好处是减少了数据值间的差距,而LN有点像在某一个样本的所有特征上进行归一化,由于不同的特征可能量纲不同所以LN这种方式相比于BN不仅缩小了数值差异而且还避免了量纲的影响。由于BN它不仅是可进行前向归一化还可以反向恢复为近似原始输入,在反向恢复中有两个参数需要训练γ \gammaγβ \betaβy i = γ x i ^ + β y_i=\gamma\hat{x_i}+\betayi=γxi^+β=>x i x_ixi。看一下BN中有多少个参数。由于每个进行归一化的像素集是不同的那么各像素集的恢复参数也不会相同,故BN层会有2*C个参数。我们用Keras来看一下:

from keras.models import Sequential
from keras.layers import BatchNormalization
model = Sequential()
model.add(BatchNormalization(input_shape=(55,55,96)))
model.summary()
'''
结果:
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
batch_normalization_1 (Batch (None, 55, 55, 96)        384       
=================================================================
Total params: 384
Trainable params: 192
Non-trainable params: 192
_________________________________________________________________
'''

可以看到参数为384个,不等于2*96,为啥?翻一下keras实现BN的代码可以发现对于每一个像素集它有两个可训练参数gamma和beta,还有另外两个参数moving_mean,moving_variance这两个参数被设计为不可训练。所以384个参数是指这个BN层中所有的参数包括192个可训练参数和192个不可训练参数,从结果后面的汇总信息也可以看出Total params: 384 Trainable params: 192 Non-trainable params: 192。那么为啥Keras的BN层要设计另外两个参数moving_mean,moving_variance?因为:训练时使用一个minibatch的训练数据计算均值和方差然后标准化数据,在test的时候我们也希望作相同的处理,比较直接的方法是在训练集上重新计算一遍统计量,但是,如果有1000w数据,这种计算就比较花费时间,而test的速度越快越好,所以在训练的时候,顺便就把均值和方差计算出来了,当然不是精确值,是近似值,这就是moving_mean和moving_variance,它们两个是用来记录训练时均值和方差的偏移的,以便在测试时直接使用,故而他们俩不需要学习。
对于LN,它的一个像素集为一个样本的所有特征图的像素集合。那么对于整个batch的输入归一化它需要分别在N个像素集上进行归一化操作才能完成。
对于IN,它的一个像素集为一个特征图像素点集合,那么对于输入需要进行N×C次的归一化。对于GN,它的一个像素集为一个样本的一部分连续特征图的像素点集合。
GN实现:

def GroupNorm(x, gamma, beta, G, eps=1e − 5):
    # x: input features with shape [N,C,H,W]
    # gamma, beta: scale and offset, with shape [1,C,1,1]
    # G: number of groups for GN
    N, C, H, W = x.shape
    x = tf.reshape(x, [N, G, C // G, H, W])
    mean, var = tf.nn.moments(x, [2, 3, 4], keep dims=True)
    x = (x − mean) / tf.sqrt(var + eps)
    x = tf.reshape(x, [N, C, H, W])
    return x ∗ gamma + beta

所以对给定的激活状态作为输入(包括N,针对一个batch的输入不是针对一个样本)要对它进行归一化,并不是在整个输入像素集上进行一次归一化,而是按区域分别归一化。(对于一个batch的输入BN需要C次,LN需要N次,IN需要N×C次,GN需要N×C g \frac CggC次的归一化)


版权声明:本文为buchidanhuang原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。