视频详细讲解(一行一行代码讲解实现过程):逐行讲解Transformer的代码实现和原理讲解:层归一化原理_哔哩哔哩_bilibili
1 目的
层规范化可以帮助稳定训练过程并加速收敛。
在深度学习中,随着网络层数的增加,梯度消失或爆炸问题以及内部协变量偏移(internal covariate shift)问题会变得更加严重。内部协变量偏移是指当模型训练时,前面层的参数更新会导致后续层接收的输入分布发生变化,这使得网络难以学习。为了解决这些问题,提出了多种归一化技术,比如批量归一化(Batch Normalization)、实例归一化(Instance Normalization)、层归一化(Layer Normalization)等。
2 层归一化计算过程
假设我们有一个简单的输入张量,形状为 (batch_size, sequence_length, model_dimension)
。为了简化说明,我们将使用一个较小的例子。
示例数据
假设有以下输入张量 x
,形状为 (2, 3, 4)
,即有两个样本,每个样本有三个时间步,每个时间步有四个特征。
1import torch
2import torch.nn as nn
3
4# 输入张量
5x = torch.tensor([
6 [
7 [1.0, 2.0, 3.0, 4.0],
8 [5.0, 6.0, 7.0, 8.0],
9 [9.0, 10.0, 11.0, 12.0]
10 ],
11 [
12 [13.0, 14.0, 15.0, 16.0],
13 [17.0, 18.0, 19.0, 20.0],
14 [21.0, 22.0, 23.0, 24.0]
15 ]
16], dtype=torch.float32)
创建 LayerNorm 层
接下来,我们创建一个 nn.LayerNorm
层,指定 model_dimension
为 4,因为我们希望沿着最后一个维度(特征维度)进行归一化。
1layer_norm = nn.LayerNorm(normalized_shape=4, eps=1e-5)
计算均值和方差
对于每个样本,我们需要计算其特征的均值和方差。这里我们只关注第一个样本的第一个时间步,其余部分的计算类似。
第一个样本的第一个时间步
取第一个样本的第一个时间步的特征向量 [1.0, 2.0, 3.0, 4.0]
。
计算所有时间步
我们重复上述步骤,对所有时间步进行相同的计算。
执行层规范化
现在我们直接使用 layer_norm
对整个输入张量进行处理,并打印结果。
normalized_x = layer_norm(x)
print(normalized_x)
结果
以下是计算后的结果(四舍五入到小数点后四位):
1tensor([[[ -1.3416, -0.4472, 0.4472, 1.3416],
2 [ -1.3416, -0.4472, 0.4472, 1.3416],
3 [ -1.3416, -0.4472, 0.4472, 1.3416]],
4 [[ -1.3416, -0.4472, 0.4472, 1.3416],
5 [ -1.3416, -0.4472, 0.4472, 1.3416],
6 [ -1.3416, -0.4472, 0.4472, 1.3416]]])
可以看到,每个样本的每个时间步的特征都被归一化了。由于 gamma
和 beta
初始都是 1 和 0,因此归一化后的结果就是标准化后的值。