层标准化有两个,但是通常是对单一的vector
进行标准化,也就是layerNorm
。
层标准化又两个必须要计算出来的,一个是平均值mean
,一个是标准差std
。
input.mean( dim, keepdim=False, *, out=None) → Tensor
也可写成torch.mean(input, dim, keepdim=False, *, out=None) → Tensor
函数:把input
按dim
维度获取平均值,且维度减少;如果keepdim
为True
,就会保持原有维度。
False
x = np.random.rand(batch_size, seq_max, hidden_size)
x = torch.FloatTensor(x)
# torch.Size([2, 4, 8])
mean = x.mean(-1, keepdim = True)
print(mean.shape)
# torch.Size([2, 4, 1])
# 如果Keepdim=false
print(mean.shape)
# torch.Size([2, 4])
input.std( dim, unbiased=True, keepdim=False, *, out=None) → Tensor
也可以写作:torch.std(input, dim, unbiased=True, keepdim=False, *, out=None) → Tensor
函数:返回输入张量给定维度上每行的标准差。如果keepdim
为True
,则输出张量的大小与输入的大小相同,否则尺寸-1。
std = input_batch.std(-1, keepdim = True)
print(std.shape)
# torch.Size([2, 4, 1])
通常我们的数据都是[batch_size, seq_len, hidden_size]
需要数据归一化,因为不归一化的,在softmax很容易出现数据标签溢出的问题。
函数定义如下:
# 输入是[batch_size, seq_len, hidden_size]
def norm_mat(mat):
mean = mat.mean(-1, keepdim=True)
std = mat.std(-1, keepdim=True)
return (mat-mean)/(std+1e-9)
但是也有问题,会破坏数据的完整表达信息,损失一部分信息。
通常更常用的是transformer
的向量标准化
class BertLayerNorm(nn.Module):
"""LayerNorm层, 见Transformer---编码器(encoder)"""
def __init__(self, hidden_size, eps=1e-12):
super(BertLayerNorm, self).__init__()
#self.weight = nn.Parameter(torch.ones(hidden_size))
#self.bias = nn.Parameter(torch.zeros(hidden_size))
self.weight = nn.Parameter(torch.ones(2*hidden_size))
self.bias = nn.Parameter(torch.zeros(2*hidden_size))
self.variance_epsilon = eps
def forward(self, x):
u = x.mean(-1, keepdim=True)
s = (x - u).pow(2).mean(-1, keepdim=True)
x = (x - u) / torch.sqrt(s + self.variance_epsilon)
return self.weight * x + self.bias
或者
class LayerNorm(nn.Module):
"Construct a layernorm module (See citation for details)."
# hidden_size
def __init__(self, features, eps=1e-6):
super(LayerNorm, self).__init__()
self.a_2 = nn.Parameter(torch.ones(features))
self.b_2 = nn.Parameter(torch.zeros(features))
self.eps = eps
def forward(self, x):
# [B,S,H] → [B,S,1]
mean = x.mean(-1, keepdim=True)
# [B,S,H] → [B,S,1]
std = x.std(-1, keepdim=True)
# 等价于(x-mean) / std 不同的是保留那些东西了。
return self.a_2 * (x - mean) / (std + self.eps) + self.b_2
个人喜欢第二个实现方法。