简介
Layer Normalization (LayerNorm) 是一种归一化技术,常用于深度学习模型中,特别是在 Transformer 模型中。
Layer normalization 是在特征维度上进行标准化的,而不是在数据批次维度上。
目的
收敛模型数据数值差异,缓解内部协变量偏移问题,提高训练速度和模型性能。
简单来说就是让模型的数据更加平滑,减小差异,方便计算
下面看一组差异较大的数据:
[1.1, 1, 0.9, 0.5, 0.4, 0.2],
[22, 11, 1, 99, 10, 5],
[888, 666, 5, 0, 10086, 99]
经过LayerNorm处理后的:
[ 1.2484, 0.9488, 0.6492, -0.5493, -0.8489, -1.4482],
[-0.0787, -0.4036, -0.6988, 2.1949, -0.4331, -0.5807],
[-0.2929, -0.3537, -0.5347, -0.5361, 2.2264, -0.5090]
可以看到数据看起来,似乎没那么突兀了~
计算公式
计算公式为
主要分两步计算:
1.计算均值和方差
2.标准化和重新缩放
归一化
归一化是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为标量,当然百度百科的答案
什么意思呢?
归一化是一种数据处理方式,将有量纲转化为无量纲,同时将数据归一化至同一量级,解决数据间的可比性问题。
将特定的度量转化为数目,去掉单位,统一起来进行计算比较。如12小时、1公斤、3米,这三个量纲是无法直接进行比较和计算的,也没有意义。
标准化
标准化又叫z值归一化,将数值缩放到0附近,且数据的分布变为均值为0,标准差为1的标准正态分布
计算过程
过程中共需要计算的中间变量有:平均值、方差、标准差、标准化结果、线性变换
- 平均值 E(x)
向量和/向量总数,矢量加法,然后除以总数,得到x
(x1+x2+…xn) / n = E(x) - 方差
各个数据与这组数据的平均数的差的平方的平均数
Var(x) = [(x1 - x)(x1 - x) + (x2 - x)(x2 - x) + … (xn - x)*(xn - x) ] / n - 标准差
方差开平方,加上一个很小的值𝜀防止出现除零。
Sqrt( + 𝜀) - 标准化
(当前向量值 - 平均值) / 方差(防止除零)
x^ = (x1 - E(x)) / Sqrt(Var(x) + 𝜀) - 线性变换
标准化结果乘以gamma,加上beta得到最终结果
x^ * g + b
方差简化版
方差还有一个简化的计算公式,可以根据方差计算公式推导,简化版的计算公式在实际应用中可以减少循环计数
(a-b)² = a² - 2ab + b²
方差公式
( (x1-E(x))² + (x2-E(x))² +… + (xn-E(x))² ) / n
方差公式转换
=( (x1² - 2x1E(x) + E(x)²) + (x2² - 2x2E(x) + E(x)²) +…+ (xn² - 2xnE(x) + E(x)²) ) / n
=( (x1² + x1² +…+xn²) - 2*(x1 + x2 + … + xn)E(x) + nE(x)² ) / n
=( (x1² + x1² +…+xn²) - 2 * n * ((x1 + x2 + … + xn) / n) * E(x) + nE(x)² ) / n
=( (x1² + x1² +…+xn²) - 2 * n * E(x)² + nE(x)² ) / n
=( (x1² + x1² +…+xn²) - n *E(x)² ) / n
=(x1² + x1² +…+xn²) / n - E(x)²
手动计算
对一行数据进行LayerNorm手动计算,其中方差使用简化公式(x1² + x1² +…+xn²) / n - E(x)²
【1.1, 1, 0.9, 0.5, 0.4, 0.2】
平均值:(1.1 + 1 + 0.9 + 0.5 + 0.4 + 0.2) / 6 = 4.1 / 6 = 0.683
平方和:1.1² + 1² + 0.9² + 0.5² + 0.4² + 0.2² = 3.47
方差:
3.47/6 - 0.683²=0.111
标准差,方差开平方 sqrt(0.111)= 0.333
标准化:
(1.1 - 0.683) / 0.333 = 1.252
(1.0 - 0.683) / 0.333 = 0.952
(0.9 - 0.683) / 0.333 = 0.652
(0.5 - 0.683) / 0.333 = -0.55
(0.4 - 0.683) / 0.333 = -0.85
(0.2 - 0.683) / 0.333 = -1.45
Python计算
import torch
import torch.nn as nninput = torch.tensor([[[[1.1, 1, 0.9, 0.5, 0.4, 0.2]]]])
ly = nn.LayerNorm(normalized_shape=6)
res = ly(input)
inputR = input.reshape(1, 1, 1, -1)
mean = inputR.mean(dim=-1).reshape(list(inputR.shape)[:-1] + [1] * (input.dim()-inputR.dim()+1))
std = inputR.std(dim=-1, unbiased=False).reshape(list(inputR.shape)[:-1] + [1] * (input.dim()-inputR.dim()+1))
std = torch.where(std == 0, 1e-8, std)
manual = (input - mean) / std
print("res:", manual)#结果:
#res: tensor([[[[ 1.2484, 0.9488, 0.6492, -0.5493, -0.8489, -1.4482]]]])