深度学习算法中常用归一化方法


介绍

归一化方法已经成为深度学习算法中不可或缺的一个重要模块,并且存在多种不同版本的归一化方法,其本质都是减均值除以方差,进行线性映射后,使其数据满足某个稳定分布。
y = γ ( x − μ ( x ) σ ( x ) ) + β y = γ(\frac{x-μ(x)}{σ(x)}){+β} y=γ(σ(x)xμ(x))+β


1 为什么要做归一化处理

目的:解决数据分布不稳定带来的问题,从而加速训练、稳定优化过程并提升模型性能。主要解决以下几个问题:

解决内部协变量偏移

  • 问题描述:
    • 深度网络由多个层叠加而成,每一层的输入都是前一层的输出。在训练过程中,随着网络参数的不断更新,每一层的输入数据的分布会发生剧烈变化(均值、方差偏移)。这种现象就称为内部协变量偏移。
    • 例如:某一层输入原本集中在 [-1, 1] 范围内,参数更新后下一批输入可能偏移到 [100, 200]。
  • 带来的后果
    • 学习目标持续变化:​ 后层需要不断适应新的数据分布,降低了学习效率。想象打靶时靶心一直在随机移动,射手很难命中。
    • 需要极小学习率:​ 为了保证在剧烈波动的输入下网络仍然能稳定学习,只能使用很小的学习率,导致收敛极慢。
    • 训练不稳定:​ 梯度计算变得不可靠,容易引起震荡或发散。
  • 归一化的作用:
    • BN/LN/IN/GN 等操作强制性地将每一层的输入(激活值)拉回一个稳定的分布(通常是零均值、单位方差)​。后续的缩放平移参数 γ, β 赋予网络调整分布的灵活性。
    • 这样后层面对的是一个更稳定、更“标准”​ 的输入分布,可以把主要精力放在学习“有用特征”上,而不是费力地适应输入的剧烈变化,大大加速训练。

解决梯度问题(梯度消失/爆炸)

  • 问题描述:​
    • 深度网络中梯度需要通过反向传播逐层传递。
    • 如果激活函数的输入值过大或过小(例如 Sigmoid、Tanh 的饱和区),或者各层输入的尺度差异巨大,会导致梯度变得极大(爆炸)或极小(消失),使得参数无法有效更新或更新幅度失控。
  • 归一化的作用:​
    • 将激活值归一化到合理的范围(如均值为0,标准差为1),使其通常落在激活函数的线性区或不饱和区附近。
    • Sigmoid/Tanh:​ 其导数值在输入接近0时最大,在两端接近0。归一化使输入集中在线性区,确保梯度具有较大且稳定的值。
    • ReLU 族:​ 虽然不存在“饱和区”,但输入值过大会导致激活值可能过大(尤其在深层),后续层计算的梯度也可能很大。归一化使输入保持在一个相对标准的尺度范围内,有助于稳定梯度的反向传播。
    • 从而显著缓解梯度消失和梯度爆炸问题。

允许使用更大的学习率

  • 问题描述:​
    • 如第1点所述,内部协变量偏移的存在迫使我们必须使用很小的学习率,以防网络因输入分布突变而变得不稳定。
  • 归一化的作用:​
    • 由于归一化大大稳定了各层的输入分布,​减小了训练过程中的震荡风险。
    • 这使得我们可以使用更大的学习率而不用担心训练发散。更大的学习率显著加速了模型在训练初期的收敛速度。

降低对权重初始化的敏感度

  • 问题描述:​
    • 在深度神经网络中,参数的初始值对训练的成败至关重要。不当的初始化容易导致梯度消失、爆炸或训练停滞。为深度网络找到完美的初始值是个难题。
  • 归一化的作用:​
    • 归一化(尤其是 BN、LN、GN)​减轻了网络对初始权重的依赖。即使初始权重设置得不是特别理想(例如初始输出值偏离0很多,或者方差过大/过小),归一化操作也能快速地将这些分布的偏移修正过来,使训练能够正常启动并继续下去。
    • 这大大降低了设计深度网络架构和训练策略的门槛。

因此,加入归一化操作后,相当于给神经网络安装了:

  • 稳定器(Stabilizer):​ 让每一层的输入都在一个“舒适区”工作。
  • 加速器(Accelerator):​ 可以开足马力(大学习率)训练,大大加快收敛。
  • 润滑剂(Lubricant):​ 让梯度流动得更顺畅,解决深层网络的梯度消失/爆炸问题。
  • 防护罩(Shield):​ 降低对初始化和超参的敏感性,提升训练的鲁棒性。
  • 轻微的随机干扰器(Light Regularizer):​ 特别是 BN,有助于提升泛化能力。

2 归一化算子

下表对比了最常用的几种归一化操作。

  • 批归一化(Batch Normalization, BN)
    原理: 对每一批数据的每个特征维度进行均值方差归一化,引入可学习的缩放和平移参数。
    公式:
    x norm = x − μ B σ B 2 + ϵ , y = γ x norm + β x_{\text{norm}} = \frac{x - \mu_{\mathcal{B}}}{\sqrt{\sigma_{\mathcal{B}}^2 + \epsilon}}, \quad y = \gamma x_{\text{norm}} + \beta xnorm=σB2+ϵ xμB,y=γxnorm+β
    优点: 缓解内部协变量偏移,允许更大的学习率。
    局限: 依赖批量大小,在小批量场景下性能下降。

  • 层归一化(Layer Normalization, LN)
    原理: 对单个样本的所有特征进行归一化,适用于RNN和Transformer等序列模型。
    公式:
    x norm = x − μ L σ L 2 + ϵ x_{\text{norm}} = \frac{x - \mu_{\mathcal{L}}}{\sqrt{\sigma_{\mathcal{L}}^2 + \epsilon}} xnorm=σL2+ϵ xμL
    优点: 不依赖批量大小,适合动态网络结构。
    应用: Transformer中的自注意力机制。

  • 实例归一化(Instance Normalization, IN)
    原理: 对每个样本的每个通道单独归一化,常见于图像生成任务。
    优点: 保留图像风格信息,适合风格迁移。
    对比: 与BN和LN的区别在于归一化维度。

  • 组归一化(Group Normalization, GN)
    原理: 将通道分组后对每组进行归一化,折中BN和LN的优势。
    适用场景: 目标检测、小批量训练(如YOLOv3)。

  • 其他归一化技术
    权重归一化(Weight Normalization): 直接对网络权重参数归一化。
    谱归一化(Spectral Normalization): 用于GAN训练,约束判别器 Lipschitz 常数。
    归一化算子

2.1 Layernorm算子

对于一个样本(或序列中的一个时间步),将其在该层所有神经元(特征单元)上的输出激活值进行标准化(减均值,除以方差),再应用可学习的缩放和平移。

计算步骤:

  • 计算均值和方差:沿特征维度(N)计算均值和方差。
  • 归一化:对每个特征值进行归一化。
  • 仿射变换:应用可学习参数缩放和平移。

PyTorch中的代码实现:

def layer_norm(x, normalized_shape, gamma, beta, eps=1e-5):
  """
  x: 输入张量
  normalized_shape: 归一化部分的形状 (如 (hidden_size,) 或 (d_model,))
  gamma: 缩放参数 (形状 = normalized_shape)
  beta: 偏移参数 (形状 = normalized_shape)
  eps: 小常数
  """
  # 1. 计算归一化轴上的均值和方差
  mean = np.mean(x, axis=-1, keepdims=True)   # 在最后一个轴(特征轴)上求均值
  var = np.var(x, axis=-1, keepdims=True)      # 在最后一个轴上求方差
  # 2. 标准化
  x_hat = (x - mean) / np.sqrt(var + eps)
  # 3. 应用仿射变换
  out = gamma * x_hat + beta
  return out

2.2.1 归一化轴

在layernorm算子中,有一个比较重要的属性:归一化轴(axis)。
归一化轴的作用就是在,计算均值和方差时,按照指定维度计算,计算后被指定的维度会被压缩(保留为维度1以便于广播)。例如,输入形状(B, S, D)中指定axis=-1,计算结果形状会变为(B, S, 1)。

注:缩放参数gamma和平移参数beta的维度必须与axis指定的归一化维度完全一致。例如指定axis=(-1,)时,gamma/beta形状为(D,);指定axis=(-2,-1)时,gamma/beta形状应为(S,D)。

另外,计算均值和方差时shape发生变化,最终的输出shape是不会变的。
下面是deepseek的解释:
在这里插入图片描述

2.2.1 ONNX算子定义

在ONNX算子定义中,layernorm算子只在opset17及以上有op定义。因此,在低版本的opset中,往往是一些小算子的组合形式表示layernorm算子。
如下图所示,详细描述的layernorm算子的组合中各个小算子的作用:
在这里插入图片描述

  • 属性:

    1. axis:类型(int),默认值为 -1。规范化维度,如果 rank(X) 为 r,则 axis 允许的范围为 [-r, r]。负值表示从后面计算维度。
    2. epsilon:类型(float),默认值 1e-05。计算方差时的数值稳定性常数。
    3. stash_type: 类型(int) ,默认值为1。Mean 和 InvStdDev 的类型,还指定了第一阶段的计算精度。
    
  • 输入:

      1. X:        输入tensor
      2. Scale:    均值
      3. B:        偏移
    
  • 输出:

      1. Y:          输出tensor
      2. Mean:       在训练期间用于加速梯度计算的保存均值
      3. InvStdDev:  在训练期间用于加快梯度计算保存的逆标准差
    

另外,在ONNX中衍生出一种新的算子,就是addlayernorm算子。
addlayernorm算子结合了残差连接(add)和层归一化(layernorm)两个操作。

AddLayerNorm(x, y) = LayerNorm(x + y)

2.2 groupnorm算子

对于一个shape为[N,C,H,W]的输入,GroupNorm将每个[C,H,W]在C维度上分为groupnum组,然后对每一组进行归一化。最后对归一化后的特征进行缩放和平移。其中缩放参数和平移参数是可训练的。

  • 计算公式:
# mean 和 variance 是按每组 channels 的每个实例计算的,并且为每组通道指定 'scale' 和 'bias'。参数 'num_groups' 应当能被通道数整除,以便与每组的通道数相等
y = scale * (x - mean) / sqrt(variance + epsilon) + bias

当组数与通道数相同时,该运算符等效于 InstanceNormalization。当只有一个组时,此运算符等效于 LayerNormalization。

2.3.1 ONNX算子定义

在ONNX算子定义中,groupnorm算子只在opset18及以上有op定义。因此,在低版本的opset中,往往是一些小算子的组合形式表示。
如下图所示,详细描述的groupnorm算子的组合中各个小算子的作用:
在这里插入图片描述

  • 属性:

      1. epsilon:    类型(float),默认值 1e-05。计算方差时的数值稳定性常数。
      2. num_groups: 类型(int)必填 ,默认值为1。通道组的数量。它应该是通道数 'C' 的除数。
    
  • 输入:

      1. X:          输入数据张量。
      2. scale:      缩放因子。
      3. Bias:        偏移。
    
  • 输入:

      1. Y:           输出数据张量。
    

总结

以上就是今天要讲的内容,本文简单介绍了深度学习算法中常用的归一化方法,并且对layernorm和groupnorm算子进行详细介绍,加深了我们对归一化方法的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值