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

参数:
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
下图是在网络前馈(青色)和反向传播(红色)时,进行权重梯度标准化的计算表达式:
以卷积神经网络中的卷积核为例,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的时候, 可以使用这种归一化。