1. 程式人生 > >神經網路的Trick之Dropout的理解與實現

神經網路的Trick之Dropout的理解與實現

Dropout2012年深度學習視覺領域的開山之作paper:《ImageNet Classification with Deep Convolutional》所提到的演算法,用於防止過擬合。在我剛入門深度學習,搞視覺的時候,就有所耳聞,當時只知道它是為了防止過擬合。記得以前啥也不懂,看到ImageNet Classification with Deep Convolutional》的思路,然後看到很多文獻都是採用了同樣的思路,於是就跟著模仿,也不知道為什麼要這麼設計,然後去kaggle競賽,感覺自己模仿設計出來的網路,感覺精度都好爛,然後也不會分析網路設計哪些合理,哪些不合理。當時要麼就是模仿別人,要麼就是直接用別人的網路,被領導鄙視了一番……還是不囉嗦了,說多了都是淚。

    網上都說dropout是讓某些神經元以一定的概率不工作,但是具體程式碼怎麼實現?原理又是什麼,還是有點迷糊,所以就大體掃描了文獻:《Improving neural networks by preventing co-adaptation of feature detectors》、《Improving Neural Networks with Dropout》、《Dropout: A Simple Way to Prevent Neural Networks from Overtting》,不過感覺看完以後,還是收穫不是很大。下面是我的學習筆記,因為看的不是很細,也沒有深入理解,有些地方可能有錯,如有錯誤還請指出。

二、演算法概述

我們知道如果要訓練一個大型的網路,訓練資料很少的話,那麼很容易引起過擬合(也就是在測試集上的精度很低),可能我們會想到用L2正則化、或者減小網路規模。然而深度學習領域大神Hinton,在2012年文獻:Improving neural networks by preventing co-adaptation of feature detectors》提出了,在每次訓練的時候,讓一半的特徵檢測器停過工作,這樣可以提高網路的泛化能力,Hinton又把它稱之為dropout。

Hinton認為過擬合,可以通過阻止某些特徵的協同作用來緩解。在每次訓練的時候,每個神經元有百分之50的機率被移除,這樣可以讓一個神經元的出現不應該依賴於另外一個神經元。

另外,我們可以把dropout理解為 模型平均。假設我們要實現一個圖片分類任務,我們設計出了100000個網路,這100000個網路,我們可以設計得各不相同,然後我們對這100000個網路進行訓練,訓練完後我們採用平均的方法,進行預測,這樣肯定可以提高網路的泛化能力,或者說可以防止過擬合,因為這100000個網路,它們各不相同,可以提高網路的穩定性。而所謂的dropout我們可以這麼理解,這n個網路,它們權值共享,並且具有相同的網路層數(這樣可以大大減小計算量)。我們每次dropout後,網路模型都可以看成是整個網路的子網路。(需要注意的是如果採用dropout,訓練時間大大延長,但是對測試階段沒影響)。

囉嗦了這麼多,那麼到底是怎麼實現的?Dropout說的簡單一點就是我們讓在前向傳導的時候,讓某個神經元的啟用值以一定的概率p,讓其停止工作,示意圖如下:

 

左邊是原來的神經網路,右邊是採用Dropout後的網路。這個說是這麼說,但是具體程式碼層面是怎麼實現的?怎麼讓某個神經元以一定的概率停止工作?這個我想很多人還不是很瞭解,程式碼層面的實現方法,下面就講解一下其程式碼層面的實現。以前我們網路的計算公式是:

 

採用dropout後計算公式就變成了:

 

上面公式中Bernoulli函式,是為了以概率p,隨機生成一個0、1的向量。

演算法實現概述:

1、其實Dropout很容易實現,原始碼只需要幾句話就可以搞定了,讓某個神經元以概率p,停止工作,其實就是讓它的啟用值以概率p變為0。比如我們某一層網路神經元的個數為1000個,其啟用值為x1,x2……x1000,我們dropout比率選擇0.4,那麼這一層神經元經過drop後,x1……x1000神經元其中會有大約400個的值被置為0。

2、經過上面遮蔽掉某些神經元,使其啟用值為0以後,我們還需要對向量x1……x1000進行rescale,也就是乘以1/(1-p)。如果你在訓練的時候,經過置0後,沒有對x1……x1000進行rescale,那麼你在測試的時候,就需要對權重進行rescale:

問題來了,上面為什麼經過dropout需要進行rescale?查找了相關的文獻,都沒找到比較合理的解釋,後面再結合原始碼說一下我對這個的見解

    所以在測試階段:如果你既不想在訓練的時候,對x進行放大,也不願意在測試的時候,對權重進行縮小(乘以概率p)。那麼你可以測試n次,這n次都採用了dropout,然後對預測結果取平均值,這樣當n趨近於無窮大的時候,就是我們需要的結果了(也就是說你可以採用train階段一模一樣的程式碼,包含了dropout在裡面,然後前向傳導很多次,比如1000000次,然後對著1000000個結果取平均值)。

三、原始碼實現

下面我引用kerasdropout實現原始碼進行講解,keras開源專案github地址為:

  1. #dropout函式的實現
  2. def dropout(x, level):  
  3.     if level < 0.or level >= 1:#level是概率值,必須在0~1之間
  4.         raise Exception('Dropout level must be in interval [0, 1[.')  
  5.     retain_prob = 1. - level  
  6.     #我們通過binomial函式,生成與x一樣的維數向量。binomial函式就像拋硬幣一樣,我們可以把每個神經元當做拋硬幣一樣
  7.     #硬幣 正面的概率為p,n表示每個神經元試驗的次數
  8.     #因為我們每個神經元只需要拋一次就可以了所以n=1,size引數是我們有多少個硬幣。
  9.     sample=np.random.binomial(n=1,p=retain_prob,size=x.shape)#即將生成一個0、1分佈的向量,0表示這個神經元被遮蔽,不工作了,也就是dropout了
  10.     print sample  
  11.     x *=sample#0、1與x相乘,我們就可以遮蔽某些神經元,讓它們的值變為0
  12.     print x  
  13.     x /= retain_prob  
  14.     return x  
  15. #對dropout的測試,大家可以跑一下上面的函式,瞭解一個輸入x向量,經過dropout的結果
  16. x=np.asarray([1,2,3,4,5,6,7,8,9,10],dtype=np.float32)  
  17. dropout(x,0.4)</span>  

函式中,x是本層網路的啟用值。Level就是dropout就是每個神經元要被丟棄的概率。不過對於dropout後,為什麼需要進行rescale:

  1. x /= retain_prob  

有的人解釋有點像歸一化一樣,就是保證網路的每一層在訓練階段和測試階段資料分佈相同。我查找了很多文獻,都沒找到比較合理的解釋,除了在文獻《Regularization of Neural Networks using DropConnect》稍微解釋了一下,其它好像都沒看到相關的理論解釋。

我們前面說過,其實Dropout是類似於平均網路模型。我們可以這麼理解,我們在訓練階段訓練了1000個網路,每個網路生成的概率為Pi,然後我們在測試階段的時候,我們肯定要把這1000個網路的輸出結果都計算一遍,然後用這1000個輸出,乘以各自網路的概率Pi,求得的期望值就是我們最後的平均結果。我們假設,網路模型的輸出如下:

M是Dropout中所有的mask集合。所以當我們在測試階段的時候,我們就是對M中所有的元素網路,最後所得到的輸出,做一個期望:


P(M)表示網路各個子網路出現的概率。因為dropout過程中,所有的子網路出現的概率都是相同的,所以。

個人總結:個人感覺除非是大型網路,才採用dropout,不然我感覺自己在一些小型網路上,訓練好像很是不爽。之前搞一個比較小的網路,搞人臉特徵點定位的時候,因為訓練資料不夠,怕過擬合,於是就採用dropout,最後感覺好像訓練速度好慢,從此就對dropout有了偏見,感覺訓練過程一直在波動,很是不爽。

參考文獻:

1、《Improving neural networks by preventing co-adaptation of feature detectors》

2、《Improving Neural Networks with Dropout》

3、《Dropout: A Simple Way to Prevent Neural Networks from Overtting》

4、ImageNet Classification with Deep Convolutional