当前位置: 首页 > news >正文

实现层归一化

五、Layer Normalization

层归一化介绍

  • 层归一化(LayerNorm)通过对同一层的神经元输出进行归一化处理,有效提升模型训练稳定性。与BatchNorm不同,LayerNorm对单个样本的所有特征维度进行归一化,使其对序列长度变化具有更好的适应性。

    当处理变长序列数据时,LayerNorm保持每个时间步的独立计算特性,避免不同序列长度带来的统计量偏差。该操作通过可学习的缩放参数gamma和平移参数beta保留模型的表达能力。

数学公式

  • 层归一化对输入张量最后一个维度进行标准化处理:

    μ = 1 d m o d e l ∑ i = 1 d m o d e l x i σ 2 = 1 d m o d e l ∑ i = 1 d m o d e l ( x i − μ ) 2 out = γ ⋅ x − μ σ 2 + ϵ + β \mu = \frac{1}{d_{model}}\sum_{i=1}^{d_{model}}x_i \\ \sigma^2 = \frac{1}{d_{model}}\sum_{i=1}^{d_{model}}(x_i - \mu)^2 \\ \text{out} = \gamma \cdot \frac{x - \mu}{\sqrt{\sigma^2 + \epsilon}} + \beta μ=dmodel1i=1dmodelxiσ2=dmodel1i=1dmodel(xiμ)2out=γσ2+ϵ xμ+β
    其中:

    • γ ∈ R d _ m o d e l \gamma \in \mathbb{R}^{d\_{model}} γRd_model:可学习缩放参数(初始化为1)
    • β ∈ R d _ m o d e l \beta \in \mathbb{R}^{d\_{model}} βRd_model:可学习平移参数(初始化为0)
    • ϵ \epsilon ϵ:数值稳定系数(默认1e-12)

    d _ m o d e l d\_model d_model 为模型维度。

代码实现

  • 层归一化代码实现

    import torch
    from torch import nnclass LayerNorm(nn.Module):def __init__(self, d_model, eps=1e-12):super(LayerNorm, self).__init__()self.d_model = d_modelself.eps = eps# 可学习参数初始化self.gamma = nn.Parameter(torch.ones(d_model))  # 缩放参数self.beta = nn.Parameter(torch.zeros(d_model))   # 平移参数def forward(self, x):"""shape of x:              [batch_size,seq_len,d_model]shape of mean and var :  [batch_size,seq_len,1]shape of gamma and beta: [d_model]"""# 步骤1:计算最后一个维度的均值和方差mean = x.mean(dim=-1, keepdim=True)var = x.var(dim=-1, unbiased=False,  # 使用有偏方差估计(与PyTorch官方实现保持一致)keepdim=True # 保持维度对其)# 步骤2:标准化计算normalized = (x - mean) / torch.sqrt(var + self.eps)# 步骤3:仿射变换out = self.gamma * normalized + self.betareturn out
    
  • 注意

    1. 在统计学中,“unbiased”(无偏)通常指的是一个估计量,其期望值等于所估计的参数值。对于方差的计算,有两种常用的方法:无偏估计和最大似然估计。

      无偏估计(Bessel’s Correction):在计算样本方差时,通常使用无偏估计,其公式为:
      Var = 1 N − 1 ∑ i = 1 N ( x i − x ˉ ) 2 \text{Var} = \frac{1}{N-1} \sum_{i=1}^{N} (x_i - \bar{x})^2 Var=N11i=1N(xixˉ)2
      这里我们除以的是 (N-1),而不是样本数量 (N)。这是因为用 (N-1) 除法能够补偿样本方差相对于总体方差的系统性低估,也就是所谓贝塞尔校正(Bessel’s correction)。

      有偏估计(或最大似然估计,MLE):这是普遍用于深度学习中的方法,就是直接使用:
      Var = 1 N ∑ i = 1 N ( x i − x ˉ ) 2 \text{Var} = \frac{1}{N} \sum_{i=1}^{N} (x_i - \bar{x})^2 Var=N1i=1N(xixˉ)2

      其中 N 为样本总量,延伸到我们transformer中就是 d _ m o d e l d\_model d_model

    2. 使用有偏估计可以减小计算的偏差,提升计算的效率和速度,这个同事也在深度学习过程中允许更快的梯度更新,虽然有轻微的偏差,但通常在大量数据下这并不显著影响模型的训练效果。

    3. unbiased=False 是指定要使用有偏估计来计算方差。这默认为 False,偏向于加速计算并使得在深度学习环境下的表现更加稳定。

  • 维度计算流程

    操作步骤张量形状变化示例
    输入数据[batch_size, seq_len, d_model]
    步骤1 - 计算均值(dim=-1)[batch_size, seq_len, 1]
    步骤1 - 计算方差(dim=-1)[batch_size, seq_len, 1]
    步骤2 - 标准化计算[batch_size, seq_len, d_model]
    步骤3 - 线性变换(gamma/beta)[batch_size, seq_len, d_model]

使用示例

  • 测试代码

    if __name__ == "__main__":# 参数配置batch_size = 4seq_len = 100d_model = 512# 生成测试数据x = torch.randn(batch_size, seq_len, d_model)# 实例化层归一化模块layer_norm = LayerNorm(d_model=d_model)# 前向传播out = layer_norm(x)# 验证输出print("输入形状:", x.shape)        # torch.Size([4, 100, 512])print("输出形状:", out.shape)      # torch.Size([4, 100, 512])print("参数gamma形状:", layer_norm.gamma.shape)  # torch.Size([512])print("参数beta形状:", layer_norm.beta.shape)    # torch.Size([512])
    

相关文章:

  • 燃气经营从业人员有哪些类别
  • 计算机组成原理-408考点-数的表示
  • [DDD传灯录]禅师:这,就是领域驱动设计(01-02)
  • py语法基础理解
  • C++中随机数的产生
  • 登高架设作业证考试的实操项目有哪些?
  • Linux服务器离线安装ollama及大模型
  • 使用ACME给动态域名下的Synology NAS免费申请SSL证书(无需开放80/443端口)
  • 终端运行java出现???
  • Java基本概念
  • Veo 2:Gemini API赋能的革命性视频生成工具,重新定义动态内容创作——从逼真物理模拟到精细镜头控制,开发者的新一代视频生成利器
  • Vuex 和 Pinia 的区别
  • 【版本控制】SVN + TortoiseSVN版本管理实用教程(附安装+开发常用操作)
  • C语言基础语法详解:从入门到掌握
  • Object.defineProperty 与 Proxy解析
  • Python Cookbook-6.9 快速复制对象
  • 为什么vue的key值,不用index?
  • 文件传输过滤器绕过:Exe2Hex
  • 【资料推荐】LVDS Owner’s Manual
  • pcd2pgm的launch文件实现
  • 男子称喝中药治肺结节三个月后反变大增多,自贡卫健委回应
  • 马上评丨马拉松“方便门”被处罚,是一针清醒剂
  • 高糖高脂食物可能让你 “迷路”
  • 上海银行一季度净赚逾62亿增2.3%,不良贷款率与上年末持平
  • 第六次“太空会师”,神舟二十号3名航天员顺利进驻中国空间站
  • 魏晓栋已任上海崇明区委常委、组织部部长