pytorch常用normalization函數


參考:https://blog.csdn.net/liuxiao214/article/details/81037416

歸一化層,目前主要有這幾個方法,Batch Normalization(2015年)、Layer Normalization(2016年)、Instance Normalization(2017年)、Group Normalization(2018年)、Switchable Normalization(2019年);

將輸入的圖像shape記為[N, C, H, W],這幾個方法主要的區別就是在,

  • batchNorm是在batch上,對NHW做歸一化,對小batchsize效果不好;
  • layerNorm在通道方向上,對CHW歸一化,主要對RNN作用明顯;
  • instanceNorm在圖像像素上,對HW做歸一化,用在風格化遷移;
  • GroupNorm將channel分組,然后再做歸一化;
  • SwitchableNorm是將BN、LN、IN結合,賦予權重,讓網絡自己去學習歸一化層應該使用什么方法。

 

 

 

1.BN

batchNorm是在batch上,對NHW做歸一化;即是將同一個batch中的所有樣本的同一層特征圖抽出來一起求mean和variance

加快收斂速度,允許網絡使用更高的學習率。可作為一個正則化器,減少對dropout的需求

但是當batch size較小時(小於16時),效果會變差,這時使用group norm可能得到的效果會更好

 

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

對小批量(mini-batch)3d數據組成的4d輸入進行批標准化(Batch Normalization)操作

進行了兩步操作:可見Batch Normalization的解釋

  • 先對輸入進行歸一化,E(x)為計算的均值,Var(x)為計算的方差
  • 然后對歸一化的結果進行縮放和平移,設置affine=True,即意味着weight(γ)和bias(β)將被使用

在每一個小批量(mini-batch)數據中,計算輸入各個維度的均值和標准差。γ與β是可學習的大小為C的參數向量(C為輸入大小)。默認γ取值為U(0,1),β設置為0

同樣,默認情況下,在訓練期間,該層將運行其計算的平均值和方差的估計值,然后在驗證期間使用這些估計值(即訓練求得的均值/方差)進行標准化。運行估計(running statistics)時保持默認momentum為0.1。

如果track_running_stats被設置為False,那么這個層就不會繼續運行驗證,並且在驗證期間也會使用批處理統計信息。

 

⚠️這個momentum參數不同於優化器optimizer類中使用的momentum參數和momentum的傳統概念。從數學上講,這里運行統計數據的更新規則是 :

  • x是估計的數據
  • xt是新的觀察到的數據

xnew = (1-momentum) * x + momentum * xt

 

因為批處理規范化是在C維(channel通道維度)上完成的,計算(N,H,W)片上的統計信息,所以通常將其稱為空間批處理規范化。

參數:

  • num_features: C來自期待的輸入大小(N,C,H,W)
  • eps: 即上面式子中分母的ε ,為保證數值穩定性(分母不能趨近或取0),給分母加上的值。默認為1e-5。
  • momentum: 動態均值和動態方差所使用的動量。默認為0.1。
  • affine: 一個布爾值,當設為true,給該層添加可學習的仿射變換參數,即γ與β。
  • track_running_stats:一個布爾值,當設置為True時,該模塊跟蹤運行的平均值和方差,當設置為False時,該模塊不跟蹤此類統計數據,並且始終在train和eval模式中使用批處理統計數據。默認值:True

Shape: 

輸入:(N, C,H, W)

輸出:(N, C, H, W)(輸入輸出相同)

 

舉例:

當affine=True時

import torch
from torch import nn m = nn.BatchNorm2d(2,affine=True) print(m.weight) print(m.bias) input = torch.randn(1,2,3,4) print(input) output = m(input) print(output) print(output.size())

返回:

Parameter containing:
tensor([0.5247, 0.4397], requires_grad=True) Parameter containing: tensor([0., 0.], requires_grad=True) tensor([[[[ 0.8316, -1.6250, 0.9072, 0.2746], [ 0.4579, -0.2228, 0.4685, 1.2020], [ 0.8648, -1.2116, 1.0224, 0.7295]], [[ 0.4387, -0.8889, -0.8999, -0.2775], [ 2.4837, -0.4111, -0.6032, -2.3912], [ 0.5622, -0.0770, -0.0107, -0.6245]]]]) tensor([[[[ 0.3205, -1.1840, 0.3668, -0.0206], [ 0.0916, -0.3252, 0.0982, 0.5474], [ 0.3409, -0.9308, 0.4373, 0.2580]], [[ 0.2664, -0.2666, -0.2710, -0.0211], [ 1.0874, -0.0747, -0.1518, -0.8697], [ 0.3160, 0.0594, 0.0860, -0.1604]]]], grad_fn=<NativeBatchNormBackward>) torch.Size([1, 2, 3, 4])

 

當affine=False時

import torch
from torch import nn m = nn.BatchNorm2d(2,affine=False) print(m.weight) print(m.bias) input = torch.randn(1,2,3,4) print(input) output = m(input) print(output) print(output.size())

返回:

None
None
tensor([[[[-1.5365, 0.2642, 1.0482, 2.0938], [-0.0906, 1.8446, 0.7762, 1.2987], [-2.4138, -0.5368, -1.2173, 0.2574]], [[ 0.2518, -1.9633, -0.0487, -0.0317], [-0.9511, 0.2488, 0.3887, 1.4182], [-0.1422, 0.4096, 1.4740, 0.5241]]]]) tensor([[[[-1.2739, 0.0870, 0.6795, 1.4698], [-0.1811, 1.2814, 0.4740, 0.8689], [-1.9368, -0.5183, -1.0326, 0.0819]], [[ 0.1353, -2.3571, -0.2028, -0.1837], [-1.2182, 0.1320, 0.2894, 1.4478], [-0.3080, 0.3129, 1.5106, 0.4417]]]]) torch.Size([1, 2, 3, 4])

 

 2.InstanceNorm2d(當mini-batch時使用)

instanceNorm在圖像像素上,對HW做歸一化;即是對batch中的單個樣本的每一層特征圖抽出來一層層求mean和variance,與batch size無關。若特征層為1,即C=1,准則instance norm的值為輸入本身

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

在4D輸入上應用instance Normalization(帶有額外channel維度的mini-batch 2D輸入),即shape為[N,C,H,W]

在mini-batch中的對象的均值和標准差是每個維度分開計算的。如果affine=True,則γ和β這兩個可學習的參數向量,大小為C,C為輸入大小。

這一層使用從訓練和評估模式的輸入數據計算得到的instace數據。

 

如果track_running_stats被設置為True,那么在訓練期間,該層將繼續運行計算均值和方差的估計,得到的均值和方差將使用到評估(eval)時的normalization中。運行估計時保持默認momentum為0.1。

 

⚠️這個momentum參數不同於優化器optimizer類中使用的momentum參數和momentum的傳統概念。從數學上講,這里運行統計數據的更新規則是 :

  • x是估計的數據
  • xt是新的觀察到的數據

xnew = (1-momentum) * x + momentum * xt

 

⚠️

InstanceNorm2d和LayerNorm非常相似,但是有一些細微的差別。InstanceNorm2d應用於RGB圖像等信道數據的每個信道,而LayerNorm通常應用於整個樣本,並且通常用於NLP任務。此外,LayerNorm應用元素仿射變換,而InstanceNorm2d通常不應用仿射變換。

參數:

  • num_features: C來自期待的輸入大小(N,C,H,W)
  • eps: 即上面式子中分母的ε ,為保證數值穩定性(分母不能趨近或取0),給分母加上的值。默認為1e-5。
  • momentum: 動態均值和動態方差所使用的動量。默認為0.1。
  • affine: 一個布爾值,當設為true,給該層添加可學習的仿射變換參數,即γ與β。
  • track_running_stats:一個布爾值,當設置為True時,該模塊跟蹤運行的平均值和方差,當設置為False時,該模塊不跟蹤此類統計數據,並且始終在train和eval模式中使用批處理統計數據。默認值:False

Shape: 

輸入:(N, C,H, W)

輸出:(N, C, H, W)(輸入輸出相同)

 

舉例:

import torch
input = torch.randn(2,3,2,2)
input

返回:

tensor([[[[-0.9262,  0.1619],
          [ 2.3522,  1.2739]],

         [[-2.1725,  1.3967],
          [ 1.4407,  1.3133]],

         [[-0.8386, -1.1728],
          [-3.0443, -0.3651]]],


        [[[ 0.9468, -0.9257],
          [ 0.5376,  0.4858]],

         [[ 1.1766,  0.4704],
          [ 0.8294, -0.3892]],

         [[ 0.2836,  0.5864],
          [-0.3070,  0.3229]]]])
View Code

 

import torch.nn as nn
#聲明仿射變換要寫成
#m = nn.InstanceNorm2d(3, affine=True)
m = nn.InstanceNorm2d(3)#feature數量,即channel number = 3
output = m(input)
output

返回:

tensor([[[[-1.3413, -0.4523],
          [ 1.3373,  0.4563]],

         [[-1.7313,  0.5856],
          [ 0.6141,  0.5315]],

         [[ 0.5082,  0.1794],
          [-1.6616,  0.9740]]],


        [[[ 0.9683, -1.6761],
          [ 0.3904,  0.3173]],

         [[ 1.1246, -0.0883],
          [ 0.5283, -1.5646]],

         [[ 0.1903,  1.1173],
          [-1.6182,  0.3106]]]])
View Code

 

3.LayerNorm(當mini-batch時使用)

layerNorm在通道方向上,對CHW歸一化;即是將batch中的單個樣本的每一層特征圖抽出來一起求一個mean和variance,與batch size無關,不同通道有着相同的均值和方差

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

平均值和標准偏差分別計算在最后幾個維數上,這些維數必須是normalized_shape指定的形狀。如果elementwise_affine=True,則γ和β為兩個可學習的仿射變換參數向量,大小為normalized_shape

⚠️與batch normalization和instance normalization不同,batch normalization使用affine選項為每個通道/平面應用標量尺度γ和偏差β,而layer normalization使用elementwise_affine參數為每個元素應用尺度和偏差。

 

這一層使用從訓練和評估模式的輸入數據計算得到的統計數據。

參數:

  • normalized_shape (int or list or torch.Size) 來自期待輸入大小的輸入形狀

    如果使用單個整數,則將其視為一個單例列表,並且此模塊將在最后一個維度上進行規范化,而最后一個維度應該具有特定的大小。

  • eps: 即上面式子中分母的ε ,為保證數值穩定性(分母不能趨近或取0),給分母加上的值。默認為1e-5。
  • elementwise_affine 一個布爾值,當設置為True時,此模塊具有可學習的元素仿射參數,γ初始化為1(表示權重)和β初始化為0(表示偏差)。默認值:True。

Shape: 

輸入:(N, *)

輸出:(N, *)(輸入輸出相同)

 

舉例:

import torch
input = torch.randn(2,3,2,2)
input

返回:

tensor([[[[-0.9262,  0.1619],
          [ 2.3522,  1.2739]],

         [[-2.1725,  1.3967],
          [ 1.4407,  1.3133]],

         [[-0.8386, -1.1728],
          [-3.0443, -0.3651]]],


        [[[ 0.9468, -0.9257],
          [ 0.5376,  0.4858]],

         [[ 1.1766,  0.4704],
          [ 0.8294, -0.3892]],

         [[ 0.2836,  0.5864],
          [-0.3070,  0.3229]]]])
View Code

 

import torch.nn as nn
#取消仿射變換要寫成
#m = nn.LayerNorm(input.size()[1:], elementwise_affine=False)
m1 = nn.LayerNorm(input.size()[1:])#input.size()[1:]為torch.Size([3, 2, 2])
output1 = m1(input)
output1

返回:

tensor([[[[-0.5555,  0.1331],
          [ 1.5192,  0.8368]],

         [[-1.3442,  0.9146],
          [ 0.9423,  0.8618]],

         [[-0.5001, -0.7116],
          [-1.8959, -0.2004]]],


        [[[ 1.0599, -2.1829],
          [ 0.3512,  0.2616]],

         [[ 1.4578,  0.2348],
          [ 0.8565, -1.2537]],

         [[-0.0887,  0.4357],
          [-1.1115, -0.0206]]]], grad_fn=<AddcmulBackward>)
View Code

 

#只normalize后兩個維度
m2 = nn.LayerNorm([2,2])
output2 = m2(input)
output2

返回:

tensor([[[[-1.3413, -0.4523],
          [ 1.3373,  0.4563]],

         [[-1.7313,  0.5856],
          [ 0.6141,  0.5315]],

         [[ 0.5082,  0.1794],
          [-1.6616,  0.9740]]],


        [[[ 0.9683, -1.6761],
          [ 0.3904,  0.3173]],

         [[ 1.1246, -0.0883],
          [ 0.5283, -1.5646]],

         [[ 0.1903,  1.1173],
          [-1.6182,  0.3106]]]], grad_fn=<AddcmulBackward>)
View Code

 

#只normalize最后一個維度
m3 = nn.LayerNorm(2)
output3 = m3(input)
output3

返回:

tensor([[[[-1.0000,  1.0000],
          [ 1.0000, -1.0000]],

         [[-1.0000,  1.0000],
          [ 0.9988, -0.9988]],

         [[ 0.9998, -0.9998],
          [-1.0000,  1.0000]]],


        [[[ 1.0000, -1.0000],
          [ 0.9926, -0.9926]],

         [[ 1.0000, -1.0000],
          [ 1.0000, -1.0000]],

         [[-0.9998,  0.9998],
          [-0.9999,  0.9999]]]], grad_fn=<AddcmulBackward>)
View Code

 

 

4.GroupNorm(當mini-batch時使用)

GroupNorm將channel分組;即是將batch中的單個樣本的G層特征圖抽出來一起求mean和variance,與batch size無關

當batch size較小時(小於16時),使用該normalization方法效果更好

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

輸入通道被分成num_groups組,每個組包含num_channels / num_groups個通道。每組的均值和標准差分開計算。如果affine=True,則γ和β這兩個可學習的通道仿射變換參數向量的大小為num_channels。

這一層使用從訓練和評估模式的輸入數據計算得到的統計數據。

 

參數:

  • num_features(int): 將通道分成的組的數量
  • num_channels(int):輸入期待的通道數
  • eps: 即上面式子中分母的ε ,為保證數值穩定性(分母不能趨近或取0),給分母加上的值。默認為1e-5。
  • affine: 一個布爾值,當設為true,給該層添加可學習的仿射變換參數,即γ與β。

Shape: 

輸入:(N, C,*) ,C = num_channels

輸出:(N, C, *)(輸入輸出相同)

 

 舉例:

import torch
input = torch.randn(2,4,3,3)
input

返回:

tensor([[[[-0.9154,  0.7312,  1.0657],
          [ 0.1783,  1.4014,  1.3043],
          [-0.7661, -0.6346,  0.7620]],

         [[ 0.9533,  2.1763,  0.4636],
          [ 0.0624, -0.0880,  1.2591],
          [ 0.5080,  0.2156,  0.0312]],

         [[ 0.2077, -0.2373,  0.2203],
          [-0.0628, -0.4680, -0.0094],
          [ 0.8615,  0.8549,  0.4138]],

         [[ 1.2188, -0.6487,  1.9315],
          [-1.0211, -0.1721,  0.6426],
          [-0.8192,  1.1049,  0.3663]]],


        [[[ 1.7522, -0.5378, -0.6105],
          [ 0.0658, -0.5731,  0.8737],
          [-0.2006,  0.3185,  0.6959]],

         [[ 0.5581, -1.5815,  0.3467],
          [-1.7975,  1.1900, -0.0935],
          [-0.7640, -0.7520, -1.2672]],

         [[-0.3703,  1.8731, -0.4689],
          [ 0.3615,  1.7101,  0.7305],
          [-0.0244, -0.5019,  0.3259]],

         [[-0.1413, -0.7416, -0.0747],
          [-0.6557,  0.5025, -0.0574],
          [ 0.2727,  2.2837,  1.6237]]]])
View Code

 

import torch.nn as nn
#將4個通道分為2組
m1 = nn.GroupNorm(2,4)
output1 = m1(input)
output1

返回:

tensor([[[[-1.7640,  0.3119,  0.7336],
          [-0.3852,  1.1568,  1.0344],
          [-1.5757, -1.4099,  0.3508]],

         [[ 0.5919,  2.1338, -0.0254],
          [-0.5312, -0.7208,  0.9774],
          [ 0.0305, -0.3381, -0.5706]],

         [[-0.0478, -0.6420, -0.0310],
          [-0.4090, -0.9500, -0.3377],
          [ 0.8251,  0.8163,  0.2273]],

         [[ 1.3022, -1.1914,  2.2539],
          [-1.6886, -0.5550,  0.5328],
          [-1.4190,  1.1501,  0.1639]]],


        [[[ 2.0315, -0.4375, -0.5158],
          [ 0.2133, -0.4755,  1.0844],
          [-0.0739,  0.4858,  0.8927]],

         [[ 0.7441, -1.5628,  0.5162],
          [-1.7956,  1.4254,  0.0415],
          [-0.6814, -0.6685, -1.2239]],

         [[-0.8227,  1.6729, -0.9325],
          [-0.0087,  1.4915,  0.4018],
          [-0.4380, -0.9692, -0.0482]],

         [[-0.5680, -1.2358, -0.4939],
          [-1.1402,  0.1482, -0.4747],
          [-0.1075,  2.1296,  1.3954]]]], grad_fn=<AddcmulBackward>)
View Code

 

#將4個通道分為4組,等價於Instance Norm
m2 = nn.GroupNorm(4,4)
output2 = m2(input)
output2

返回:

tensor([[[[-1.4648,  0.4451,  0.8332],
          [-0.1962,  1.2226,  1.1099],
          [-1.2916, -1.1390,  0.4809]],

         [[ 0.4819,  2.2510, -0.2265],
          [-0.8068, -1.0243,  0.9242],
          [-0.1623, -0.5852, -0.8520]],

         [[ 0.0230, -1.0124,  0.0523],
          [-0.6064, -1.5490, -0.4821],
          [ 1.5439,  1.5284,  0.5023]],

         [[ 0.9624, -0.9711,  1.7004],
          [-1.3567, -0.4777,  0.3659],
          [-1.1476,  0.8445,  0.0798]]],


        [[[ 2.0642, -0.9777, -1.0742],
          [-0.1760, -1.0246,  0.8973],
          [-0.5298,  0.1598,  0.6611]],

         [[ 1.0550, -1.1571,  0.8364],
          [-1.3803,  1.7083,  0.3813],
          [-0.3119, -0.2995, -0.8321]],

         [[-0.9221,  1.7498, -1.0396],
          [-0.0506,  1.5556,  0.3889],
          [-0.5102, -1.0789, -0.0929]],

         [[-0.4993, -1.1290, -0.4294],
          [-1.0388,  0.1761, -0.4113],
          [-0.0650,  2.0445,  1.3521]]]], grad_fn=<AddcmulBackward>)
View Code

 

#將4個通道分為4組,等價於layer Norm
m3 = nn.GroupNorm(4,4)
output3 = m3(input)
output3

返回:

tensor([[[[-1.4648,  0.4451,  0.8332],
          [-0.1962,  1.2226,  1.1099],
          [-1.2916, -1.1390,  0.4809]],

         [[ 0.4819,  2.2510, -0.2265],
          [-0.8068, -1.0243,  0.9242],
          [-0.1623, -0.5852, -0.8520]],

         [[ 0.0230, -1.0124,  0.0523],
          [-0.6064, -1.5490, -0.4821],
          [ 1.5439,  1.5284,  0.5023]],

         [[ 0.9624, -0.9711,  1.7004],
          [-1.3567, -0.4777,  0.3659],
          [-1.1476,  0.8445,  0.0798]]],


        [[[ 2.0642, -0.9777, -1.0742],
          [-0.1760, -1.0246,  0.8973],
          [-0.5298,  0.1598,  0.6611]],

         [[ 1.0550, -1.1571,  0.8364],
          [-1.3803,  1.7083,  0.3813],
          [-0.3119, -0.2995, -0.8321]],

         [[-0.9221,  1.7498, -1.0396],
          [-0.0506,  1.5556,  0.3889],
          [-0.5102, -1.0789, -0.0929]],

         [[-0.4993, -1.1290, -0.4294],
          [-1.0388,  0.1761, -0.4113],
          [-0.0650,  2.0445,  1.3521]]]], grad_fn=<AddcmulBackward>)
View Code

 

pix2pix代碼中該部分的使用:

class Identity(nn.Module):
    def forward(self, x):
        return x


def get_norm_layer(norm_type='instance'):
    """返回標准化層

    Parameters:
        norm_type (str) -- 標准化層的名字,有: batch | instance | none

    對於BatchNorm,我們使用可學習的仿射參數並追蹤運行數據(mean/stddev)
    對於InstanceNorm,我們不使用可學習的仿射參數也不追蹤運行數據
    """
    if norm_type == 'batch':
        norm_layer = functools.partial(nn.BatchNorm2d, affine=True, track_running_stats=True)
    elif norm_type == 'instance':
        norm_layer = functools.partial(nn.InstanceNorm2d, affine=False, track_running_stats=False)
    elif norm_type == 'none':
        norm_layer = lambda x: Identity()
    else:
        raise NotImplementedError('normalization layer [%s] is not found' % norm_type)
    return norm_layer

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM