背景
协变量偏移(Covariate Shift)是统计学的一个概念,它描述了源域($S$)和目标域($T$)边缘分布的不一致,但是它们的条件分布却是相同的即$P_{T}(y|x)=P_{S}(y|x)$。
对深度学习来说条件分布$P(y|x)$是我们训练得到的模型,如果训练集分布和测试集分布存在差异,即$P(X_{train})$和$P(X_{test})$不一致,那么就会出现Covariate Shift。
此时会出现两个结果:
- 用训练集得到的模型在测试集上做性能评估,得到的不是模型的真实水平
- 训练集和测试集分布差异过大,我们训练得到的不是真实模型
因此在机器学习中,我们期望数据是独立同分布的,这要求训练集和测试集的样本都是从同一个分布独立采样而来。独立同分布的数据可以简化常规机器学习模型的训练,提升机器学习模型的预测能力。
但是在深层神经网络的训练中,当中间神经层的前一层参数发生改变时,该层的输入分布也会发生改变,也就是存在内部协变量偏移(Internal Covariate Shift)问题。中间的神经层需要不断适应这种变化,这会降低整个网络的收敛速度。
由于参数更新导致网络中的每一层输入值分布发生改变,这才导致了ICS问题,因此可以通过固定每一层网络的输入值分布来减缓ICS问题。
一般来说,有两种策略:
- 白化(Whitening)
白化之后的数据特征之间相关性较低,所有特征具有相同的方差
不过由于以下原因,白化不是目前的主流选择:1)白化过程计算成本太高,如PCA中需要计算协方差矩阵,并在每一轮训练的每一层都执行该运算;2)白化过程改变了网络中每一层的分布,因此改变了网络层中本身数据的表达能力,底层网络学习到的参数信息会被白化操作丢失。 - 归一化(Normalization)
Normalization能够使得样本处于同一分布,且可以解决每批训练数据分布不同的问题;而且Normalization包含线性变换操作,可以让数据尽可能恢复本身的表达能力
任何Normalization的意义都是为了让使用Normalization的网络的输入数据分布变得更好,也即转换为标准正态分布,以减缓梯度消失,从而更容易训练。执行的操作也差不多,先减去均值,再除以标准差,最后做一次线性变换。主要区别在于操作的特征维度不同。
不过要明确,在某一维度内进行Normalization,那么在该维度内相对大小是有意义的;但是在Normalization之后的不同维度之间,相对大小是没有意义的。这意味着舍弃了除此维度之外其它维度的信息。
Batch Normalization
假设输入数据的维度是:$x \in \mathbb{R}^{N \times C \times H \times W}$,Batch Normalization在对其求均值和方差时,将在$N$,$H$,$W$维度上操作,保留通道$C$的维度。
代码实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import torch
from torch import nn
N, C, H, W = 10, 3, 5, 5
# [N, C, H, W]
x = torch.rand(N, C, H, W) * 10000
bn = nn.BatchNorm2d(num_features=C, eps=0, affine=False, track_running_stats=False)
# [N, C, H, W]
official_bn = bn(x)
# [C, N * H * W]
x1 = x.permute(1, 0, 2, 3).reshape(C, -1)
# [1, C, 1, 1]
mu = x1.mean(dim=1).reshape(1, C, 1, 1)
std = x1.std(dim=1, unbiased=False).reshape(1, C, 1, 1)
# [N, C, H, W]
my_bn = (x - mu) / std
print(my_bn.shape)
# 误差在1e-5量级
diff = (official_bn - my_bn).sum()
print(diff)
Batch Normalization广泛应用于CV,针对同一特征,以跨样本的方式开展归一化,也就是对不同样本的同一channel间的所有像素值进行归一化。因此不会破坏不同样本同一特征之间的关系,因为“减均值,除标准差”只是一个平移+缩放的线性操作,归一化前较大的数值在归一化之后依旧是较大的。
这一性质决定了经过归一化操作之后,样本之间仍然具有可比较性。但是特征和特征之间不再具备可比较性。
此外,测试阶段的样本不像训练样本那么多,因此$\mu$和$\sigma$的计算一定是有偏估计。我们可以采用整体样本的无偏估计,或者对训练阶段每个batch计算得到的均值和方差采用指数加权平均来得到测试阶段的均值和方差的估计。
Layer Normalization
假设输入数据的维度是:$x \in \mathbb{R}^{N \times C \times H \times W}$,Layer Normalization在对其求均值和方差时,将在$C$,$H$,$W$维度上求均值和标准差,保留$N$维度。
代码实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import torch
from torch import nn
N, C, H, W = 10, 3, 5, 5
# [N, C, H, W]
x = torch.rand(N, C, H, W) * 10000
ln = nn.LayerNorm(normalized_shape=[C, H, W], eps=0, elementwise_affine=False)
# [N, C, H, W]
official_ln = ln(x)
# [N, C * H * W]
x1 = x.reshape(N, -1)
# [N, 1, 1, 1]
mu = x1.mean(dim=1).reshape(N, 1, 1, 1)
std = x1.std(dim=1, unbiased=False).reshape(N, 1, 1, 1)
# [N, C, H, W]
my_ln = (x - mu) / std
# 误差在1e-5量级
diff = (official_ln - my_ln).sum()
print(diff)
Layer Normalization的优势是不需要批训练,在单条数据内部就能归一化。而且由于Layer Normalization常用于NLP任务,实际的输入数据的维度一般是$x \in \mathbb{R}^{N \times H \times W}$,不过计算方式都是一样的。
为什么不在NLP任务中使用Batch Normalization?
假设有三个句子:为中华之崛起而读书,我爱中国,母爱最伟大。在NLP中使用Batch Normalization对不同样本同一特征的信息进行归一化没有意义(把“为”,“我”,“母”归一化到同一分布有啥用?),而且舍弃了同一样本的不同维度信息之后(第一句中的“为”和“中”不再具有可比性,无法判断句子中哪个词重要性更高),会丧失序列信息。
LLM时代有一些针对Layer Normalization改进的Normalization手段,如RMSNorm和DeepNorm,同时Normalization的位置也有一些区别,分为Pre-Norm和Post-Norm,此处不展开。
Instance Normalization
假设输入数据的维度是:$x \in \mathbb{R}^{N \times C \times H \times W}$,Instance Normalization在对其求均值和方差时,将在$H$,$W$维度上求均值和标准差,保留$N$、$C$维度。也就是说,它只在channel内部求均值和标准差。
代码实现:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import torch
from torch import nn
N, C, H, W = 10, 3, 5, 5
# [N, C, H, W]
x = torch.rand(N, C, H, W) * 10000
In = nn.InstanceNorm2d(num_features=C, eps=0, affine=False, track_running_stats=False)
# [N, C, H, W]
official_in = In(x)
# [N * C, H * W]
x1 = x.reshape(N * C, -1)
# [N, C, 1, 1]
mu = x1.mean(dim=1).reshape(N, C, 1, 1)
std = x1.std(dim=1, unbiased=False).reshape(N, C, 1, 1)
# [N, C, H, W]
my_in = (x - mu) / std
# 误差在1e-5量级
diff = (official_in - my_in).sum()
print(diff)
Instance Normalization最初用于图像的风格迁移。在生成模型中,各个channel的均值和方差会影响最终生成图像的风格,因此可以把图像先在channel层面归一化,然后再用目标风格图片对应的channel的均值和标准差“去归一化”,以期获得目标图片的风格。
Instance Normalization也是在单个样本内部进行,不依赖batch。
Group Normalization
假设输入数据的维度是:$x \in \mathbb{R}^{N \times C \times H \times W}$,Group Normalization在对其求均值和方差时,把每一个样本在特征的channel维度上分为$G$组,每组将有$C/G$个channel。然后将这些channel中的元素求均值和标准差。各组channel用其对应的归一化参数独立地归一化。
代码实现:
1 | import torch |
Group Normalization是Layer Normalization和Instance Normalization的折中,也是独立于batch的。Group Normalization适用于占用显存比较大的任务,如图像分割。
总结
各Normalization方法的优缺点:
- Batch Normalization
- 优点
- 在CV领域取得了很好的效果
- 缺点
- 处理序列数据时(如文本),Batch Normalization可能不会表现很好
- 对于较小的Batch size,Batch normalization可能会表现得不好,因为每个batch的统计特性会有较大波动
- 优点
- Layer Normalization
- 优点
- Layer Normalization是对每个样本进行归一化,因为它对batch size不敏感,这使得它在处理序列数据时表现得更好
- Layer Normalization在处理不同长度的序列时更加灵活
- 缺点
- 如果不同输入特征不属于相似的类别,比如颜色,那么Layer Normalization的处理可能会降低模型的表达能力
- 优点
- Instance Normalization
- 优点
- Instance Normalization是对每个样本的每个特征进行归一化,因此它可以捕捉到更多的细节信息
- 缺点
- Instance Normalization可能会过度强调细节信息,忽视了更宏观的信息
- Instance Normalization的计算成本相比Batch Normalization和Layer Normalization更高
- 优点
- Group Normalization
- 优点:
- Group Normalization是Batch Normalization和Instance Normalization的折中方案,它在Batch的一个子集(即组)上进行归一化,这使得Group Normalization既可以捕获到Batch的统计特性,又可以捕获到样本的细节信息
- Group Normalization对Batch Size大小不敏感
- 缺点:
- Group Normalization的性能取决于组的大小,需要通过实验来确定最优的组大小
- Group Normalization的计算成本比Batch Normalization和Layer Normalization要高
- 优点:
【参考文献】