為何Keras中的CNN是有問題的,如何修復它們?
在訓練了 50 個 epoch 之後,本文作者驚訝地發現模型什麼都沒學到,於是開始深挖背後的問題,並最終從愷明大神論文中得到的知識解決了問題。
選自Medium,作者:Nathan Hubens,機器之心編譯,參與:Nurhachu Null、張倩。
上個星期我做了一些實驗,用了在 CIFAR10 資料集上訓練的 VGG16。我需要從零開始訓練模型,所以沒有使用在 ImageNet 上預訓練的版本。
我開始了 50 個 epoch 的訓練,然後去喝了個咖啡,回來就看到了這些學習曲線:
模型什麼都沒學到!
我見過網路收斂得極其緩慢、振盪、過擬合、發散,但這是我第一次發現這種行為——模型根本就沒有起任何作用。
因此我就深挖了一下,看看究竟發生了什麼。
實驗
這是我建立模型的方法。它遵循了 VGG16 的原始結構,但是,大多數全連線層被移除了,所以只留下了相當多的卷積層。
現在讓我們瞭解一下是什麼導致了我在文章開頭展示的訓練曲線。
學習模型過程中出現錯誤時,檢查一下梯度的表現通常是一個好主意。我們可以使用下面的方法得到每層梯度的平均值和標準差:
然後將它們畫出來,我們就得到了以下內容:
使用 Glorot 函式初始化的 VGG16 梯度的統計值
呀。。。 我的模型中根本就沒有梯度,或許應該檢查一下啟用值是如何逐層變化的。我們可以試用下面的方法得到啟用值的平均值和標準差:
然後將它們畫出來:
使用 Glorot 函式進行初始化的 VGG16 模型的啟用值
這就是問題所在!
提醒一下,每個卷積層的梯度是透過以下公式計算的:
其中Δx 和Δy 用來表示梯度∂L/∂x 和∂L/∂y。梯度是透過反向傳播演算法和鏈式法則計算的,這意味著我們是從最後一層開始,反向傳遞到較淺的層。但當最後一層的啟用值接近零時會發生什麼呢?這正是我們面臨的情況,梯度到處都是零,所以不能反向傳播,導致網路什麼都學不到。
由於我的網路是相當簡約的:沒有批歸一化,沒有 Dropout,沒有資料增強,所以我猜問題可能來源於比較糟糕的初始化,因此我拜讀了何愷明的論文——《Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification》
論文連結:
https://
arxiv。org/pdf/1502。0185
2。pdf
下面簡要描述一下論文內容。
初始化方法
初始化始終是深度學習研究中的一個重要領域,尤其是結構和非線性經常變化的時候。實際上一個好的初始化是我們能夠訓練深度神經網路的原因。
以下是何愷明論文中的關鍵思想,他們展示了初始化應該具備的條件,以便使用 ReLU 啟用函式正確初始化 CNN。這裡會需要一些數學知識,但是不必擔心,你只需抓住整體思路。
我們將一個卷積層 l 的輸出寫成下面的形式:
接下來,如果偏置值被初始化為 0,再假設權重 w 和元素 x 相互獨立並且共享相同的分佈,我們就得到了:
其中 n 是一層的權重數目(例如 n=k²c)。透過獨立變數的乘積的方差公式:
它變成了:
然後,如果我們讓權重 w 的均值為 0,就會得到:
透過 König-Huygens 性質:
最終得到:
然而,由於我們使用的是 ReLU 啟用函式,所以就有了:
因此:
這就是一個單獨卷積層的輸出的方差,到那時如果我們想考慮所有層的情況,就必須將它們乘起來,這就得到了:
由於我們做了乘積,所以現在很容易看到如果每一層的方差不接近於 1,網路就會快速衰減。實際上,如果它比 1 小,就會快速地朝著零消散,如果比 1 大,啟用的值就會急劇增長,甚至變成一個你的計算機都無法表示的數字(NaN)。因此,為了擁有表現良好的 ReLU CNN,下面的問題必須被重視:
作者比較了使用標準初始化(Xavier/Glorot)[2] 和使用它們自己的解初始化深度 CNN 時的情況:
在一個 22 層的 ReLU CNN 上使用 Glorot(藍色)初始化和 Kaiming 的初始化方法進行訓練時的對比。使用 Glorot 初始化的模型沒有學到任何東西。
這幅圖是不是很熟悉?這就是我在文章開始向你們展示的圖形!使用 Xavier/Glorot 初始化訓練的網路沒有學到任何東西。
現在猜一下 Keras 中預設的初始化是哪一種?
沒錯!在 Keras 中,卷積層預設是以 Glorot Uniform 分佈進行初始化的:
所以如果我們將初始化方法改成 Kaiming Uniform 分佈會怎麼樣呢?
使用 Kaiming 的初始化方法
現在來建立我們的 VGG16 模型,但是這次將初始化改成 he_uniform。
在訓練模型之前,讓我們來檢查一下啟用值和梯度。
所以現在,使用 Kaiming 的初始化方法時,我們的啟用擁有 0。5 左右的均值,以及 0。8 左右的標準差。
可以看到,現在我們有一些梯度,如果希望模型能夠學到一些東西,這種梯度就是一種好現象了。
現在,如果我們訓練一個新的模型,就會得到下面的學習曲線:
我們可能需要增加一些正則化,但是現在,哈哈,已經比之前好很多了,不是嗎?
結論
在這篇文章中,我們證明,初始化是模型中特別重要的一件事情,這一點你可能經常忽略。此外,文章還證明,即便像 Keras 這種卓越的庫中的預設設定,也不能想當然拿來就用。
參考文獻和擴充套件閱讀:
[1]: Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification:
https://
arxiv。org/pdf/1502。0185
2。pdf
[2]: Understanding the difficulty of training deep feedforward neural networks:
http://
proceedings。mlr。press/v
9/glorot10a/glorot10a。pdf
[3]: 吳恩達課程:
https://www。
youtube。com/watch?
v=s2coXdufOzE
原文地址:
https://
towardsdatascience。com/
why-default-cnn-are-broken-in-keras-and-how-to-fix-them-ce295e5e5f2