當前位置:
首頁 > 知識 > 為何Keras中的CNN是有問題的,如何修復它們?

為何Keras中的CNN是有問題的,如何修復它們?

選自Medium

作者:Nathan Hubens

機器之心編譯

參與:Nurhachu Null、張倩

在訓練了 50 個 epoch 之後,本文作者驚訝地發現模型什麼都沒學到,於是開始深挖背後的問題,並最終從愷明大神論文中得到的知識解決了問題。

上個星期我做了一些實驗,用了在 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.01852.pdf

下面簡要描述一下論文內容。

初始化方法

初始化始終是深度學習研究中的一個重要領域,尤其是結構和非線性經常變化的時候。實際上一個好的初始化是我們能夠訓練深度神經網路的原因。

以下是何愷明論文中的關鍵思想,他們展示了初始化應該具備的條件,以便使用 ReLU 激活函數正確初始化 CNN。這裡會需要一些數學知識,但是不必擔心,你只需抓住整體思路。

我們將一個卷積層 l 的輸出寫成下面的形式:

接下來,如果偏置值被初始化為 0,再假設權重 w 和元素 x 相互獨立並且共享相同的分布,我們就得到了:

其中 n 是一層的權重數目(例如 n=k2c)。通過獨立變數的乘積的方差公式:

它變成了:

然後,如果我們讓權重 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 這種卓越的庫中的默認設置,也不能想當然拿來就用。

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

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


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

見過火系的暴鯉龍嗎?這個項目利用CycleGAN生成不同屬性神奇寶貝
前瞻研究:生物製藥行業智能製造技術應用現狀及展望

TAG:機器之心 |