神經網路的引數優化方法
轉載自:https://www.cnblogs.com/bonelee/p/8528863.html
著名: 本文是從 Michael Nielsen的電子書Neural Network and Deep Learning的深度學習那一章的卷積神經網路的引數優化方法的一些總結和摘錄,並不是我自己的結論和做實驗所得到的結果。我想Michael的實驗結果更有說服力一些。本書在github上有中文翻譯的版本,
前言
最近卷積神經網路(CNN)很火熱,它在影象分類領域的卓越表現引起了大家的廣泛關注。本文總結和摘錄了Michael Nielsen的那本Neural Network and Deep Learning一書中關於深度學習一章中關於提高泛化能力的一些概述和實驗結果。力爭用資料給大家一個關於正則化
本文並不會介紹正則化,棄權(Dropout), 池化等方法的原理,只會介紹它們在實驗中的應用或者起到的效果,更多的關於這些方法的解釋請自行查詢。
mnist資料集介紹
本文的實驗是基於mnist資料集合的,mnist是一個從0到9的手寫數字集合,共有60,000張訓練圖片,10,000張測試圖片。每張圖片大小是28*28大小。我們的實驗就是構建一個神經網路來高精度的分類圖片,也就是提高泛化能力。
提高泛化能力的方法
一般來說,提高泛化能力的方法主要有以下幾個:
- 正則化
- 增加神經網路層數
- 使用正確的代價函式
- 使用好的權重初始化技術
- 人為拓展訓練集
- 棄權技術
下面我們通過實驗結果給這些引數優化理論一個直觀的結果
1. 普通的全連線神經網路的效果
我們使用一個隱藏層,包含100個隱藏神經元,輸入層是784,輸出層是one-hot編碼的形式,最後一層是Softmax層。訓練過程採用對數似然代價函式,60次迭代,學習速率η=0.1,隨機梯度下降的小批量資料大小為10,沒有正則化。在測試集上得到的結果是97.8%
2.使用卷積神經網路 — 僅一個卷積層
輸入層是卷積層,5*5的區域性感受野,也就是一個5*5的卷積核,一共20個特徵對映。最大池化層選用2*2的大小。後面是100個隱藏神經元的全連線層。結構如圖所示
在這個架構中,我們把卷積層和chihua層看做是學習輸入訓練影象中的區域性感受野,而後的全連線層則是一個更抽象層次的學習,從整個影象整合全域性資訊。也是60次迭代,批量資料大小是10,學習率是0.1。
經過三次執行取平均後,準確率是98.78%,這是相當大的改善。錯誤率降低了1/3,。卷積神經網路開始顯現威力。
3.使用卷積神經網路 — 兩個卷積層
我們接著插入第二個卷積-混合層,把它插入在之前的卷積-混合層和全連線層之間,同樣的5*5的區域性感受野,2*2的池化層。
這一次,我們擁有了99.06%的準確率。
4.使用卷積神經網路 — 兩個卷積層+線性修正單元(ReLU)+正則化
上面我們使用的Sigmod啟用函式,現在我們換成線性修正啟用函式ReLU
f(z)=max(0,z)
,我們選擇60個迭代期,學習速率η=0.03, ,使用L2正則化,正則化引數λ=0.1
這一次,我們獲得了99.23%的準確率,超過了S型啟用函式的99.06%. ReLU的優勢是max(0,z)
中z取最大極限時不會飽和,不像是S函式,這有助於持續學習。
5.使用卷積神經網路 — 兩個卷基層+線性修正單元(ReLU)+正則化+拓展資料集
拓展訓練集資料的一個簡單方法是將每個訓練影象由一個畫素來代替,無論是上一個畫素,下一個畫素,或者左右的畫素。其他的方法也有改變亮度,改變解析度,圖片旋轉,扭曲,位移等。
我們把50,000幅影象人為拓展到250,000幅影象。使用第4節一樣的網路,因為我們是在訓練5倍的資料,所以減少了過擬合的風險。
這次的到了99.37的訓練正確率。
6.使用卷積神經網路 — 兩個卷基層+線性修正單元(ReLU)+正則化+拓展資料集+繼續插入額外的全連線層
繼續上面的網路,我們拓展全連線層的規模,300個隱藏神經元和1000個神經元的額精度分別是99.46%和99.43%.
我們插入一個額外的全連線層
這次取得了99.43%的精度。拓展後的網路並沒有幫助太多。
7.使用卷積神經網路 — 兩個卷基層+線性修正單元(ReLU)+拓展資料集+繼續插入額外的全連線層+棄權技術
棄權的基本思想就是在訓練網路時隨機的移除單獨的啟用值,使得模型對單獨的依據丟失更為強勁,因此不太依賴於訓練資料的特質。我們嘗試應用棄權技術到最終的全連線層(不是在卷基層)。這裡,減少了迭代期的數量為40個,全連線層使用1000個隱藏神經元,因為棄權技術會丟棄一些神經元。Dropout是一種非常有效有提高泛化能力,降低過擬合的方法!
使用棄權技術,的到了99.60%的準確率。
8.使用卷積神經網路 — 兩個卷基層+線性修正單元(ReLU)+正則化+拓展資料集+繼續插入額外的全連線層+棄權技術+組合網路
組合網路類似於隨機森林或者adaboost的整合方法,建立幾個神經網路,讓他們投票來決定最好的分類。我們訓練了5個不同的神經網路,每個都大到了99.60%的準去率,用這5個網路來進行投票表決一個影象的分類。
採用這個方法,達到了99.67%的準確率。
總結
卷積神經網路 的一些技巧總結如下:
1. 使用卷積層極大地減小了全連線層中的引數的數目,使學習的問題更容易
2. 使用更多強有力的規範化技術(尤其是棄權和卷積)來減小過度擬合,
3. 使用修正線性單元而不是S型神經元,來加速訓練-依據經驗,通常是3-5倍,
4. 使用GPU來計算
5. 利用充分大的資料集,避免過擬合
6. 使用正確的代價函式,避免學習減速
7. 使用好的權重初始化,避免因為神經元飽和引起的學習減速
CNN超引數優化和視覺化技巧詳解
轉自:https://zhuanlan.zhihu.com/p/27905191
在深度學習中,有許多不同的深度網路結構,包括卷積神經網路(CNN或convnet)、長短期記憶網路(LSTM)和生成對抗網路(GAN)等。
在計算機視覺領域,對卷積神經網路(簡稱為CNN)的研究和應用都取得了顯著的成果。CNN網路最初的誕生收到了動物視覺神經機制的啟發,目前已成功用於機器視覺等領域中。
技術部落格Towards Data Science最近釋出了一篇文章,作者Suki Lau。文章討論了在卷積神經網路中,該如何調整超引數以及視覺化卷積層。
為什麼用卷積神經網路?
首先,我們想要計算機具有什麼能力呢?
當我們看到一隻貓跳上窗臺或在沙發上睡覺時,我們的潛意識會認出它是一隻貓。
我們希望計算機也能完成這項任務,即將影象輸入後,找出其獨有的特徵,最終輸出該影象的類別資訊。
卷積神經網路可以完成這項任務。
何為卷積神經網路?
先談定義,卷積神經網路是一種特殊的神經網路,其中至少包含一個卷積層。在典型的CNN網路結構中,輸入一張影象,經由一系列卷積層、非線性啟用層、池化層和全連線層後,可輸出相應的類別標籤。
卷積神經網路的特別之處在於加入了卷積層。
在經典的神經網路中,整張圖片會被傳入網路中來訓練各網路層權值。當輸入為簡單居中的影象時,如Mnist手寫數字圖,網路識別效果較優,但是當輸入變為更為複雜多變的影象時,如跳上窗戶的小貓,此時網路識別效果不佳甚至無法辨識。
加入更多隱含層學習輸入影象的抽象特徵,可能會有所幫助,但是這樣會增加神經元的數目,大大增加訓練所需的計算資源和佔用過多的記憶體,這是不切實際的。
而CNN識別目標的過程,是先尋找諸如邊緣、線段和曲線等相關低階特徵,然後使用多個卷積層來構建更多抽象的高階特徵。
在卷積層的學習過程中,CNN網路通過共享多個卷積核(或特徵檢測器)的權值,來學習每張圖片的區域性資訊,並用於構建抽象特徵圖譜。卷積核共享特性大大降低了訓練網路所需的引數量。
由於經過訓練的檢測器可以通過卷積層重複用來組合地檢測圖片中的抽象特徵,因此卷積神經網路更適用於複雜的影象識別任務。
超引數調整
在深度神經網路中,調整超引數組合並非易事,因為訓練深層神經網路十分耗時,且需要配置多個引數。
接下來,我們簡單列舉幾個影響CNN網路的關鍵超引數。
學習率
學習率是指在優化演算法中更新網路權重的幅度大小。
學習率可以是恆定的、逐漸降低的、基於動量的或者是自適應的,採用哪種學習率取決於所選擇優化演算法的型別,如SGD、Adam、Adagrad、AdaDelta或RMSProp等演算法。
優化策略這方面的內容可參閱量子位之前編譯過的“一文看懂各種神經網路優化演算法:從梯度下降到Adam方法”。
迭代次數
迭代次數是指整個訓練集輸入到神經網路進行訓練的次數。當測試錯誤率和訓練錯誤率相差較小時,可認為當前的迭代次數是合適的,否則需繼續增大迭代次數,或調整網路結構。
批次大小
在卷積神經網路的學習過程中,小批次會表現得更好,選取範圍一般位於區間[16,128]內。
還需要注意的是,CNN網路對批次大小的調整十分敏感。
啟用函式
啟用函式具有非線性,理論上可以使模型擬合出任何函式。通常情況下,rectifier函式在CNN網路中的效果較好。當然,可以根據實際任務,選擇其他型別的啟用函式,如Sigmoid和Tanh等等。
隱含層的數目和單元數
增加隱含層數目以加深網路深度,會在一定程度上改善網路效能,但是當測試錯誤率不再下降時,就需要尋求其他的改良方法。增加隱含層數目也帶來一個問題,即提高了訓練該網路的計算成本。
當網路的單元數設定過少時,可能會導致欠擬合,而單元數設定過多時,只要採取合適的正則化方式,就不會產生不良影響。
權重初始化
在網路中,通常會使用小隨機數來初始化各網路層的權重,以防止產生不活躍的神經元,但是設定過小的隨機數可能生成零梯度網路。一般來說,均勻分佈方法效果較好。
Dropout方法
作為一種常用的正則化方式,加入Dropout層可以減弱深層神經網路的過擬合效應。該方法會按照所設定的概率引數,在每次訓練中隨機地不啟用一定比例的神經單元。該引數的預設值為0.5。
手動調整超引數是十分費時也不切實際。接下來介紹兩種搜尋最優超引數的常用方法。
網格搜尋和隨機搜尋
網格搜尋是通過窮舉法列出不同的引數組合,確定性能最優的結構。隨機搜尋是從具有特定分佈的引數空間中抽取出一定數量的候選組合。
網格搜尋方法也需要制定策略,在初始階段最好先確定各超引數值的大概範圍。可以先嚐試在較小迭代次數或較小規模的訓練集上進行大步幅的網格搜尋。然後在下個階段中,設定更大的迭代次數,或是使用整個訓練集,實現小幅精確定位。
雖然在許多機器學習演算法中,通常會使用網格搜尋來確定超引數組合,但是隨著引數量的增大,訓練網路所需的計算量呈指數型增長,這種方法在深層神經網路的超引數調整時效果並不是很好。
有研究指出,在深度神經網路的超引數調整中,隨機搜尋方法比網格搜尋的效率更高,具體可參考文末中的“隨機搜尋在超引數優化中的應用”。
當然,可根據神經網路的理論經驗,進行超引數的手動調整在一些場景下也是可行的。
視覺化
我們可以通過視覺化各個卷積層,來更好地瞭解CNN網路是如何學習輸入影象的特徵。
視覺化有兩種直接方式,分別是視覺化啟用程度和視覺化相關權重。在網路訓練過程中,卷積層的啟用情況通常會變得更為稀疏和具有區域性特性。當不同輸入影象的啟用圖都存在大片未啟用的區域,那麼可能是設定了過高的學習率使得卷積核不起作用,導致產生零啟用影象。
效能優良的神經網路通常含有多個明顯而平滑的卷積器,且沒有任何干擾特徵。若在權重中觀察到相關干擾特徵,可能原因是網路未被充分訓練,或是正則化強度較低導致了過擬合效應。
神經網路引數優化--基於CNN的驗證
轉自:https://ziyubiti.github.io/2016/11/20/cnnpara/
當使用多層更深的隱藏層全連線網路時,引數量會變得非常巨大,達到數十億量級;而採用CNN結構,則可以層間共享權重,極大減小待訓練的引數量;同時可採用二維卷積,保留影象的空間結構資訊;採用池化層,進一步減少引數計算。
一般來說,提高泛化能力的方法主要有: 正則化、增加神經網路層數、改變啟用函式與代價函式、使用好的權重初始化技術、人為擴充套件訓練集、棄權技術。
下面以MNIST為例,結合CNN、Pooling、Fc結構,通過不同的網路結構變化,給這些引數優化理論一個直觀的驗證結果。
CNN不同網路結構效能比較
可以看出:
1、使用L2正則化,dropout技術,擴充套件資料集等,有效緩解過擬合,提升了效能;
2、使用ReLU,導數為常量,可以緩解梯度下降問題,並加速訓練;
3、增加Conv/Pooling與Fc層,可以改善效能。(我自己實測也是如此)
Note:
1、網路並非越深越好,單純的Conv/Pooling/Fc結構,增加到一定深度後由於過擬合效能反而下降。
2、網路結構資訊更重要,如使用GoogleNet、ResNet等。
知乎上的討論:
轉自:https://www.zhihu.com/question/41631631
訓練技巧對深度學習來說是非常重要的,作為一門實驗性質很強的科學,同樣的網路結構使用不同的訓練方法訓練,結果可能會有很大的差異。這裡我總結了近一年來的煉丹心得,分享給大家,也歡迎大家補充指正。
引數初始化。
下面幾種方式,隨便選一個,結果基本都差不多。但是一定要做。否則可能會減慢收斂速度,影響收斂結果,甚至造成Nan等一系列問題。
下面的n_in為網路的輸入大小,n_out為網路的輸出大小,n為n_in或(n_in+n_out)*0.5
Xavier初始法論文:http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf
He初始化論文:https://arxiv.org/abs/1502.01852
- uniform均勻分佈初始化: w = np.random.uniform(low=-scale, high=scale, size=[n_in,n_out])
- Xavier初始法,適用於普通啟用函式(tanh,sigmoid):scale = np.sqrt(3/n)
- He初始化,適用於ReLU:scale = np.sqrt(6/n)
- normal高斯分佈初始化: w = np.random.randn(n_in,n_out) * stdev # stdev為高斯分佈的標準差,均值設為0
- Xavier初始法,適用於普通啟用函式 (tanh,sigmoid):stdev = np.sqrt(n)
- He初始化,適用於ReLU:stdev = np.sqrt(2/n)
- svd初始化:對RNN有比較好的效果。參考論文:https://arxiv.org/abs/1312.6120
資料預處理方式
- zero-center ,這個挺常用的. X -= np.mean(X, axis = 0) # zero-center X /= np.std(X, axis = 0) # normalize
- PCA whitening,這個用的比較少.
訓練技巧
- 要做梯度歸一化,即算出來的梯度除以minibatch size
- clip c(梯度裁剪): 限制最大梯度,其實是value = sqrt(w1^2+w2^2….),如果value超過了閾值,就算一個衰減繫系數,讓value的值等於閾值: 5,10,15
- dropout對小資料防止過擬合有很好的效果,值一般設為0.5,小資料上dropout+sgd在我的大部分實驗中,效果提升都非常明顯(實測sgd比adam好).因此可能的話,建議一定要嘗試一下。 dropout的位置比較有講究, 對於RNN,建議放到輸入->RNN與RNN->輸出的位置.關於RNN如何用dropout,可以參考這篇論文:http://arxiv.org/abs/1409.2329
- adam,adadelta等,在小資料上,我這裡實驗的效果不如sgd, sgd收斂速度會慢一些,但是最終收斂後的結果,一般都比較好。如果使用sgd的話,可以選擇從1.0或者0.1的學習率開始,隔一段時間,在驗證集上檢查一下,如果cost沒有下降,就對學習率減半. 我看過很多論文都這麼搞,我自己實驗的結果也很好. 當然,也可以先用ada系列先跑,最後快收斂的時候,更換成sgd繼續訓練.同樣也會有提升.據說adadelta一般在分類問題上效果比較好,adam在生成問題上效果比較好。
- 除了gate之類的地方,需要把輸出限制成0-1之外,儘量不要用sigmoid,可以用tanh或者relu之類的啟用函式.1. sigmoid函式在-4到4的區間裡,才有較大的梯度。之外的區間,梯度接近0,很容易造成梯度消失問題。2. 輸入0均值,sigmoid函式的輸出不是0均值的。
- rnn的dim和embdding size,一般從128上下開始調整. batch size,一般從128左右開始調整.batch size合適最重要,並不是越大越好.
- word2vec初始化,在小資料上,不僅可以有效提高收斂速度,也可以可以提高結果.
- 儘量對資料做shuffle
- LSTM 的forget gate的bias,用1.0或者更大的值做初始化,可以取得更好的結果,來自這篇論文:http://jmlr.org/proceedings/papers/v37/jozefowicz15.pdf, 我這裡實驗設成1.0,可以提高收斂速度.實際使用中,不同的任務,可能需要嘗試不同的值.
- Batch Normalization據說可以提升效果,不過我沒有嘗試過,建議作為最後提升模型的手段,參考論文:Accelerating Deep Network Training by Reducing Internal Covariate Shift
- 如果你的模型包含全連線層(MLP),並且輸入和輸出大小一樣,可以考慮將MLP替換成Highway Network,我嘗試對結果有一點提升,建議作為最後提升模型的手段,原理很簡單,就是給輸出加了一個gate來控制資訊的流動,詳細介紹請參考論文: http://arxiv.org/abs/1505.00387
- 來自@張馨宇的技巧:一輪加正則,一輪不加正則,反覆進行。
Ensemble
Ensemble是論文刷結果的終極核武器,深度學習中一般有以下幾種方式
- 同樣的引數,不同的初始化方式
- 不同的引數,通過cross-validation,選取最好的幾組
- 同樣的引數,模型訓練的不同階段,即不同迭代次數的模型。
- 不同的模型,進行線性融合. 例如RNN和傳統模型.
其實我發現現在深度學習越來越成熟,調參工作比以前少了很多,絕大多數情況自己設計的引數都不如教程和框架的預設引數好,不過有一些技巧我一直都在用的
(1)relu+bn。這套好基友組合是萬精油,可以滿足95%的情況,除非有些特殊情況會用identity,比如迴歸問題,比如resnet的shortcut支路,sigmoid什麼的都快從我世界裡消失了
(2)dropout 。分類問題用dropout ,只需要最後一層softmax 前用基本就可以了,能夠防止過擬合,可能對accuracy提高不大,但是dropout 前面的那層如果是之後要使用的feature的話,效能會大大提升(例如max pool進入fc,實測發現加BN效果非常明顯)
(3)資料的shuffle 和augmentation 。這個沒啥好說的,aug也不是瞎加,比如行人識別一般就不會加上下翻轉的,因為不會碰到頭朝下的異型種
(4)降學習率。隨著網路訓練的進行,學習率要逐漸降下來,如果你有tensorboard,你有可能發現,在學習率下降的一瞬間,網路會有個巨大的效能提升,同樣的fine-tuning也要根據模型的效能設定合適的學習率,比如一個訓練的已經非常好的模型你上來就1e-3的學習率,那之前就白訓練了,就是說網路效能越好,學習率要越小
(5)tensorboard。以前不怎麼用,用了之後發現太有幫助,幫助你監視網路的狀態,來調整網路引數
(6)隨時存檔模型,要有validation 。這就跟打遊戲一樣存檔,把每個epoch和其對應的validation 結果存下來,可以分析出開始overfitting的時間點,方便下次載入fine-tuning
(7)網路層數,引數量什麼的都不是大問題,在效能不丟的情況下,減到最小
(8)batchsize通常影響沒那麼大,塞滿卡就行,除了特殊的演算法需要batch大一點
(9)輸入減不減mean歸一化在有了bn之後已經不那麼重要了
上面那些都是大家所知道的常識,也是外行人覺得深度學習一直在做的就是這些很low的東西,其實網路設計(關鍵!!!實測發現對於acc影響極大!)上博大精深,這也遠超過我的水平範疇,只說一些很簡單的
(1)卷積核的分解。從最初的5×5分解為兩個3×3,到後來的3×3分解為1×3和3×1,再到resnet的1×1,3×3,1×1,再xception的3×3 channel-wise conv+1×1,網路的計算量越來越小,層數越來越多,效能越來越好,這些都是設計網路時可以借鑑的
(2)不同尺寸的feature maps的concat,只用一層的feature map一把梭可能不如concat好,pspnet就是這種思想,這個思想很常用
(3)resnet的shortcut確實會很有用,重點在於shortcut支路一定要是identity,主路是什麼conv都無所謂,這是我親耳聽resnet作者所述
(4)針對於metric learning,對feature加個classification 的約束通常可以提高效能加快收斂
補充一點,adam收斂雖快但是得到的解往往沒有sgd+momentum得到的解更好,如果不考慮時間成本的話還是用sgd吧。
再補充一個rnn trick,仍然是不考慮時間成本的情況下,batch size=1是一個很不錯的regularizer, 起碼在某些task上,這也有可能是很多人無法復現alex graves實驗結果的原因之一,因為他總是把batch size設成1。。。
沒做過CNN,RNN,調過連續值DNN,以下經驗僅限於CTR
1.樣本要足夠隨機
2.樣本要做歸一化
3.啟用函式要視樣本輸入選擇
4.minibatch很重要,幾百到幾千是比較合適的(很大資料量的情況下)
5.learning rate很重要,可以直接用adagrad or adadelta,省去一些麻煩,然後把衝量調到0.9以上
6.權重初始化,可用高斯分佈乘上一個很小的數
小白一枚,在這裡總結一下我在試驗中觀察到的現象(必然有理解錯誤的地方):
1. Adam收斂速度的確要快一些,可是結果總是不如其他優化演算法,如果很看重結果不在乎速度還是用其他的試試。
2. Dropout的放置位置以及大小非常重要,求大神能分享經驗.....
3. Relu並不是一定比Tanh好,如果不太懂的話,用的不合適,可能會導致梯度消失?(不知道是不是網路結構問題,為什麼一用relu梯度一會兒就變成Nan)
4. pretrain 的 Embedding在訓練中不調優泛化能力要更好一些,調優的話引數會增加好多啊。
另:心得體會
1. 深度學習真是一門實驗科學,很多地方解釋不了為什麼好,為什麼不好。
2.如果你機器配置很不到位,也沒有人帶你,畢業設計千萬別選深度學習,天天愁,好坑啊。
最近在看 Karpathy 的 cs231n, 還沒看完, 不過過程中總結了一下他提到的一些技巧:
關於引數:
- 通常情況下, 更新引數的方法預設用 Adam 效果就很好
- 如果可以載入全部資料 (full batch updates), 可以使用 L-BFGS
Model Ensembles:
- 訓練多個模型, 在測試時將結果平均起來, 大約可以得到 2% 提升.
- 訓練單個模型時, 平均不同時期的 checkpoints 的結果, 也可以有提升.
- 測試時可以將測試的引數和訓練的引數組合起來:
分享幾個常用的trick:
1.增加每個step的輪數
2.early stop
3.用小一些的學習率warmup
4.回退到更大的學習率
5.nesterov momentum sgd
6.搜尋初始學習率
1.better initialization helps a lot
2.use minibatch and choose batch_size(must)
3.use batch_norm &dropout
4.use adam
5.plot the learning rate curve
6.plot the loss curve.
7.lstm &gru are almost always better than sample RNN
8.use better framework(like tensorflow with tensorboard)
9.find hyper parameters used most often in paper
10 pray
cnn的調參主要是在優化函式、embedding的維度還要殘差網路的層數幾個方面。
- 優化函式方面有兩個選擇:sgd、adam,相對來說adam要簡單很多,不需要設定引數,效果也還不錯。
- embedding隨著維度的增大會出現一個最大值點,也就是開始時是隨維度的增加效果逐漸變好,到達一個點後,而後隨維度的增加,效果會變差。
- 殘差網路的層數與embedding的維度有關係,隨層數的增加,效果變化也是一個凸函式。
另外還有啟用函式,dropout層和batchnormalize層的使用。啟用函式推薦使用relu,dropout層數不易設定過大,過大會導致不收斂,調節步長可以是0.05,一般調整到0.4或者0.5就可找到最佳值。
以上是個人調參的一些經驗,可供參考。
1.無論是cnn還是rnn,batch normalization都有用,不一定結果提高几個點,收斂快多了
2.資料初始時normalize得好,有時候直接提高2個點,比如cifar10,轉到yuv下normalize再scn
3.loss不降了lr就除10
4. google的inception系列按它論文裡說的永遠無法復現
如何訓練深度神經網路?老司機的 15 點建議
導語:印度深度學習專家 Rishabh Shukla 對開發深度神經網路的經驗總結。
本文為印度深度學習專家、創業者 Rishabh Shukla 在 GitHub 上發表的長博文,總結了他過去的開發經驗,旨在給新入門的開發者提供指導。雷鋒網做了不改變原意的編譯。
在深度學習領域,為了高效訓練深度神經網路,有些實踐方法被過來人強烈推薦。
在這篇博文中,我會覆蓋幾種最常使用的實踐方法,從高品質訓練資料的重要性、超引數(hyperparameters)到更快建立 DNN(深度神經網路) 原型模型的一般性建議。這些推薦方法中的大多數,已被學術界的研究所證實,並在論文中展示了相關實驗、數學證據,比如 Efficient BackProp(Yann LeCun et al.) 和 Practical Recommendations for Deep Architectures(Yoshua Bengio)。
1. 訓練資料
許多 ML 開發者習慣把原始訓練資料直接扔給 DNN——為什麼不這麼做呢?既然任何 DNN (大多數人的假設)仍然能夠給出不錯的結果,不是嗎?但是,有句老話叫“給定恰當的資料型別,一個簡單的模型能比複雜 DNN 提供更好、更快的結果”。雖然這有一些例外,但在今天,這句話仍然沒有過時。因此,不管你是在計算機視覺( CV),自然語言處理(NLP)還是統計建模(Statistical Modelling)等領域,想要對原始資料預處理,有幾個方法可以得到更好的訓練資料:
-
獲取越大的資料庫越好。DNN 對資料很飢渴,越多越好。
-
去除所有包含損壞資料的訓練樣本,比如短文字,高度扭曲的影象,假輸出標籤,包含許多虛值(null values)的屬性。
-
Data Augmentation(資料擴張)——生成新樣例。以影象為例,重新調節,增加噪聲等等。
2. 選擇恰當的激勵函式(activation function)
激勵函式是所有神經網路的核心部分之一。
激勵函式把渴望已久的非線性(non-linearity)加入了模型。多年來,Sigmoid 函式 一直是多數人傾向的選擇。但是,Sigmoid 函式不可避免地存在兩個缺陷:1. 尾部 sigmoids 的飽和,進一步導致梯度消失。2. 不以 0 為中心(輸出在 0 到 1 之間)。
一個更好的替代選擇是 Tanh 函式。數學上來說,Tanh 只是調整、平移過的 Sigmoid 函式:tanh(x) = 2*sigmoid(x) - 1。雖然 Tanh 仍舊存在梯度消失的缺陷,但好訊息是:Tanh 以 0 為中心。因此,把 Tanh 作為激勵函式能更快地收斂(converge)。我發現使用 Tanh 通常比 Sigmoid 效果更好。
你還可以探索其他選擇,比如 ReLU, SoftSign 等等。對於一些特定任務, 它們能夠改善上述問題。
3. 隱藏單元和隱層(Hidden Units and Layers)的數量
保留超出最優數量的隱藏單元,一般是比較保險的做法。這是因為任何正則化方法( regularization method)都會處理好超出的單元,至少在某種程度上是這樣。在另一方面,保留比最優數量更少的隱藏單元,會導致更高的模型欠擬合(underfitting)機率。
另外,當採用無監督預訓練的表示時(unsupervised pre-trained representations,下文會做進一步解釋),隱藏單元的最優數目一般會變得更大。因此,預訓練的表示可能會包含許多不相關資訊(對於特定任務)。通過增加隱藏單元的數目,模型會得到所需的靈活性,以在預訓練表示中過濾出最合適的資訊。
選擇隱層的最優數目比較直接。正如 Yoshua Bengio 在 Quora 中提到的:
“你只需不停增加層,直到測試誤差不再減少。”
4. 權重初始化 (Weight Initialization)
永遠用小的隨機數字初始化權重,以打破不同單元間的對稱性(symmetry)。但權重應該是多小呢?推薦的上限是多少?用什麼概率分佈產生隨機數字?
當使用 Sigmoid 激勵函式時,如果權重初始化為很大的數字,那麼 sigmoid 會飽和(尾部區域),導致死神經元(dead neurons)。如果權重特別小,梯度也會很小。因此,最好是在中間區域選擇權重,比如說那些圍繞平均值均衡分佈的數值。
幸運的是,已經有許多關於初始權重合適取值的研究。這對於高效的收斂非常重要。為初始化均衡分佈的權重,均勻分佈(uniform distribution )或許是最好的選擇之一。另外,就像論文中所展示的(Glorot and Bengio, 2010),有更多輸入連線(fan_in)的單位,應該有相對更小的權重。
多虧這些十分透徹的試驗,現在我們已經有了經過檢驗的公式,可以直接用來權重的初始化。
比如說在 ~ Uniform(-r, r) 提取的權重,對於 tanh 激勵 r=sqrt(6/(fan_in+fan_out));對於 sigmoid 激勵 r=4*(sqrt(6/fan_in+fan_out)) 。fan_in 是上一層的大小, 而 fan_out 是下一層的。
5. 學習率
這或許是最重要的超引數之一,調節著學習過程。如果學習率設定得太小,你的模型很可能需要 n 年來收斂。設定得太大,再加上不多的初始訓練樣本,你的損失可能會極高。一般來說,0.01 的學習率比較保險
相比固定學習率,在每個週期、或每幾千個樣例後逐漸降低學習率是另一個選擇。雖然這能更快地訓練,但需要人工決定新的學習率。一般來說,學習率可以在每個週期後減半。幾年前,這種策略十分普遍。
幸運的是,我們現在有了更好的、基於動能(momentum based)的方法,來調整學習率。這取決於誤差函式的曲率。另外,既然有些引數有更快、或更慢的學習速率;它或許能幫助我們針對模型中的單獨引數,設定不同的學習率。
最近有大量關於優化方法的研究,導致了自適應學習率(adaptive learning rates)。目前我們有許多選擇,從老式動能方法( Momentum Method ),到 Adagrad、Adam (個人最愛)、 RMSProp 等等。;類似於 Adagrad 或 Adam 的方法,能替我們省去人工選擇初始學習率的麻煩;給定合適的時間,模型會開始平滑地收斂。當然,選擇一個特別合適的初始學習率仍然能起到幫助作用。
6. 超引數調參:扔掉網格搜尋,擁抱隨機搜尋
網格搜尋(Grid Search )在經典機器學習中十分普遍。但它在尋找 DNN 的最優超引數方面一點也不高效。這主要是由於 DNN 嘗試不同超引數組合所耗費的時間。隨著超引數不斷增長,網格搜尋需要的計算效能會指數級增長。
有兩種解決辦法:
-
取決於你之前的經驗,你可以人工對部分常見超引數調參,比如學習率、隱層數目。
-
採用隨機搜尋(random search),或者隨機取樣代替網格搜尋,來選擇最優超引數。
超引數組合通常在期望範圍之內、從均勻分佈中被選擇出來。加入之前獲得的知識來進一步縮小搜尋空間,也是有可能的(比如,學習率不應該太大也不應該太小)。大家發現,隨機搜尋比網格搜尋高效地多。
7. 學習方法
隨機梯度下降( Stochastic Gradient Descent )的老方法也許對於 DNN 不是那麼有效率(有例外)。最近,有許多研究聚焦於開發更靈活的優化演算法,比如 Adagrad、Adam,、AdaDelta,、RMSProp 等等。在提供自適應學習率之外,這些複雜的方法還對於模型的不同引數使用不同的學習率,通常能有更平滑的收斂。把這些當做超引數是件好事,你應該每次都在訓練資料的子集上試試它們。
8. 權重的維度保持為 2 的冪
即便是執行最先進的深度學習模型,使用最新、最強大的計算硬體,記憶體管理仍然在位元組(byte)級別上進行。所以,把引數保持在 64, 128, 512, 1024 等 2 的次方永遠是件好事。這也許能幫助分割矩陣和權重,導致學習效率的提升。當用 GPU 運算,這變得更明顯。
9. 無監督預訓練(Unsupervised Pretraining )
不管你進行的是 NLP(自然語言處理)、計算機視覺還是語音識別等任務,無監督預訓練永遠能幫助你訓練監督、或其他無監督模型:NLP 中詞向量就(Word Vectors)無所不在;你可以用 ImageNet 的資料庫,使用無監督方式對你的模型預訓練,或是對於兩個類別的監督分類;或是更大頻域的音訊樣本,來在揚聲器消崎模型(speaker disambiguation model)中使用該資訊。
10. Mini-Batch(小批量) 對比隨機學習(Stochastic Learning)
訓練一個模型的主要目的是學習合適的引數,即產生輸入到輸出的最優對映。這些引數利用每個訓練樣本進行調參,不管你決定使用 batch, mini-batch 還是隨機學習。當採用隨機學習方法時,學習每個訓練樣本後權重的梯度都會進行調參,向梯度加入噪音(隨機學習中“隨機”的由來)。這樣做的結果十分理想,比如說,訓練中加入的噪音使得模型更不容易過擬合。
但是,隨機學習方法也許效率不高。如今的計算裝置有非常可觀的運算能力,隨機學習很可能會浪費其中的一大部分。如果我們能計算矩陣相乘,那麼為什麼要限制自己,重複單個向量組之間的乘法呢?因此,為了更高的吞吐率和更快的學習,我推薦使用 mini-batch 而不是隨機學習。
但是,選擇適當的 batch 規模同樣重要。所以我們能保留一些噪音(相比大規模 batch),與此同時更高效地利用計算效能。一般來說,包含 16 個到 128 個樣例的 batch(2 的冪)是不錯的選擇。通常,一旦你發現了更重要的超引數(通過隨機搜尋或是人工搜尋),batch 規模就會確性下來。但是,有些場景中模型得到訓練資料流(比如網路學習),那麼採用隨機學習就是不錯的選擇。
11. 打亂訓練樣本
這來自於資訊理論(Information Theory)——“學習到一件不太可能發生的事卻發生了,比學習一件很可能發生的事已經發生,包含更多的資訊。”同樣的,把訓練樣例的順序隨機化(在不同週期,或者 mini-batch),會導致更快的收斂。如果模型看到的很多樣例不在同一種順序下,運算速度會有小幅提升。
12. 使用 Dropout 正則化
如果有數百萬的引數需要學習,正則化就是避免 DNN 過擬合的必須手段。你也可以繼續使用 L1/L2 正則化,但 Dropout 是檢查 DNN 過擬合的更好方式(雷鋒網按:Dropout 是指隨機讓網路某些隱層節點的權重不工作,不工作的那些節點可以暫時認為不是網路結構的一部分,但是它的權重會保留下來)。執行 Dropout 很容易,並且通常能帶來更快地學習。0.5 的預設值是一個不錯的選擇,當然,這取決於具體任務。如果模型不太複雜,0.2 的 Dropout 值或許就夠了。
在測試階段,Dropout 應該被關閉,權重要調整到相應大小。只要對一個模型進行 Dropout 正則化,多一點訓練時間,誤差一定會降低。
13. 週期 / 訓練迭代次數
“對深度學習模型進行多個週期的訓練,會得到更好的模型”——我們經常聽到這句話。但多少週期才是“多”呢?其實,這裡有一個簡單的策略:繼續按照一個固定的樣例數或者週期訓練模型,比如兩萬個樣例或者一個週期。在每批樣例之後,比較測試誤差(test error)和訓練誤差(train error),如果它們的差距在縮小,那麼繼續訓練。另外,記得在每批訓練之後,儲存模型的引數,所以訓練好之後你可以從多個模型中做選擇。
14. 視覺化
訓練深度學習模型有上千種出差錯的方式。我猜大家都遇到過這樣的場景:模型已經訓練了幾個小時或者好幾天,然而在訓練完成之後,才意識到某個地方出問題了。為了不讓你自己神經錯亂,一定要對訓練過程作視覺化處理。比較顯而易見的措施是儲存或列印損失值、訓練誤差、測試誤差等專案的日誌。
在此之外,一個很好的措施是採用視覺化庫(visualization library ),在幾個訓練樣例之後、或者週期之間,生成權重柱狀圖。這或許能幫助我們追蹤深度學習模型中的一些常見問題,比如梯度消失與梯度爆發(Exploding Gradient)。
15. 使用支援 GPU 和自動微分法 (Automatic Differentiation)的庫
謝天謝地,對於快速建立原型模型,我們已經有了相當不錯的庫,比如 Theano, Tensorflow, Keras 等等。幾乎所有這些深度學習庫支援 GPU 計算和自動微分法。所以,你不需要深入研究核心 GPU 程式設計技術(除非你想——這絕對很有意思)。你也不需要寫自己的微分程式碼——在非常複雜的模型上這相當費勁(但若需要,你應該有能力去做)。 Tensorflow還提供了分散式計算的支援——如果你是土豪的話.