Layer Normalization(层规范化)

本文介绍了层规范化(LayerNormalization,LN),一种在训练深度神经网络时减少计算时间并适用于RNN的方法。与批量规范化相比,LN无需依赖于批次大小,且能直接处理小样本和在线学习场景。它通过直接根据隐藏层内神经元的输入进行规范化,从而提高稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


详细内容在这篇论文:Layer Normalization


训练深度神经网络需要大量的计算,减少计算时间的一个有效方法是规范化神经元的活动,例如批量规范化BN(batch normalization)技术,然而,批量规范化对小批量大小(batch size)敏感并且无法直接应用到RNN中(recurrent neural networks),为了解决上述问题,层规范化LN(Layer Normalization)被提出,不仅能直接应用到RNN,还能显著减少训练时间。与批量归一化不同,层规范化直接根据隐藏层内神经元的总输入估计归一化统计数据,因此不会在训练案例之间引入任何新的依赖关系。

🍎 背景

A feed-forward neural network is a non-linear mapping from a input pattern x \mathbf{x} x to an output vector y y y. Consider the l th  l^{\text {th }} lth  hidden layer in a deep feed-forward, neural network, and let a l a^l al be the vector representation of the summed inputs to the neurons in that layer. a i l a_i^l ail是第 l l l层第 i i i个神经元的线性加权输出。 The summed inputs are computed through a linear projection with the weight matrix W l W^l Wl and the bottom-up inputs h l h^l hl given as follows:
a i l = w i l ⊤ h l h i l + 1 = f ( a i l + b i l ) a_i^l=w_i^{l^{\top}} h^l \quad h_i^{l+1}=f\left(a_i^l+b_i^l\right) ail=wilhlhil+1=f(ail+bil)

where f ( ⋅ ) f(\cdot) f() is an element-wise non-linear function(激活函数) and w i l w_i^l wil is the incoming weights to the i t h i^{t h} ith hidden units and b i l b_i^l bil is the scalar bias parameter. The parameters in the neural network are learnt using gradient-based optimization algorithms with the gradients being computed by back-propagation.

🍌 Batch Normalization

BN是为了减少协变量偏移提出的,它在训练阶段对隐神经元加权输出进行规范化,例如,对于 l t h l^{th} lth层的 i t h i^{th} ith个加权输出 a i l a_i^l ail,BN根据输入数据的分布进行了缩放
a ˉ i l = g i l σ i l ( a i l − μ i l ) μ i l = E x ∼ P ( x ) [ a i l ] σ i l = E x ∼ P ( x ) [ ( a i l − μ i l ) 2 ] \bar{a}_i^l=\frac{g_i^l}{\sigma_i^l}\left(a_i^l-\mu_i^l\right) \quad \mu_i^l=\underset{\mathbf{x} \sim P(\mathbf{x})}{\mathbb{E}}\left[a_i^l\right] \quad \sigma_i^l=\sqrt{\underset{\mathbf{x} \sim P(\mathbf{x})}{\mathbb{E}}\left[\left(a_i^l-\mu_i^l\right)^2\right]} aˉil=σilgil(ailμil)μil=xP(x)E[ail]σil=xP(x)E[(ailμil)2]

where a ˉ i l \bar{a}_i^l aˉil is normalized summed inputs to the i t h i^{t h} ith hidden unit in the l t h l^{t h} lth layer and g i g_i gi is a gain parameter scaling the normalized activation before the non-linear activation function.

实际中不会计算真正的 μ \mu μ σ \sigma σ,转而去估计一个batch里的 μ \mu μ σ \sigma σ,所以BN要求这个batchsize不能太小。然而,在一些在线学习任务以及超大分布模型中往往需要很小的batchsize。

🍑 Layer Normalization

μ l = 1 H ∑ i = 1 H a i l σ l = 1 H ∑ i = 1 H ( a i l − μ l ) 2 \mu^l=\frac{1}{H} \sum_{i=1}^H a_i^l \quad \sigma^l=\sqrt{\frac{1}{H} \sum_{i=1}^H\left(a_i^l-\mu^l\right)^2} μl=H1i=1Hailσl=H1i=1H(ailμl)2

H H H是一个隐藏层中的隐藏单元数量。在LN中,同一个层共享 μ \mu μ σ \sigma σ, but different training cases have different normalization terms. Unlike batch normalization, layer normalization does not impose any constraint on the size of a mini-batch and it can be used in the pure online regime with batch size 1.

In a standard RNN, the summed inputs in the recurrent layer are computed from the current input x t \mathbf{x}^t xt and previous vector of hidden states h t − 1 \mathbf{h}^{t-1} ht1 which are computed as a t = W h h h t − 1 + W x h x t \mathbf{a}^t=W_{h h} h^{t-1}+W_{x h} \mathbf{x}^t at=Whhht1+Wxhxt. The layer normalized recurrent layer re-centers and re-scales its activations using the extra normalization terms :
h t = f [ g σ t ⊙ ( a t − μ t ) + b ] μ t = 1 H ∑ i = 1 H a i t σ t = 1 H ∑ i = 1 H ( a i t − μ t ) 2 \mathbf{h}^t=f\left[\frac{\mathbf{g}}{\sigma^t} \odot\left(\mathbf{a}^t-\mu^t\right)+\mathbf{b}\right] \quad \mu^t=\frac{1}{H} \sum_{i=1}^H a_i^t \quad \sigma^t=\sqrt{\frac{1}{H} \sum_{i=1}^H\left(a_i^t-\mu^t\right)^2} ht=f[σtg(atμt)+b]μt=H1i=1Haitσt=H1i=1H(aitμt)2

where W h h W_{h h} Whh is the recurrent hidden to hidden weights and W x h W_{x h} Wxh are the bottom up input to hidden weights. ⊙ \odot is the element-wise multiplication between two vectors. b \mathbf{b} b and g \mathbf{g} g are defined as the bias and gain parameters of the same dimension as h t \mathbf{h}^t ht.

在标准RNN中存在梯度爆炸和消失问题,用了LN之后会更加稳定。

贴两个图便于理解:
在这里插入图片描述
在这里插入图片描述

视频讲解可以参考:What is Layer Normalization? | Deep Learning Fundamentals


🍟 举个例子

BatchNorm(批归一化)

BN 是在一个 batch 内,同一维度、不同样本之间做归一化。

举例说明:

假如每个样本有 5 个指标(特征):

  • 身高、体重、血压、心率、血糖

一个 batch 里有 4 个人(4 个样本),数据可能如下:

身高体重血压心率血糖
人117065120755.2
人218072130684.8
人316060110805.0
人417570125725.1

BatchNorm 对身高这一列:

  • 会把这一列的 4 个值 (170, 180, 160, 175) 计算均值和方差,然后归一化(减均值除方差)。
  • 体重这一列也是同理,分别对每一列归一化。

本质上:

  • 同一维度(比如身高),不同样本之间做归一化。
  • 这样可以减少由于 batch 内分布变化造成的不稳定。
  • 但是对 batch size 比较敏感,batch size 太小效果会变差。

LayerNorm(层归一化)

LN 是在每个样本内部,所有特征之间做归一化。

举例说明:

同样的数据,每个人是一个样本(向量),LN 对每个人自己单独做归一化。

比如人1([170, 65, 120, 75, 5.2]):

  • 计算这 5 个值的均值和方差
  • 把这 5 个值全部归一化(每个人的 5 个指标都做减均值、除方差)

对人2也是对 [180, 72, 130, 68, 4.8] 这5个值单独做。

本质上:

  • 同一个样本(人),所有特征之间做归一化。
  • 不依赖 batch size,每个样本可以独立处理。
  • 适合做 NLP/Transformer 或者时序任务,或者 batch size 比较小的场景。

小结一句话:

  • BN:横向对比,一群人某个指标如何分布
  • LN:纵向对比,一个人自身各项指标如何分布

📖 代码实现

这边贴一个Restormer中的LN层的实现

首先定义两个函数用于reshape。4d到3d不需要参数,因为只需要把已有的两个维度合并;3d到4d需要参数,因为需要把一个维度分成两个维度

def to_3d(x):
    return rearrange(x, 'b c h w -> b (h w) c')

def to_4d(x,h,w):
    return rearrange(x, 'b (h w) c -> b c h w',h=h,w=w)

定义一个没有bias的LN层,weight是可学习的参数,所以用 n n . P a r a m e t e r nn.Parameter nn.Parameter包装

# 没有bias的LayerNorm层
class BiasFree_LayerNorm(nn.Module):
    def __init__(self, normalized_shape):
        super(BiasFree_LayerNorm, self).__init__()
        if isinstance(normalized_shape, numbers.Integral):
            normalized_shape = (normalized_shape,)
        normalized_shape = torch.Size(normalized_shape)

        assert len(normalized_shape) == 1

        self.weight = nn.Parameter(torch.ones(normalized_shape))
        self.normalized_shape = normalized_shape

    def forward(self, x):
    	#x的维度(batch_size, height x width, channels)
    	#sigma的维度(batch_size, height x width, 1)
        sigma = x.var(-1, keepdim=True, unbiased=False)
        return x / torch.sqrt(sigma+1e-5) * self.weight

定义一个有bias的LN层,同样的,weight和bias都是可学习的参数

class WithBias_LayerNorm(nn.Module):
    def __init__(self, normalized_shape):
        super(WithBias_LayerNorm, self).__init__()
        #如果输入的normalized_shape是个整数,则化为元组
        if isinstance(normalized_shape, numbers.Integral):
            normalized_shape = (normalized_shape,)
        normalized_shape = torch.Size(normalized_shape)

        assert len(normalized_shape) == 1

        self.weight = nn.Parameter(torch.ones(normalized_shape))
        #比上面多定义一个bias
        self.bias = nn.Parameter(torch.zeros(normalized_shape))
        self.normalized_shape = normalized_shape

    def forward(self, x):
        mu = x.mean(-1, keepdim=True)
        sigma = x.var(-1, keepdim=True, unbiased=False)
        return (x - mu) / torch.sqrt(sigma+1e-5) * self.weight + self.bias#这边加了bias

把上面的函数包装起来,定义一个统一的层规范化函数

class LayerNorm(nn.Module):
    def __init__(self, dim, LayerNorm_type):
        super(LayerNorm, self).__init__()
        if LayerNorm_type =='BiasFree':
            self.body = BiasFree_LayerNorm(dim)
        else:
            self.body = WithBias_LayerNorm(dim)

    def forward(self, x):
        h, w = x.shape[-2:]
        return to_4d(self.body(to_3d(x)), h, w)
### Layer Normalization 与 Batch Normalization 的概念对比 #### 定义与机制 Batch Normalization 是一种通过减少内部协变量偏移来加速深度网络训练的技术[^2]。它通过对每一批次的数据计算均值和方差,标准化每一输入的分布,从而稳定学习过程并允许更高的学习率。 相比之下,Layer Normalization 不依赖于批次中的样本数量,而是针对单一样本的所有特征进行规范化处理[^3]。具体来说,对于给定的一个样本,其所有维度上的激活值会被用来计算均值和方差,并据此调整这些激活值。 #### 计算方式差异 - **Batch Normalization**: 对于一个批量 \(B\) 中的每一个特征 \(i\), \[ \mu_B = \frac{1}{m} \sum_{j=1}^{m} x_{ij}, \quad \sigma_B^2 = \frac{1}{m} \sum_{j=1}^{m} (x_{ij} - \mu_B)^2, \] 其中 \(m\) 表示批大小。随后对每个样本应用如下变换: \[ \hat{x}_{ij} = \frac{x_{ij} - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}, \] - **Layer Normalization**: 针对单个样本 \(x_i\) 所有维度的整体均值和方差定义为: \[ \mu_L(x_i) = \frac{1}{H} \sum_{k=1}^{H} x_{ik}, \quad \sigma_L^2(x_i) = \frac{1}{H} \sum_{k=1}^{H} (x_{ik} - \mu_L(x_i))^2. \] 接着对该样本执行逐维归一化操作: \[ \hat{x}_i = \frac{x_i - \mu_L(x_i)}{\sqrt{\sigma_L^2(x_i) + \epsilon}}. \] #### 应用场景分析 Batch Normalization 更适合大规模数据集以及能够提供充足样本来构成有效统计量的情况。然而,在小批量或者极端情况下(如 RNN 或者 Transformer 结构中),由于批间波动较大可能导致不稳定的结果,此时 Layer Normalization 显示出了优势。 另外需要注意的是 Dropout 技术虽然也旨在提高泛化能力,但它的工作原理完全不同——随机丢弃部分神经元以防止过拟合现象发生[^4]。 ```python import torch.nn as nn # Example of applying BatchNorm and LayerNorm in PyTorch class Model(nn.Module): def __init__(self): super(Model, self).__init__() self.fc = nn.Linear(100, 50) self.bn = nn.BatchNorm1d(50) # Batch Normalization layer self.ln = nn.LayerNorm([50]) # Layer Normalization layer def forward(self, x): out = self.fc(x) bn_out = self.bn(out) # Apply BN during training phase only ln_out = self.ln(out) # Can be applied at any stage without dependency on batch size return bn_out, ln_out ``` ### 总结 综上所述,尽管两者都致力于解决不同类型的优化难题,但在实际部署时需考虑具体的任务需求及模型结构特点来决定采用哪种方法更为合适。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

果壳小旋子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值