参考:
1、pytorch LayerNorm参数详解,计算过程
2、nn.LayerNorm的具体实现方法(通过公式复现)
如果传入整数,比如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。
归一化时加在分母上防止除零。
如果设为False,则LayerNorm层不含有任何可学习参数。
如果设为True(默认是True)则会包含可学习参数weight和bias,用于仿射变换,即对输入数据归一化到均值0方差1后,乘以weight,即bias。
torch.nn.LayerNorm(
normalized_shape: Union[int, List[int], torch.Size],
eps: float = 1e-05,
elementwise_affine: bool = True)
import torch
a = torch.tensor([[1,2,4,1],[6,3,2,4],[2,4,6,1]]).float()
print(a)
输出
tensor([[1., 2., 4., 1.],
[6., 3., 2., 4.],
[2., 4., 6., 1.]])
print(nn.LayerNorm([4])(a))
tensor([[-0.8165, 0.0000, 1.6330, -0.8165],
[ 1.5213, -0.5071, -1.1832, 0.1690],
[-0.6509, 0.3906, 1.4321, -1.1717]],
grad_fn=<NativeLayerNormBackward>)
a = torch.tensor([[1,2,4,1],[6,3,2,4],[2,4,6,1]]).float()
print(a)
print(nn.LayerNorm([3,4])(a))
tensor([[1., 2., 4., 1.],
[6., 3., 2., 4.],
[2., 4., 6., 1.]])
tensor([[-1.1547, -0.5773, 0.5773, -1.1547],
[ 1.7320, 0.0000, -0.5773, 0.5773],
[-0.5773, 0.5773, 1.7320, -1.1547]],
grad_fn=<NativeLayerNormBackward>)