如今的神經網絡一般都特別深,在輸出層向輸入層傳播導數的過程當中,梯度很容易被激活函數或是權重以指數級的規模縮小或放大,從而產生「梯度消失」或「梯度爆炸」的現象,形成訓練速度降低和效果不理想。網絡
如何避免或者減輕這一現象的發生呢?歸一化就是方法的一種。歸一化將網絡中層與層之間傳遞的數據限制在必定範圍內,從而避免了梯度消失和爆炸的發生。下面介紹一種最基本的歸一化:批量歸一化(BN, Batch Normalization)。另外還有層歸一化(LN, Layer Normalization)和權重歸一化(WN, Weight Normalization),和BN大同小異。函數
批量歸一化層的是這樣定義的,當使用批量梯度降低(或小批量)時,對前一層的輸出在批量的維度上進行歸一化,即學習
\begin{align} &\hat{X}_i^t=\frac{X_i^{t-1}-E(X^{t-1})}{\sqrt{D(X^{t-1})+\varepsilon}} \\ \text{where}\;\; &E(X^{t-1}) = \frac{1}{n}\sum\limits_{i=1}^nX_i^{t-1}\notag\\ &D(X^{t-1}) = \frac{1}{n-1}\sum\limits_{i=1}^n\left[X_i^{t-1}-E(X^{t-1})\right]^2\notag \end{align}spa
其中$n$是輸入批量,$X_i^{t-1}$是前一層輸出批量中的第$i$個,$\varepsilon$是爲避免0除而設置的較小數。以上都是按元素進行的操做。這樣作的顯式優勢在於,大部分的輸出都被映射到了-1和1之間,而諸如sigmoid激活函數,在這個區間內的梯度是最大的,從而避免因激活函數值的飽和而產生的梯度消失。而且因爲層輸出的歸一化約束,反向傳播的累積不會特別顯著,梯度爆炸也得以免。code
可是,若是僅僅進行以上操做,網絡的擬合能力就會降低。這是由於,神經網絡強大的擬合能力在於激活函數的非線性。通過以上操做,激活函數的輸入一般都集中在-1和1之間,而sigmoid函數在這區間內的導數變化率是比較低的,或者說是比較線性的。爲了防止這一點,BN在這基礎上再加一個「反向」操做,將權重輸出再乘上自學習的標準差和均值,映射到激活函數曲率(或者說二階導數絕對值、導數變化率)相對更大的位置,在得到較大導數的同時,保留激活非線性。公式以下:orm
$ \begin{aligned} &X_i^t= \gamma^t\hat{X}_i^t+\beta^t\\ \end{aligned} $blog
與$(1)$式聯合獲得:圖片
$ \begin{aligned} &X_i^t= \frac{\gamma^t}{\sqrt{D(X^{t-1})+\varepsilon}}X_i^{t-1} + \left(\beta^t-\frac{E(X^{t-1})\gamma^t}{\sqrt{D(X^{t-1})+\varepsilon}}\right) \\ \end{aligned} $it
其中$\gamma,\beta$都是模型中用反向傳播學習的參數。這樣一來,BN層能夠本身「決定」將輸出映射到合適位置。io
另外,在訓練結束進行推理時,咱們輸入模型的一般都是單個樣本,畢竟一個樣本是不能求樣本方差的。因此BN使用滑動平均(moving average)來保存全部輸入的均值和方差,以用於對單一輸入的歸一化。
Keras中已經實現了BN層能夠直接使用,而不用咱們本身從新寫這個輪子。使用方式以下:
x = keras.layers.BatchNormalization(axis=-1,#對輸入的哪一個軸執行BN momentum=0.99,#滑動平均和方差的動量 epsilon=0.001,#防止0除的較小值 center=True,#是否使用beta調整歸一化後的輸出均值 scale=True,#是否使用gamma調整歸一化後的輸出方差 trainable=True)(x)
其中要注意axis,對於全鏈接層的輸出,BN是如咱們所想的那樣僅對批量維度進行歸一化。可是若是輸入是高維的,歸一化操做則是對批量維度和axis維度對應的張量進行的。好比,BN層的輸入是三通道圖片,axis=-1,均值就是全部批量的全部像素對應的三維向量的平均,方差的計算也是以這個維度進行。對於下面的代碼:
from keras import layers,Model,Input Input_img = Input(shape = [320,320,3]) x = layers.BatchNormalization(axis=-1, momentum=0.99, epsilon=0.001, center=True, scale=True)(Input_img) model = Model(Input_img,x) model.summary()
summary()輸出可訓練參數和不可訓練參數各6個。可訓練參數就是$\gamma,\beta$,不可訓練參數是滑動平均所保存的均值和方差。另外,若是將BN層的traninable標記設置爲False,那麼$\gamma,\beta$就會被固定,不會被訓練;而若是設置爲True,則只有$\gamma,\beta$會被訓練,另外6個不可訓練參數依然是不可訓練狀態,由於它們是經過滑動平均而不是反向傳播來修改的。