機器都會學習了,你的神經網絡還跑不動?來看看這些建議
大數據文摘出品
編譯:什錦甜、倪倪、胡笳、云舟
在很多機器學習的實驗室中,機器已經進行了上萬小時的訓練。在這個過程中,研究者們往往會走很多彎路,也會修復很多bug,但可以肯定的是,在機器學習的研究過程中,學到經驗和知識的并不僅僅是機器,我們人類也積累的豐富的經驗,本文就將給你幾條最實用的研究建議。
接下來本文將介紹一些訓練深度神經網絡時的經驗(主要基于TensorFlow平臺)。有些建議可能對你來說很顯而易見,但對其他人來說可能很重要。有些建議可能對某些特定任務并不適用,請謹慎使用!
一般性建議
使用 ADAM優化器。和批量梯度下降等傳統優化器相比,Adam優化器效果更好。
TensorFlow使用建議:保存和恢復權重時,記得在創建Adam優化器后創建Saver,因為Adam也有state(也叫學習速率的單位權重)需要恢復。
Relu是最好的非線性映射(激活函數)。就像 Sublime是最好的文本編輯器, ReLU快速、簡單,神奇的地方在于它在訓練過程中不會逐漸減少梯度。雖然教科書中常用sigmoid作為激活函數,但是它在DNN中不能很好地傳遞梯度。
不要在輸出層用激活函數。這一點應該很明顯,但是如果你在構建網絡的每一層都使用了一個共享的函數,那這個錯誤就很常見了。請確保你在輸出層沒有使用激活函數。
在每一層中增加一個偏差值。這是機器學習入門知識:偏差本質上的作用是把一個平面轉化到最佳擬合位置。在y=mx+b函數中, b就是一個偏差值,可以把直線移動到最佳擬合的位置。
使用方差縮放初始化(variance-scaled initialization)。在Tensorflow中,使用類似于tf.contrib.layers.variance_scaling_initializer()這樣的方法初始化。
根據我們的經驗,這個方法比常規的高斯分布初始化,截斷正態分布初始化和Xavier初始化方法效果更好。
總體上講,方差縮放初始化可以根據每一層輸入和輸出的數量(TensorFlow中默認使用輸入的數量),來調整初始隨機權重的方差,從而幫助信號在不需要通過截斷或者批量規范化等額外的方法來在網絡中傳遞得更深。
Xavier初始化方法和它類似,只是Xavier初始化在所有層中基本一樣,如果網絡的層與層之間的取值范圍差異很大(常見于卷積網絡),每一層使用同一個方差可能就不適用了。
輸入數據歸一化。在訓練時,減去數據集的均值,然后除以標準差。這樣可以減少權重在每個方向上的拉伸,幫助神經網絡更快更好地學習。保持輸入的數據以方差為均值中心可以很好的實現這點。你也要保證每次測試輸入采取一致的歸一化方法,從而保證你的訓練集能夠模擬真實數據環境。
合理地縮放數據。這與歸一化處理相關,但應該在歸一化之前進行。比如,數據x在現實生活中的范圍是[0, 140000000],可能服從tanh(x)或者 tanh(x/C)分布,其中 C為常量,用于調整曲線幫助輸入數據更好的符合tanh函數的坡度部分。尤其當你輸入數據地在一端或者兩端無界的情況下,神經網絡在 (0,1)范圍里可以學習的更好。
通常情況下,不要費力去降低學習速率。SGD中學習速率衰減更常見,但是 ADAM可以更自然地處理它。如果你一定要計較細微的性能差別:在訓練結束時短暫地降低學習速率,你可能會看到一個誤差突然降低一點,然后再次趨于平穩。
如果你的卷積層有64或128個濾波器,這可能就有些多余了,尤其對于深度網絡來說,128個濾波器真的有些多了。如果你已經有了大量的濾波器,再添加可能毫無意義。
池化(pooling)是為了最大程度保持變換的不變性。pooling本質上是使神經網絡學習圖像中一部分的整體特征。比如,max pooling可以使圖像在卷積網絡中經過位移、旋轉和縮放等變換之后,仍然保持特征的不變性。
調試神經網絡
如果你的神經網絡不能夠學習,也就是說訓練時損失或者精確度不收斂,或者不能得到預期的結果。嘗試以下的建議:
- 過擬合!如果你的網絡不收斂,第一件要做的事是去過擬合一個訓練點,精度應該達到 100%或99.99%,或者誤差接近0。如果你的神經網絡不能過擬合單個數據點,那么你的架構存在嚴重但可能很細微的問題。如果你可以過擬合一個數據點但訓練更大的數據集時不能收斂,那么可以嘗試如下建議。
- 降低學習速率。你的網絡會學習的慢一些,但是它可以下降到最小值,之前無法達到是因為步長設置的太大。(想象一下尋找最小值就相當于你想抵達溝渠最低點,而步長太大導致你直接跨過了溝渠。)
- 提高學習率。較大的學習率有助于縮短訓練時間,減少反饋環路,這就意味著可以較快地預判網絡模型是不是可行。不過雖然網絡模型能夠更快的收斂,但是結果可能不會特別理想,甚至會有較大的振蕩。(我們發現對于ADAM優化器,0.001的學習率在許多實驗中收效不錯。)
- 減小批處理的樣本數。使用樣本數為1的批處理能夠獲取更細粒度的權重以更新反饋,你可以使用TensorBoard查看(或者其他調試/可視化的工具。)
- 去掉批處理規范化。在批處理樣本數減少到1的同時,去掉批處理規范化,可以暴露梯度消失或者梯度爆炸的問題。我們曾有一個神經網絡模型在幾個星期后仍舊不能收斂。直到去掉了批處理規范化,我們才意識到在第二輪迭代后所有的輸出都是NaN。批處理規范化的作用如同止血時的創口貼,但是只有在你的網絡模型沒有錯誤的情況下才管用。
- 增加批處理的樣本數。較大樣本的批處理,比如使用整個數據集,減少了梯度更新的方差,可以使得每輪迭代的結果更精確。換句話說,權重迭代將朝著正確的方向進行。但是,這個方法受到物理內存大小限制。通常,前面兩個使用樣本數為1 的批處理和除去批處理規范化的技巧比這個技巧要更有用。
- 檢查矩陣變形。較大的矩陣變形(例如改變圖像的橫縱軸)會破壞空間的局部性特征,給模型的學習增添了難度,因為矩陣變形也是需要學習的一部分。(自然的特征變得四分五裂。事實上自然特征的空間局部特征也是卷積神經網絡之所以有效的原因。)要特別注意多圖形/通道的矩陣變形;用numpy.stack()進行適當的調整。
- 檢查損失函數。如果使用的是復雜的損失函數,就先試一下簡單的例如L1或者L2損失函數。我們發現L1對于異常值沒那么敏感,因此受噪音數據影響較小。
- 檢查可視化。檢查你的可視化工具包(matplotlib,OpenCV,等)是否調整了數值的數量級,或者有值域限制?也可以考慮使用統一的配色方案。
案例解析
為了使上述的步驟更容易理解,這里我們展示幾張(通過TensorBoard)卷積神經網絡做的回歸實驗的損失圖。
首先,這個神經網絡根本沒有收斂:
我們嘗試剪裁數值值域,以防止他們超出范圍:
哎呀,看這個沒有光滑處理過的線是多么的雜亂。是學習率太大了嗎?我們試著衰減了學習率并只用一個樣本點進行訓練:
你可以看到學習率發生了變化(大概在300到3000步間)。顯然,學習率降的太快了。所以,我們放緩了迭代速率,效果就好些了:
你可以看我們在2000到5000步間進行了衰減。結果好些了,但是還不夠,因為損失還沒有降到0。
然后我們停止了學習率的衰減并且嘗試了將數值壓縮到更小的值域并取代了tanh函數。雖然這樣損失降到了1,我們仍然不能達到過擬合。
我們就是在這一步發現,去掉批處理規范化后,網絡輸出很快在一到兩次迭代后變成NaN。于是,我們停止了批處理規范化并且把初始化改為方差標準化。這樣一下就解決了問題,用一兩個輸入樣本訓練就能達到過擬合。雖然圖下方的Y軸的值被剪切了,但是初始的誤差在5以上,表明誤差幾乎下降了4個數量級。
上圖的上半部分是經過光滑處理的,但是你仍可看到對測試數據很快達到了過擬合,整個訓練集的損失也降到了0.01以下。而這時我們還沒有衰減學習率。我們將學習率降低了一個數量級后繼續訓練神經網絡,得到了更加好的結果:
這些結果好太多了!但是如果我們將學習率成幾何級衰減而不是將訓練分成兩部分會怎么樣呢?
如果將學習率在每一步迭代都乘以0.9995,這個結果就不那么妙了:
原因估計是因為學習率衰減的太快。用0.999995會稍微好一些,但是結果幾乎跟沒有衰減一樣。我們從這一系列的實驗中總結出,批處理規范化掩蓋了由初始化不當導致的梯度爆炸,而除了最后階段學習率的衰減,衰減的學習率對于ADAM優化器也不是很有用。伴隨著批處理正規化,剪裁值域只是掩蓋了真實的問題。我們還通過使用tanh激活函數對我們高方差的輸入數據進行了轉化。
我希望這些基本的技巧可以對你學習深度神經網絡有所幫助。事情往往就是這樣,簡單的細節可以產生重大的影響。
相關報道:
https://pcc.cs.byu.edu/2017/10/02/practical-advice-for-building-deep-neural-networks/
【本文是51CTO專欄機構大數據文摘的原創譯文,微信公眾號“大數據文摘( id: BigDataDigest)”】