Deep Learning模型之:CNN卷積神經網路(三)CNN常見問題總結

Bicelove發表於2014-05-20

[1]Deep learning簡介

[2]Deep Learning訓練過程

[3]Deep Learning模型之:CNN卷積神經網路推導和實現

[4]Deep Learning模型之:CNN的反向求導及練習

[5]Deep Learning模型之:CNN卷積神經網路(一)深度解析CNN

[6]Deep Learning模型之:CNN卷積神經網路(二)文字識別系統LeNet-5

[7]Deep Learning模型之:CNN卷積神經網路(三)CNN常見問題總結


一、遇到的問題

(1)梯度消失

我在實現過程中犯的第一個錯誤是沒有循序漸進。仗著自己寫過一些神經網路的程式碼以為手到擒來,直接按照LeNet-5的結構寫,過於複雜的結構給測試和除錯都帶來了很大的麻煩,可謂不作死就不會死。

簡單分析一下LeNet-5的結構:第一層8個5*5的卷積核,第二層分別作2*2pooling,第三層16個5*5的卷積核,第四層2*2pooling,隨後是三個節點數分別為120、84、10的全連線層(做手寫數字識別)。這時的引數個數為卷積核及其偏置+pooling層放縮係數及偏置+全連線層權重及偏置,全連結層的引數個數比前四層的引數個數多了兩個數量級

過多的引數個數會極大地提升運算時間,降低測試的效率;同時過多的層數伴隨著嚴重的梯度消失問題(vanishing gradient),嚴重影響訓練效果。在上面提到的網路結構下,我發現傳到第一層的梯度已經小於1e-10,只有後面的全連線層在變化,卷積層幾乎訓不動了。

我對付這個問題的手段包括:

  1. 減少層數
  2. 增大學習率(learning rate)
  3. 用ReLU代替sigmoid

其中前兩種雖然也有效果,只能算是權宜之計,第三種才算是正經的解決了這個問題。在採用ReLU作為啟用函式之後,傳到輸入層的梯度已經達到1e-5~1e-4這個量級。我用MNIST資料集裡的5000個樣本訓練,1000個樣本測試,發現測試結果差不多,收斂速度快了2倍左右。據@kevin好好學習的說法,ReLU還使網路的啟用具有了稀疏的特性,我對這方面就沒研究了。

(2)非線性對映的位置:

在前面提到的Bouvrie的文章中,非線性對映放在卷積層還是pooling層後面都可以,微博上幾位大牛也是這個觀點。奇怪的是,我在一開始實現的時候把sigmoid放在了pooling層後面,雖然很渣但至少能跑出結果。後來我把sigmoid放在卷積層後面就訓不動了,感覺跟梯度消失的時候很像。我猜測也許是卷積層和pooling層啟用程度不同導致傳回去的梯度大小不一樣。

(3)權重衰減(weight decay)

因為我用的資料很少(資料多了跑起來太慢),我擔心會出現過擬合,所以在cost function里加了一項正則項。但結果是不加正則項訓練結果很好,一加就出現嚴重的under fitting,不管怎麼調引數都沒用。原來一直聽說CNN的權重共享就相當於自帶某種正則化,現在看起來確實是這樣。

(4)隨機梯度下降(SGD)的引數選擇

最主要的就一個引數,minibatch的大小。在Deep Learning Toolbox的demo裡,這個值取的是50。但是我的實驗中,似乎minibatch取1的時候收斂最快。

我的感覺:訓練樣本順序隨機的話,每次產生的梯度也是隨機的,那麼50個樣本平均一下梯度就很小了,也許這樣比較穩健,但收斂會比較慢;相反,每個樣本更新一次梯度就大得多,不過也許會比較盲目。

另外還有一個引數是learning rate。在實驗中,增大minibatch會出現訓不動的情況,這時適當增大learning rate能夠讓training cost繼續下降。

另外Yann LeCun似乎說過每一層應該採取不同的learning rate,不過我沒試。

(5)引數的隨機初始化

我試過將引數初始化到(0, 1)區間和(-1, 1)區間,感覺似乎差別不大?

(6)增加全連線層數後的效能

關於這點我不是很確定,但似乎除了增加訓練時間外沒什麼實際作用…


二、網路的改進

(1)自動學習組合係數

為了打破對稱性,從第一個卷積層到第二個卷積層並不是全連結,例如第二層第一個卷積核只卷積第一層的第123個feature map,第二層第二個卷積核只卷積第一層的第345個feature map。在LeNet裡這個組合是人為規定的,Bouvrie的文章中提出這個組合係數也是可以學出來的。但是我的實驗里人為規定和自動學習的效果好像差別不大,不知道更復雜的資料集上會怎麼樣。

(2)ReLU的位置

如果網路的最後一層是softmax分類器的話似乎其前一層就不能用ReLU,因為ReLU輸出可能相差很大(比如0和幾十),這時再經過softmax就會出現一個節點為1其它全0的情況。softmax的cost function裡包含一項log(y),如果y正好是0就沒法算了。所以我在倒數第二層還是採用sigmoid。

(3)其他高階玩法

本來還打算玩一些其他更有趣的東西,比如dropout、maxout、max pooling等等。但是時間有限,老闆已經嫌我不務正業了。


三、總結

這次的收穫:
  1. 寫複雜的演算法不能急於求成,要循序漸進
  2. 測試很重要。上Andrew Ng公開課時候覺得gradient check很煩,現在看來簡直是神器
  3. 機器越快越好……

轉自:http://blog.csdn.net/huangbo10/article/details/24941079

相關文章