Pytorch中不同的Norm归一化详细讲解
在做项目或者看论文时,总是能看到Norm这个关键的Layer,但是不同的Norm Layer具有不同的作用,准备好接招了吗?(本文结论全部根据pytorch官方文档得出,请放心食用)
一. LayerNorm
LayerNorm的公示如下:
y
=
x
−
E
[
x
]
Var
[
x
]
+
ϵ
∗
γ
+
β
y=\frac{x-\mathrm{E}[x]}{\sqrt{\operatorname{Var}[x]+\epsilon}} * \gamma+\beta
y=Var[x]+ϵx−E[x]∗γ+β
Parameters(参数):
- normalized_shape
- eps(确保分母不为0)
- elementwise_affine(布尔类型,是否要为每个元素添加一个可学习的仿射变换参数)
- bias(布尔类型,在elementwise_affine为True时可选择为每个元素另外加上一个可学习的偏置项)
其中可变化的量即可学习的参数即 elementwise_affine涉及的权重以及bias。
归一化的维度是由normalized_shape来决定的。假设输入的张量形状是[B,C,H,W],此时常见的normalized_shape为[C,H,W]。换句话说,由于最后三个维度包含一张完整的图片信息,它会计算每个图片的 CxHxW 张量的均值和标准差,并进行归一化,使得这个张量在归一化后均值为 0,标准差为 1。
举个具体的例子来说明,假设输入张量 x 如下:
x
=
[
[
1
2
3
4
5
6
7
8
9
10
11
12
]
[
13
14
15
16
17
18
19
20
21
22
23
24
]
]
x=\left[\begin{array}{c}{\left[\begin{array}{cccc}1 & 2 & 3 & 4 \\5 & 6 & 7 & 8 \\9 & 10 & 11 & 12\end{array}\right]} \\{\left[\begin{array}{cccc}13 & 14 & 15 & 16 \\17 & 18 & 19 & 20 \\21 & 22 & 23 & 24\end{array}\right]}\end{array}\right]
x=
159261037114812
131721141822151923162024
我们假设要对后两个维度进行归一化。
1. 计算均值
E
[
x
1
]
=
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
12
=
78
12
=
6.5
\mathrm{E}\left[x_{1}\right]=\frac{1+2+3+4+5+6+7+8+9+10+11+12}{12}=\frac{78}{12}=6.5
E[x1]=121+2+3+4+5+6+7+8+9+10+11+12=1278=6.5
E
[
x
2
]
=
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
12
=
222
12
=
18.5
\mathrm{E}\left[x_{2}\right]=\frac{13+14+15+16+17+18+19+20+21+22+23+24}{12}=\frac{222}{12}=18.5
E[x2]=1213+14+15+16+17+18+19+20+21+22+23+24=12222=18.5
2. 对每个样本的二维切片计算方差。
第一个样本:
Var
[
x
1
]
=
(
1
−
6.5
)
2
+
(
2
−
6.5
)
2
+
⋯
+
(
12
−
6.5
)
2
12
=
11.9167
\operatorname{Var}\left[x_{1}\right]=\frac{(1-6.5)^{2}+(2-6.5)^{2}+\cdots+(12-6.5)^{2}}{12}=11.9167
Var[x1]=12(1−6.5)2+(2−6.5)2+⋯+(12−6.5)2=11.9167
第二个样本:
Var
[
x
2
]
=
(
13
−
18.5
)
2
+
(
14
−
18.5
)
2
+
⋯
+
(
24
−
18.5
)
2
12
=
11.9167
\operatorname{Var}\left[x_{2}\right]=\frac{(13-18.5)^{2}+(14-18.5)^{2}+\cdots+(24-18.5)^{2}}{12}=11.9167
Var[x2]=12(13−18.5)2+(14−18.5)2+⋯+(24−18.5)2=11.9167
3. 计算归一化后的值
方便起见,我们设定 ϵ=0:
y
1
=
[
−
1.593
−
1.301
−
1.010
−
0.718
−
0.426
−
0.135
0.157
0.449
0.740
1.032
1.323
1.615
]
y_{1}=\left[\begin{array}{cccc}-1.593 & -1.301 & -1.010 & -0.718 \\-0.426 & -0.135 & 0.157 & 0.449 \\0.740 & 1.032 & 1.323 & 1.615\end{array}\right]
y1=
−1.593−0.4260.740−1.301−0.1351.032−1.0100.1571.323−0.7180.4491.615
y
2
=
[
−
1.593
−
1.301
−
1.010
−
0.718
−
0.426
−
0.135
0.157
0.449
0.740
1.032
1.323
1.615
]
y_{2}=\left[\begin{array}{cccc}-1.593 & -1.301 & -1.010 & -0.718 \\-0.426 & -0.135 & 0.157 & 0.449 \\0.740 & 1.032 & 1.323 & 1.615\end{array}\right]
y2=
−1.593−0.4260.740−1.301−0.1351.032−1.0100.1571.323−0.7180.4491.615
4. 应用可学习的仿射变换(可选)
具体应用:
我们的核心目标是对一个完整对象利用LayerNorm,所以这是我们的第一目标。
- NLP:
在NLP领域中,最常见的单体对象就是word。常见的输入形状是[B,Seq_len,Word_dim],即batch_size,每个句子包含几个单词,每个单词的具体维度。所以我们在最后一个维度即单词维度进行归一化。
# NLP Example
batch, sentence_length, embedding_dim = 20, 5, 10
embedding = torch.randn(batch, sentence_length, embedding_dim)
layer_norm = nn.LayerNorm(embedding_dim)
# Activate module
layer_norm(embedding)
- CV:
视觉也不用多说了,最多的就是在后三个维度(即完整的一张图像上)进行归一化。
N, C, H, W = 20, 5, 10, 10
input = torch.randn(N, C, H, W)
# Normalize over the last three dimensions (i.e. the channel and spatial dimensions)
# as shown in the image below
layer_norm = nn.LayerNorm([C, H, W])
output = layer_norm(input)
二. BatchNorm2d
公式与LayerNorm完全相同。但是在代码中其操作的维度不一样。LayerNorm是对整张图像进行归一化(操作后三个维度),而BatchNorm2d则是对通道进行归一化,比如说我们有256张图片作为一个批次,每张图片有3个通道为R,G,B,那么在R通道在归一化需要使用这256张图片的R通道。(G,B通道同理)
Parameters(参数):
- num_features:定义了通道数。
- eps :用于数值稳定性。
- momentum: 控制运行均值和方差的更新速度。
- affine: 决定是否有可学习的缩放和偏移参数。
- track_running_stats: 控制是否在推理时使用运行时统计量。
示例代码如下:
# With Learnable Parameters
m = nn.BatchNorm2d(100)
# Without Learnable Parameters
m = nn.BatchNorm2d(100, affine=False)
input = torch.randn(20, 100, 35, 45)
output = m(input)
三. InstanceNorm2d
公式还是和上面的完全一样。InstanceNorm2d与BatchNorm2d非常相似,只不过InstanceNorm2d更进一步,它实现了单个样本单通道的归一化。
Parameters(参数):
- num_features 定义了通道数。
- eps 用于防止数值不稳定。
- momentum 控制 running_mean 和 running_var 的更新速度(如果track_running_stats=True)。
- affine 决定是否有可学习的缩放和偏移参数。
- track_running_stats 决定是否在推理时使用累计的均值和方差,还是每次使用当前样本的统计量。
示例代码如下:
输入:(B,C,H,W) or (C,H,W)
输出:(B,C,H,W) or (C,H,W) 形状不变,当B=1时即(C,H,W),此时就是支持单个样本进行归一化的情况。
# Without Learnable Parameters
m = nn.InstanceNorm2d(100)
# With Learnable Parameters
m = nn.InstanceNorm2d(100, affine=True)
input = torch.randn(20, 100, 35, 45)
output = m(input)
四. GroupNorm
公式还是和上面三个一样。然而GroupNorm在Instance的基础上,可以将通道进行分组归一化。比如说一个样本共有8个通道,设置num_groups=2,那么1-4的channels,2-4的channels将被分组进行归一化。
Parameters(参数):
- num_groups:定义了将通道分为多少组,每组内独立计算均值和方差。
- num_channels:定义了输入数据的通道数,确保与 num_groups 匹配。
- eps:防止除零错误的小值,确保计算稳定性。
- affine:决定是否为每个通道学习仿射参数(缩放和偏移)。
示例代码:
input = torch.randn(20, 6, 10, 10)
# Separate 6 channels into 3 groups
m = nn.GroupNorm(3, 6)
# Separate 6 channels into 6 groups (equivalent with InstanceNorm)
m = nn.GroupNorm(6, 6)
# Put all 6 channels into a single group (equivalent with LayerNorm)
m = nn.GroupNorm(1, 6)
# Activating the module
output = m(input)
纸上得来终觉浅,绝知此事要躬行!多分析源码,收获良多。