参考链接:
https://zhuanlan.zhihu.com/p/69659844
https://www.cnblogs.com/cxq1126/p/13299859.html
目录
Batch Normalization (BN)
举例说明:
Tip:
Layer Normalization (LN)
Instance Normalization (IN)
Group Normalization (GN)
总结
神经网络中有各种归一化算法:Batch Normalization (BN)、Layer Normalization (LN)、Instance Normalization (IN)、Group Normalization (GN)。从公式看它们都差不多,如 (1) 所示:无非是减去均值,除以标准差,再施以线性映射。
输入数据是6张3通道784个像素点的数据,将其分到三个通道上,在每个通道上也就是[6, 784]的数据,然后分别得到和通道数一样多的统计数据均值μ和方差σ,将每个像素值减去μ除以σ也就变换到了接近N(0,1)的分布,后面又使用参数β和γ将其变换到接近N(β,γ)的分布。
μ和σ只是样本中的统计数据,是没有梯度信息的,不过会保存在运行时参数里。而γ和β属于要训练的参数,他们是有梯度信息的。
import torch from torch import nn x = torch.rand(100, 16, 784) #100张16通道784像素点的数据,均匀分布 layer = nn.BatchNorm1d(16) #传入通道数,因为H和W已经flatten过了,所以用1d out = layer(x) print(layer.running_mean) #tensor([0.0499, 0.0501, 0.0501, 0.0501, 0.0501, 0.0502, 0.0500, 0.0499, 0.0499, # 0.0501, 0.0500, 0.0500, 0.0500, 0.0501, 0.0500, 0.0500]) print(layer.running_var) #tensor([0.9083, 0.9083, 0.9083, 0.9084, 0.9083, 0.9083, 0.9084, 0.9083, 0.9083, # 0.9083, 0.9083, 0.9083, 0.9084, 0.9084, 0.9083, 0.9083]) import torch from torch import nn x = torch.rand(1, 16, 7, 7) #1张16通道的7*7的图像 layer = nn.BatchNorm2d(16) #传入通道数(必须和上面的通道数目一致) out = layer(x) print(out.shape) #torch.Size([1, 16, 7, 7]) print(layer.running_mean) print(layer.running_var) print(layer.weight.shape) #torch.Size([16])对应上面的γ print(layer.bias.shape) #torch.Size([16])对应上面的β print(vars(layer)) #查看网络中一个层上的所有参数 # {'training': True, # '_parameters': # OrderedDict([('weight', Parameter containing: # tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.], requires_grad=True)), # ('bias', Parameter containing: # tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], requires_grad=True))]), # '_buffers': # OrderedDict([('running_mean', tensor([0.0527, 0.0616, 0.0513, 0.0488, 0.0484, 0.0510, 0.0590, 0.0459, 0.0448, 0.0586, 0.0535, 0.0464, 0.0581, 0.0481, 0.0420, 0.0549])), # ('running_var', tensor([0.9089, 0.9075, 0.9082, 0.9079, 0.9096, 0.9098, 0.9079, 0.9086, 0.9081, 0.9075, 0.9052, 0.9081, 0.9093, 0.9075, 0.9086, 0.9073])), # ('num_batches_tracked', tensor(1))]), # '_backward_hooks': OrderedDict(), # '_forward_hooks': OrderedDict(), # '_forward_pre_hooks': OrderedDict(), # '_state_dict_hooks': OrderedDict(), # '_load_state_dict_pre_hooks': OrderedDict(), # '_modules': OrderedDict(), # 'num_features': 16, # 'eps': 1e-05, # 'momentum': 0.1, # 'affine': True, # 'track_running_stats': True}layer.weight和layer.bias是当前batch上的;
如果在定义层时使用了参数affine=False,那么就是固定γ=1和β=0不自动学习,这时参数layer.weight和layer.bias将是None。
Group Normalization (GN) 适用于占用显存比较大的任务,例如图像分割。对这类任务,可能 batchsize 只能是个位数,再大显存就不够用了。而当 batchsize 是个位数时,BN 的表现很差,因为没办法通过几个样本的数据量,来近似总体的均值和标准差。GN 也是独立于 batch 的,它是 LN 和 IN 的折中。正如提出该算法的论文展示的:
import torch from torch import nn x = torch.rand(10, 20, 5, 5)*10000 # 分成 4 个 group # 其余设定和之前相同 gn = nn.GroupNorm(num_groups=4, num_channels=20, eps=0, affine=False) official_gn = gn(x) # 把同一 group 的元素融合到一起 x1 = x.view(10, 4, -1) mu = x1.mean(dim=-1).reshape(10, 4, -1) std = x1.std(dim=-1).reshape(10, 4, -1) x1_norm = (x1-mu)/std my_gn = x1_norm.reshape(10, 20, 5, 5) diff = (my_gn-official_gn).sum() print('diff={}'.format(diff)) # 误差在 1e-4 级除了上面这些归一化方法,还有基于它们发展出来的算法,例如 Conditional BatchNormalization 和 AdaIN,可以分别参考下面的博客:
https://zhuanlan.zhihu.com/p/61248211
https://zhuanlan.zhihu.com/p/57875010