當前位置:
首頁 > 知識 > 構建深度神經網路,我有20條「不成熟」的小建議

構建深度神經網路,我有20條「不成熟」的小建議

選自PCC

作者:Matt H、Daniel R

機器之心編譯

參與:Geek ai、路

本文介紹了構建深度神經網路的一些基本技巧,從通用技巧、神經網路調試和案例研究三方面展開。

在我們的機器學習實驗室中,我們已經在許多高性能的機器上進行了成千上萬個小時的訓練,積累了豐富的經驗。在這個過程中,並不只有電腦學習到了很多的知識,事實上我們研究人員也犯了很多錯誤,並且修復了很多漏洞。

在本文中,我們將根據自身經驗(主要基於 TensorFlow)向大家提供一些訓練深度神經網路的實用秘訣。有些建議可能對你來說可能已經很熟悉了,但是其他人可能並不太了解。另外還有些建議可能並不適用,甚至可能對於特定的任務來說是不好的建議,所以請謹慎使用!

這些都是一些廣為人知的方法,我們也是站在了巨人的肩膀上!本文的目的只是高屋建瓴地對如何在實踐中使用它們進行總結。

通用秘訣

使用 ADAM 優化器。它確實很有效,相對於較傳統的優化器(如原版梯度下降),我們更喜歡使用 ADAM。在 TensorFlow 環境下使用 ADAM 時,請注意:如果你想要保存和恢復模型權重,請記住在設置完 AdamOptimizer 後設置 Saver,這是因為 ADAM 也有需要恢復的狀態(即對應於每個權重的學習率)。

ReLU 是最好的非線性(激活函數),這就好比 Sublime 是最好的文本編輯器。但說實話,ReLU 確實是運行速度最快、最簡便的,而且令人驚訝的是,它們在工作時梯度並不會逐漸減小(從而能夠防止梯度消失)。儘管 sigmoid 是一個常用激活函數,但是它在 DNN 中傳播梯度的效果並不太好。

不要在輸出層使用激活函數。這應該是顯而易見的,但是如果你通過一個共用的函數構建每一層,那這可能是一個很容易犯的錯誤:請確保在輸出層不要使用激活函數。

為每一層添加一個偏置項。這是機器學習的入門知識:本質上,偏置項將一個平面轉換到最佳擬合位置。在 y=mx+b 式中,b 是偏置項,使直線能夠向上或向下移動到最佳的擬合位置。

白化(歸一化)輸入數據。在訓練中,令樣本點的值減去數據集的均值,然後除以它的標準差。當網路的權重在各個方向上延伸和擴展的程度越小,你的網路就能更快、更容易地學習。保持數據輸入以均值為中心且方差不變有助於實現這一點。你還必須對每個測試輸入也執行相同的歸一化過程,所以請確保你的訓練集與真實數據類似。

以合理地保留動態範圍的方式對輸入數據進行縮放。這個步驟和歸一化有關,但是應該在歸一化操作之前進行。例如,在真實世界中範圍為 [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。

加大(小)批量處理的規模。使用一個更大的批處理規模——還覺得不夠的話,如果可以,你不妨使用整個訓練集——能減小梯度更新的方差,使每次迭代變得更加準確。換句話說,權重更新能夠朝著正確的方向發展。但是!它的有效性存在上限,而且還有一些物理內存的限制。我們發現,這條建議通常不如前兩個建議(將批處理規模減小到 1、刪除批歸一化層)有用。

檢查你矩陣的重構「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 函數控制高方差的輸入值。

我們希望這些基本的訣竅在你對構建深度神經網路更加熟悉的時候能夠提供幫助。通常,正是簡單的事情讓一切變得不同。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 機器之心 的精彩文章:

一個Python特徵選擇工具,助力實現高效機器學習
當前訓練神經網路最快的方式:AdamW優化演算法+超級收斂

TAG:機器之心 |