1. 程式人生 > 實用技巧 >【深度學習】歸一化方法

【深度學習】歸一化方法

為什麼要做歸一化?

神經網路學習的本質就是學習資料的分佈。如果沒有對資料進行歸一化處理,那麼每一批次訓練的資料的分佈就有可能不一樣。從大的方面來講,神經網路需要在多個分佈中找到一個合適的平衡點;從小的方面來說,由於每層網路的輸入資料在不斷的變化,這會導致不容易找到合適的平衡點,最終使得構建的神經網路模型不容易收斂。當然,如果只是對輸入資料做歸一化,這樣只能保證資料在輸入層是一致的,並不能保證每層網路的輸入資料分佈是一致的,所以在神經網路模型的中間層也需要加入歸一化處理。

現階段常見的歸一化方法主要有:batch noralization(論文:https://arxiv.org/pdf/1502.03167.pdf

)、layer normalization(論文:https://arxiv.org/pdf/1607.06450v1.pdf)、instance normalization(論文:https://arxiv.org/pdf/1607.08022.pdf)、group normalization(論文:https://arxiv.org/pdf/1803.08494.pdf)以及switchable normalization(論文:https://arxiv.org/pdf/1806.10779.pdf)

將輸入的feature map shape記作 $ [ N, C, H, W] $

這幾種方法的主要區別在於:

1. batch normalization(BN)是在batch上,對 $ N, H, W $ 做歸一化,而保留通道 $ C $ 的維度。BN對較小的batch size效果不好。BN適用於固定深度的前向神經網路,如CNN,不適用於RNN;

2. layer normalization(LN)在通道方向上,對 $ C, H, W $ 在做歸一化,主要對RNN效果明顯;

3. instance normalization(IN)在影象像數上,對 $ H, W $ 做歸一化,用在風格化遷移;

4. group normalization(GN)將channel分組,然後再做歸一化。

給個子圖表示一個特徵圖,其中 $ N $ 為批量, $ C $ 為通道, $ (H, W) $ 為特徵圖的高度和寬度。通過藍色部分的值來計算均值和方差,從而進行歸一化。

如果把特徵圖 $x\in \mathbb{R}^{N\times C\times H\times W} $ 比喻成一本書,這摞書總共有 $ N $ 本,每本有 $ C $ 頁,煤業有 $ H $ 行,每行有 $ W $ 個字元。

  • BN求均值時,相當於是報這些書按照頁碼一一對應地加起來(如,第一本書第36頁,第二本書第36頁……),再除以每個頁碼下的字元總數: $N\times H\times W $ ,因此可以把BN看成求“平均書”的操作(注意這個“平均書”每頁只有一個字),求標準差時也是同理。
  • LN求均值時,相當於把每一本書的所有字加起來,再除以這本書的字元總數:$N\times H\times W $ ,即求整本書的“平均字”,求標準差也是同理。
  • IN求均值時,相當於把一頁書中所有字加起來,再除以該頁的總字數:$ H\times W $ ,即求每頁書的“平均字”,求標準差也是同理。
  • GN相當於把一本 $ C $ 頁的書平均分為 $ G $ 份,每份成為有 $ C/G $ 頁的小冊子,求每個小冊子的“平均字”和字的“標準差”。


1.batch normalization,BN

BN的主要思想:針對每個神經元,使資料再進入啟用函式之前,沿著通道計算每個batch的均值、方差,“強迫”資料保持均值為0,方差為1的正態分佈,避免梯度消失。具體來說,就是把第1個樣本的第1個通道,加上第2個樣本的第1個通道,……,再加上第 $ N $ 個樣本的第1個通道,求平均值,得到通道1的均值(注意是除以$N\times H\times W $ ,而不是單純的除以 $ N $ ,最後得到的是一個代表這個batch第1個通道的平均值,而不是一個$ H\times W $ 的矩陣)。求通道1的方差也是同理。對所有的通道都施加一邊這個操作,就得到了所有通道的均值和方差。

BN的位置:全連線層或者卷積層後,啟用函式前。

BN演算法流程:

  • 沿著通道計算每個batch的均值 $\mu$
  • 沿著通道計算每個batch的方差 $\sigma ^{2}$
  • 做歸一化
  • 加入縮放和平移變數 $\gamma ,\beta $

\begin{align}
\mu &=\frac{1}{m}\sum_{i=1}^{m}z^{(i)}\\
\sigma ^{2}&=\frac{1}{m}\sum_{i=1}^{m}(z^{(i)}-\mu)^{2}\\
z_{Norm}^{i}&=\frac{z^{(i)}}{\sqrt{\sigma ^{2}+\varepsilon }}\\
\tilde{z}^{(i)}&=\gamma z_{Norm}^{i}+\beta
\end{align}

其中, $\varepsilon $ 是一個很小的正值,如 $10^{-8} $ 。加入縮放和平移變數的兩個原因:保證每一次資料經過歸一化後還保留原有學習到的特徵,同時又能完成歸一化操作,加速訓練。這兩個引數是用來學習的引數。

BN的作用:

  • 允許較大的學習率;
  • 減弱對初始化的強依賴性;
  • 保持隱藏層中數值的均值、方差不變,讓數值更穩定,為後面的網路提供堅實的基礎;
  • 有輕微的正則化作用(相當於給隱藏層加入噪聲,類似於dropout)。

BN存在的問題:

  • 每次是在一個batch上計算均值、方差,如果batch太小,則計算的均值、方差不足以代表整個資料分佈。
  • batch size太大:會超過記憶體容量,需要跑更多的epoch,導致總訓練時間邊長,會直接固定梯度下降的方向,導致很難更新。

在tensorflow中可以通過使用 $tf.layers.batch\_normalization() $ 來實現BN。這個operation隱藏了mean,var,alpha和beta引數的顯示宣告。因此在呼叫過程中,需要特別注意正確呼叫的方式。

【使用BN訓練】

注意把 $tf.layers.batch\_normalization(x, training=is\_training,name=scope) $ 輸入引數的 $training=True $ 。此外還需要新增 $ update\_ops $ 以便於每一次訓練結束後及時跟新BN引數。

1 update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
2 
3 # 保證train_op在update_ops執行之後再執行
4 with tf.control_dependencies(update_ops):
5     train_op = optimizer.minimize(loss)

【儲存帶BN的模型】

儲存模型的時候,不能只儲存trainable_variables,因為BN的引數不屬於trainable_variables。為了方便,可以使用tf.global_variables()。使用方法如下:

1 ####
2 saver = tf.train.Saver(var_list=tf.global_variables())
3 
4 savepath = saver.save(sess, 'here_is_your_personal_model_path')
5 ####

【讀取帶BN的模型】

與儲存類似,讀取模型的時候,變數也需要為global_variables。

1 saver = tf.train.Saver()
2 
3 # or saver = tf.train.Saver(tf.global_variables())
4 
5 saver.restore(sess, "here_is_your_pesonal_model_path")

在inference的時候還需要把$tf.layers.batch\_normalization(x, training=is\_training,name=scope) $裡的 $training $ 引數設定為$ False $


2.layer normalization,LN

針對BN不適用於深度不固定的網路(sequence長度不一致,如RNN),LN對深度網路某一層的所有神經元的輸入按照以下公式進行normalization操作:

\begin{align}
\mu ^{l}&=\frac{l}{H}\sum_{i=1}^{H}a_{i}^{l}\\
\sigma ^{l}&=\sqrt{\frac{l}{H}\sum_{i=1}^{H}(a_{i}^{l}-\mu ^{l})^{2}}
\end{align}

LN中同層神經元的輸入擁有相同的均值和方差,不同的輸入樣本有不同的均值和方差。

對於特徵圖$x\in \mathbb{R}^{N\times C\times H\times W} $ ,LN對每個樣本的 $ C, G, W $ 維度上的資料求均值和標準差,保留維度 $ N $ 。其均值和標準差的計算公式如下:

\begin{align}
\mu _{n}(x)&=\frac{1}{CHW}\sum_{c=1}^{C}\sum_{h=1}^{H}\sum_{w=1}^{W}x_{nchw}\\
\sigma _{n}(x)&=\sqrt{\frac{1}{CHW}\sum_{c=1}^{C}\sum_{h=1}^{H}\sum_{w=1}^{W}(x_{nchw}-\mu _{n(x)^{2}+\varepsilon })}
\end{align}

LN的優勢時不需要批訓練,在單條資料內部就能歸一化。LN不依賴batch size和輸入sequence的長度,因此可以用在batch size為1的網路和RNN中。LN用於RNN效果比較明顯,效果不如BN。


3.instance normalization,IN

IN針對影象畫素做normalization,最初用於影象的風格化遷移。在影象風格化中,生成結果主要依賴於某個影象例項,feature map的各個channel的均值和方差會影響到最終生成的影象風格。所以對整個batch歸一化不適合影象風格化中,因此對 $ H, W $ 坐歸一化。可以加速模型的收斂,並且保持每個影象例項之間的獨立。

對於特徵圖$x\in \mathbb{R}^{N\times C\times H\times W} $ ,IN對每個樣本的 $ H, W $ 維度的資料求均值和標準差,保留 $ N, C $ 維度,也就是說,它只在channel內部求均值和標準差,計算公式如下:

\begin{align}
y_{tijk}&=\frac{x_{tijk}-\mu_{ti}}{\sqrt{\sigma _{ti}^{2}+\varepsilon }}\\
\mu _{ti}&=\frac{1}{HW}\sum_{l=1}^{W}\sum_{m=1}^{H}x_{tilm}\\
\sigma _{ti}^{2}&=\frac{1}{HW}\sum_{l=1}^{W}\sum_{m=1}^{H}(x_{tilm}=mu_{ti})
\end{align}


4.group normalization,GN

GN是為了解決BN對較小的mini-batch size效果差的問題。GN適用於佔用視訊記憶體較大的任務,例如影象分割。對於這類問題,可能batch size只能是個位數,再大視訊記憶體就不夠用了。當batch size是個位數時,BN的表現很差,因為沒有辦法通過幾個樣本的資料量來近似總體的均值和方差。GN也是獨立於batch的,它是LN和IN的折中方法。

GN的主要思想:在channel方向進行分組(group),然後在每個group內做normalization,計算 $ (C/G)*H*W $ 的均值和方差,這樣就使得與batch size無關,不受其約束。

具體實現方法:GN計算 均值和標準差時,把每一個樣本的feature map的channel分成 $ G $ 組,每組將有 $ C/G $ 個channel,然後將這些channel中的元素計算均值和標準差。各組channel用其對應的歸一化引數獨立的進行歸一化。具體的計算公式如下:

\begin{align}
\mu _{ng}(x)&=\frac{1}{(C/G)HW}\sum_{c=gC/G}^{(g+1)C/G}\sum_{h=1}^{H}\sum_{w=1}^{W}x_{nchw}\\
\sigma _{ng}(x)&=\sqrt{\frac{1}{(C/G)HW}\sum_{c=gC/G}^{(g+1)C/G}\sum_{h=1}^{H}\sum_{w=1}^{W}(x_{nchw}-\mu _{ng}(x))^{2}+\varepsilon }
\end{align}

 1 def GroupNorm(x, gamma, beta, G, eps=1e-5):
 2     # x:input features with shape [N,C, H, W]
 3     # gamma, beta: scale and offset, with shape [1, C, 1, 1]
 4     # G: number of groups for GN
 5     N, C, H, W = x.shape
 6     x = tf.reshape(x, [N, G, C // G, H, W])
 7 
 8     mean, var = tf.nn.moments(x, [2, 3, 4], keep_dims=True)
 9 
10     x = tf.reshape(x, [N, C, H, W])
11 
12     return x * gamma + beta

總結

  • BN是在batch上,對 $ N, H, W $ 做歸一化,保留通道 $ C $ 的維度。BN相當於把這些書按照頁碼一一對應地加起來,再除以每個頁碼下的字元總數:$N\times H\times W $。
  • LN在通道的方向上,對$ C, H, W $ 做歸一化。LN相當於把每一本書的所有字加起來,在初一這本書的字元總數:$C\times H\times W $。
  • IN在影象畫素上,對$ H, W $ 做歸一化。IN相當於把一頁書中所有字加起來,再除以該頁的總字數:$ H\times W $。
  • GN將channel分組,然後再做歸一化。GN相當於把一本 $ C $ 頁的書平均分成 $ G $ 份,每一份有 $ C/G $ 頁的小冊子,對每一個小冊子做normalization。

此外,還需注意他們的對映引數 $\gamma ,\beta $ 的區別:對於BN,IN,GN,其中$\gamma ,\beta$ 都是維度等於通道數 $ C $ 的向量。而對於LN, 其$\gamma ,\beta$ 都是維度等於normalized_shape的矩陣。

BN和IN可以設定引數:momentum和track_running_stats來獲得在整體資料上更準確的均值和標準差。LN和GN只能計算當前batch內資料的真實均值和標準差。