参考来源:
脚本之家:pytorch LayerNorm 参数的用法及计算过程
LayerNorm
:channel
方向做归一化,算 CHW 的均值,主要对 RNN 作用明显;
LayerNorm
中不会像 BatchNorm
那样跟踪统计全局的均值方差,因此 train()
和 eval()
对 LayerNorm
没有影响。
LayerNorm 参数
torch.nn.LayerNorm(
normalized_shape: Union[int, List[int], torch.Size],
eps: float = 1e-05,
elementwise_affine: bool = True
)
normalized_shape
- 如果传入整数,比如 4,则被看做只有一个整数的
list
,此时LayerNorm
会对输入的最后一维进行归一化,这个**int**
值需要和输入的最后一维一样大。- 假设此时输入的数据维度是
[3, 4]
,则对 3 个长度为 4 的向量求均值方差,得到 3 个均值和 3 个方差,分别对这 3 行进行归一化(每一行的 4 个数字都是均值为 0,方差为 1);LayerNorm
中的weight
和bias
也分别包含 4 个数字,重复使用 3 次,对每一行进行仿射变换(仿射变换即乘以weight
中对应的数字后,然后加bias
中对应的数字),并会在反向传播时得到学习。
- 假设此时输入的数据维度是
- 如果输入的是个
**list**
或者**torch.Size**
,比如[3, 4]
或torch.Size([3, 4])
,则会对网络最后的两维进行归一化,且要求输入数据的最后两维尺寸也是[3, 4]
。- 假设此时输入的数据维度也是
[3, 4]
,首先对这 12 个数字求均值和方差,然后归一化这个 12 个数字;weight
和bias
也分别包含 12 个数字,分别对 12 个归一化后的数字进行仿射变换(仿射变换即乘以weight
中对应的数字后,然后加bias
中对应的数字),并会在反向传播时得到学习。 - 假设此时输入的数据维度是
[N, 3, 4]
,则对着N
个[3,4]
做和上述一样的操作,只是此时做仿射变换时,weight
和bias
被重复用了N
次。 - 假设此时输入的数据维度是
[N, T, 3, 4]
,也是一样的,维度可以更多。
- 假设此时输入的数据维度也是
注意:显然 LayerNorm
中 weight
和 bias
的 shape
就是传入的 normalized_shape
。
eps
归一化时加在分母上防止除零。
elementwise_affine
- 如果设为
False
,则LayerNorm
层不含有任何可学习参数。 - 如果设为
True
(默认是True
)则会包含可学习参数weight
和bias
,用于仿射变换,即对输入数据归一化到均值 0 方差 1 后,乘以weight
,加bias
。
LayerNorm 前向传播(以 normalized_shape 为一个 int 举例)
1、如下所示输入数据的 shape
是 (3, 4)
,此时 normalized_shape
传入 4(输入维度最后一维的 size),则沿着最后一维(沿着最后一维的意思就是对最后一维的数据进行操作)求 E[x]
和 Var[x]
,并用这两个结果把 batch
沿着最后一维归一化,使其均值为 0,方差为 1。归一化公式用到了 eps()
,即
tensor = torch.FloatTensor([[1, 2, 4, 1],
[6, 3, 2, 4],
[2, 4, 6, 1]])
此时,E[x]=[2.0,3.75,3.25]
,Var[x]=[1.5000,2.1875,3.6875]
(有样本偏差),归一化后的值如下面所示。
[[-0.8165, 0.0000, 1.6330, -0.8165],
[ 1.5213, -0.5071, -1.1832, 0.1690],
[-0.6509, 0.3906, 1.4321, -1.1717]]
举例说明:第 0 行第 2 列的数字 4,减去第 0 行的均值 2.0 等于 2,然后除以 (1.5+ε)0.5=(1.50001)0.5=1.224749
,即 2/1.224749≈1.6330
。
2、如果 elementwise_affine==True
,则对归一化后的 batch
进行仿射变换,即乘以模块内部的 weight
(初值是 [1., 1., 1., 1.]
)然后加上模块内部的 bias
(初值是 [0., 0., 0., 0.]
),这两个变量会在反向传播时得到更新。
3、如果 elementwise_affine==False
,则 LayerNorm
中不含有 weight
和 bias
两个变量,只做归一化,不会进行仿射变换。
总结
在使用 LayerNorm
时,通常只需要指定 normalized_shape
就可以了。
补充:【Pytorch】F.layer_norm 和 nn.LayerNorm 到底有什么区别?
【背景】
最近在做视频方向,处理的是时序特征,就想着能不能用 Batch Normalization
来做视频特征 BN 层?在网上查阅资料发现,时序特征并不能用 Batch Normalization
,因为一个 batch
中的序列有长有短。
此外,BN 的一个缺点是需要较大的 batchsize
才能合理估训练数据的均值和方差,这导致内存很可能不够用,同时它也很难应用在训练数据长度不同的 RNN 模型上。Layer Normalization
(LN) 的一个优势是不需要批训练,在单条数据内部就能归一化。
对于 RNN 等时序模型,有时候同一个 batch
内部的训练实例长度不一(不同长度的句子),则不同的时态下需要保存不同的统计量,无法正确使用 BN 层,只能使用 Layer Normalization
。
查阅 Layer Normalization
(下述 LN)后发现,这东西有两种用法,一个是 **F.layer_norm**
,一个是 **torch.nn.LayerNorm**
,本文探究他们的区别。
F.layer_norm
用法
F.layer_norm(
x,
normalized_shape,
self.weight.expand(normalized_shape),
self.bias.expand(normalized_shape)
)
其中:
**x**
是输入的Tensor
。**normalized_shape**
是要归一化的维度,可以是x
的后若干维度。**self.weight.expand(normalized_shape)**
,可选参数,自定义的weight
。**self.bias.expand(normalized_shape)**
,可选参数,自定义的bias
。
示例
很容易看出来,跟 F.normalize
基本一样,没有可学习的参数,或者自定义参数。具体使用示例如下:
import torch.nn.functional as F
input = torch.tensor(a)
y = F.layer_norm(input,(4,))
print(y)
#####################输出################
tensor([[[-0.8095, -1.1224, 1.2966, 0.6354],
[-1.0215, -0.9661, 0.8387, 1.1488],
[-0.3047, 1.0412, -1.4978, 0.7613]],
[[ 0.4605, 1.2144, -1.5122, -0.1627],
[ 1.5676, 0.1340, -1.0471, -0.6545],
[ 1.5388, -0.3520, -1.2273, 0.0405]]])
添加缩放:
w = torch.tensor([1,1,2,2])
b = torch.tensor([1,1,1,1])
y = F.layer_norm(input,(4,),w,b)
print(y)
#########################输出######################
tensor([[[ 0.1905, -0.1224, 3.5931, 2.2708],
[-0.0215, 0.0339, 2.6775, 3.2976],
[ 0.6953, 2.0412, -1.9956, 2.5225]],
[[ 1.4605, 2.2144, -2.0243, 0.6746],
[ 2.5676, 1.1340, -1.0942, -0.3090],
[ 2.5388, 0.6480, -1.4546, 1.0810]]])
nn.LayerNorm
用法
torch.nn.LayerNorm(
normalized_shape: Union[int, List[int], torch.Size],
eps: float = 1e-05,
elementwise_affine: bool = True
)
**normalized_shape**
: 输入尺寸, [∗×normalized_shape[0]×normalized_shape[1]×…×normalized_shape[−1]]
**eps**
: 为保证数值稳定性(分母不能趋近或取 0),给分母加上的值。默认为 1e-5
。
**elementwise_affine**
: 布尔值,当设为 True
,给该层添加可学习的仿射变换参数。
示例elementwise_affine
如果设为 False
,则 LayerNorm
层不含有任何可学习参数。
如果设为 True
(默认是 True
)则会包含可学习参数 weight
和 bias
,用于仿射变换,即对输入数据归一化到均值 0 方差 1 后,乘以 weight
,加 bias
。
import torch
input = torch.randn(2,3,2,2)
import torch.nn as nn
#取消仿射变换要写成
#m = nn.LayerNorm(input.size()[1:], elementwise_affine=False)
m1 = nn.LayerNorm(input.size()[1:])#input.size()[1:]为torch.Size([3, 2, 2])
output1 = m1(input)
#只normalize后两个维度
m2 = nn.LayerNorm([2,2])
output2 = m2(input)
#只normalize最后一个维度
m3 = nn.LayerNorm(2)
output3 = m3(input)
总结
**F.layer_norm**
中没有可学习参数,而 **nn.LayerNorm**
有可学习参数。当 elementwise_affine
设为 False
时,nn.LayerNorm
退化为 F.layer_norm
。