2020年深度學習調參技巧合集

夕小瑶發表於2020-10-21

重點說明:本文主要為整理總結,大部分參考文末資料,感謝分享。

尋找合適的學習率

學習率是一個非常非常重要的超引數,這個引數呢,面對不同規模、不同batch-size、不同最佳化方式、不同資料集,其最合適的值都是不確定的,我們無法光憑經驗來準確地確定lr的值,我們唯一可以做的,就是在訓練中不斷尋找最合適當前狀態的學習率。比如下圖利用fastai中的lr_find()函式尋找合適的學習率,根據下方的學習率-損失曲線得到此時合適的學習率為1e-2

2020年深度學習調參技巧合集

推薦一篇fastai首席設計師「Sylvain Gugger」的一篇部落格:How Do You Find A Good Learning Rate[1]以及相關的論文Cyclical Learning Rates for Training Neural Networks[2]。

learning-rate與batch-size的關係

一般來說,越大的batch-size使用越大的學習率。原理很簡單,越大的batch-size意味著我們學習的時候,收斂方向的confidence越大,我們前進的方向更加堅定,而小的batch-size則顯得比較雜亂,毫無規律性,因為相比批次大的時候,批次小的情況下無法照顧到更多的情況,所以需要小的學習率來保證不至於出錯。可以看下圖損失Loss學習率Lr的關係:

2020年深度學習調參技巧合集

在視訊記憶體足夠的條件下,最好採用較大的batch-size進行訓練,找到合適的學習率後,可以加快收斂速度。

另外,較大的batch-size可以避免batch normalization出現的一些小問題,參考如下Pytorch庫Issue[3]。

權重初始化

權重初始化相比於其他的trick來說在平常使用並不是很頻繁。因為大部分人使用的模型都是預訓練模型,使用的權重都是在大型資料集上訓練好的模型,當然不需要自己去初始化權重了。只有沒有預訓練模型的領域會自己初始化權重,或者在模型中去初始化神經網路最後那幾個全連線層的權重。常用的權重初始化演算法是「kaiming_normal」或者「xavier_normal」。相關論文:

  • Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification[4]
  • Understanding the difficulty of training deep feedforward neural networks[5]
  • Xavier初始化論文[6]
  • He初始化論文[7]

不初始化可能會減慢收斂速度,影響收斂效果。以下為網路的輸入大小,為網路的輸出大小,為或

  • uniform均勻分佈初始化:
    • Xavier初始法,適用於普通啟用函式(tanh, sigmoid):

  • He初始化,適用於ReLU:

  • normal高斯分佈初始化, 其中stdev為高斯分佈的標準差,均值設為0:

  • Xavier初始法,適用於普通啟用函式 (tanh,sigmoid):

  • He初始化,適用於ReLU:

  • svd初始化:對RNN有比較好的效果。參考論文:

    https://arxiv.org/abs/1312.6120[8]

dropout

dropout是指在深度學習網路的訓練過程中,對於神經網路單元,按照一定的機率將其暫時從網路中丟棄。注意是「暫時」,對於隨機梯度下降來說,由於是隨機丟棄,故而每一個mini-batch都在訓練不同的網路。Dropout類似於bagging ensemble減少variance。也就是投透過投票來減少可變性。通常我們在全連線層部分使用dropout,在卷積層則不使用。但「dropout」並不適合所有的情況,不要無腦上DropoutDropout一般適合於全連線層部分,而卷積層由於其引數並不是很多,所以不需要dropout,加上的話對模型的泛化能力並沒有太大的影響。2020年深度學習調參技巧合集我們一般在網路的最開始和結束的時候使用全連線層,而hidden layers則是網路中的卷積層。所以一般情況,在全連線層部分,採用較大機率的dropout而在卷積層採用低機率或者不採用dropout。

資料集處理

主要有「資料篩選」 以及 「資料增強」

fastai中的影像增強技術為什麼相對比較好[9]


多模型融合

Ensemble是論文刷結果的終極核武器,深度學習中一般有以下幾種方式

  • 同樣的引數,不同的初始化方式
  • 不同的引數,透過cross-validation,選取最好的幾組
  • 同樣的引數,模型訓練的不同階段,即不同迭代次數的模型。
  • 不同的模型,進行線性融合. 例如RNN和傳統模型.

提高模型效能和魯棒性大法:probs融合 和 投票法。假設這裡有model 1, model 2, model 3,可以這樣融合:

1. model1 probs + model2 probs + model3 probs ==> final label

2. model1 label , model2 label , model3 label ==> voting ==> final label

3. model1_1 probs + ... + model1_n probs ==> mode1 label, model2 label與model3獲取的label方式與1相同  ==> voting ==> final label

第三個方式的啟發來源於,如果一個model的隨機種子沒有固定,多次預測得到的結果可能不同。以上方式的效果要根據label個數,資料集規模等特徵具體問題具體分析,表現可能不同,方式無非是probs融合和投票法的單獨使用or結合。

差分學習率與遷移學習

首先說下遷移學習,遷移學習是一種很常見的深度學習技巧,我們利用很多預訓練的經典模型直接去訓練我們自己的任務。雖然說領域不同,但是在學習權重的廣度方面,兩個任務之間還是有聯絡的。

2020年深度學習調參技巧合集

由上圖,我們拿來「model A」訓練好的模型權重去訓練我們自己的模型權重(「Model B」),其中,modelA可能是ImageNet的預訓練權重,而ModelB則是我們自己想要用來識別貓和狗的預訓練權重。那麼差分學習率和遷移學習有什麼關係呢?我們直接拿來其他任務的訓練權重,在進行optimize的時候,如何選擇適當的學習率是一個很重要的問題。一般地,我們設計的神經網路(如下圖)一般分為三個部分,輸入層,隱含層和輸出層,隨著層數的增加,神經網路學習到的特徵越抽象。因此,下圖中的卷積層和全連線層的學習率也應該設定的不一樣,一般來說,卷積層設定的學習率應該更低一些,而全連線層的學習率可以適當提高。

2020年深度學習調參技巧合集

這就是差分學習率的意思,在不同的層設定不同的學習率,可以提高神經網路的訓練效果,具體的介紹可以檢視下方的連線。

2020年深度學習調參技巧合集

上面的示例圖來自:
towardsdatascience.com/transfer-le…[10]

餘弦退火(cosine annealing)和熱重啟的隨機梯度下降

「餘弦」就是類似於餘弦函式的曲線,「退火」就是下降,「餘弦退火」就是學習率類似餘弦函式慢慢下降。「熱重啟」就是在學習的過程中,「學習率」慢慢下降然後突然再「回彈」(重啟)然後繼續慢慢下降。兩個結合起來就是下方的學習率變化圖:2020年深度學習調參技巧合集更多詳細的介紹可以檢視知乎機器學習演算法如何調參?這裡有一份神經網路學習速率設定指南[11]
以及相關論文SGDR: Stochastic Gradient Descent with Warm Restarts[12]

嘗試過擬合一個小資料集

這是一個經典的小trick了,但是很多人並不這樣做,可以嘗試一下。關閉正則化/隨機失活/資料擴充,使用訓練集的一小部分,讓神經網路訓練幾個週期。確保可以實現零損失,如果沒有,那麼很可能什麼地方出錯了。

多尺度訓練

多尺度訓練是一種「直接有效」的方法,透過輸入不同尺度的影像資料集,因為神經網路卷積池化的特殊性,這樣可以讓神經網路充分地學習不同解析度下影像的特徵,可以提高機器學習的效能。也可以用來處理過擬合效應,在影像資料集不是特別充足的情況下,可以先訓練小尺寸影像,然後增大尺寸並再次訓練相同模型,這樣的思想在Yolo-v2的論文中也提到過:

2020年深度學習調參技巧合集

需要注意的是:多尺度訓練並不是適合所有的深度學習應用,多尺度訓練可以算是特殊的資料增強方法,在影像大小這一塊做了調整。如果有可能最好利用視覺化程式碼將多尺度後的影像近距離觀察一下,「看看多尺度會對影像的整體資訊有沒有影響」,如果對影像資訊有影響的話,這樣直接訓練的話會誤導演算法導致得不到應有的結果。

Cross Validation 交叉驗證

在李航的統計學方法中說到,交叉驗證往往是對實際應用中「資料不充足」而採用的,基本目的就是重複使用資料。在平常中我們將所有的資料分為訓練集和驗證集就已經是簡單的交叉驗證了,可以稱為1折交叉驗證。「注意,交叉驗證和測試集沒關係,測試集是用來衡量我們的演算法標準的,不參與到交叉驗證中來。」交叉驗證只針對訓練集和驗證集。交叉驗證是Kaggle比賽中特別推崇的一種技巧,我們經常使用的是5-折(5-fold)交叉驗證,將訓練集分成5份,隨機挑一份做驗證集其餘為訓練集,迴圈5次,這種比較常見計算量也不是很大。還有一種叫做leave-one-out cross validation留一交叉驗證,這種交叉驗證就是n-折交叉,n表示資料集的容量,這種方法只適合資料量比較小的情況,計算量非常大的情況很少用到這種方法。吳恩達有一節課The nuts and bolts of building applications using deep learning[13]中也提到了。2020年深度學習調參技巧合集

最佳化演算法

按理說不同的最佳化演算法適合於不同的任務,不過我們大多數採用的最佳化演算法還是是adam和SGD+monmentum。Adam 可以解決一堆奇奇怪怪的問題(有時 loss 降不下去,換 Adam 瞬間就好了),也可以帶來一堆奇奇怪怪的問題(比如單詞詞頻差異很大,當前 batch 沒有的單詞的詞向量也被更新;再比如Adam和L2正則結合產生的複雜效果)。用的時候要膽大心細,萬一遇到問題找各種魔改 Adam(比如 MaskedAdam[14], AdamW 啥的)搶救。但看一些部落格說adam的相比SGD,收斂快,但泛化能力差,更優結果似乎需要精調SGD。

adam,adadelta等, 在小資料上,我這裡實驗的效果不如sgd, sgd收斂速度會慢一些,但是最終收斂後的結果,一般都比較好。如果使用sgd的話,可以選擇從1.0或者0.1的學習率開始,隔一段時間,在驗證集上檢查一下,如果cost沒有下降,就對學習率減半. 我看過很多論文都這麼搞,我自己實驗的結果也很好. 當然,也可以先用ada系列先跑,最後快收斂的時候,更換成sgd繼續訓練.同樣也會有提升.據說adadelta一般在分類問題上效果比較好,adam在生成問題上效果比較好。
adam收斂雖快但是得到的解往往沒有sgd+momentum得到的解更好,如果不考慮時間成本的話還是用sgd吧。

adam是不需要特別調lr,sgd要多花點時間調lr和initial weights。

資料預處理方式

zero-center ,這個挺常用的:


PCA whitening,這個用的比較少。

訓練技巧

  • 要做梯度歸一化,即算出來的梯度除以minibatch size

  • clip c(梯度裁剪): 限制最大梯度,其實是value = sqrt(w1^2+w2^2….),如果value超過了閾值,就算一個衰減繫系數,讓value的值等於閾值: 5,10,15

  • dropout對小資料防止過擬合有很好的效果,值一般設為0.5


    • 小資料上dropout+sgd在我的大部分實驗中,效果提升都非常明顯.因此可能的話,建議一定要嘗試一下。
  • dropout的位置比較有講究, 對於RNN,建議放到輸入->RNN與RNN->輸出的位置.關於RNN如何用dropout,可以參考這篇論文:http://arxiv.org/abs/1409.2329[15]

  • 除了gate之類的地方,需要把輸出限制成0-1之外,儘量不要用sigmoid,可以用tanh或者relu之類的啟用函式.


    • sigmoid函式在-4到4的區間裡,才有較大的梯度。之外的區間,梯度接近0,很容易造成梯度消失問題。
    • 輸入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[16]

    我這裡實驗設成1.0,可以提高收斂速度.實際使用中,不同的任務,可能需要嘗試不同的值.

  • Batch Normalization據說可以提升效果,參考論文:Accelerating Deep Network Training by Reducing Internal Covariate Shift

  • 如果你的模型包含全連線層(MLP),並且輸入和輸出大小一樣,可以考慮將MLP替換成Highway Network,我嘗試對結果有一點提升,建議作為最後提升模型的手段,原理很簡單,就是給輸出加了一個gate來控制資訊的流動,詳細介紹請參考論文:http://arxiv.org/abs/1505.00387[17]

  • 來自@張馨宇的技巧:一輪加正則,一輪不加正則,反覆進行。

  • 在資料集很大的情況下,一上來就跑全量資料。建議先用 1/100、1/10 的資料跑一跑,對模型效能和訓練時間有個底,外推一下全量資料到底需要跑多久。在沒有足夠的信心前不做大規模實驗。

  • subword 總是會很穩定地漲點,只管用就對了。

  • GPU 上報錯時儘量放在 CPU 上重跑,錯誤資訊更友好。例如 GPU 報 "ERROR:tensorflow:Model diverged with loss = NaN" 其實很有可能是輸入 ID 超出了 softmax 詞表的範圍。

  • 在確定初始學習率的時候,從一個很小的值(例如 1e-7)開始,然後每一步指數增大學習率(例如擴大1.05 倍)進行訓練。訓練幾百步應該能觀察到損失函式隨訓練步數呈對勾形,選擇損失下降最快那一段的學習率即可。

  • 補充一個rnn trick,仍然是不考慮時間成本的情況下,batch size=1是一個很不錯的regularizer, 起碼在某些task上,這也有可能是很多人無法復現alex graves實驗結果的原因之一,因為他總是把batch size設成1。

  • 注意實驗的可復現性和一致性,注意養成良好的實驗記錄習慣 ==> 不然如何分析出實驗結論。

  • 超參上,learning rate 最重要,推薦瞭解 cosine learning rate 和 cyclic learning rate,其次是 batchsize 和 weight decay。當你的模型還不錯的時候,可以試著做資料增廣和改損失函式錦上添花了。

相關文章