pytorch:层标准化的实现,Layersnorm

前言

层标准化有两个,但是通常是对单一的vector进行标准化,也就是layerNorm
层标准化又两个必须要计算出来的,一个是平均值mean,一个是标准差std

1. 必要函数

1.1 input.mean( dim, keepdim=False, *, out=None) → Tensor

也可写成torch.mean(input, dim, keepdim=False, *, out=None) → Tensor

函数:把inputdim维度获取平均值,且维度减少;如果keepdimTrue,就会保持原有维度。

  • input(Tensor) : 输入的tensor
  • dim(通常是int) : 平均维度且维度减少;
  • keepdim(bool) : 为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])
1.2 input.std( dim, unbiased=True, keepdim=False, *, out=None) → Tensor

也可以写作:torch.std(input, dim, unbiased=True, keepdim=False, *, out=None) → Tensor

函数:返回输入张量给定维度上每行的标准差。如果keepdimTrue,则输出张量的大小与输入的大小相同,否则尺寸-1。

  • input(tensor) : input
  • dim(int) : 要减小的尺寸
  • keepdim(bool) : 是否保留原有尺寸

例子:

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

个人喜欢第二个实现方法。

你可能感兴趣的:(pytorch)