各种归一化层(BatchNorm、LayerNorm、InstanceNorm、GroupNorm、Weight Standardization)及其Pytorch实现

21 篇文章 4 订阅

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)

BN图示

参数:

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,给该层添加可学习的仿射变换参数。

 实现公式:

Tensorflow的代码如下: 

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)

LN图示

参数:

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

论文《Micro-Batch Training with Batch-ChannelNormalization and Weight Standardization JOURNAL OF LATEX CLASS FILES, VOL. 14, NO. 8, AUGUST 20151

代码 Github/joe-siyuan-qiao / WeightStandardization

下图是在网络前馈青色)和反向传播红色)时,进行权重梯度标准化的计算表达式:

以卷积神经网络中的卷积核为例,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总结

下图是对BatchNorm, LayerNorm, InstanceNormGroupNorm四种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等价于当GroupNormnum_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的时候, 可以使用这种归一化。

 

  • 32
    点赞
  • 171
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值