給卷積神經網絡“修理工”的一份“說明書”
大數據文摘出品
編譯:羅然、雪清、Aileen
這篇文章的主要內容來自作者的自身經驗和一些在線資源(如最出名的斯坦福大學的CS231n課程講義),是關于如何調試卷積神經網絡從而提升其性能的。
文章主要關注深度神經網絡架構下的有監督學習方式。雖然這個指南基于Python3.6壞境使用tensorflow(TF)編程,但它仍然可以作為一種語言無關的指南來使用。
假設我們有一個卷積神經網絡來訓練和評估,并假設評估結果比預期的更糟。
下文是排除故障并逐步提高性能的步驟,第一部分是進行故障排除之前的必備事項和良好實踐。每個后續的章節標題都對應著一個問題,該部分專門用于解決這個問題。
我們會先拋出“更為常見”的問題,在每個標題下,也會優先給出“最容易實現”的解決方案。
故障排除前…
以下是在編寫深度學習算法時要遵循的最佳實踐,關于這個主題的很好的資料來源于CS231n課程講義以及Bengio的綜述論文。
- Stanford's CS231n課程講義:http://cs231n.github.io/
- Bengio的綜述論文:https://arxiv.org/pdf/1206.5533v2.pdf
1. 使用適當的日志記錄和有意義的變量名稱。在TF中能夠通過名稱來跟蹤不同的變量,并在TF的可視化工具TensorBoard中顯示出計算圖。
最重要的是,每隔幾個訓練步驟都要確保記錄了相關的值,例如:step_number, accuracy, loss, learning_rate。適用的話,加上更具體的度量標準(例如在圖像分割任務中使用mean_intersection_over_union,即mean_iou)。之后,就可以根據訓練步驟畫出損失曲線。
譯者注:IoU,預測窗口與標記窗口之間的交并比。
2. 確保你的網絡連接正確。使用TensorBoard或其他調試技術確保計算圖中每個操作的輸入和輸出都準確無誤,還要確保在將數據和標簽送入網絡之前對其進行適當的預處理和匹配。
3. 實施數據擴充(data augmentation)技術。雖然這一點并不是對所有情況都適用,但是如果處理圖像的話,應用簡單的數據擴充技術(例如鏡像,旋轉,隨機裁剪和尺度變換,添加噪聲,elastically deforming等),大部分時候會帶來巨大的性能提升。而且TF具有大多數這些操作的內置函數,十分良心了。
4. 對所有層使用權重初始化和正則化。不要將權重初始化為相同的值,更糟的是將其初始化為0。這樣做會帶來對稱性(symmetry)和潛在的梯度彌散問題,在大多數情況下會導致可怕的結果。通常,如果在權重初始化時遇到問題,可以考慮將Batch Normalization層添加到網絡中。
BN論文鏈接:https://arxiv.org/abs/1502.03167。
5. 確保正則項不會“壓倒”損失函數中的其他項。關閉正則化,找出“損失”的數量級,然后適當地調整正則項大小。確保隨著正則化強度的增加,損失也在增加。
6. 嘗試過擬合一個小數據集。關閉正則化/隨機失活/數據擴充,使用訓練集的一小部分,讓神經網絡訓練幾個周期。確??梢詫崿F零損失,如果沒有,那么很可能什么地方出錯了。
在某些情況下,將損失降到0尤其具有挑戰性。例如,在圖像語義分割中,如果你的損失涉及每個像素的softmax-ed logits和ground truth labels之間的交叉熵,那么可能真的難以將其降低到0。不過,你應當尋求達到接近100%的準確率,通過獲取softmax-ed logits的argmax并將其與ground truth labels進行比較來計算。
譯者注:在機器學習中,“ground truth”一詞指的是監督學習技術中訓練集分類的準確性,簡單地說就是正確標注的數據。
7. 在過擬合上述小數據集的同時,找到合適的學習率。下面的內容直接引自Bengio的論文:最優學習率通常接近于不會增加訓練誤差的最大學習率,一種可以指導啟發式設置學習率的觀測方法是,例如,以較大的學習率開始,如果訓練誤差發散,就用最大學習率除以3再試試,直到觀察不到發散為止。
8. 執行梯度檢驗(gradient checks)。如果你在計算圖中使用自定義操作——即不是內置的TF操作,則梯度檢驗尤其重要。下面的鏈接有一些實現梯度檢驗的技巧。
Gradient checks:http://cs231n.github.io/neural-networks-3/
如果損失(Loss Value)沒有改善…
如果你訓練了幾個周期,損失還是沒有改善,甚至還越來越大,則應該考慮下面幾個步驟了:
1.確保使用了合理的損失函數,而且優化的是正確的張量。此處提供常見的損失函數列表。
https://en.wikipedia.org/wiki/Loss_functions_for_classification
2. 使用一個得當的優化器,此處提供了常用優化器列表。
https://keras.io/optimizers/
3. 確保變量真的在訓練。為了檢查這一點,你可以查看TensorBoard的直方圖,或者編寫一個腳本,在幾個不同的訓練實例中計算每個張量的范數(L1或 L∞),并打印出這些張量的名稱。
如果你的變量未按預期進行訓練,請參閱下列文章:
https://gist.github.com/zeyademam/0f60821a0d36ea44eef496633b4430fc#variable-not-training
4. 調整初始學習率并實施適當的學習率計劃(learning rate schedule),這可能是最具影響力的“修復”。如果損失越來越嚴重,可能是初始學習率太大了。另一方面,如果損失幾乎不變,可能是初始學習率太小了。無論如何,一旦確定了有效的初始學習率,就應該進行學習率衰減。像ADAM這樣的優化器會在內部實現學習率衰減,但是,這些學習率的更新通常會很慢,在優化器之上實現自己的學習率計劃會是個好主意。
5. 確保沒有過擬合。有一些方法可以實現過擬合,也有一些方法可以避免它。繪制損失值與訓練周期的曲線圖,如果曲線看起來像拋物線,那么很可能過擬合了。
請參閱這篇文章:
https://gist.github.com/zeyademam/0f60821a0d36ea44eef496633b4430fc#overfitting
如果變量沒在訓練…
像上面說的那樣,使用TensorBoard的直方圖,或編寫一個腳本,在幾個不同的訓練實例中計算每個張量的范數,并打印出這些張量的名稱。如果變量未按預期進行訓練:
1. 確保TF將其視為可訓練的變量。查看TF GraphKeys以獲取更多詳細信息。
https://www.tensorflow.org/api_docs/python/tf/GraphKeys
2. 確保沒發生梯度彌散。如果下游變量(接近輸出的變量)訓練正常但上游變量(接近輸入的變量)幾乎不變,則可能遇上了梯度彌散的問題。
請參閱下面的文章:
https://gist.github.com/zeyademam/0f60821a0d36ea44eef496633b4430fc#vanishingexploding-gradients
3. 確保ReLus還在“放電”。如果大部分神經元“電壓”被“鉗制”為零,那么應該重新修正權重初始化策略,嘗試使用不太激進的學習率計劃,并嘗試減少正則化(權重衰減)。
譯者注:ReLu,線性整流函數,又稱修正線性單元,是一種人工神經網絡中常用的激活函數。
梯度彌散/梯度爆炸…
1. 考慮使用更好的權重初始化策略。如果在訓練開始時梯度更新非常小,則這點尤其重要。
2. 考慮換一下激活函數。如果正在使用ReLus,請考慮使用leaky ReLu或MaxOut激活函數替換它們。你應該完全避免sigmoid激活函數,并遠離tanh。
3.如果用遞歸神經網絡的話,考慮使用LSTM。
詳情請看這篇文章:
https://medium.com/@karpathy/yes-you-should-understand-backprop-e2f06eab496b
過擬合…
過擬合就是網絡“記住”了訓練數據的情況。如果網絡在訓練集和驗證集上,準確率差別很大,可能它就過擬合了。
參見此處的Train / Val準確率部分:http://cs231n.github.io/neural-networks-3/
1. 實施數據擴充技術??缮戏帘疚牡谝还?ldquo;故障排除前”中的內容。
2. 實施隨機失活(dropout)。隨機失活指在訓練期間每個步驟隨機地忽略掉一些神經元,在前向傳播期間這些神經元的貢獻被移除并且在反向傳播期間它們不被更新。
了解更多信息:
https://machinelearningmastery.com/dropout-regularization-deep-learning-models-keras/
3. 增加正則化。
4. 實施批規范化操作(Batch normalization)。
詳情請看這里:https://arxiv.org/abs/1502.03167
5. 實施基于驗證集的早期停止(early stopping)。由于網絡訓練了太多個周期,因此可能會發生過擬合,早期停止有助于消除這個問題。
參考這里:
https://en.wikipedia.org/wiki/Early_stopping#Validation-based_early_stopping
6. 如果其他一切都失敗了,請使用較小的網絡。這真的應該是你的最后手段,事實上這里的課程講義對這種做法保持謹慎。
還能調試些什么…
1. 考慮使用加權的損失函數(weighted loss function)。例如,在圖像語義分割中,神經網絡對輸入圖像中的每個像素進行分類。與其他類相比,某些類可能很少出現,在這種情況下,權衡少見的類可能會改進mean_iou度量。
2. 更改網絡架構。你之前的網絡可能太深或太淺。
3. 考慮使用集成模型。
4. 用小數步長卷積(strided convolutions)替換最大值匯合層和平均值匯合層。
5. 執行徹底的超參數搜索。
6. 更改隨機數種子。
7. 如果上面的方法都失敗了,還是去尋找更多數據吧。
相關報道:https://gist.github.com/zeyademam/0f60821a0d36ea44eef496633b4430fc
【本文是51CTO專欄機構大數據文摘的原創譯文,微信公眾號“大數據文摘( id: BigDataDigest)”】

戳這里,看該作者更多好文