常見的幾種normalization方法

文章目錄

    幾種常見的normalization方法
        基本知識
        數學原理
        Batch Normalization (BN)
        Layer Normalization (LN)
            pytorch中的LN
        Instance Normalization (IN)
        Group Normalization (GN)
            PyTorch中的使用
        總結


這篇筆記主要來自餘庭嵩的講解。

幾種常見的normalization方法
基本知識

爲什麼要normalization?因爲如果初始值分佈不好時,數據尺度會隨着網絡層數加深而變化異常,詳情可參考之前這篇筆記:梯度消失或梯度爆炸原理。而normalization不僅可以解決這樣的問題,還可以給神經網絡訓練的過程帶來更多其他方便,所以就出現了不同的normalization方法。幾種常見的normalization方法有:batch normalization,layer normalization,instance normalization以及group normalization等等。建議先看BN部分的內容之後再看其他部分。
數學原理

如果一批數據(數據集)含有m個樣本輸入x1,x2,…,xm
x1​,x2​,…,xm​。
這批數據的均值爲
μℬ←1m∑mi=1xiμB​←m1​i=1∑m​xi​
這批數據的方差爲
σ2ℬ←1m∑mi=1(xi−μℬ)2σB2​←m1​i=1∑m​(xi​−μB​)2
那麼如何將這一批數據的方差轉變成1,也就是如何標準化?對每個xixi​進行如下操作(下面的ϵϵ是防止分母是0)
xˆi←xi−μℬσ2ℬ+ϵ√x
i​←σB2​+ϵ
​xi​−μB​​
那如何將這一批數據的均值變爲0?或者如何對數據進行平移和縮放?
yi←γxˆi+β≡BNγ,β(xi)yi​←γx
i​+β≡BNγ,β​(xi​)
這一步驟就叫affine transform。這裏的兩個參數γγ,ββ是可學習的參數,讓模型自己選擇是否對數據進行變換操作。這裏還有一個重要的點,如果γγ,β

β分別學習爲是方差和均值,那麼標準化操作將被逆操作回來,由此就可視爲沒有標準化這一步。這就使得模型更加靈活了。
這裏的BN,LN,IN和GN相同的地方是:對於每一個樣本的操作都是一樣的,都是按照上面最後兩個公式進行操作
不同的地方是:上面開頭兩個公式,也就是均值和方差的求取方式不一樣。BN是在batch中尋找均值和方差,LN是在網絡層裏面尋找均值和方差,IN是依據實例求取均值方差(圖像生成),GN是分組求取均值和方差。
Batch Normalization (BN)

由於batch normalization篇幅較大,實驗較多,所以單寫了一篇筆記:動手理解Batch Normalization,裏面對batch normalization從理論到實驗都進行了探討說明。
Layer Normalization (LN)

LN主要出自文章《Layer Normalization》,如果想知道更多細節和實驗對比,可以看原文。
起因:BN不適用於變長的網絡,如RNN
思路:逐層計算均值和方差,每個網絡層的輸出都有其均值方差。

注意事項:
不再有running_mean和running_var,因爲給定特徵圖的情況下都是固定的標量了,是根據該層內所有元素的均值和方差計算的。
兩個參數γ
γ和ββ是逐元素的,也就是每個神經元都有其參數γγ和β

β。
pytorch中的LN

主要參數有

    normalized_shape:該層的特徵形狀
    eps:分母修正項,默認1e-5
    elementwise_affine:是否需要affine transform,默認true

代碼實例如下,需要給nn.LayerNorm傳遞的參數是特徵的shape(除去batch維),需要從後往前設置維度,例如數據是AxBxCxD的,可以輸入D,[C, D],但是不可以輸入[B, C]:

batch_size = 8
num_features = 6

features_shape = (3, 4)

feature_map = torch.ones(features_shape)
feature_maps = torch.stack([feature_map * (i + 1) for i in range(num_features)], dim=0)
feature_maps_bs = torch.stack([feature_maps for i in range(batch_size)], dim=0)

ln = nn.LayerNorm(feature_maps_bs.size()[1:], elementwise_affine=True)

output = ln(feature_maps_bs)

print("Layer Normalization")
print(ln.weight.shape)
print(feature_maps_bs[0, ...])
print(output[0, ...])

輸出結果:

Layer Normalization
torch.Size([6, 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.]],

        [[4., 4., 4., 4.],
         [4., 4., 4., 4.],
         [4., 4., 4., 4.]],

        [[5., 5., 5., 5.],
         [5., 5., 5., 5.],
         [5., 5., 5., 5.]],

        [[6., 6., 6., 6.],
         [6., 6., 6., 6.],
         [6., 6., 6., 6.]]])
tensor([[[-1.4638, -1.4638, -1.4638, -1.4638],
         [-1.4638, -1.4638, -1.4638, -1.4638],
         [-1.4638, -1.4638, -1.4638, -1.4638]],

        [[-0.8783, -0.8783, -0.8783, -0.8783],
         [-0.8783, -0.8783, -0.8783, -0.8783],
         [-0.8783, -0.8783, -0.8783, -0.8783]],

        [[-0.2928, -0.2928, -0.2928, -0.2928],
         [-0.2928, -0.2928, -0.2928, -0.2928],
         [-0.2928, -0.2928, -0.2928, -0.2928]],

        [[ 0.2928,  0.2928,  0.2928,  0.2928],
         [ 0.2928,  0.2928,  0.2928,  0.2928],
         [ 0.2928,  0.2928,  0.2928,  0.2928]],

        [[ 0.8783,  0.8783,  0.8783,  0.8783],
         [ 0.8783,  0.8783,  0.8783,  0.8783],
         [ 0.8783,  0.8783,  0.8783,  0.8783]],

        [[ 1.4638,  1.4638,  1.4638,  1.4638],
         [ 1.4638,  1.4638,  1.4638,  1.4638],
         [ 1.4638,  1.4638,  1.4638,  1.4638]]], grad_fn=<SelectBackward>)

Instance Normalization (IN)

起因:BN在圖像生成中不適用,每個batch中的圖像有不同的風格,模式和style,所以不能把一個batch中的數據拿到一起計算。
思路:逐instance(channel)計算均值和方差
例如,AxBxCxD的圖,A是batchsize,B是channel數,C和D代表一張圖的所有像素點。那麼是不可以使用nn.batchnorm2d那樣直接把各個batch的對應相同通道的特徵圖拿在一起計算均值和方差的。
所以instance normalization就是不僅逐樣本,還逐通道地計算每一個特徵圖(CxD)的均值和方差。
Group Normalization (GN)

可參考論文《Group Normalization》
起因:在小batch樣本中,BN估計不準確。樣本越多,估計的均值和方差就比較準,但如果batchsize是1或者2的時候,估計的樣本就很少,這樣估計值就不準確。那麼這個情況下再計算所有batch在該特徵下的平均值和方差就不可行了,就需要把多個特徵合併一下,併爲一組(group),來求均值和方差。
注意:和layernorm一樣,不再有running_mean和running_var,兩個參數γ
γ和β

β是逐通道的。
應用場景:大模型,特徵數非常多,此時的batchsize只能設置比較小。
PyTorch中的使用

主要參數:
num_groups:分組數,一般是2的n次冪,因爲其要能被特徵數整除
num_channels:通道數

代碼實例

batch_size = 2
num_features = 4
num_groups = 2

features_shape = (2, 2)

feature_map = torch.ones(features_shape)    # 2D
feature_maps = torch.stack([feature_map * (i + 1) for i in range(num_features)], dim=0)
feature_maps_bs = torch.stack([feature_maps * (i + 1) for i in range(batch_size)], dim=0)  # 4D

gn = 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>)

總結

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章