深度神經網絡難訓練一個重要的原因就是深度神經網絡涉及很多層的疊加,每一層的參數變化都會導致下一層輸入數據分布的變化,隨着層數的增加,高層輸入數據分布變化會非常劇烈,這就使得高層需要不斷適應低層的參數更新。為了訓練好模型,我們需要謹慎初始化網絡權重,調整學習率等。
本篇博客總結幾種歸一化辦法,並給出相應計算公式和代碼。
歸一化層,目前主要有這幾個方法,Batch Normalization(2015年)、Layer Normalization(2016年)、Instance Normalization(2017年)、Group Normalization(2018年)、Switchable Normalization(2018年);
將輸入的圖像shape記為[N, Channel, Height, Width],這幾個方法主要的區別就是在,
- batch Norm:在batch上,對NHW做歸一化,對小batchsize效果不好;
- layer Norm:在通道方向上,對CHW歸一化,主要對RNN作用明顯;
- instance Norm:在圖像像素上,對HW做歸一化,用在風格化遷移;
- Group Norm:將channel分組,然后再做歸一化;
- Switchable Norm:將BN、LN、IN結合,賦予權重,讓網絡自己去學習歸一化層應該使用什么方法。
那我們就看看下面的兩個動圖, 這就是在每層神經網絡有無 batch normalization 的區別
沒有normalization 的輸出數據很多都等於0,導致后面的神經元“死掉”,起不到任何作用。
Batch Normalization
首先,在進行訓練之前,一般要對數據做歸一化,使其分布一致,但是在深度神經網絡訓練過程中,通常以送入網絡的每一個batch訓練,這樣每個batch具有不同的分布;而且在訓練過程中,數據分布會發生變化,對下一層網絡的學習帶來困難。
batch normalization就是強行將數據拉回到均值為0,方差為1的正太分布上,這樣不僅數據分布一致,而且避免發生梯度消失。保證每一次數據經過歸一化后還保留原有學習來的特征,同時又能完成歸一化操作,加速訓練。
$$\mu=\frac{1}{m}\sum_{i=1}^mx_i$$
$$\sigma =\sqrt {\frac{1}{m}\sum_{i=1}^m(x_i-\mu)^2)}$$
$$y= \frac{(x-\mu)}{\sqrt{\sigma ^2+\epsilon }}+\beta =BN(x)$$
tf.nn.batch_normalization(x, mean, variance, offset, scale, variance_epsilon, name=None)
參數
- x:輸入數據
- mean:均值
- variance:方差
返回
- 標准化后的數據
Layer Normalizaiton
batch normalization存在以下缺點:
- 對batch size的大小比較敏感,由於每次計算均值和方差是在一個batch上,所以如果batch size太小,則計算的均值、方差不足以代表整個數據分布;
- BN實際使用時需要計算並且保存某一層神經網絡batch的均值和方差等統計信息,對於對一個固定深度的前向神經網絡(DNN,CNN)使用BN,很方便;但對於RNN來說,sequence的長度是不一致的,換句話說RNN的深度不是固定的,不同的time-step需要保存不同的statics特征,可能存在一個特殊sequence比其他sequence長很多,這樣training時,計算很麻煩。
LN是針對深度網絡的某一層的所有神經元的輸入按以下公式進行normalize操作。
$$\mu^l=\frac{1}{H}\sum^H_{i=1}a_i^l$$
$$\sigma ^l=\sqrt {\frac{1}{H}\sum^H_{i=1}(a_i^l-\mu^l)^2}$$
BN與LN的區別在於:
- LN中同層神經元輸入擁有相同的均值和方差,不同的輸入樣本有不同的均值和方差;
- BN中則針對不同神經元輸入計算均值和方差,同一個batch中的輸入擁有相同的均值和方差。
所以,LN不依賴於batch的大小和輸入sequence的深度,因此可以用於batchsize為1和RNN中對邊長的輸入sequence的normalize操作。
LN用於RNN效果比較明顯,但是在CNN上,不如BN。
tf.keras.layers.LayerNormalization(axis=-1, epsilon=0.001, center=True, scale=True)
參數
- axis:想要規范化的軸(通常是特征軸)
- epsilon:將較小的浮點數添加到方差以避免被零除。
- center:如果為True,則將的偏移
beta
量添加到標准化張量。 scale
:如果為True,則乘以gamma
返回
- shape與輸入形狀相同的值
Instance Normalization
BN注重對每個batch進行歸一化,保證數據分布一致,因為判別模型中結果取決於數據整體分布。
但是圖像風格化中,生成結果主要依賴於某個圖像實例,所以對整個batch歸一化不適合圖像風格化中,因而對HW做歸一化。可以加速模型收斂,並且保持每個圖像實例之間的獨立。
$$\mu_{ti}=\frac{1}{HW}\sum_{l=1}^{W}\sum_{m=1}^{H}x_{tilm}$$
$$\sigma =\sqrt{\frac{1}{HW}\sum_{l=1}^{W}\sum_{m=1}^{H}(x_{tilm}-\mu_{yi})^2}$$
$$y_{tijk}=\frac{x_{Ptijk}-\mu_{yi}}{\sqrt {\sigma ^2_{ti}}-\epsilon }$$
tfa.layers.normalizations.InstanceNormalization
輸入:僅在該層只有一個輸入(即,它連接到一個傳入層)時適用。
返回:輸入張量或輸入張量列表。
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
Group Normalization
主要是針對Batch Normalization對小batchsize效果差,GN將channel方向分group,然后每個group內做歸一化,算(C//G)*H*W的均值,這樣與batchsize無關,不受其約束。
$$S_i=\{k|k_N=i_N,[\frac{k_C}{C/G}]=[\frac{i_C}{C/G}]\}$$
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
Switchable Normalization
本篇論文作者認為,
- 第一,歸一化雖然提高模型泛化能力,然而歸一化層的操作是人工設計的。在實際應用中,解決不同的問題原則上需要設計不同的歸一化操作,並沒有一個通用的歸一化方法能夠解決所有應用問題;
- 第二,一個深度神經網絡往往包含幾十個歸一化層,通常這些歸一化層都使用同樣的歸一化操作,因為手工為每一個歸一化層設計操作需要進行大量的實驗。
因此作者提出自適配歸一化方法——Switchable Normalization(SN)來解決上述問題。與強化學習不同,SN使用可微分學習,為一個深度網絡中的每一個歸一化層確定合適的歸一化操作。
$$\hat{h}_{hcij}=\gamma \frac{h_{hcij}-\sum_{k\epsilon \Omega W_k\mu_k}}{\sqrt {\sum_{k\epsilon \Omega}w'_k\sigma _k^2+\epsilon }}+\beta $$
$$w_k=\frac{e^{\lambda _k}}{\sum_{z\epsilon \{in,ln,bn\}e^{\lambda _z}}},\quad k\in \{in,ln,bn\}$$
$$\mu_{in}=\frac{1}{HW}\sum_{i,j}^{H,W}h_{ncij},\quad \sigma ^2=\frac{1}{HW}\sum_{i,j}^{H,W}(h_{ncij}-\mu_{in})^2$$
$$\mu_{ln}=\frac{1}{C}\sum_{c=1}^{C}\mu_{in},\quad \sigma ^2_{ln}=\frac{1}{C}\sum_{c=1}^{C}(\sigma^2 _{in} +\mu ^2_{in})-\mu^2_{ln}$$
$$\mu_{bn}=\frac{1}{N}\sum_{n=1}^{N}\mu_{in},\quad \sigma ^2=\frac{1}{N}\sum_{n=1}^{N}(\sigma _{in}^2+\mu_{in}^2)-\mu_{bn}^2$$
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
結果比較
參考