[轉] BatchNormalization、LayerNormalization、InstanceNorm、GroupNorm、SwitchableNorm總結


原文鏈接:BatchNormalization、LayerNormalization、InstanceNorm、GroupNorm、SwitchableNorm總結

本篇博客總結幾種歸一化辦法,並給出相應計算公式和代碼。
1、綜述
1.1 論文鏈接

1、Batch Normalization

https://arxiv.org/pdf/1502.03167.pdf

2、Layer Normalizaiton

https://arxiv.org/pdf/1607.06450v1.pdf

3、Instance Normalization

https://arxiv.org/pdf/1607.08022.pdf

https://github.com/DmitryUlyanov/texture_nets

4、Group Normalization

https://arxiv.org/pdf/1803.08494.pdf

5、Switchable Normalization

https://arxiv.org/pdf/1806.10779.pdf

https://github.com/switchablenorms/Switchable-Normalization
1.2 介紹

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

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

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

 


2、Batch Normalization

首先,在進行訓練之前,一般要對數據做歸一化,使其分布一致,但是在深度神經網絡訓練過程中,通常以送入網絡的每一個batch訓練,這樣每個batch具有不同的分布;此外,為了解決internal covarivate shift問題,這個問題定義是隨着batch normalizaiton這篇論文提出的,在訓練過程中,數據分布會發生變化,對下一層網絡的學習帶來困難。

所以batch normalization就是強行將數據拉回到均值為0,方差為1的正太分布上,這樣不僅數據分布一致,而且避免發生梯度消失。

此外,internal corvariate shift和covariate shift是兩回事,前者是網絡內部,后者是針對輸入數據,比如我們在訓練數據前做歸一化等預處理操作。


算法過程:

    1. 沿着通道計算每個batch的均值u
    2. 沿着通道計算每個batch的方差σ^2
    3. 對x做歸一化,x’=(x-u)/開根號(σ^2+ε)
    4. 加入縮放和平移變量γ和β ,歸一化后的值,y=γx’+β

加入縮放平移變量的原因是:保證每一次數據經過歸一化后還保留原有學習來的特征,同時又能完成歸一化操作,加速訓練。 這兩個參數是用來學習的參數。

import numpy as np

def Batchnorm(x, gamma, beta, bn_param):

    # x_shape:[B, C, H, W]
    running_mean = bn_param['running_mean']
    running_var = bn_param['running_var']
    results = 0.
    eps = 1e-5

    x_mean = np.mean(x, axis=(0, 2, 3), keepdims=True)
    x_var = np.var(x, axis=(0, 2, 3), keepdims=True0)
    x_normalized = (x - x_mean) / np.sqrt(x_var + eps)
    results = gamma * x_normalized + beta

    # 因為在測試時是單個圖片測試,這里保留訓練時的均值和方差,用在后面測試時用
    running_mean = momentum * running_mean + (1 - momentum) * x_mean
    running_var = momentum * running_var + (1 - momentum) * x_var

    bn_param['running_mean'] = running_mean
    bn_param['running_var'] = running_var

    return results, bn_param

3、Layer Normalizaiton

batch normalization存在以下缺點:

    對batchsize的大小比較敏感,由於每次計算均值和方差是在一個batch上,所以如果batchsize太小,則計算的均值、方差不足以代表整個數據分布;
    BN實際使用時需要計算並且保存某一層神經網絡batch的均值和方差等統計信息,對於對一個固定深度的前向神經網絡(DNN,CNN)使用BN,很方便;但對於RNN來說,sequence的長度是不一致的,換句話說RNN的深度不是固定的,不同的time-step需要保存不同的statics特征,可能存在一個特殊sequence比其他sequence長很多,這樣training時,計算很麻煩。(參考於https://blog.csdn.net/lqfarmer/article/details/71439314

與BN不同,LN是針對深度網絡的某一層的所有神經元的輸入按以下公式進行normalize操作。

BN與LN的區別在於:

    1. LN中同層神經元輸入擁有相同的均值和方差,不同的輸入樣本有不同的均值和方差;
    2. BN中則針對不同神經元輸入計算均值和方差,同一個batch中的輸入擁有相同的均值和方差。
    3. 所以,LN不依賴於batch的大小和輸入sequence的深度,因此可以用於batchsize為1和RNN中對邊長的輸入sequence的normalize操作。


LN用於RNN效果比較明顯,但是在CNN上,不如BN。

def ln(x, b, s):
    _eps = 1e-5
    output = (x - x.mean(1)[:,None]) / tensor.sqrt((x.var(1)[:,None] + _eps))
    output = s[None, :] * output + b[None,:]
    return output

用在四維圖像上,

def Layernorm(x, gamma, beta):

    # x_shape:[B, C, H, W]
    results = 0.
    eps = 1e-5

    x_mean = np.mean(x, axis=(1, 2, 3), keepdims=True)
    x_var = np.var(x, axis=(1, 2, 3), keepdims=True0)
    x_normalized = (x - x_mean) / np.sqrt(x_var + eps)
    results = gamma * x_normalized + beta
    return results

4、Instance Normalization

BN注重對每個batch進行歸一化,保證數據分布一致,因為判別模型中結果取決於數據整體分布。

但是圖像風格化中,生成結果主要依賴於某個圖像實例,所以對整個batch歸一化不適合圖像風格化中,因而對HW做歸一化。可以加速模型收斂,並且保持每個圖像實例之間的獨立。


公式:

代碼:

def Instancenorm(x, gamma, beta):

    # x_shape:[B, C, H, W]
    results = 0.
    eps = 1e-5

    x_mean = np.mean(x, axis=(2, 3), keepdims=True)
    x_var = np.var(x, axis=(2, 3), keepdims=True0)
    x_normalized = (x - x_mean) / np.sqrt(x_var + eps)
    results = gamma * x_normalized + beta
    return results

5、Group Normalization

主要是針對Batch Normalization對小batchsize效果差,GN將channel方向分group,然后每個group內做歸一化,算(C//G)*H*W的均值,這樣與batchsize無關,不受其約束。

公式:


偽代碼:


代碼:

def GroupNorm(x, gamma, beta, G=16):

    # x_shape:[B, C, H, W]
    results = 0.
    eps = 1e-5
    x = np.reshape(x, (x.shape[0], G, x.shape[1]/16, x.shape[2], x.shape[3]))

    x_mean = np.mean(x, axis=(2, 3, 4), keepdims=True)
    x_var = np.var(x, axis=(2, 3, 4), keepdims=True0)
    x_normalized = (x - x_mean) / np.sqrt(x_var + eps)
    results = gamma * x_normalized + beta
    return results

6、Switchable Normalization

本篇論文作者認為,

    第一,歸一化雖然提高模型泛化能力,然而歸一化層的操作是人工設計的。在實際應用中,解決不同的問題原則上需要設計不同的歸一化操作,並沒有一個通用的歸一化方法能夠解決所有應用問題;
    第二,一個深度神經網絡往往包含幾十個歸一化層,通常這些歸一化層都使用同樣的歸一化操作,因為手工為每一個歸一化層設計操作需要進行大量的實驗。

因此作者提出自適配歸一化方法——Switchable Normalization(SN)來解決上述問題。與強化學習不同,SN使用可微分學習,為一個深度網絡中的每一個歸一化層確定合適的歸一化操作。

公式:





代碼:

def SwitchableNorm(x, gamma, beta, w_mean, w_var):
    # x_shape:[B, C, H, W]
    results = 0.
    eps = 1e-5

    mean_in = np.mean(x, axis=(2, 3), keepdims=True)
    var_in = np.var(x, axis=(2, 3), keepdims=True)

    mean_ln = np.mean(x, axis=(1, 2, 3), keepdims=True)
    var_ln = np.var(x, axis=(1, 2, 3), keepdims=True)

    mean_bn = np.mean(x, axis=(0, 2, 3), keepdims=True)
    var_bn = np.var(x, axis=(0, 2, 3), keepdims=True)

    mean = w_mean[0] * mean_in + w_mean[1] * mean_ln + w_mean[2] * mean_bn
    var = w_var[0] * var_in + w_var[1] * var_ln + w_var[2] * var_bn

    x_normalized = (x - mean) / np.sqrt(var + eps)
    results = gamma * x_normalized + beta
    return results


結果比較:

 




免責聲明!

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



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