1. 程式人生 > >深度學習小白——神經網路3(資料預處理,dropout,正則化)

深度學習小白——神經網路3(資料預處理,dropout,正則化)

一、資料預處理

資料矩陣X,維度是【N*D】N是資料樣本數,D是資料維度

1.均值減法

它對資料中每個獨立特徵減去平均值,從幾何上可以理解為在每個維度上都將資料雲的中心都遷移到原點

X-=np.mean(X,axis=0)

2.歸一化

先對資料做零中心化,然後每個維度都除以其標準差,實現程式碼為X/=np.std(X,axis=0)(對每一列)

3.PCA和白化(Whitening)

先對資料進行零中心化處理,然後計算協方差矩陣,它展示了資料中的相關性結構

X-=np.mean(X,axis=0)

cov=np.dot(X.T,X)/X.shape[0]   #協方差矩陣

U,S,V=np.linalg.svd(cov) #進行奇異值分解運算

U的列是特徵向量,S是裝有奇異值的1維陣列,為了去除資料相關性,將已經零中心化處理過的原始資料投影到特徵基準上

Xrot=np.dot(X,U)

因為U的列是標準正交向量,所以投影對應X中的一個旋轉,旋轉產生的結果就是新的特徵向量。

由於U中特徵向量是按照特徵值的大小排列的,我們可以利用這個性質來對資料降維,只使用前面小部分的特徵向量,丟掉後面的

Xrot_reduced=np.dot(X,U[:,:100])

【白化】輸入為特徵基準上的資料,然後對每個維度除以其特徵值來對數值範圍進行歸一化。經過白化後,資料分佈將會是一個均值為0,協方差相等的矩陣

注意: 資料預訓練一定要在訓練集上操作,不能再驗證集或者測試集上操作,應該先分訓練/驗證/測試集,然後只在訓練集中求圖片平均值,然後各個集中的影象再減去這個平均值

二、權重初始化

錯誤:全0初始化

因為如果網路中的每個神經元都計算出同樣的輸出,然後它們就會在反向傳播中計算出同樣的梯度,從而進行同樣的引數更新,這樣神經元之間就失去了不對稱性的源頭

1.小隨機數初始化

W=0.01* np.random.randn(D,H) ,其中randn函式是基於零均值和標準差的一個高斯分佈來生成隨機數的

warning:並不是小數值一定會得到好的結果,比如一個神經網路的層中的權重值很小, 那麼在反向傳播的時候就會計算出非常小的梯度,這就會很大程度上減小反向傳播中的“梯度訊號”,在深度網路中就會出現問題

2.使用1/sqrt(n)校準方法

w=np.random/randn(n)/sqrt(n)這樣可以保證網路中所有神經元起始時有近似同樣的輸出分佈,這樣可以提高收斂速度

3.稀疏初始化

將權重矩陣設為0,每個神經元都同下一層固定數目的神經元隨機連線

4、偏置(biases)初始化

通常都設為0,因為W已經打破了對稱性

5.Batch Normalization 批量歸一化

其做法是讓啟用資料在訓練開始前通過一個網路,網路處理資料使其服從標準高斯分佈。因為歸一化是一個簡單可求導的操作,所以上述思路是可行的。在實現層面,應用這個技巧通常意味著全連線層(或者是卷積層,後續會講)與啟用函式之間新增一個BatchNorm層。

其實如果是僅僅使用上面的類似於白化的歸一化公式,對網路某一層A的輸出資料做歸一化,然後送入網路下一層B,這樣是會影響到本層網路A所學習到的特徵的。打個比方,比如我網路中間某一層學習到特徵資料本身就分佈在S型啟用函式的兩側,你強制把它給我歸一化處理、標準差也限制在了1,把資料變換成分佈於s函式的中間部分,這樣就相當於我這一層網路所學習到的特徵分佈被你搞壞了,這可怎麼辦?於是文獻使出了一招驚天地泣鬼神的招式:變換重構,引入了可學習引數γ、β,這就是演算法關鍵之處:

 

每一個神經元xk都會有一對這樣的引數γ、β。這樣其實當:


是可以恢復出原始的某一層所學到的特徵的。因此我們引入了這個可學習重構引數γ、β,讓我們的網路可以學習恢復出原始網路所要學習的特徵分佈。最後Batch Normalization網路層的前向傳導過程公式就是:

 

上面的公式中m指的是mini-batch size。

6. Batch Renormalization

統計學上有一個問題叫Internal Covariate Shift,我也不知道該怎麼翻譯,暫且叫它ICS吧。說的是這樣一個事情,即在偏統計的機器學習中,有這樣一個假設,要求最初的資料的分佈和最終分類結果的資料分佈應該一致,一般來講它們的條件分佈應該是相同的P_{data}(Y|X=x)=P_{target}(Y|X=x),但是它們的邊緣密度就不一定了,P_{data}(X)\ne P_{target}(X),在我們的神經網路中,相當於每一層都是對原資料的一個抽象對映和特徵提取,但是對於每一層來說,我們的target是一致的,可我們每一層都是一個對映啊,資料的邊緣分佈肯定是不一樣的,這時候就尷尬了。

可我們的BN做的是這樣一個事情,把它變成一個0均值1方差的分佈上(不包括後面修正),這樣在一定程度上,可以減小ICS帶來的影響,可是也不是完全解決,畢竟你只保證了均值和方差相同,分佈卻不一定相同。

本文系batch norm原作者對其的優化,該方法保證了train和inference階段的等效性,解決了非獨立同分布和小minibatch的問題。其實現如下:

其中r和d首先通過minibatch計算出,但stop_gradient使得反傳中r和d不被更新,因此r和d不被當做訓練引數對待。試想如果r和d作為引數來更新,如下式所示:

這樣一來,就相當於在訓練階段也使用moving averages  μ和σ,這會引起梯度優化和normalization之間的衝突,優化的目的是通過對權重的scale和shift去適應一個minibatch,normalization則會抵消這種影響,而moving averages則消除了歸一化後的啟用對當前minibatch的依賴性,使得minibatch喪失了對每次權重更新方向的調整,從而使得權重尺度因normalization的抵消而無邊界的增加卻不會降低loss。而在前傳中r和d的仿射變換修正了minibatch和普適樣本的差異,使得該層的啟用在inference階段能得到更有泛化性的修正。
這樣的修正使得minibatch很小甚至為1時的仍能發揮其作用,且即使在minibatch中的資料是非獨立同分布的,也會因為這個修正而消除對訓練集合的過擬合。
Bayesian的角度看,這種修正比需要自己學習的scale和shift能更好地逆轉對錶徵的破壞,且這種逆轉的程度是由minibatch資料驅動的,在inference時也能因地制宜,而scale和shift對不同資料在inference時會施加相同的影響,因此這樣的修正進一步降低了不同訓練樣本對訓練過程的影響,也使得train和inference更為一致。


三、正則化

L2正則化可能是最常用的正則化方法了。可以通過懲罰目標函式中所有引數的平方將其實現。即對於網路中的每個權重w,向目標函式中增加一個\frac{1}{2}\lambda w^2,其中\lambda是正則化強度。L2正則化可以直觀理解為它對於大數值的權重向量進行嚴厲懲罰,傾向於更加分散的權重向量。線上性分類章節中討論過,由於輸入和權重之間的乘法操作,這樣就有了一個優良的特性:使網路更傾向於使用所有輸入特徵,而不是嚴重依賴輸入特徵中某些小部分特徵。最後需要注意在梯度下降和引數更新的時候,使用L2正則化意味著所有的權重都以w += -lambda * W向著0線性下降。

四、Dropout

在訓練的時候,隨機失活的實現方法是讓神經元以超引數p的概率被啟用或者被設定為0。


在訓練過程中,隨機失活可以被認為是對完整的神經網路抽樣出一些子集,每次基於輸入資料只更新子網路的引數(然而,數量巨大的子網路們並不是相互獨立的,因為它們都共享引數)

在測試過程中不使用隨機失活,可以理解為是對數量巨大的子網路們做了模型整合(model ensemble),以此來計算出一個平均的預測。

注意:predict函式中不進行隨機失活,但是對於兩個隱層的輸出都要乘以p,調整其數值範圍。p=0.5為例,在測試時神經元必須把它們的輸出減半,這是因為在訓練的時候它們的輸出只有一半。為了理解這點,先假設有一個神經元x的輸出,那麼進行隨機失活的時候,該神經元的輸出就是px+(1-p)0,這是有1-p的概率神經元的輸出為0。在測試時神經元總是啟用的,就必須調整x\to px來保持同樣的預期輸出。在測試時會在所有可能的二值遮罩(也就是數量龐大的所有子網路)中迭代並計算它們的協作預測,進行這種減弱的操作也可以認為是與之相關的。

實際更傾向使用反向隨機失活(inverted dropout),它是在訓練時就進行數值範圍調整,從而讓前向傳播在測試時保持不變。這樣做還有一個好處,無論你決定是否使用隨機失活,預測方法的程式碼可以保持不變。反向隨機失活的程式碼如下:

p = 0.5 # 啟用神經元的概率. p值更高 = 隨機失活更弱

def train_step(X):
  # 3層neural network的前向傳播
  H1 = np.maximum(0, np.dot(W1, X) + b1)
  U1 = (np.random.rand(*H1.shape) < p) / p # 第一個隨機失活遮罩. 注意/p!
  H1 *= U1 # drop!
  H2 = np.maximum(0, np.dot(W2, H1) + b2)
  U2 = (np.random.rand(*H2.shape) < p) / p # 第二個隨機失活遮罩. 注意/p!
  H2 *= U2 # drop!
  out = np.dot(W3, H2) + b3

  # 反向傳播:計算梯度... (略)
  # 進行引數更新... (略)

def predict(X):
  # 前向傳播時模型整合
  H1 = np.maximum(0, np.dot(W1, X) + b1) # 不用數值範圍調整了
  H2 = np.maximum(0, np.dot(W2, H1) + b2)
  out = np.dot(W3, H2) + b3

六、損失函式

資料損失是對所有樣本的資料損失求平均。

1.分類問題

這類問題中,常見的損失函式有

SVM:       \displaystyle L_i=\sum_{j\not=y_i}max(0,f_j-f_{y_i}+1)

Softmax分類器:      \displaystyle L_i=-log(\frac{e^{f_{y_i}}}{\sum_je^{f_j}})

2.屬性分類

上面兩個損失公式的前提,都是假設每個樣本只有一個正確的標籤yi,但如果yi是一個二值向量, 每個樣本可能有,也可能沒有某個屬性。如一張圖

可以同時有多個標籤,這種情況下,為每個屬性建立一個獨立的二分類的分類器。

\displaystyle L_i=\sum_jmax(0,1-y_{ij}f_j)

3.迴歸問題

是預測實數的值的問題,通常是計算預測值和真實值之間的損失,然後用L2平方正規化度量差異,對於某個樣本,L2正規化計算如下:

L_i=||f-y_i||^2_2

注意: L2損失比起穩定的Softmax損失來,其優化過程要困難得多。它需要對於每個輸入都要輸出一個確切的正確值,而softmax中,每個評分的準確值並不是那麼重要,而是比較的量級。而且L2損失的魯棒性不好,因為異常值可以導致很大的梯度,所以在面對一個迴歸問題時,先要考慮能不能轉化為分類問題。儘量把輸出變成二分類,然後對它們進行分類。