15.3 层归一化
在Transformer里采用了一种更适合序列数据的归一化方式:层归一化(Layer Normalization),本节我们就来介绍。
15.3.1 序列归一化问题
序列问题的一大特点是序列长度是可变的,为了让这些可变长度的序列放入维度固定的tensor,会在一个batch里短的序列后边填充
15.3.2 Layer Norm
在解决序列问题时,层归一化,会按照每个token来分别统计每个token所有特征的均值和方差。然后在token特征的每个维度都定义两个可学习参数γ和β来进行线性变化。
所以,如果一个token的编码维度为512维,则对每个token的这512个特征数字计算均值和方差,并且所有token共享512个γ参数和512个β参数。
通过Layer Norm后基本保证了每个token的特征大致分布为均值为0,方差为1。这样保证了后边进行注意力计算时点积值的稳定性,不会落入softmax的失活区域。
Layer Norm因为是对输入每个token embedding的维度进行均值和方差的统计。对于推理状态也可以进行,所以不区分训练状态和推理状态。
15.3.3 PyTorch实现
class LayerNormalization(nn.Module):
def __init__(self, features: int, eps: float = 10 ** -6) -> None:
super().__init__()
self.eps = eps
# 可学习权重
self.alpha = nn.Parameter(torch.ones(features))
# 可学习偏差
self.bias = nn.Parameter(torch.zeros(features))
def forward(self, x):
# x: (batch, seq_len, hidden_size)
# 保留维度来进行广播
mean = x.mean(dim=-1, keepdim=True) # (batch, seq_len, 1)
std = x.std(dim=-1, keepdim=True) # (batch, seq_len, 1)
# eps 是为了防止除0设置的很小的值
return self.alpha * (x - mean) / (std + self.eps) + self.bias