出處: Michael Nielsen的《Neural Network and Deep Learning》,本節譯者:朱小虎 、張廣宇。
目錄
1、使用神經網路識別手寫數字
2、反向傳播演算法是如何工作的
3、改進神經網路的學習方法
4、神經網路可以計算任何函式的視覺化證明
5、為什麼深度神經網路的訓練是困難的
- 梯度消失問題
- 什麼導致了梯度消失問題?神經網路中的梯度不穩定性
- 在更加複雜網路中的不穩定性梯度
- 其他深度學習的障礙
6、深度學習
那麼,在我們訓練深度網路時究竟哪裡出了問題?
為了回答這個問題,讓我們重新看看使用單一隱藏層的神經網路示例。這裡我們也是用MNIST 數字分類問題作為研究和實驗的物件。
這裡你也可以在自己的電腦上訓練神經網路。或者就直接讀下去。如果希望實際跟隨這些步驟,那就需要在電腦上安裝 Python 2.7,Numpy 和程式碼,可以通過下面的命令複製所需要的程式碼:
git clone https://github.com/mnielsen/neural-networks-and-deep-learning.git
如果你不使用 git,那麼就直接從https://github.com/mnielsen/neural-networks-and-deep-learning/archive/master.zip 下載資料和程式碼。然後需要轉入 src 子目錄。
然後,在 Python 命令提示符中我們載入 MNIST 資料:
>>> import mnist_loader
>>> training_data, validation_data, test_data = \
… mnist_loader.load_data_wrapper()
設定我們的網路:
>>> import network2
>>> net = network2.Network([784, 30, 10])
這個網路擁有 784 個輸入層神經元,對應於輸入圖片的 個畫素點。我們設定隱藏層神經元為 30 個,輸出層為 10 個神經元,對應於 10 個 MNIST 數字(‘0’, ‘1’, ‘2’, …, 9)。
讓我們訓練 30 個完整的 epochs,使用 minibatch 大小為 10, 學習率 ,規範化引數 。在訓練時,我們也會在 validation_data 上監控分類的準確度。注意網路可能需要花費幾分鐘來訓練,要看你機器的速度。所以如果你正在執行程式碼,你可能願意繼續閱讀並稍後回來,而不是等待程式碼完成執行。
>>> net.SGD(training_data, 30, 10, 0.1, lmbda=5.0,
… evaluation_data=validation_data, monitor_evaluation_accuracy=True)
最終我們得到了分類的準確率為 96.48%(也可能不同,每次執行實際上會有一點點的偏差)這和我們前面的結果相似。
現在,我們增加另外一層隱藏層,同樣地是 30 個神經元,試著使用相同的超引數進行訓練:
>>> net = network2.Network([784, 30, 30, 10])
>>> net.SGD(training_data, 30, 10, 0.1, lmbda=5.0,
… evaluation_data=validation_data, monitor_evaluation_accuracy=True)
最終的結果分類準確度提升了一點,96.90%。這點令人興奮:一點點的深度帶來了效果。那麼就再增加一層同樣的隱藏層:
>>> net = network2.Network([784, 30, 30, 30, 10])
>>> net.SGD(training_data, 30, 10, 0.1, lmbda=5.0,
… evaluation_data=validation_data, monitor_evaluation_accuracy=True)
哦,這裡並沒有什麼提升,反而下降到了 96.57%,這與最初的淺層網路相差無幾。再增加一層:
>>> net = network2.Network([784, 30, 30, 30, 30, 10])
>>> net.SGD(training_data, 30, 10, 0.1, lmbda=5.0,
… evaluation_data=validation_data, monitor_evaluation_accuracy=True)
分類準確度又下降了,96.53%。這可能不是一個統計顯著地下降,但是會讓人們覺得沮喪。
這裡表現出來的現象看起非常奇怪。直覺地,額外的隱藏層應當讓網路能夠學到更加複雜的分類函式,然後可以在分類時表現得更好吧。可以肯定的是,事情並沒有變差,至少新的層次增加上,在最壞的情形下也就是沒有影響。事情並不是這樣子的。
那麼,應該是怎樣的呢?假設額外的隱藏層的確能夠在原理上起到作用,問題是我們的學習演算法沒有發現正確地權值和偏置。那麼現在就要好好看看學習演算法本身有哪裡出了問題,並搞清楚如何改進了。
為了獲得一些關於這個問題直覺上的洞察,我們可以將網路學到的東西進行視覺化。下面,我畫出了一部分 的網路,也就是包含兩層各有 個隱藏神經元的隱藏層。圖中的每個神經元有一個條形統計圖,表示這個神經元在網路進行學習時改變的速度。更大的條意味著更快的速度,而小的條則表示變化緩慢。更加準確地說,這些條表示了 每個神經元上的,也就是代價函式關於神經元的偏置更變的速率。回顧第二章,我們看到了這個梯度的數值不僅僅是在學習過程中偏置改變的速度,而且也控制了輸入到神經元權重的變數速度。如果沒有回想起這些細節也不要擔心:目前要記住的就是這些條表示了每個神經元權重和偏置在神經網路學習時的變化速率。
為了讓圖裡簡單,我只展示出來最上方隱藏層上的 個神經元。這裡忽略了輸入層神經元,因為他們並不包含需要學習的權重或者偏置。同樣輸出層神經元也忽略了,因為這裡我們做的是層層之間的比較,所以比較相同數量的兩層更加合理啦。在網路初始化後立即得到訓練前期的結果如下1:
該網路是隨機初始化的,因此看到了神經元學習的速度差異其實很大。而且,我們可以發現,第二個隱藏層上的條基本上都要比第一個隱藏層上的條要大。所以,在第二個隱藏層的神經元將學習得更加快速。這僅僅是一個巧合麼,或者第二個隱藏層的神經元一般情況下都要比第一個隱藏層的神經元學習得更快? 為了確定我們的猜測,擁有一種全域性的方式來比較學習速度會比較有效。我們這裡將梯度表示為 在第 層的第 個神經元的梯度。我們可以將 看做是一個向量其中元素表示第一層隱藏層的學習速度, 則是第二層隱藏層的學習速度。接著使用這些向量的長度作為全域性衡量這些隱藏層的學習速度的度量。因此, 就代表第一層隱藏層學習速度,而 就代表第二層隱藏層學習速度。 藉助這些定義,在和上圖同樣的配置下, 而,所以這就確認了之前的疑惑:在第二層隱藏層的神經元學習速度確實比第一層要快。
如果我們新增更多的隱藏層呢?如果我們有三個隱藏層,比如說在一個 的網路中,那麼對應的學習速度就是 。這裡前面的隱藏層學習速度還是要低於最後的隱藏層。假設我們增加另一個包含 30 個隱藏神經元的隱藏層。那麼,對應的學習速度就是:。還是一樣的模式:前面的層學習速度低於後面的層。
現在我們已經看到了訓練開始時的學習速度,這是剛剛初始化之後的情況。那麼這個速度會隨著訓練的推移發生什麼樣的變化呢?讓我們看看只有兩個隱藏層。學習速度變化如下:
為了產生這些結果,我在 個訓練影象上進行了 輪 batch 梯度下降。這和我們通常訓練方式還是不同的——我沒有使用 minibatch,僅僅使用了 個訓練影象,而不是全部的 幅圖。我並不是想做點新鮮的嘗試,或者矇蔽你們的雙眼,但因為使用 minibatch 隨機梯度下降會在結果中帶來更多的噪聲(儘管在平均噪聲的時候結果很相似)。使用我已經確定的引數可以對結果進行平滑,這樣我們可以看清楚真正的情況是怎樣的。 如圖所示,兩層在開始時就有著不同的速度。然後兩層的學習速度在觸底前迅速下落。在最後,我們發現第一層的學習速度變得比第二層更慢了。
那麼更加複雜的網路是什麼情況呢?這裡是一個類似的實驗,但是這次有三個隱藏層():
同樣,前面的隱藏層要比後面的隱藏層學習的更慢。最後一個實驗,就是增加第四個隱藏層(),看看這裡會發生什麼:
同樣的情況出現了,前面的隱藏層的學習速度要低於後面的隱藏層。這裡,第一層的學習速度和最後一層要差了兩個數量級,也就是比第四層慢了 倍。難怪我們之前在訓練這些網路的時候遇到了大麻煩!
現在我們已經有了一項重要的觀察結果:至少在某些深度神經網路中,在我們在隱藏層 BP的時候梯度傾向於變小。這意味著在前面的隱藏層中的神經元學習速度要慢於後面的隱藏層。這兒我們只在一個網路中發現了這個現象,其實在多數的神經網路中存在著更加根本的導致這個現象出現的原因。這個現象也被稱作是梯度消失問題(vanishing gradient problem)2。
為何消失的梯度問題會出現呢?我們可以通過什麼方式避免它?還有在訓練深度神經網路時如何處理好這個問題?實際上,這個問題是可以避免的,儘管替代方法並不是那麼有效,同樣會產生問題——在前面的層中的梯度會變得非常大!這也叫做梯度爆炸問題 ( exploding gradient problem),這也沒比梯度消失問題更好處理。更加一般地說,在深度神經網路中的梯度是不穩定的,在前面的層中或會消失,或會激增。這種不穩定性才是深度神經網路中基於梯度學習的根本問題。這就是我們需要理解的東西,如果可能的話,採取合理的步驟措施解決問題。
一種有關消失的(不穩定的)梯度的看法是確定這是否確實是一個問題。此刻我們暫時轉換到另一個話題,假設我們正要數值優化一個一元的函式 。如果其導數 很小,這難道不是一個好訊息麼?是不是意味著我們已經接近極值點了?同樣的方式,在深度神經網路中前面隱藏層的小的梯度是不是表示我們不需要對權重和偏置做太多調整了?
當然,實際情況並不是這樣的。想想我們隨機初始網路中的權重和偏置。在面對任意的一種任務,單單使用隨機初始的值就能夠獲得一個較好的結果是太天真了。具體講,看看 MNIST問題的網路中第一層的權重。隨機初始化意味著第一層丟失了輸入影象的幾乎所有資訊。即使後面的層能夠獲得充分的訓練,這些層也會因為沒有充分的資訊而很難識別出輸入的影象。因此,在第一層不進行學習的嘗試是不可能的。如果我們接著去訓練深度神經網路,我們需要弄清楚如何解決梯度消失問題。
注:
1. 繪製的資料圖形由程式 generate_gradient.py (https://github.com/mnielsen/neural-networks-and-deep-learning/blob/master/fig/generate_gradient.py)生成。同樣的程式也用來生成本節後面引用的結果。
2. 參見 Gradient flow in recurrent nets: the difficulty of learning long-term dependencies (http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.24.7321),作者為 Sepp Hochreiter,Yoshua Bengio, Paolo Frasconi, 和 Jürgen Schmidhuber (2001)。這篇論文研究了遞迴神經網路,但是其本質現象和我們正在研究的前饋網路中的是一樣的。還可看看 Sepp Hochreiter的早期的學位論文 Untersuchungen zu dynamischen neuronalen Netzen (http://www.idsia.ch/~juergen/SeppHochreiter1991ThesisAdvisorSchmidhuber.pdf, 1991,德語。
本文來源於哈工大SCIR