【基础知识】深度学习中各种归一化方式详解

本文转载自 https://blog.csdn.net/qq_23981335/article/details/106572171
仅作记录学习~

总结

BN,LN,IN,GN,WS 从学术上解释差异

  • BatchNorm:batch方向做归一化,算NHW的均值,对小batchsize效果不好;BN主要缺点是对batchsize的大小比较敏感,由于每次计算均值和方差是在一个batch上,所以如果batchsize太小,则计算的均值、方差不足以代表整个数据分布;
  • LayerNorm:channel方向做归一化,算CHW的均值,主要对RNN作用明显;
  • InstanceNorm:一个channel内做归一化,算H*W的均值,用在风格化迁移;因为在图像风格化中,生成结果主要依赖于某个图像实例,所以对整个batch归一化不适合图像风格化中,因而对HW做归一化。可以加速模型收敛,并且保持每个图像实例之间的独立。
  • GroupNorm:将channel方向分group,然后每个group内做归一化,算(C//G)HW的均值;这样与batchsize无关,不受其约束。
  • SwitchableNorm:将BN、LN、IN结合,赋予权重,让网络自己去学习归一化层应该使用什么方法。
  • Weight Standardization:权重标准化,2019年约翰霍普金斯大学研究人员提出。

在这里插入图片描述
在这里插入图片描述

详细阐述

1. BatchNorm

torch.nn.BatchNorm1d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
torch.nn.BatchNorm3d(num_features, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

在这里插入图片描述
参数:

  • num_features: 来自期望输入的特征数,该期望输入的大小为’batch_size × num_features [× width]’
  • eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
  • momentum: 动态均值和动态方差所使用的动量。默认为0.1。 affine: 布尔值,当设为true,给该层添加可学习的仿射变换参数。
  • track_running_stats:布尔值,当设为true,记录训练过程中的均值和方差;

公式:
在这里插入图片描述
大部分深度网络通常都会使用 BN 层去加速训练和帮助模型更好收敛。虽然 BN 层非常实用,但从研究者的角度看,依然有一些非常显眼的缺点。比如
(1)我们非常缺乏对于 BN 层成功原因的理解;
(2)BN 层仅在 batch size 足够大时才有明显的效果,因此不能用在微批次的训练中。虽然现在已经有专门针对微批次训练设计的归一化方法(GN),但图 1 所示,它很难在大批次训练时媲美 BN 的效果。

2. GroupNorm

FAIR 团队的吴育昕和何恺明提出了组归一化(Group Normalization,简称 GN)的方法,GN 将信号通道分成一个个组别,并在每个组别内计算归一化的均值和方差,以进行归一化处理。GN 的计算与批量大小无关,而且在批次大小大幅变化时,精度依然稳定。通常来说,在使用 Batch Normalization(以下将简称 BN)时,采用小批次很难训练一个网络,而对于不使用批次的优化方法来说,效果很难媲美采用大批次BN时的训练结果。当使用 Group Normalization(以下将简称 GN),且 batch size 大小为 1 时,仅需要多写两行代码加入权重标准化方法,就能比肩甚至超越大批次BN时的训练效果。

torch.nn.GroupNorm(num_groups, num_channels, eps=1e-05, affine=True)

参数:

  • num_groups:需要划分为的groups
  • num_features: 来自期望输入的特征数,该期望输入的大小为’batch_size x num_features [x width]’
  • eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
  • momentum: 动态均值和动态方差所使用的动量。默认为0.1。
  • affine: 布尔值,当设为true,给该层添加可学习的仿射变换参数。

实现公式

在这里插入图片描述
tf代码如下:
在这里插入图片描述

3. InstanceNorm

torch.nn.InstanceNorm1d(num_features, eps=1e-05, momentum=0.1, affine=False, track_running_stats=False)
torch.nn.InstanceNorm2d(num_features, eps=1e-05, momentum=0.1, affine=False, track_running_stats=False)
torch.nn.InstanceNorm3d(num_features, eps=1e-05, momentum=0.1, affine=False, track_running_stats=False)

参数:

  • num_features: 来自期望输入的特征数,该期望输入的大小为’batch_size x num_features [x width]’
  • eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
  • momentum: 动态均值和动态方差所使用的动量。默认为0.1。
  • affine: 布尔值,当设为true,给该层添加可学习的仿射变换参数。
  • track_running_stats:布尔值,当设为true,记录训练过程中的均值和方差;

实现公式:
在这里插入图片描述

4. LayerNorm

torch.nn.LayerNorm(normalized_shape, eps=1e-05, elementwise_affine=True)

在这里插入图片描述
参数:

  • normalized_shape: 输入尺寸 [∗×normalized_shape[0]×normalized_shape[1]×…×normalized_shape[−1]]
  • eps: 为保证数值稳定性(分母不能趋近或取0),给分母加上的值。默认为1e-5。
  • elementwise_affine: 布尔值,当设为true,给该层添加可学习的仿射变换参数。

实现公式:
在这里插入图片描述

5. LocalResponseNorm

torch.nn.LocalResponseNorm(size, alpha=0.0001, beta=0.75, k=1.0)

参数:

  • size:用于归一化的邻居通道数
  • alpha:乘积因子,Default: 0.0001
  • beta :指数,Default: 0.75
  • k:附加因子,Default: 1

实现公式:
在这里插入图片描述

6. Weight Standardization

在这里插入图片描述
下图是在**网络前馈(青色)反向传播(红色)**时,进行权重梯度标准化的计算表达式:
在这里插入图片描述
以卷积神经网络中的卷积核为例,Pytorch中传统的卷积模块为:
在这里插入图片描述
在这里插入图片描述
引入WS后的实现为:

# Pytorch
class Conv2d(nn.Conv2d):
    '''
    shape:
    input: (Batch_size, in_channels, H_in, W_in)
    output: ((Batch_size, out_channels, H_out, W_out))
    '''
    def __init__(self, in_channels, out_channels, kernel_size, stride=1,
                 padding=0, dilation=1, groups=1, bias=True):
        super(Conv2d, self).__init__(in_channels, out_channels, kernel_size, stride,
                 padding, dilation, groups, bias)
 
    def forward(self, x):
        weight = self.weight   #self.weight 的shape为(out_channels, in_channels, kernel_size_w, kernel_size_h)
        weight_mean = weight.mean(dim=1, keepdim=True).mean(dim=2,
                                  keepdim=True).mean(dim=3, keepdim=True)
        weight = weight - weight_mean
        std = weight.view(weight.size(0), -1).std(dim=1).view(-1, 1, 1, 1) + 1e-5
        weight = weight / std.expand_as(weight)
        return F.conv2d(x, weight, self.bias, self.stride,
                        self.padding, self.dilation, self.groups)

附录

个人理解和代码测试

下图是对BatchNorm, LayerNorm, InstanceNorm和GroupNorm四种Normalization方式的一个汇总(我个人感觉这个图看起来方便一些).

  • 图中每一个正方体块表示一个数据(比如说这里一个正方体就是一个图像)
  • 每一个正方体中的C, H, W分别表示channel(通道个数), height(图像的高), weight(图像的宽)
  • 下图介绍了4中Norm的方式, 如Layer Norm中NHWC----->N111表示是将后面的三个进行标准化, 不与batchsize有关.
  • 我们可以看到, 后面的LayerNorm, InstanceNorm和GroupNorm这三种方式都是和Batchsize是没有关系的。

在这里插入图片描述
下面我们使用一个(2, 2, 4)的数据来举一个例子, 我们可以将其看成有2个图像组成的单通道的图像,

(1)生成测试使用数据

我们首先生成测试使用的数据, 数据的大小为(2, 2, 4);

x_test = np.array([[[1,2,-1,1],[3,4,-2,2]],
                   [[1,2,-1,1],[3,4,-2,2]]])
x_test = torch.from_numpy(x_test).float()
x_test
"""
tensor([[[ 1.,  2., -1.,  1.],
         [ 3.,  4., -2.,  2.]],
        [[ 1.,  2., -1.,  1.],
         [ 3.,  4., -2.,  2.]]])
"""

(2)测试LayerNorm与GroupNorm

关于这里的计算的细节, 会在后面的计算细节描述部分进行叙述. 这里就看一下如何使用Pytorch来进行计算, 和最终计算得到的结果。

LayerNorm就是对(2, 2, 4), 后面这一部分进行整个的标准化。可以理解为对整个图像进行标准化。

m = nn.LayerNorm(normalized_shape = [2,4])
output = m(x_test)
output
"""
tensor([[[-0.1348,  0.4045, -1.2136, -0.1348],
         [ 0.9439,  1.4832, -1.7529,  0.4045]],
        [[-0.1348,  0.4045, -1.2136, -0.1348],
         [ 0.9439,  1.4832, -1.7529,  0.4045]]], grad_fn=<AddcmulBackward>)
"""

当GroupNorm中group的数量是1的时候, 是与上面的LayerNorm是等价的.

# Separate 2 channels into 1 groups (equivalent with LayerNorm)
m = nn.GroupNorm(num_groups=1, num_channels=2, affine=False)
output = m(x_test)
output
"""
tensor([[[-0.1348,  0.4045, -1.2136, -0.1348],
         [ 0.9439,  1.4832, -1.7529,  0.4045]],
        [[-0.1348,  0.4045, -1.2136, -0.1348],
         [ 0.9439,  1.4832, -1.7529,  0.4045]]])
"""

(3)测试InstanceNorm和GroupNorm

InstanceNorm就是对(2, 2, 4), 标红的这一部分进行Norm。

m = nn.InstanceNorm1d(num_features=2)
output = m(x_test)
output
"""
tensor([[[ 0.2294,  1.1471, -1.6059,  0.2294],
         [ 0.5488,  0.9879, -1.6465,  0.1098]],
        [[ 0.2294,  1.1471, -1.6059,  0.2294],
         [ 0.5488,  0.9879, -1.6465,  0.1098]]])
"""

上面这种InstanceNorm等价于当GroupNorm时num_groups的数量等于num_channel的数量。

# Separate 2 channels into 2 groups (equivalent with InstanceNorm)
m = nn.GroupNorm(num_groups=2, num_channels=2, affine=False)
output = m(x_test)
output
"""
tensor([[[ 0.2294,  1.1471, -1.6059,  0.2294],
         [ 0.5488,  0.9879, -1.6465,  0.1098]],
        [[ 0.2294,  1.1471, -1.6059,  0.2294],
         [ 0.5488,  0.9879, -1.6465,  0.1098]]])
"""

(4)计算细节描述

我们看一下在上面的LayerNorm和InstanceNorm中的结果是如何计算出来的. 我们只看第一行第一列的数据1进行标准化的过程. 下面是详细的计算的过程(这里的计算结果与上面直接计算的结果是相同的)。
在这里插入图片描述

(5)每一种方式适合的场景

  • batchNorm是在batch上,对小batchsize效果不好;
  • layerNorm在通道方向上,主要对RNN作用明显;
  • instanceNorm在图像像素上,用在风格化迁移;
  • GroupNorm将channel分组,然后再做归一化, 在batchsize<16的时候, 可以使用这种归一化。
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 归一是深度学习一种常见的数据预处理技术,旨在将数据缩放到一个统一的尺度,以便网络更容易处理。归一的主要方法包括: - 均值归一:将数据减去平均值,再除以标准差,以使得数据的均值为0,标准差为1。 - 小数定标归一:将数据除以最大值,以使得数据在0~1之间。 - 正则:将数据缩放到一个比较小的范围,以防止梯度消失或爆炸。 通过归一数据,网络能够更快地收敛,并且更容易找到全局最优解,从而提高网络的准确性。 ### 回答2: 深度学习归一是指将输入数据进行预处理,将其缩放到一个特定的范围或分布,以便更好地进行模型训练和优。 在深度学习,常见的归一方法有两种:批量归一(Batch Normalization)和层归一(Layer Normalization)。 批量归一是在每个隐藏层对每一批输入数据进行归一处理。它的原理是通过对每个特征按照均值和方差进行标准,使得输入数据的均值为0,方差为1。这样可以防止某些特征值过大或过小对网络模型的训练造成影响,提高了网络的稳定性和收敛速度。批量归一还可以作为正则项,减少过拟合的风险。 层归一是对每个样本在一个特定维度上进行归一处理,通常是在通道维度上进行归一。它的原理类似于批量归一,但是不同的是计算均值和方差的范围不同,可以更好地应用在递归神经网络等无法完全取得批次数据进行训练的情况下。 归一在深度学习的作用主要有三个方面:一是加速收敛速度,使得模型更快地达到最优解;二是提高模型的泛能力,减少模型过拟合;三是解决梯度消失和梯度爆炸等训练问题,使得模型训练更稳定。 在实际应用归一是深度学习的一项重要技术,可以使得模型在处理不同尺度、不同分布的数据时更加稳定和有效。通过归一的预处理,可以提高深度学习模型的性能和表现。 ### 回答3: 在深度学习归一(Normalization)是对输入数据进行预处理的一种重要技术。它恢复了输入数据的统计特性,使得神经网络能够更加稳定、高效地进行训练,提升了模型的泛能力。 深度学习归一通常包括两种常见方法:批量归一(Batch Normalization)和层归一(Layer Normalization)。 批量归一是将每一个批次的输入数据进行归一处理。通过计算每个特征在整个训练集上的均值和方差,然后对每个输入样本进行标准,即将特征值减去均值,再除以方差,将数据分布调整到均值为0、方差为1的标准正态分布。批量归一能够减小不同特征之间的尺度差异,加速网络的收敛速度,减少梯度消失问题。 层归一则是将每一层神经元的输出进行归一处理。它与批量归一不同之处在于,它将每一层的输出看作一个整体进行归一。通过计算每个神经元在一层上的均值和方差,再进行标准处理。层归一适用于无法批量处理的情况,例如循环神经网络。 归一技术可以有效地降低梯度爆炸和消失问题,提高网络的稳定性。此外,归一还有助于加速网络的收敛速度,减少训练时间。通过提高模型的泛能力,归一技术能够显著提高深度学习的精度和性能。 综上所述,归一是深度学习的一种重要技术,能够对输入数据进行处理,提高网络的稳定性和泛能力。无论是批量归一还是层归一,在不同的场景都有各自的优势和适用性,可根据具体问题的需求选择合适的归一方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值