PyTorch框架学习十八——Layer Normalization、Instance Normalization、Group Normalization
PyTorch框架學習十八——Layer Normalization、Instance Normalization、Group Normalization
- 一、為什么要標準化?
- 二、BN、LN、IN、GN的異同
- 三、Layer Normalization
- 四、Instance Normalization
- 五、Group Normalization
上次筆記介紹了Batch Normalization以及它在PyTorch中的使用:https://blog.csdn.net/qq_40467656/article/details/108375181
這次筆記將介紹由BN引發的其他標準化層,它們各自適用于不同的應用場景,分別是適用于變長網絡的Layer Normalization;適用于圖像生成的Instance Normalization;適用于小mini-batch的Group Normalization。
一、為什么要標準化?
這個在上次BN的筆記中介紹過,本意是為了解決ICS問題,即隨著網絡層數加深,數據分布異常(很小或很大),從而導致訓練困難。詳情回顧:https://blog.csdn.net/qq_40467656/article/details/108375181
二、BN、LN、IN、GN的異同
- 同:都做了標準化的工作。
- 異:均值和方差的求取方式不一樣,即選擇的計算區域不一樣,這個可以看完下一小節的詳細介紹回過來看,可能會更能理解。
三、Layer Normalization
LN提出的起因是因為BN不適用于變長的網絡,如RNN,這部分的內容還沒有接觸過,但是可以簡單理解為這種網絡的神經元個數是會變化的,不是一樣的,如下圖所示:
ps:注意這里的橫軸不是數據樣本個數,只是代表這層網絡層神經元可能會變為5/3/4個,在每種個數的情況下,樣本數還是一個batchsize的大小。
第一次可能有五個特征,計算得到五個均值和方差,而第二輪計算時,網絡層的神經元變為3個,而BN里計算均值和方差是需要用到之前的結果的,這里之前的五個均值方差就對應不了三個特征,所以BN在這種情況下是不適用的。
那么LN是怎么計算均值和方差的呢?以一維的情況為例:
之所以稱為Layer Norm,就是對該層的數據求均值和方差,不再按照特征那個維度去求,每個樣本都單獨求其均值方差,可以理解為逐樣本的求取方式。
二維三維的情況類似,如下圖所示:
LN需要注意的地方:
- 不再有running_mean和running_var
- gamma和beta為逐元素的
LN在PyTorch中的實現:
torch.nn.LayerNorm(normalized_shape: Union[int, List[int], torch.Size], eps: float = 1e-05, elementwise_affine: bool = True)參數如下所示:
下面看一個PyTorch實現的例子:
import torch import numpy as np import torch.nn as nn import sys, os hello_pytorch_DIR = os.path.abspath(os.path.dirname(__file__)+os.path.sep+".."+os.path.sep+"..") sys.path.append(hello_pytorch_DIR) from tools.common_tools import set_seedset_seed(1) # 設置隨機種子# ======================================== nn.layer norm flag = 1 # flag = 0 if flag:batch_size = 8num_features = 3features_shape = (3, 4)feature_map = torch.ones(features_shape) # 2Dfeature_maps = torch.stack([feature_map * (i + 1) for i in range(num_features)], dim=0) # 3Dfeature_maps_bs = torch.stack([feature_maps for i in range(batch_size)], dim=0) # 4D# feature_maps_bs shape is [8, 3, 3, 4], B * C * H * Wln = nn.LayerNorm(feature_maps_bs.size()[1:], elementwise_affine=True)# ln = nn.LayerNorm(feature_maps_bs.size()[1:], elementwise_affine=False)# ln = nn.LayerNorm([3, 3, 4])# ln = nn.LayerNorm([3, 3])output = ln(feature_maps_bs)print("Layer Normalization")print(ln.weight.shape)print(feature_maps_bs[0, ...])print(output[0, ...])結果如下:
Layer Normalization torch.Size([3, 3, 4]) tensor([[[1., 1., 1., 1.],[1., 1., 1., 1.],[1., 1., 1., 1.]],[[2., 2., 2., 2.],[2., 2., 2., 2.],[2., 2., 2., 2.]],[[3., 3., 3., 3.],[3., 3., 3., 3.],[3., 3., 3., 3.]]]) tensor([[[-1.2247, -1.2247, -1.2247, -1.2247],[-1.2247, -1.2247, -1.2247, -1.2247],[-1.2247, -1.2247, -1.2247, -1.2247]],[[ 0.0000, 0.0000, 0.0000, 0.0000],[ 0.0000, 0.0000, 0.0000, 0.0000],[ 0.0000, 0.0000, 0.0000, 0.0000]],[[ 1.2247, 1.2247, 1.2247, 1.2247],[ 1.2247, 1.2247, 1.2247, 1.2247],[ 1.2247, 1.2247, 1.2247, 1.2247]]], grad_fn=<SelectBackward>)這邊只打印了第一個數據的結果,它的均值是2,所以中間一個3×4的特征標準化之后全為0。
四、Instance Normalization
IN層的提出是因為在圖像生成任務中,一個batch里的圖像的風格可能不盡相同,不能通過BN的計算方式去將各個風格的特征混為一談,所以BN在這種情況下會不適用。
那么,IN層的計算方式的思路是逐Instance(channel)地計算均值和方差,如下圖所示:
它是每一個樣本每一個特征都去計算均值方差然后標準化。
IN層在PyTorch中的實現如下所示:(以二維為例)
torch.nn.InstanceNorm2d(num_features: int, eps: float = 1e-05, momentum: float = 0.1, affine: bool = False, track_running_stats: bool = False)參數如下所示:
看一個IN的例子:
flag = 1 # flag = 0 if flag:batch_size = 3num_features = 3momentum = 0.3features_shape = (2, 2)feature_map = torch.ones(features_shape) # 2Dfeature_maps = torch.stack([feature_map * (i + 1) for i in range(num_features)], dim=0) # 3Dfeature_maps_bs = torch.stack([feature_maps for i in range(batch_size)], dim=0) # 4Dprint("Instance Normalization")print("input data:\n{} shape is {}".format(feature_maps_bs, feature_maps_bs.shape))instance_n = nn.InstanceNorm2d(num_features=num_features, momentum=momentum, affine=True, track_running_stats=True)for i in range(1):outputs = instance_n(feature_maps_bs)print(outputs)print("\niter:{}, running_mean.shape: {}".format(i, instance_n.running_mean.shape))print("iter:{}, running_var.shape: {}".format(i, instance_n.running_var.shape))print("iter:{}, weight.shape: {}".format(i, instance_n.weight.shape))print("iter:{}, bias.shape: {}".format(i, instance_n.bias.shape))結果如下:
Instance Normalization input data: tensor([[[[1., 1.],[1., 1.]],[[2., 2.],[2., 2.]],[[3., 3.],[3., 3.]]],[[[1., 1.],[1., 1.]],[[2., 2.],[2., 2.]],[[3., 3.],[3., 3.]]],[[[1., 1.],[1., 1.]],[[2., 2.],[2., 2.]],[[3., 3.],[3., 3.]]]]) shape is torch.Size([3, 3, 2, 2]) tensor([[[[0., 0.],[0., 0.]],[[0., 0.],[0., 0.]],[[0., 0.],[0., 0.]]],[[[0., 0.],[0., 0.]],[[0., 0.],[0., 0.]],[[0., 0.],[0., 0.]]],[[[0., 0.],[0., 0.]],[[0., 0.],[0., 0.]],[[0., 0.],[0., 0.]]]], grad_fn=<ViewBackward>)iter:0, running_mean.shape: torch.Size([3]) iter:0, running_var.shape: torch.Size([3]) iter:0, weight.shape: torch.Size([3]) iter:0, bias.shape: torch.Size([3])五、Group Normalization
GN的提出是因為,隨著如今數據樣本變得越來越大,以現有的GPU能力可能只能放置比較小的mini-batch,而一個batch比較少的數據的話,使用BN可能計算得到的均值和方差就有較大的偏差,估計的值不準,所以BN在小mini-batch的場景下不適用。
那么GN的計算思路就是:數據樣本不夠,通道(特征)數來湊,其如下所示:
圖中所示是將一個樣本的兩個特征劃分為一個group,這里只是為了說明GN的原理,實際上特征數是很多的,比如256,那么我們分為兩組的話,一組有128個特征通道,數量還是比較可觀的,在這樣的分組下對每一組單獨求取均值方差然后標準化。
注意:
- 不再有running_mean和running_var,與LN一致。
- gamma和beta為逐通道的。
應用場景:大模型,小batch size的任務。
GN在PyTorch中的實現如下:
torch.nn.GroupNorm(num_groups: int, num_channels: int, eps: float = 1e-05, affine: bool = True)參數如下所示:
下面看一個例子:
flag = 1 # flag = 0 if flag:batch_size = 2num_features = 4num_groups = 2 # 3 Expected number of channels in input to be divisible by num_groupsfeatures_shape = (2, 2)feature_map = torch.ones(features_shape) # 2Dfeature_maps = torch.stack([feature_map * (i + 1) for i in range(num_features)], dim=0) # 3Dfeature_maps_bs = torch.stack([feature_maps * (i + 1) for i in range(batch_size)], dim=0) # 4Dgn = nn.GroupNorm(num_groups, num_features)outputs = gn(feature_maps_bs)print("Group Normalization")print(gn.weight.shape)print(outputs[0])結果如下:
Group Normalization torch.Size([4]) tensor([[[-1.0000, -1.0000],[-1.0000, -1.0000]],[[ 1.0000, 1.0000],[ 1.0000, 1.0000]],[[-1.0000, -1.0000],[-1.0000, -1.0000]],[[ 1.0000, 1.0000],[ 1.0000, 1.0000]]], grad_fn=<SelectBackward>)最后放一張BN、LN、IN和GN的計算方式示例圖,幫助理解:
總結
以上是生活随笔為你收集整理的PyTorch框架学习十八——Layer Normalization、Instance Normalization、Group Normalization的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 散列表(字典)
- 下一篇: GIOU loss+DIOU loss+