Batch Normalization和Layer Normalization的区别(二)

上一篇具体讲解了Batch Normalization的原理,如果没看的小伙伴可以移步了解:

Batch Normalization和Layer Normalization的区别(一)https://blog.csdn.net/weixin_55236001/article/details/147602671

如果真正明白了Batch Normalization的原理,那么理解Layer Normalization就不在话下。本篇博文将从以下几个方面进行讲解:

1. BN用于CV, LN用于NLP?

2.LN:与BN的对比学习

3.Pytorch的LayerNorm类

4.使用Pytorch进行验证

5. Vision Transformer 中使用 LN 的原因

参考:WSLGN:BatchNorm和LayerNorm——通俗易懂的理解https://blog.csdn.net/Little_White_9/article/details/123345062?ops_request_misc=%257B%2522request%255Fid%2522%253A%25224801c4db0366bd061cc57b36d94965c7%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=4801c4db0366bd061cc57b36d94965c7&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-123345062-null-null.142^v102^pc_search_result_base7&utm_term=layernorm&spm=1018.2226.3001.4449

太阳花的小绿豆:Layer Normalization解析https://blog.csdn.net/qq_37541097/article/details/117653177

1. BN用于CV, LN用于NLP?        

可能很多人都知道BatchNorm一般用于CV领域,而LayerNorm一般用于NLP领域。那为什么会这么暴力地进行归纳呢?其实是有一定道理的:

1. 归一化的对象不一样

  • BatchNorm它是在“一整批数据”上做归一化。想象有一堆照片,BatchNorm 是把每张照片的同一个位置(比如左上角的像素)放在一起,计算它们的平均值和标准差,然后调整每个像素的值。这样做的好处是,它能够利用整批数据的信息来稳定训练,但缺点是如果批量太小,计算出来的平均值和标准差就不够准确。

  • LayerNorm它是在“单个样本”上做归一化。还是用照片举例,LayerNorm 是把一张照片的所有像素放在一起,计算这张照片的平均值和标准差,然后调整每个像素的值。它不依赖于批量大小,哪怕只有一张照片也能工作得很好。

2. 对批量大小的依赖不一样

  • BatchNorm:它很依赖批量大小。如果批量太大,计算出来的统计量会比较准确,训练效果就好;但如果批量太小,统计量就不够稳定,训练效果就会变差。在计算机视觉(CV)任务中,我们通常可以使用比较大的批量,所以 BatchNorm 很适合。

  • LayerNorm:它完全不依赖批量大小。不管批量有多大或多小,它都能正常工作。这在自然语言处理(NLP)任务中特别有用,因为 NLP 的数据通常是变长的(比如句子有长有短),很难使用很大的批量,而且有些任务可能一次只处理一个样本。

3. 适合的任务类型不一样

  • BatchNorm:它更适合处理图像数据。图像数据是规则的网格结构,每张图片的大小和形状都一样,不同图片的同一个位置(比如左上角)的像素值可以放在一起比较。BatchNorm 可以很好地利用这种规律性来加速训练。

  • LayerNorm:它更适合处理文本数据。文本数据是变长的序列,每个句子的长度可能不一样,而且句子内部的单词之间有语义关系。LayerNorm 可以独立地对每个句子进行归一化,不会因为句子长度不同而受到影响,因此在 NLP 任务中表现更好。

2.LN:与BN的对比学习

下面将通过与BatchNorm的对比来学习LayerNorm:

2.1 公式形式相似,但归一化的范围不同

  • 公式:LayerNorm 和 BatchNorm 的公式看起来很像,都是“减去均值,除以标准差”,并且都加了一个很小的量 ϵ(默认值为 10−5)来防止分母为零。它们也都引入了两个可训练参数 β 和 γ,用于调整归一化后的结果。

  • 关键区别

    • BatchNorm 是对一个批次(batch)中的每个特征通道(channel)进行归一化。它计算的是整个批次的均值和标准差。

    • LayerNorm 是对单个样本的指定维度进行归一化,与批次(batch)无关。它只关心单个样本内部的特征分布。

2.2 BatchNorm 需要累计统计量,LayerNorm 不需要

  • BatchNorm

    • 在训练时,BatchNorm 需要计算每个特征通道的均值和方差,并且会累计两个变量:moving_mean(滑动平均均值)和 moving_var(滑动平均方差)。这是为了在推理(测试)阶段能够使用这些统计量来归一化数据。

    • 因此,BatchNorm 总共有 4 个参数:moving_meanmoving_var、β 和 γ。

  • LayerNorm

    • 它不需要累计任何统计量,因为它只对单个样本进行操作,不需要考虑批次之间的统计信息。

    • LayerNorm 只有 β 和 γ 两个可训练参数。

2.3 适用场景不同

  • BatchNorm

    • 依赖于批次大小,适合处理规则的、批量化的数据,比如图像数据(每个批次的图像大小和通道数固定)。

    • 它通过利用整个批次的统计信息来归一化数据,适合需要大规模并行计算的场景。

  • LayerNorm

    • 不依赖于批次大小,适合处理变长的、单个样本内部的特征归一化,比如文本数据(句子长度可能不同)。

    • 它更适合处理单个样本内部的特征关系,不会受到批次大小的影响。

3.Pytorch的LayerNorm类

现在来详细讲解 PyTorch 的 LayerNorm 中的 normalized_shape 参数。

3.1 normalized_shape 参数的作用

normalized_shapeLayerNorm 的一个关键参数,它决定了要对输入数据的哪些维度进行归一化处理。具体来说:

  • normalized_shape 指定的是从输入张量的最后一维开始的若干个维度。

  • 这些维度将被用来计算均值和标准差,并进行归一化。

3.2 normalized_shape 的规则

  • 必须从最后一维开始normalized_shape 只能指定输入张量的最后若干个维度。

  • 不能跳过中间维度:不能指定中间维度,只能从最后一维开始连续指定。

3.3 示例解释

假设输入数据的形状是 [4, 2, 3],我们来分析不同 normalized_shape 的情况:

  (1) normalized_shape=[3]
  • 解释:只对最后一维(大小为 3 的维度)进行归一化。

  • 输入数据的形状[4, 2, 3]

  • 归一化的范围:对每个 [4, 2] 的子张量(即每个 2×3 的矩阵)的最后一维进行归一化。

  • 结果:每个 2×3 的矩阵的每一行都会被独立归一化。

(2) normalized_shape=[2, 3]
  • 解释:对最后两个维度(大小为 2 和 3 的维度)进行归一化。

  • 输入数据的形状[4, 2, 3]

  • 归一化的范围:对每个 [4] 的子张量(即每个 2×3 的矩阵)的全部元素进行归一化。

  • 结果:每个 2×3 的矩阵会被整体归一化。

(3) normalized_shape=[4, 2, 3]
  • 解释:对整个输入张量的所有维度进行归一化。

  • 输入数据的形状[4, 2, 3]

  • 归一化的范围:对整个 [4, 2, 3] 的张量的所有元素进行归一化。

  • 结果整个张量会被整体归一化。

3.4 为什么 normalized_shape=[2] 会报错?

如果输入数据的形状是 [4, 2, 3],而 normalized_shape=[2],这表示你希望对倒数第二维(大小为 2 的维度)进行归一化。然而,根据 LayerNorm 的规则:

  • normalized_shape 必须从最后一维开始,不能单独指定倒数第二维。

  • 系统会期望输入数据的形状是 [*, 2],即最后一维的大小必须是 2。

  • 但实际输入的形状是 [4, 2, 3],最后一维的大小是 3,因此会报错。

4.使用Pytorch进行验证

通过自定义layer_norm_process函数,与PyTorch 官方的LayerNorm 模块进行对比验证。

import torch
import torch.nn as nn

#自己定义一个计算LayerNorm的函数
def layer_norm_process(feature: torch.Tensor, beta=0., gamma=1., eps=1e-5):
    
    #计算输入张量feature在指定维度(这里是最后一维 dim=-1)上的方差和均值。
    #返回值var_mean是一个包含两个元素的元组
    var_mean = torch.var_mean(feature, dim=-1, unbiased=False)
    # 均值
    mean = var_mean[1]
    # 方差
    var = var_mean[0]

    # 归一化过程
    #mean[..., None]:通过在 mean 的最后一维添加一个新的维度(使用 None 或 unsqueeze),使其形状与 feature 的最后一维对齐。
    #e.g.: 如果 mean 的形状是 [batch_size, feature_dim],那么 mean[..., None] 的形状会变成 [batch_size, feature_dim, 1]。
    feature = (feature - mean[..., None]) / torch.sqrt(var[..., None] + eps)
    feature = feature * gamma + beta

    return feature


def main():
    t = torch.rand(4, 2, 3)
    print(t)
    # 官方layer norm处理
    # 仅在最后一个维度上做norm处理
    norm = nn.LayerNorm(normalized_shape=t.shape[-1], eps=1e-5)
    t1 = norm(t)
    # 自己实现的layer norm处理
    t2 = layer_norm_process(t, eps=1e-5)
    print("t1:\n", t1)
    print("t2:\n", t2)


if __name__ == '__main__':
    main()

输出结果,可见两个结果一致:

tensor([[[0.8947, 0.4506, 0.6332],
         [0.6751, 0.5315, 0.5019]],

        [[0.2671, 0.4455, 0.3127],
         [0.8801, 0.6446, 0.5402]],

        [[0.9030, 0.7113, 0.8915],
         [0.3900, 0.4035, 0.4836]],

        [[0.5544, 0.3215, 0.6418],
         [0.5021, 0.7900, 0.2064]]])
t1:
 tensor([[[ 1.2903, -1.1460, -0.1443],
         [ 1.3949, -0.5025, -0.8924]],

        [[-0.9858,  1.3695, -0.3837],
         [ 1.3488, -0.3073, -1.0415]],

        [[ 0.7713, -1.4113,  0.6400],
         [-0.8624, -0.5349,  1.3974]],

        [[ 0.3586, -1.3637,  1.0050],
         [ 0.0108,  1.2192, -1.2300]]], grad_fn=<NativeLayerNormBackward0>)
t2:
 tensor([[[ 1.2903, -1.1460, -0.1443],
         [ 1.3949, -0.5025, -0.8924]],

        [[-0.9858,  1.3695, -0.3837],
         [ 1.3488, -0.3073, -1.0415]],

        [[ 0.7713, -1.4113,  0.6400],
         [-0.8624, -0.5349,  1.3974]],

        [[ 0.3586, -1.3637,  1.0050],
         [ 0.0108,  1.2192, -1.2300]]])

5. Vision Transformer 中使用 LN 的原因

        之前有提到,在图像处理领域中BN比LN是更有效的,但现在很多人将自然语言领域的模型用来处理图像,比如Vision Transformer,此时还是会涉及到LN。Vision Transformer 将图像分割成多个小块(patches),然后将这些块视为序列输入到 Transformer 中。在这种情况下,LN 的归一化方式更适合处理这些变长的序列数据LN 不依赖于批次大小,这使得它在处理小批次数据时比 BN 更稳定。这对于 ViT 的训练尤为重要,因为 ViT 通常需要较大的模型和较小的批次大小。在 Transformer 架构中,LN 能够更好地处理长序列数据,减少内部协变量偏移。这种特性使得 LN 在处理图像块序列时表现更好。在 Vision Transformer 中使用 LN 是为了适应其架构特点,而不是因为 LN 在图像处理中比 BN 更有效。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值