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

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

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

对于NLP

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

手动实现

import torch
import torch.nn as nn

ln_layer = nn.LayerNorm(normalized_shape=[3,20,20], elementwise_affine=False)
input = torch.randn(8, 3, 20, 20)
ln_outputs = ln_layer(input)

mean = torch.mean(input, dim=[1,2,3], keepdim=True)
var = torch.var(input, dim=[1,2,3], keepdim=True, unbiased=False)
output = (input-mean) / (torch.sqrt(var) + ln_layer.eps)

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也可以

带参数的写法

import torch
from torch import nn

class LayerNorm(nn.Module):
    def __init__(self, dim, eps=1e-6):
        super().__init__()
    
        self.size = dim
        # 使用两个可以学习的参数来进行 normalisation
        #self.alpha即self.weight
        self.alpha = nn.Parameter(torch.ones(3,20,20))
        self.bias = nn.Parameter(torch.zeros(3,20,20))
        # self.weight = Parameter(torch.Tensor(*normalized_shape))
        # self.bias = Parameter(torch.Tensor(*normalized_shape))
        self.eps = eps
    
    def forward(self, x):
        norm = self.alpha * (x - x.mean(dim=[1,2,3], keepdim=True)) \
                / (x.std(dim=[1,2,3], keepdim=True) + self.eps) + self.bias
        return norm


 
ln_layer = nn.LayerNorm(normalized_shape=[3,20,20], elementwise_affine=False)
input = torch.randn(8, 3, 20, 20)
ln_outputs = ln_layer(input)

my_lnlayer = LayerNorm(dim=3)
input = torch.randn(8, 3, 20, 20)
output = my_lnlayer(input)

 
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好

  • 15
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值