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

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

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

譯文作者:kbsc13

聯繫方式:

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

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