原文地址:http://blog.csdn.net/hjimce/article/details/50413257
作者:hjimce
一、相關工作
本來今天是要搞《Maxout Networks》和《Network In Network》的,結果發現maxout和dropout有點類似,所以就對dropout做一下相關的總結,了解一下其代碼層面的實現。
Dropout是2012年深度學習視覺領域的開山之作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個結果取平均值)。
三、源碼實現
下面我引用keras的dropout實現源碼進行講解,keras開源項目github地址為:
https://github.com/fchollet/keras/tree/master/keras。其dropout所在的文件為:
https://github.com/fchollet/keras/blob/master/keras/backend/theano_backend.py,dropout實現函數如下:
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 15 return x 16 #對dropout的測試,大家可以跑一下上面的函數,了解一個輸入x向量,經過dropout的結果 17 x=np.asarray([1,2,3,4,5,6,7,8,9,10],dtype=np.float32) 18 dropout(x,0.4)
函數中,x是本層網絡的激活值。Level就是dropout就是每個神經元要被丟棄的概率。不過對於dropout后,為什么需要進行rescale:
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》