Chapter4.2:Normalizing activations with layer normalization

4 Implementing a GPT model from Scratch To Generate Text

4.2 Normalizing activations with layer normalization

通过层归一化(Layer Normalization)对激活值进行归一化处理。

  • Layer normalization (LayerNorm):将激活值中心化到均值为 0,归一化方差为 1,稳定训练并加速收敛。

    应用位置

    1. transformer block 中的 multi-head attention module 前后。

    2. 最终输出层之前。

    下图提供了LayerNormalization的直观概述

    从一个小例子看看LayerNormalization发生了什么

    torch.manual_seed(123)
    
    batch_example = torch.randn(2, 5) 
    
    layer = nn.Sequential(nn.Linear(5, 6), nn.ReLU())
    out = layer(batch_example)
    print(out)
    print(out.shape)
    
    # 计算均值和方差
    mean = out.mean(dim=-1, keepdim=True)
    var = out.var(dim=-1, keepdim=True)
    
    print("Mean:\n", mean)
    print("Variance:\n", var)
    
    out_norm = (out - mean) / torch.sqrt(var)
    print("Normalized layer outputs:\n", out_norm)
    
    mean = out_norm.mean(dim=-1, keepdim=True)
    var = out_norm.var(dim=-1, keepdim=True)
    print("Mean:\n", mean)
    print("Variance:\n", var)
    
    """输出"""
    tensor([[0.2260, 0.3470, 0.0000, 0.2216, 0.0000, 0.0000],
            [0.2133, 0.2394, 0.0000, 0.5198, 0.3297, 0.0000]],
           grad_fn=<ReluBackward0>)
    
    torch.Size([2, 6])
    
    Mean:
     tensor([[0.1324],
            [0.2170]], grad_fn=<MeanBackward1>)
    
    Variance:
     tensor([[0.0231],
            [0.0398]], grad_fn=<VarBackward0>)
    
    Normalized layer outputs:
     tensor([[ 0.6159,  1.4126, -0.8719,  0.5872, -0.8719, -0.8719],
            [-0.0189,  0.1121, -1.0876,  1.5173,  0.5647, -1.0876]],
           grad_fn=<DivBackward0>)
    
    Mean:
     tensor([[9.9341e-09],
            [0.0000e+00]], grad_fn=<MeanBackward1>)
    Variance:
     tensor([[1.0000],
            [1.0000]], grad_fn=<VarBackward0>)
    

    归一化会独立应用于两个输入(行)中的每一个;使用 dim=-1 表示在最后一个维度(在本例中为特征维度)上进行计算,而不是在行维度上进行计算。

    关闭科学计数法

    torch.set_printoptions(sci_mode=False) #关闭科学计数法
    print("Mean:\n", mean)
    print("Variance:\n", var)
    
    """输出"""
    Mean:
     tensor([[    0.0000],
            [    0.0000]], grad_fn=<MeanBackward1>)
    Variance:
     tensor([[1.0000],
            [1.0000]], grad_fn=<VarBackward0>)
    
  • LayerNorm 类实现:基于归一化思路,实现一个 LayerNorm 类,稍后我们可以在 GPT 模型中使用它

    class LayerNorm(nn.Module):
        def __init__(self, emb_dim):
            super().__init__()
            self.eps = 1e-5
            self.scale = nn.Parameter(torch.ones(emb_dim))
            self.shift = nn.Parameter(torch.zeros(emb_dim))
    
        def forward(self, x):
            mean = x.mean(dim=-1, keepdim=True)
            var = x.var(dim=-1, keepdim=True, unbiased=False)
            norm_x = (x - mean) / torch.sqrt(var + self.eps)
            return self.scale * norm_x + self.shift
    

    层归一化公式(上面的例子中 γ = 1 \gamma = 1 γ=1 β = 0 \beta=0 β=0 ϵ = 0 \epsilon = 0 ϵ=0
    L a y e r N o r m ( x i ) = γ ⋅ x i − μ σ 2 + ϵ + β LayerNorm(x_i) = \gamma \cdot \frac{x_i-\mu}{\sqrt{\sigma^2 + \epsilon}} + \beta LayerNorm(xi)=γσ2+ϵ xiμ+β
    其中

    1. μ 、 σ 2 \mu 、 \sigma^2 μσ2 分别x在layer维度上的均值和方差

    2. γ 、 β \gamma 、\beta γβ 是可学习的缩放平移参数

    3. ϵ \epsilon ϵ 是一个小常数,用于防止除零错误。

    scaleshift:可训练参数,用于在归一化后调整数据的缩放和偏移。

    有偏方差:在上述方差计算中,设置 unbiased=False,意味着使用公式 ∑ i ( x − x ‾ ) n \frac{\sum_i(x- \overline x)}{n} ni(xx),不包含贝塞尔校正。其中 n 是样本大小(此处为特征或列的数量);该公式不包含贝塞尔校正(即在分母中使用 n-1),因此提供的是方差的有偏估计。(对于 LLMs,嵌入维度 n 非常大,使用 n 和 n-1 之间的差异可以忽略不计,GPT-2 是在归一化层中使用有偏方差进行训练的,因此为了与后续章节中加载的预训练权重兼容,我们也采用了这一设置。)

    ln = LayerNorm(emb_dim=5)
    out_ln = ln(batch_example)
    mean = out_ln.mean(dim=-1, keepdim=True)
    var = out_ln.var(dim=-1, unbiased=False, keepdim=True)
    
    print("Mean:\n", mean)
    print("Variance:\n", var)
    
    """输出"""
    Mean:
     tensor([[    -0.0000],
            [     0.0000]], grad_fn=<MeanBackward1>)
    Variance:
     tensor([[1.0000],
            [1.0000]], grad_fn=<VarBackward0>)
    
  • 所以、本节至此,我们介绍了实现GPT架构所需的构建块之一,如下图中打勾的部分


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值