当前位置:   article > 正文

Layer Normalization(LN) 层标准化 (为什么Transformer用LN)(手写手动实现LN)

layer normalization

CNN用BN, RNN用LN

BN又叫纵向规范化,LN又叫横向规范化

LN也是因为Transformer才为人们所熟知的

BN并不适用于RNN等动态网络和batchsize较小的时候效果不好。Layer Normalization(LN)的提出有效的解决BN的这两个问题。LN和BN不同点是归一化的维度是互相垂直的

下图的N是bs,F是H和W拍平后的维,也叫L 

叫Layer norm,其实是对单个样本做的,对batch的每一个样本做, 如果一个batch有n个feature,他就做n次。就像BN有c个channel时做c次一样。

之所以叫layer norm是因为三维的时候,一个样本就是一层

为什么Transformer用LN而不用BN

时序特征并不能用Batch Normalization,因为一个batch中的序列有长有短。就像图中画的,蓝线是BN取的,橙线是LN取的

如果使用BN,由于为了补齐长短不一的样例而添加进去的0使得较长序列中词语的含义向量规模相对变小,较短序列中的词转换为含义向量的规模相对变大。平白无故增添了误差抖动。

BatchNorm就是通过对batch size这个维度归一化来让分布稳定下来。

LayerNorm则是通过对Hidden size这个维度归一化来让某层的分布稳定。

使用LN保证每个序列中词语转成的含义向量在同一规模上

此外,BN 的一个缺点是需要较大的 batchsize 才能合理估训练数据的均值和方差,这导致内存很可能不够用,同时它也很难应用在训练数据长度不同的 RNN 模型上。

LN需要注意的地方

  • 不再有running_mean和running_var
  • gamma和beta为逐元素的

LayerNorm中不会像BatchNorm那样跟踪统计全局的均值方差,因此train()和eval()对LayerNorm没有影响

其实在eval模式下,只有BatchNorm会屏蔽,其他Norm函数不会屏蔽

LN在PyTorch中的实现

torch.nn.LayerNorm(normalized_shape, eps=1e-05, elementwise_affine=True, device=None, dtype=None)
  • normalized_shape:(int/list/torch.Size)该层的特征维度,即要被标准化的维度。
  • eps:分母修正项。
  • elementwise_affine:是否需要affine transform,这里也提醒你是逐元素的仿射变换。

LN的参数

 

对于image

  1. import torch
  2. from torch import nn
  3. N, C, H, W = 20, 5, 10, 10
  4. input = torch.randn(N, C, H, W)
  5. layer_norm = nn.LayerNorm([C, H, W]) # Normalize over the last three dimensions (i.e. the channel and spatial dimensions)
  6. output = layer_norm(input)

对于NLP

  1. import torch
  2. from torch import nn
  3. batch, sentence_length, embedding_dim = 20, 5, 10
  4. input = torch.randn(batch, sentence_length, embedding_dim)
  5. layer_norm = nn.LayerNorm(embedding_dim)
  6. output = layer_norm(input)

手动实现

  1. import torch
  2. import torch.nn as nn
  3. ln_layer = nn.LayerNorm(normalized_shape=[3,20,20], elementwise_affine=False)
  4. input = torch.randn(8, 3, 20, 20)
  5. ln_outputs = ln_layer(input)
  6. mean = torch.mean(input, dim=[1,2,3], keepdim=True)
  7. var = torch.var(input, dim=[1,2,3], keepdim=True, unbiased=False)
  8. output = (input-mean) / (torch.sqrt(var) + ln_layer.eps)
  9. assert torch.allclose(ln_outputs, output, rtol=1e-4)

偶尔还会报错,多运行几次。

这说明我们自己算的,虽然计算方法是对的,在数值上还和官方实现的有1e-6,1e-7等的差异,因为官方的实现可能是C语言底层,然后开了cuda.benmark等优化

为什么用torch.var和torch.sqrt(torch.var) 而不是直接用torch.std, 因为官网的公式是这么写的

    直接用std也可以

带参数的写法

  1. import torch
  2. from torch import nn
  3. class LayerNorm(nn.Module):
  4. def __init__(self, dim, eps=1e-6):
  5. super().__init__()
  6. self.size = dim
  7. # 使用两个可以学习的参数来进行 normalisation
  8. #self.alpha即self.weight
  9. self.alpha = nn.Parameter(torch.ones(3,20,20))
  10. self.bias = nn.Parameter(torch.zeros(3,20,20))
  11. # self.weight = Parameter(torch.Tensor(*normalized_shape))
  12. # self.bias = Parameter(torch.Tensor(*normalized_shape))
  13. self.eps = eps
  14. def forward(self, x):
  15. norm = self.alpha * (x - x.mean(dim=[1,2,3], keepdim=True)) \
  16. / (x.std(dim=[1,2,3], keepdim=True) + self.eps) + self.bias
  17. return norm
  18. ln_layer = nn.LayerNorm(normalized_shape=[3,20,20], elementwise_affine=False)
  19. input = torch.randn(8, 3, 20, 20)
  20. ln_outputs = ln_layer(input)
  21. my_lnlayer = LayerNorm(dim=3)
  22. input = torch.randn(8, 3, 20, 20)
  23. output = my_lnlayer(input)
  24. assert torch.allclose(ln_outputs, output, rtol=1e-4)

【关于 BatchNorm vs LayerNorm】那些你不知道的事-技术圈

为什么Transformer用LN

对于使用场景来说,BN在MLP和CNN上使用的效果都比较好,在RNN这种动态文本模型上使用的比较差。

BN在MLP中的应用。 BN是对每个特征在batch_size上求的均值和方差,如果BN应用到NLP任务,相当于是在对默认了在同一个位置的单词对应的是同一种特征

layer_norm针对的是文本的长度,整条序列的文本,所以比bn好

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/345682
推荐阅读
相关标签
  

闽ICP备14008679号