神經網路不收斂的 11 個原因

牧言慕語 發表於 2021-05-04
神經網路

原文:http://theorangeduck.com/page/neural-network-not-working

原文標題:My Neural Network isn't working! What should I do?

譯文作者:kbsc13

聯絡方式:

Github:https://github.com/ccc013

知乎專欄:機器學習與計算機視覺AI 論文筆記

微信公眾號:AI 演算法筆記

在這裡插入圖片描述


前言

如果你的神經網路不收斂,應該怎麼辦呢?一般來說,神經網路不收斂的原因有以下 11 種原因:

  1. 忘記對你的資料進行歸一化
  2. 忘記檢查輸出結果
  3. 沒有對資料進行預處理
  4. 沒有使用任何的正則化方法
  5. 使用了一個太大的 batch size
  6. 使用一個錯誤的學習率
  7. 在最後一層使用錯誤的啟用函式
  8. 網路包含壞的梯度
  9. 網路權重沒有正確的初始化
  10. 使用了一個太深的神經網路
  11. 隱藏層神經元數量設定不正確

接下來將一一解釋以上11 種原因並給出對應的解決辦法;


1. 忘記對你的資料進行歸一化

問題描述

在神經網路訓練中,如何對你的資料進行歸一化是非常重要的。這是一個不能省略的步驟,幾乎不可能在不進行歸一化的前提下可以訓練得到一個很好的網路模型。不過正因為這個步驟非常重要,而且在深度學習社群也很有名,所以很少人會提到它,但是對於初學者則是可能會犯下的一個錯誤。

原因

我們需要對資料進行歸一化操作的原因,主要是我們一般假設輸入和輸出資料都是服從均值為 0,標準差為 1 的正態分佈。這種假設在深度學習理論中非常常見,從權重初始化,到啟用函式,再到對訓練網路的優化演算法。

解決辦法

常用的歸一化方法主要是零均值歸一化,它會將原始資料對映到均值為 0,標準差為 1 的分佈上。假設原始特徵的均值是$\mu$、方差是$\sigma$,則公式如下:
$$
z = \frac{x-\mu}{\sigma}
$$
另一種常用的歸一化方法是線性函式歸一化(Min-Max Scaling)。它對原始資料進行線性變換,使得結果對映到[0,1]的範圍,實現對原始資料的等比縮放,公式如下:
$$
X_{norm}=\frac{X-X_{min}}{X_{max}-X_{min}}
$$

其中 X 是原始資料,$X_{max}, X_{min}$分別表示資料最大值和最小值。

未經訓練的神經網路通常輸出的值大致在-1到1之間。如果希望它輸出一些其他範圍的值(例如RGB影像,儲存為位元組的範圍是0到255),那將會有一些問題。當開始訓練時,網路將非常不穩定,因為當預期值為255時,它將產生-1或1,這個錯誤被用於訓練神經網路的大多數優化演算法認為是巨大的。這將產生巨大的梯度,你的訓練誤差可能會爆發。如果你的訓練沒有爆炸,那麼訓練的前幾個階段仍然是浪費,因為網路將學習的第一件事是縮放和轉移輸出值到大致期望的範圍。如果你規範化你的資料(在這種情況下你可以簡單地除以128減去1),那麼這些都不是問題。

一般來說,神經網路中特徵的規模也會決定它們的重要性。如果你在輸出中有一個大尺度的特徵,那麼與其他特徵相比,它會產生更大的錯誤。同樣,輸入中的大尺度特徵會主導網路,導致下游更大的變化。由於這個原因,使用許多神經網路庫的自動歸一化並不總是足夠的,這些庫盲目地減去平均值,然後除以每個特徵的標準差。你可能有一個輸入特徵一般範圍在0.0和0.001之間,這個特性的範圍如此之小,因為它是一個重要的特性(在這種情況下,也許你不想對它再縮放),或因為它有一些小型單位相比其他特性?

同樣地,要小心那些有如此小範圍的特性,它們的標準偏差接近或精確地接近於零——如果規範化它們,這些特性將產生nan的不穩定性。仔細考慮這些問題是很重要的——考慮你的每個特性真正代表了什麼,並將標準化視為製作“單元”的過程。所有輸入特徵都相等。這是我認為在深度學習中真正需要人類參與的少數幾個方面之一。

2. 忘記檢查輸出結果

問題描述

當你開始訓練你的網路幾個 epoch 後,發現誤差在減小了。這表示成功訓練網路了嗎?很不幸這並不是,這說明你的程式碼中很可能還有一些問題,可能是在資料預處理、訓練程式碼或者推理部分有問題。僅僅因為誤差在減小並不意味著你的網路正在學習有用的資訊。

原因

與傳統程式設計不同,機器學習系統幾乎在所有情況下都會悄無聲息地失敗。在傳統的程式設計中,我們習慣於電腦在出現問題時丟擲一個錯誤,並以此作為返回和檢查錯誤的訊號。

不幸的是在機器學習中並不是這樣的機制,所以我們應該非常小心檢查的通過人眼來觀察每個階段的處理過程,這樣當一個錯誤已經產生的時候,我們可以及時發現並且可以更徹底的檢查程式碼。

解決辦法

在管道的每個階段檢查資料是否正確是非常重要的。通常這意味著找到一些方法使結果形象化。如果你有影像資料,那麼很容易,動畫資料也可以視覺化,沒有太多的麻煩。

如果你有一些更奇特的東西,必須找到一種方法來檢查它,以確保它在預處理、訓練和推理管道的每個階段看起來都是正確的,並將其與地面真實資料進行比較。

有許多方法可以檢查你的網路是否正常工作。其中一部分是找出報告的訓練錯誤的真正含義。視覺化應用於訓練集資料的輸出結果,可以觀察到網路的輸出結果和真實標籤的對比

在訓練的時候,可能會看到誤差從 1.0 到 0.01,但如果 0.01仍然是一個不可接受的結果,那麼輸出結果仍可能無法使用。如果它在訓練集上是有用的,那請在驗證集上檢查它,看看它仍然適用於以前從未見過的資料嗎?

我的建議是,從一開始就習慣於視覺化一切,不要只在網路不收斂的時候才開始,並且確保在開始嘗試不同的神經網路結構之前,已經準備了通完終端使用者的完整管道,並一路進行完整的檢查。這是準確評估許多潛在不同方法的唯一方法。

3. 沒有對資料進行預處理

問題描述

大部分的資料都是棘手的——通常我們知道的相似的東西,其資料可以有非常不同的數字表示。舉個例子,以角色動畫為例,如果我們使用角色關節相對於運動捕捉工作室中心的 3D 位置表示我們的資料,然後在一個位置或朝向一個方向執行運動,則可能具有與在不同位置執行相同運動或朝向不同方向執行相同運動截然不同的數字表示。相反,我們需要做的是以不同的方式表示資料 - 例如,在某些本地參考幀中(例如相對於字元的質量中心),以便我們知道兩個動作相似,獲得類似的數字表示。

原因

神經網路只對它們作為輸入的資料做出幾個基本假設,但這些基本假設之一是資料所處的空間有些連續性,對於大多數空間來說,兩個資料點之間的點至少在某種程度上是這兩個資料點的"混合",而附近的兩個資料點在某種程度上代表著"類似"的東西。資料空間中出現大的不連續性,或者代表同一事物的大組分離資料,將使學習任務更加困難。

解決辦法

想想使用的特徵所表示的意思,是否可以對它們進行一些簡單的轉換,以確保代表我們知道的相似內容的資料點始終獲得相似的數字表示?是否有一個本地座標系統來表示資料使得事情更自然,比如可能是一個更好的顏色空間,或者其他不同的格式?

另一種考慮資料預處理的方法是嘗試減少可能需要的資料變化導致的組合爆炸。例如,如果一個受過角色動畫資料訓練的神經網路必須學習每個位置和方向中針對角色的相同動作集,那麼網路的大部分容量就會被浪費,許多學習過程就會重複。

4. 沒有使用任何的正則化方法

問題描述

正則化是現在訓練神經網路一個非常重要的方法,通常是以 dropout、噪音或者其他某種隨機過程的形式來加入到網路中。

即便資料維度比引數更多,或者是在某種情況下不需要在意過擬合或者不可能出現過擬合,加入 dropout 或者某些形式的噪音仍然是很有幫助的。

原因

正則化方法不僅僅是用於控制過擬合,通過在訓練過程中引入一些隨機過程,在某種程度上是"平滑"了成本格局。這可以加快訓練收斂的速度,幫助處理資料中的噪聲或異常值,並防止網路的極端權值配置。

解決辦法

最常用的正則化方法就是在卷積層或者全連線層之前採用 dropout 。一般會採用一個較高的概率,比如 0.75 或者 0.9,然後基於網路可能過擬合的概率來調整這個概率值,比如覺得不太可能出現過擬合,那麼就把保留神經元的概率設定得非常高,比如 0.99。

資料增強或其他型別的噪音也可以像dropout一樣實現正則化,有時候使用了足夠的資料增強就可以不用 dropout。通常 dropout 被認為是將許多隨機子網路的預測相結合的技術,但也可以將它視為一種資料增強的形式,在訓練期間產生許多相似的輸入資料變化。正如我們所知,避免過度擬合的最好方法是擁有足夠多的資料,使得神經網路永遠不會看到同樣的資料兩次!

最後,像訓練神經網路其他方面一樣,你需要小心你使用的正規化。請記住,在預測期間將其關閉,並注意,一旦它被關閉,您通常會得到略有不同的結果。在你需要極其精確的數字預測的情況下,某些形式的正則化有時會使這一切變得困難。

5.使用了一個太大的 batch size

問題描述

使用一個太大的 batch size 會因為降低了梯度下降的隨機性,導致降低了網路的準確率。

原因

使用較小的batch大小會產生波動更大,更隨機的權值更新。這有兩個好處:

  1. 首先,在訓練的時候它可以有助於"跳"出以前可能會陷入的區域性最小值;
  2. 其次,它可以讓訓練進入到極小值中,這表示其有更好的泛化效能。

解決辦法

在訓練的時候,找到一個可以容忍的最小的 batch 大小。可以讓 GPU 並行使用最優的 batch 大小並不一定可以得到最好的準確率,因為更大的 batch 可能需要訓練更多時間才能達到相同的準確率。所以大膽的從一個很小的 batch 大小開始訓練,比如 16,8,甚至是 1。

資料中的某些其他元素有時可以有效地像 batch 大小一樣工作。例如,以兩倍的解析度處理影像,其效果與使用 4 倍的 batch 大小相似。

簡單的說明這個原因,考慮在 CNN 中,每個濾波器的權值更新將平均顯示在輸入影像中應用的所有畫素以及 batch 中的每一個影像上。將影像解析度提高 2 倍,平均效果將提高 4 倍以上,其效果與將batch大小增加 4 倍的方式非常相似。

總體而言,重要的是考慮每次迭代中最終梯度更新的平均值,並確保您平衡其不利影響與儘可能多地使用 GPU 潛在並行性的必要性。

6. 使用一個錯誤的學習率

問題描述

學習率對訓練網路的容易程度有很大的影響,如果你是新手,幾乎可以肯定你的設定是錯誤的,這是因為在常見的深度學習框架中使用的各種預設選項。

原因

許多深度學習框架在預設情況下啟用梯度裁剪。這個操作是通過在訓練中的每一步中改變一個最大數量的權值來防止出現梯度爆炸的情況。

這可能很有用——特別是當你的資料包含許多異常值,這會產生很大的誤差,從而產生很大的梯度和權重更新,但預設設定也會使手工找到最佳學習率變得非常困難。我發現大多數剛接觸深度學習的人都將學習速率設定得過高,並通過梯度裁剪來解釋這一點,使整體訓練速度變慢,並且改變學習率的效果不可預測。

解決辦法

不採用梯度裁剪。找出在訓練過程中不會導致誤差爆炸的最大學習率。將學習率設定為比這個低一個數量級,這可能是非常接近最佳學習率。

如果你已經正確地清理了你的資料,刪除了大部分的異常值,並正確地設定了學習速率,那麼你真的不應該需要梯度剪裁。如果沒有它,你會發現你的訓練誤差偶爾變得非常大,那麼請使用梯度裁剪,但是請記住,看到你的訓練錯誤爆發幾乎總是表明你的一些資料有其他錯誤,梯度裁剪只是一個臨時措施。

7. 在最後一層使用錯誤的啟用函式

問題描述

在最後一層使用啟用函式有時候會導致網路不能生成要求數值的完整範圍,比如最常見的錯誤就是在最後一層採用 ReLU ,它會導致網路只能輸出正數。

原因

想想你的資料值實際代表什麼,以及標準化後其範圍是什麼。最有可能的情況是,你的輸出值是無限的正數或負數,在這種情況下,不應該在最後一層使用啟用功能。如果輸出值可能只在某個範圍內有意義,例如它由範圍 0-1 中的概率組成,則很可能在最後一層(如 sigmoid 啟用功能)上應使用特定的啟用功能。

解決辦法

如果是在做迴歸任務,大部分情況下是不需要在最後一層使用任何啟用函式,除非是你知道希望輸出的數值的一些資訊。

在最後一層上使用啟用函式有許多微妙之處。在神經網路產生輸出後,系統最終將把輸出裁剪到 [-1,1] 範圍內。那麼新增這個裁剪過程作為最終層的啟用似乎是有意義的,因為這將確保你的網路誤差函式不會懲罰大於1或小於-1的值。

但是,沒有誤差意味著這些大於或小於 1 的數值也不會有梯度,在某些情況下,這會使得網路無法訓練。或者,可能很想在最後一層使用 Tanh,因為知道此啟用函式輸出的值在 -1 到 1 範圍內,但這也會導致問題,因為該函式接近 1 或 -1 的梯度變得非常小,這可能導致權值增長巨大,試圖產生 -1 或 1。

一般來說,你最好的選擇是謹慎行事,在最後一層不使用任何啟用功能,而不是嘗試一些可能適得其反的聰明做法。

8. 網路包含壞的梯度

問題描述

使用 ReLU啟用函式的神經網路經常會遇到一些因為壞的梯度導致的“死亡神經元”的情況。它會導致網路效能下降,甚至某些情況下導致網路無法繼續訓練。

原因

對於 ReLU 啟用函式來說,其梯度對於正數和負數分別是 1 和 0。這是因為輸入的微小更改不會影響小於零的輸入輸出。這對於正數的大梯度來說似乎不是一個問題,但與許多網路層堆疊在一起,負權重能夠將大的正值與強梯度變成負值與零梯度,通常情況下,如果無論輸入是什麼,網路中有一部分或者所有的權值對於損失函式的梯度都是,這種情況就是網路是死了,權值是沒辦法更新,也就是無法繼續訓練下去了。

解決辦法

如果你發現你的訓練誤差沒有隨著迭代次數的增加而變化,那麼很可能就是出現了因為是 ReLU 啟用函式導致的神經元死亡的情況。可以嘗試使用如 leaky ReLU 或者 ELUs 等啟用函式,看看是否還出現這種情況。

任何帶有零梯度的操作,如裁剪、舍入或取最大/最小值,如果在計算損失函式對權值的導數時使用它們,也會產生糟糕的梯度。如果這些元素出現在你的符號圖中,你必須非常小心,因為它們經常會導致不可預見的困難,例如,如果它們被用於作為損失函式的一部分的自定義錯誤度量中。

9. 網路權重沒有正確的初始化

問題描述

如果你不能正確初始化你的神經網路的權值,那麼你的神經網路就不太可能進行訓練。神經網路中的許多其他元件假定某種形式的正確或標準化的權值初始化,並將權值設定為零,一般使用自己的自定義隨機初始化是行不通的。

原因

可能你聽說過可以使用“小的隨機的數值”來初始化網路的權值,但並沒有這麼簡單。常用的“he”,“xaiver”和“lecun”等權值初始化方式都是使用了很複雜和詳細的數學公式並證明了它們為什麼是最優的方法。更重要的是,其他的神經網路元件經常是圍繞著這些初始化方式建立並根據經驗來測試它們,因此如果使用自定義的初始化方式會增加了復現其他研究者成果的難度。

解決辦法

目前比較常用而且在任何情況下效果都不錯的初始化方式包括了“he”,“xaiver”和“lecun”。所以可以任意選擇其中一種,但是可以先進行實驗來找到最適合你的任務的權值初始化方式。

其他網路層可能也需要小心的初始化。網路偏差被初始化為零,而其他更復雜的層,如引數啟用函式,可能會有它們自己的初始化,這些初始化對於得到正確的結果同樣重要。

10. 使用了一個太深的神經網路

問題描述

網路是越深越好嗎?實際上並總是這樣的,越深越好一般是在做基準實驗或者是希望在某些任務上嘗試增加 1%甚至更多的準確率,但是如果 3,4,5 層的網路都學不到任何東西,那麼使用 100+的網路層也會同樣失敗, 甚至更加糟糕。

原因

雖然看起來是這樣,但神經網路並不是在某人決定堆疊數百層的時候就突然開始獲得突破性的結果的。過去十年裡對神經網路所做的所有改進都是微小的、根本性的改變,這些改變既適用於深度網路,也適用於小型網路。如果你的網路不工作,更有可能是其他問題,而不是深度問題。

解決辦法

從一個3到8層的神經網路開始。只有當訓練的網路有不錯的效能,並開始研究如何提高準確性時,才開始嘗試更深層次的網路。

從小處開始也意味著訓練你的網路會更快,推理會更快,迭代不同的設計和設定會更快。最初,所有這些東西對網路的準確性的影響要比簡單地堆疊更多的網路層大得多。

11. 隱藏層神經元數量設定不正確

問題描述

在某些情況下,使用過多或過少的隱藏神經元會讓網路難以訓練。神經元數量過少,它可能無法表達所需的任務,而神經元數量過多,它可能變得緩慢而笨拙,難以去除殘餘噪聲進行訓練。

原因

在決定要使用的隱藏神經元的數量時,關鍵是要大致考慮你認為表達你希望通過網路傳遞的資訊所需的實際值的最少數量。然後你應該把這個數字放大一點。這將允許 dropout,以便網路使用更冗餘的表示,並在你的估計中有一點餘地。如果你在做分類,你可能會使用類數量的5到10倍作為一個好的初始猜測,而如果你在做迴歸,你可能會使用輸入或輸出變數數量的 2 到 3 倍。當然,所有這些都高度依賴於環境,並且不存在簡單的自動解決方案,良好的直覺仍然是決定隱藏單位數量的最重要因素。

解決辦法

從256到1024個隱藏神經元數量開始。然後,看看其他研究人員在相似應用上使用的數字,並以此為靈感。如果其他研究人員使用的數字與上面給出的數字有很大不同,那麼可能有一些具體的原因,這可能對你來說很重要。

在現實中,與其他因素相比,隱藏神經元的數量往往對神經網路的效能有相當小的影響,在很多情況下,高估所需的隱藏神經元的數量只會使訓練變慢,而沒有什麼負面影響。一旦網路開始工作,如果你仍然擔心,就嘗試一大堆不同的數字,並測量其準確性,直到找到最有效的一個。