如何發現「將死」的ReLu?可視化工具TensorBoard助你一臂之力

  • 2019 年 11 月 14 日
  • 筆記

選自Medium

作者:Jithin Jayan

機器之心編譯

參與:魔王、張倩

深度學習模型訓練中會出現各種各樣的問題,比如梯度消失、梯度爆炸,以及 Dying ReLU。那麼如何及時發現這些問題並找出解決方案呢?本文以 Dying ReLU 問題為例,介紹了如何使用可視化工具 TensorBoard 發現該問題,並提供了不同解決思路。

本文介紹了如何利用可視化工具 TensorBoard 發現「Dying ReLU 問題」。

什麼是 ReLU?

ReLU 即修正線性單元(Rectified Linear Unit),是人工神經網路中的一種激活函數。通常情況下,ReLU 是最常使用的激活函數。其主要原因在於 ReLU 不會遇到梯度消失問題。ReLU 的數學公式為:

另外一種表達式為:

其函數影像如下所示:

注意,該函數並非線性,其輸出是非線性的。

ReLU 的導數是:

當 x=0 時,ReLU 的導數是未定義的。

什麼是 Dying ReLU 問題?

ReLU 的主要優勢在於:其輸出為 0 和 1,(無需在反向傳播過程中乘以非常小的值,)從而解決了梯度消失問題。然而,它也存在缺陷。由於它對每個負值的輸出均為 0,ReLU 神經元可能陷入負值中,持續輸出 0,且無法恢復。這叫做 Dying ReLU 問題。這個問題非常嚴重,因為一旦神經元死亡,它基本上學不到任何資訊,從而導致網路的大部分無法工作。

利用 TensorBoard 檢測 Dying ReLU 問題

使用以下程式碼創建隨機樣本:

x 表示大小為 200k x 4 的數組,其數值均從 (-1,0) 區間內均勻取樣得到。該數組內絕大部分數值為負,是 ReLU 最不喜歡的一類輸入。將該數據按照 7:3 的比例分割為訓練集和測試集。

使用一個具備 ReLU 激活函數的一層簡單網路。隨機初始化權重,將偏差初始化為 0。

現在,初始化 TensorBoard 變數。每個 epoch 都需要梯度,因此將 write_grads 初始化為 True。

最後擬合模型,在 callbacks 參數中使用 TensorBoard 變數。

繪製訓練損失和驗證損失的影像。

所有 epoch 的驗證損失(上)和訓練損失(下)。

從上圖中,我們可以清晰地看到模型損失沒有降低,這意味著模型停止了學習。現在使用 TensorBoard 對密集層的梯度和輸出進行可視化。

密集層輸出(左)和密集層梯度(右)。

從上圖中我們可以看到,對於所有 epoch,密集層梯度都為 0,輸出也均為 0。梯度圖顯示出,一旦梯度變成 0,模型試圖掙脫這種情況,但它已經完全死亡,這從損失圖中也能看出,因為損失沒有隨時間發生變化,說明模型停止學習或者學不到任何資訊。

添加層

現在,使用具備同樣 ReLU 函數的三層網路,看看上述問題是否解決。本文使用如下網路:

這是一個三層網路,所有層的激活函數均為 ReLU。

現在,通過 TensorBoard 觀察所有層的梯度:

Dense_3 梯度(左)、Dense_2 梯度(中)、Dense_1 梯度(右)。

從上圖中可以看到,添加層並沒有解決 dying ReLU 問題,所有層的梯度仍然為 0,這些梯度被反向傳播至模型其他層,從而影響模型的性能。

解決方案

1. 增加數據規模會有幫助嗎?

不會!如果新數據與原有數據屬於同一分布,則在訓練集中添加這些新數據是無用的。不過,為同樣的問題收集一個新數據集可能是一種解決方案。

2. 添加 Dropout 會有幫助嗎?

Dropout 與 ReLU 的輸出沒有任何關係,因此添加或者更改 Dropout 對 dying ReLU 沒有影響。

3. 添加層會有幫助嗎?

不會。如上所述,添加層對解決 dying ReLU 問題沒有幫助。

4. 增加訓練 epoch 會有幫助嗎?

不會,雖然每個 epoch 結束後都會更新權重,但是由於神經元死亡,梯度為 0,使得權重無法得到更新。權重一直不變,使用相同的權重計算梯度只能得到 0,因此這對解決 dying ReLU 問題沒有幫助。

5. 改變權重初始化會有幫助嗎?

我們先來嘗試不同的權重初始化器,並繪製其梯度和輸出。下圖是為使用 ReLU 激活函數的密集層梯度繪製的圖,這四個網路使用的權重初始化器分別是:he_normal、he_uniform、ecun_normal 和 random_uniform。

he_normal(左)和 he_uniform(右)。

lecun_uniform(左)和 random_uniform(右)。

從上圖中我們可以看到,權重初始化對解決 dying ReLU 問題沒有幫助。從 he_normal、he_uniform 和 lecun_normal 的圖示中可以看到,在初始化階段有輕微的改善,但是隨著 epoch 數量的增加,導數趨向於 0。

由於輸入多為負值,我們使用以下程式碼將權重初始化為負值:

分配給權重的值均從 (-1,0) 區間內隨機均勻取樣得到,這與輸入的分布相同。該網路的梯度和輸出如下圖所示:

dense_1 輸出(左)、dense_1 梯度(右)。

從上圖中同樣可以觀察到,隨著 epoch 數量的增加,梯度變為 0,輸出也集中於 0。因此我們可以認為改變初始權重是解決 dying ReLU 問題的一種辦法,但是需要確保模型不要運行太多 epoch,因為這又會導致 dying ReLU 問題。事實上,從這些圖中可以看出,改變初始權重對解決 dying ReLU 問題並沒有太大幫助。

6. 改變激活函數會有幫助嗎?

可能會。那麼要用哪種函數替代 ReLU 呢?我們可以使用 tanh 和 Sigmoid 函數。使用 ReLU 的變體 Leaky ReLU 也可以避開該問題。但是,在為該實驗創建的示例中,以上所有函數均失敗了,因為它們都遭遇了梯度消失問題。當我們需要在梯度消失和 Dying ReLU 中進行權衡時,有動靜總比沒有好。遇到梯度消失問題後,模型仍在學習,而在 Dying ReLU 中沒有學習,學習過程被中斷了。

這時候,Leaky ReLU 的加強版 SELU (Scaled Exponential Linear Units) 就派上用場了。SELU 激活函數可以自行歸一化神經網路,即歸一化後網路權重和偏差的均值為 0,方差為 1。SELU 的主要優勢是不會遭遇梯度消失和梯度爆炸,同時也不會出現激活函數死亡現象。關於 SELU 的更多資訊,參見論文《Self-Normalizing Neural Networks》

注意:SELU 必須與 lecun_normal 初始化一起使用,且將 AlphaDropout 作為 dropout。對於以上數據集,我們可以使用以下網路:

該網路密集層的梯度和輸出如下圖所示:

從梯度圖中可以看出,梯度有所改善,逐漸遠離 0。從輸出圖中可以看出,具備 SELU 激活函數的密集層輸出值很小,但也不像之前示例那樣輸出為 0。因此,即使在最糟糕的情況下,SELU 也比 ReLU 效果好。

結論

訓練和使用深度神經網路時,實時監控損失和梯度情況是一種不錯的做法,有助於發現深度學習模型訓練過程中的大部分問題。如果你不知道如何發現和解決問題,那麼寫深度網路是沒有意義的。本文只涉及了眾多問題的冰山一角。每個使用深度學習和人工神經網路的人總會遇到激活函數死亡問題,一著不慎就要浪費數個小時重新訓練模型,因為這時只改變模型參數已經沒用了。由於 ReLU 是大部分深度學習問題中最常用的激活函數,因此大家一定要謹慎地避免該問題。而有了 TensorBoard 之後,你可以輕鬆發現該問題。

原文鏈接:https://medium.com/@jithinjayan1993/is-relu-dead-27943b50102