選自PCC,做者:Matt H、Daniel R,機器之心編譯。網絡
本文介紹了構建深度神經網絡的一些基本技巧,從通用技巧、神經網絡調試和案例研究三方面展開。
在咱們的機器學習實驗室中,咱們已經在許多高性能的機器上進行了成千上萬個小時的訓練,積累了豐富的經驗。在這個過程當中,並不僅有電腦學習到了不少的知識,事實上咱們研究人員也犯了不少錯誤,而且修復了不少漏洞。架構
在本文中,咱們將根據自身經驗(主要基於 TensorFlow)向你們提供一些訓練深度神經網絡的實用祕訣。有些建議可能對你來講可能已經很熟悉了,可是其餘人可能並不太瞭解。另外還有些建議可能並不適用,甚至可能對於特定的任務來講是很差的建議,因此請謹慎使用!機器學習
這些都是一些廣爲人知的方法,咱們也是站在了巨人的肩膀上!本文的目的只是高屋建瓴地對如何在實踐中使用它們進行總結。編輯器
通用祕訣函數
使用 ADAM 優化器。它確實頗有效,相對於較傳統的優化器(如原版梯度降低),咱們更喜歡使用 ADAM。在 TensorFlow 環境下使用 ADAM 時,請注意:若是你想要保存和恢復模型權重,請記住在設置完 AdamOptimizer 後設置 Saver,這是由於 ADAM 也有須要恢復的狀態(即對應於每一個權重的學習率)。工具
ReLU 是最好的非線性(激活函數),這就比如 Sublime 是最好的文本編輯器。但說實話,ReLU 確實是運行速度最快、最簡便的,並且使人驚訝的是,它們在工做時梯度並不會逐漸減少(從而可以防止梯度消失)。儘管 sigmoid 是一個經常使用激活函數,可是它在 DNN 中傳播梯度的效果並不太好。oop
不要在輸出層使用激活函數。這應該是顯而易見的,可是若是你經過一個共用的函數構建每一層,那這多是一個很容易犯的錯誤:請確保在輸出層不要使用激活函數。性能
爲每一層添加一個偏置項。這是機器學習的入門知識:本質上,偏置項將一個平面轉換到最佳擬合位置。在 y=mx+b 式中,b 是偏置項,使直線可以向上或向下移動到最佳的擬合位置。學習
使用方差縮放初始化。在 TensorFlow 中,該方法寫做 tf.contrib.layers.variance_scaling_initializer()。根據咱們的實驗,這種初始化方法比常規高斯分佈初始化、截斷高斯分佈初始化及 Xavier 初始化的泛化/縮放性能更好。粗略地說,方差縮放初始化根據每一層輸入或輸出的數量(在 TensorFlow 中默認爲輸入的數量)來調整初始隨機權重的方差,從而幫助信號在不須要其餘技巧(如梯度裁剪或批歸一化)的狀況下在網絡中更深刻地傳播。Xavier 和方差縮放初始化相似,只不過 Xavier 中每一層的方差幾乎是相同的;可是若是網絡的各層之間規模差異很大(常見於卷積神經網絡),則這些網絡可能並不能很好地處理每一層中相同的方差。測試
白化(歸一化)輸入數據。在訓練中,令樣本點的值減去數據集的均值,而後除以它的標準差。當網絡的權重在各個方向上延伸和擴展的程度越小,你的網絡就能更快、更容易地學習。保持數據輸入以均值爲中心且方差不變有助於實現這一點。你還必須對每一個測試輸入也執行相同的歸一化過程,因此請確保你的訓練集與真實數據相似。
以合理地保留動態範圍的方式對輸入數據進行縮放。這個步驟和歸一化有關,可是應該在歸一化操做以前進行。例如,在真實世界中範圍爲 [0, 140000000] 的數據 x 一般能夠用「tanh(x)」或「tanh(x/C)」來進行操做,其中 C 是某個常數,它能夠對曲線進行拉伸,從而在 tanh 函數的動態傾斜(斜率較大)部分對更大輸入範圍內的數據進行擬合。尤爲是在輸入數據在函數的一端或者兩端都不受限的時候,神經網絡將在數據處於 (0,1) 時學習效果更好。
通常不要使用學習率衰減。在隨機梯度降低(SGD)中,下降學習率是很常見的,可是 ADAM 自然地就考慮到了這個問題。若是你真的但願達到模型性能的極致,請在訓練結束前的一小段時間內下降學習率;你可能會看到一個忽然出現的很小的偏差降低,以後它會再次趨於平緩。
若是你的卷積層有 64 或 128 個濾波器,這就已經足夠了。特別是對於深度網絡來講,好比 128 個濾波器就已經不少了。若是你已經擁有了大量的濾波器,那麼再添加更多的濾波器可能並不會提高性能。
池化是爲了變換不變性(transform invariance)。池化本質上是讓網絡學習到圖像「某個部分」的「通常概念」。例如,最大池化可以幫助卷積網絡對圖像中特徵的平移、旋轉和縮放具有必定的魯棒性。
神經網絡的調試
若是網絡學習效果不好(指網絡在訓練中的損失/準確率不收斂,或者你得不到想要的結果),你能夠試試下面的這些祕訣:
過擬合!若是你的網絡學習效果不佳,你首先應該作的就是去過擬合一個訓練數據點。準確率基本上應該達到 100% 或 99.99%,或者說偏差接近 0。若是你的神經網絡不能對一個數據點達到過擬合,那麼模型架構就可能存在很嚴重的問題,但這種問題多是十分細微的。若是你能夠過擬合一個數據點,可是在更大的集合上訓練時仍然不能收斂,請嘗試下面的幾條建議。
下降學習率。你的網絡會學習地更慢,可是它可能會找到一個以前使用較大的步長時沒找到的最小值。(直觀地說,你能夠想象一下你正在走過路邊的溝渠,此時你想要走進溝的最深處,在那裏模型的偏差是最小的。)
提升學習率。這將加快訓練速度,有助於增強反饋迴路(feedback loop)。這意味着你很快就能大概知道你的網絡是否有效。儘管這樣一來網絡應該能更快地收斂,可是訓練結果可能不會太好,並且這種「收斂」狀態可能其實是反覆震盪的。(使用 ADAM 優化器時,咱們認爲在許多實驗場景下,~0.001 是比較好的學習率。)
減少(小)批量處理的規模。將批處理大小減少到 1 能夠向你提供與權重更新相關的更細粒度的反饋,你應該將該過程在 TensorBoard(或者其餘的調試/可視化工具)中展現出來。
刪掉批歸一化層。在將批處理大小減少爲 1 時,這樣作會暴露是否有梯度消失和梯度爆炸等問題。咱們曾經遇到過一個好幾個星期都沒有收斂的網絡,當咱們刪除了批歸一化層(BN 層)以後,咱們才意識到第二次迭代的輸出都是 NaN。在這裏使用批量歸一化層,至關於在須要止血帶的傷口上貼上了創可貼。批歸一化有它可以發揮效果的地方,但前提是你肯定本身的網絡沒有 bug。
加大(小)批量處理的規模。使用一個更大的批處理規模——還以爲不夠的話,若是能夠,你不妨使用整個訓練集——能減少梯度更新的方差,使每次迭代變得更加準確。換句話說,權重更新可以朝着正確的方向發展。可是!它的有效性存在上限,並且還有一些物理內存的限制。咱們發現,這條建議一般不如前兩個建議(將批處理規模減少到 一、刪除批歸一化層)有用。
檢查你矩陣的重構「reshape」。大幅度的矩陣重構(好比改變圖像的 X、Y 維度)會破壞空間局部性,使網絡更不容易學習,由於這時網絡也必須學習重構。(天然特徵變得支離破碎。事實上天然特徵呈現出空間局部性也是卷積神經網絡可以如此有效的緣由!)使用多個圖像/通道進行重構時要特別當心;可使用 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 函數控制高方差的輸入值。
咱們但願這些基本的訣竅在你對構建深度神經網絡更加熟悉的時候可以提供幫助。一般,正是簡單的事情讓一切變得不一樣。