天天看點

神經網絡與深度學習(五):深度網絡訓練難點

想象一下你是一位工程師,需要從頭開始設計一台電腦。有一天你正在辦公室裡設計你的邏輯電路,設定AND門,OR門,等等,然後你的老闆進來了,帶來一個壞消息:客戶加了一個不可思議的需求,就是整個電腦的設計必須隻包含兩層,如下圖:

神經網絡與深度學習(五):深度網絡訓練難點

你徹底傻了,跟老闆抱怨:客戶瘋了吧。

老闆說:我也覺得他們瘋了,但是客戶是上帝,他們要什麼我們就得給什麼。

事實上,也不能說客戶完全瘋了。假定你的AND邏輯電路的輸入可以是任意多個,NAND門電路也是輸入也是任意多的,則任何一個函數都可以用這些裝置通過兩層設計出來。

但是,可以實作的設計不一定都是好設計。實際中,我們在解決實際問題(大多數的算法問題)的時候,我們通常先解決問題的子問題,然後綜合起來,得到原始問題的解法。也就是,我們通過多層次的抽象來解決問題。

比如,我們要設計一個電路用于計算兩個輸入的乘積。一般我們會通過兩個輸入的加法子電路來實作。這些實作加法的子電路,又會通過位加法的子子電路來實作。簡單來說,這個設計會類似下圖的結構:

神經網絡與深度學習(五):深度網絡訓練難點

就是這樣子,我們最終的設計至少會包含三層。實際上可能包含的更多,因為子任務可能會進一步劃分,我們領會這裡思路就好了。

是以,較深的電路設計會讓設計的過程變的簡單一些。然後他們不止是對設計有幫助。有數學研究發現,對于一些函數來說,淺層設計要比深層設計多使用指數倍的電路原件。例如,1980年代的一系列論文顯示,對于奇偶性的計算任務,如果用淺層設計來實作,需要指數倍的門電路。相反,如果使用深度設計來實作,可以使用一個很小規模的電路來實作:你隻要先計算每兩位的奇偶性,然後用計算的結果去計算四位的奇偶性,以此類推,最後計算整個數的奇偶性。是以,深度設計在本質上就比淺層網絡更強大。

目前為止,本書中的神經網絡的設計都像那位瘋了的客戶一樣。幾乎所有的設計中都隻有一層隐藏層:

神經網絡與深度學習(五):深度網絡訓練難點

這些簡單的淺層的網絡已經非常好了:在前面的章節中,我們的數字識别準确率達到了98%以上。直覺上來說,我們期望包含多層隐藏層的深度網絡會更好:

神經網絡與深度學習(五):深度網絡訓練難點

這些深度網絡,可以使用中間層建構多層次的抽象,就像布爾電路設計一樣。例如,我們在做視覺模式識别的任務,則第一層的神經元可能學習識别邊界,第二層的可以識别複雜的由邊界構成的圖形,比如三角形、長方形等等。第三層的神經元可以識别更複雜的圖形。以此類推。這種多層次抽象的能力看起來會讓深度網絡在負載模式識别的問題上具有不可抗拒的優勢。而且,類似于電路設計,也有理論研究結果表明,深度網絡本質上會比淺層網絡更強大。

我們如何來訓練這種深度網絡呢?本章中,我們會嘗試使用我們的主力學習算法–随機梯度下降算法。但是我們遇到了問題,我們的深度網絡沒有表現的比淺層網絡更好。

經過上面個讨論,這個失敗的結果确實很意外。我們沒有放棄深度網絡,我深挖一下,試圖去了解深度網絡難以訓練的原因。我們仔細觀察後發現,深度網絡中的不同層學習的速度差别很大。具體來說就是,當網絡後面的層學習很好的時候,前面的層的學習經常會卡住,幾乎學不到任何東西。這個問題不是運氣的問題。其實,學習變慢是有原因的,跟基于梯度的學習算法有關。

随着問題的研究的深入,我們發現相反的現象也會發生:前面層的學習很好,後面的層學習會卡住。事實上,我們會發現,深度網絡中,基于梯度下降的學習算法有一種内在的不穩定性。這種不穩定性導緻前面或則後面層的學習卡住。

這些聽起來都是壞消息。但是深入研究這些問題,我們逐漸領悟了深度網絡的訓練需要什麼。而這些調查是對下章内容的很好的準備。下章中我們将使用深度學習解決圖檔識别的問題。

梯度消失問題

那麼,深度網絡的訓練問題出在哪?

為了了解問題,我們回憶一下前面使用的包含一層隐藏層的神經網絡。我們還是用MNIST數字圖檔作為例子。

如果願意,讀者可以在自己的電腦上訓練。你需要Python2.7,Numpy,代碼可以下列方式取得:

當然,隻是閱讀也是可以的。

我們通過PythonShell加載MNIST資料:

>>> import mnist_loader
>>> training_data, validation_data, test_data = \
... mnist_loader.load_data_wrapper()
           

建構網絡:

>>> import network2
>>> net = network2.Network([, , ])
           

網絡是784輸入神經元對應每張圖檔的 28x28=784 28 x 28 = 784 個像素。隐藏層包含30個神經元。輸出層包含10個輸出神經元,對應圖檔的10個可能的取值(0,1,2,3,…,9)。

我們試着訓練30次,mini-batch大小為10,學習速率 η=0.1 η = 0.1 ,規則化參數 λ=5.0 λ = 5.0 。一邊訓練一邊用驗證集validation_data測試分類的準确率:

>>> net.SGD(training_data, , , , lmbda=, 
... evaluation_data=validation_data, monitor_evaluation_accuracy=True)
           

準确率達到96.48%(左右,每次運作都不太一樣)。

然後我們添加一層隐藏層,也包含30個神經元,然後使用同樣的超參訓練:

>>> net = network2.Network([, , , ])
>>> net.SGD(training_data, , , , lmbda=, 
... evaluation_data=validation_data, monitor_evaluation_accuracy=True)
           

準确率達到96.90%,有了一定的提升。很好:增加網絡深度有幫助。我們再加一層,同樣包含30個神經元:

>>> net = network2.Network([, , , , ])
>>> net.SGD(training_data, , , , lmbda=, 
... evaluation_data=validation_data, monitor_evaluation_accuracy=True)
           

準确率回到了96.57%,添加這層沒起到作用。我們再增加一層試試:

>>> net = network2.Network([, , , , , ])
>>> net.SGD(training_data, , , , lmbda=, 
... evaluation_data=validation_data, monitor_evaluation_accuracy=True)
           

準确率又下降了,到了96.53%。雖然下降的不多,但是也很失望。

結果看起來有些奇怪。直覺感覺,增加的網絡層使網絡可以計算更複雜的分類函數,進而更好的分類。而且,情況不應該變糟糕才對,因為最壞情況下,額外增加的網絡層什麼也不做就行了。但是情況并非如此。

那麼這是怎麼回事呢?我們假設增加的網絡層原則上确實有幫助,問題出在我們的學習算法沒有找到合适的權重和偏移。我們來找出學習算法的問題,改進它。

為了了解問題出在哪,我們來圖形化網絡是如何學習的。下圖中,我畫出了網絡[784,30,30,10]的一部分。每個神經元上都有一個小柱子,表示神經元變化的頻率。大的柱子表示神經元訓練過程中變化快,小的柱子表示變化的慢。更準确的說,柱子代表每個神經元的梯度 ∂C/∂b ∂ C / ∂ b 。我們知道這個變量不僅決定了訓練中偏移值的變化頻率,還決定了權重輸入變化的頻率。如果你記不太清細節也沒關系:記住柱子的大小表示每個神經元權重和偏移改變的快慢就可以了。

為了簡圖圖形,我隻花了2個隐藏層的前6個神經元。省略了輸入層,因為它們沒有權重和偏移,也省略了輸出層。因為我在做層與層之間的比較,相同數量的層之間的比較更有意義。圖像是在訓練的開始時畫出來的,也就是在網絡初始化之後不久:

神經網絡與深度學習(五):深度網絡訓練難點

網絡是随機初始化的,是以神經元變化率不一樣沒什麼奇怪的。但是有一個現象很明顯:第二隐藏層的變化比第一隐藏層的變化率普遍大很多。導緻第二隐藏層的神經元要比第一隐藏層的神經元學習快很多。這是巧合還是另有原因呢?

為了弄清情況是否如此,最好能有一個比較兩個隐藏層學習速率的方法。我們把 l l 層的jj神經元的梯度記為: δlj=∂C/∂blj δ j l = ∂ C / ∂ b j l 。我們可以用向量 δl δ l 表示 l l 層的學習速率。如此,可以通過比較||δ1||,||δ2||||δ1||,||δ2||來比較這兩層的學習速率。

我們計算得到 ||δ1||=0.07,||δ2||=0.31 | | δ 1 | | = 0.07 , | | δ 2 | | = 0.31 。是以,第一隐藏層确實比第二隐藏層學習的快。

添加更多的隐藏層會怎麼樣呢?在[784,30,30,30,10]網絡中,三個隐藏層的學習速率分别是0.012,0.060,0.283。再一次說明,前一層的學習要比後一層的學習慢。在添加一層的呢,4個隐藏層的學習速率分别是0.003,0.017,0.070,0.285.情況依然存在。

我們已經看過了訓練之初的情況,我們回到2層隐藏層的網絡,看一下整個訓練過成中兩層的學習速率對比:

神經網絡與深度學習(五):深度網絡訓練難點

實驗中使用了1000張圖檔,訓練了500次。這裡我并沒有使用mini-batch的訓練方式,是因為這種方式會産生不少噪音,使用我上面的參數使結果更明顯。

可以看出,兩層的開始速率就不同(這個我們已經知道了)。然後同時快速的下降,然後反彈。但是第一隐藏層速率始終比第二有層慢。

更複雜一些的網絡呢?我們來看一下網絡[784,30,30,30,10]的情況:

神經網絡與深度學習(五):深度網絡訓練難點

情況依然存在;網絡[784,30,30,30,30,10]呢:

神經網絡與深度學習(五):深度網絡訓練難點

再次,前面的隐藏層比後面的隐藏層學習的慢很多。這裡,第一隐藏層要比最後隐藏層慢100倍。難怪我們之前訓練深度網絡遇到了問題。

這裡我們觀察到了一個重要的現象:至少在一些深度網絡中,梯度會随着逆向向前傳播而變小。這種現象被稱為:梯度消失問題。

梯度為什麼會消失?有辦法避免嗎?訓練深度網絡的時候怎麼處理這個問題?事實上,這個現象是不可避免的,而且相反的現象也存在:有時梯度會逐漸增大,稱之為梯度爆炸問題。總得來說,深度網絡中的梯度是不穩定的,不是消失就是爆炸。這種不穩定性是深度網絡中基于梯度的學習算法的基礎問題之一。

梯度不穩定問題确實是一個問題嗎?暫時抛開神經網絡,想象一下我們需要最小化函數 f(x) f ( x ) ,導數 f′(x) f ′ ( x ) 比較小不好嗎?這不是說明我們呢已經接近極值了嗎?類似的,深度網絡找中前面的網絡層的梯度較小也許是因為我們确實不需要太多調整權重和偏移呢?

毫無疑問現實情況不是這樣的。我們的網絡是随機初始化的。初始的值不太可能做好我們需要網絡要做的工作。具體來說,比如使用[784,30,30,30,10]來分類MNIST圖檔。随機初始化的第一隐藏層會丢掉圖檔的大部分資訊。這樣,即使後面的層訓練的很好,也會很難分類圖檔,原因是沒有足夠的資訊。是以,第一層不用學習是不太可能的。是以如果我們需要訓練深度網絡,就必須解決梯度不穩定的問題。

是什麼導緻了梯度消失?深度網絡的梯度不穩定

為了了解梯度是怎麼消失的,我們來考慮下面這個最簡單的網絡:每一層隻有一個神經元:

神經網絡與深度學習(五):深度網絡訓練難點

其中, w1,w2,... w 1 , w 2 , . . . 表示權重, b1,b2,... b 1 , b 2 , . . . 表示偏移。 C C 表示損失函數。這麼畫是為了說明損失函數是關于a4a4的函數。

我們将研究一下第一隐藏神經元的梯度 ∂C/∂b1 ∂ C / ∂ b 1 。推導出 ∂C/∂b1 ∂ C / ∂ b 1 的表達式,通過表達式的學習我們就會了解為什麼梯度會消失。

首先我會直接告訴你 ∂C/∂b1 ∂ C / ∂ b 1 的表達式,看起來很複雜,其實公式結構很簡單:

神經網絡與深度學習(五):深度網絡訓練難點

為什麼會出現梯度消失的問題:為了了解這個問題,看一下梯度計算的公式:

∂C∂b1=σ′(z1)w2σ′(z2)w3σ′(z3)w4σ′(z4)∂C∂a4(122) ∂ C ∂ b 1 = σ ′ ( z 1 ) w 2 σ ′ ( z 2 ) w 3 σ ′ ( z 3 ) w 4 σ ′ ( z 4 ) ∂ C ∂ a 4 ( 122 )

除了最後一項,這個表達式是 wjσ′(zj) w j σ ′ ( z j ) 的乘積。為了了解每一項的行為,我們來看一下 σ′ σ ′ 函數的圖像:

神經網絡與深度學習(五):深度網絡訓練難點

可以看出,導函數的在0處取得最大值 σ(0)=1/4 σ ( 0 ) = 1 / 4 。我們是用标準的方式初始化網絡的權重的,這個标準的方式是使用均值為0标準差為1的高斯分布随機初始化。是以,權重通常會滿足 |wj|<1 | w j | < 1 。綜合起來,可以得出每一項 |wjσ′(zj)|<1/4 | w j σ ′ ( z j ) | < 1 / 4 。與這個值相乘結果會指數形式的減小。越多這樣的項,乘積越小。這個看起來可以解釋梯度消失了。

為了更明确的說明問題,我們來比較一下 ∂C/∂b1,∂C/∂b3 ∂ C / ∂ b 1 , ∂ C / ∂ b 3 :

神經網絡與深度學習(五):深度網絡訓練難點

可以看出 ∂C/∂b1,∂C/∂b3 ∂ C / ∂ b 1 , ∂ C / ∂ b 3 有很多共同項,但是 ∂C/∂b1 ∂ C / ∂ b 1 比 ∂C/∂b3 ∂ C / ∂ b 3 多兩項,是以 ∂C/∂b1 ∂ C / ∂ b 1 大概是 ∂C/∂b3 ∂ C / ∂ b 3 的1/16.這就是梯度消失的根本原因。

當然,這不是梯度消失的嚴格正式的證明。有例外的情況。具體來說,就是訓練中, wj w j 的值可能會增長。如果這樣, |wiσ′(zj)|<1/4 | w i σ ′ ( z j ) | < 1 / 4 就不再成立。确實如此,一旦這個值超過了1,梯度小時問題就不再出現,相反,會出現梯度爆炸問題。

梯度爆炸問題:我們來看一個梯度爆炸的例子。這個例子是我人為構造的:我将手動初始化各個參數來確定梯度會爆炸。雖然這個例子是認為構造出來的,但是它也說明了梯度爆炸不是一個純理論的問題,而是确确實實可以能發生。

再次使用上面的每層隻有一個神經元的網絡,我們需要兩步來構造出一個梯度爆炸的網絡。第一步,網絡中的權重都用比較大的值初始化,比如 w1=w2=w3=w4=100 w 1 = w 2 = w 3 = w 4 = 100 。第二步,選擇偏移值的時候注意一下,使 σ′(zj) σ ′ ( z j ) 的值不要太小。做到這點很簡單:偏移的值使得權重輸入 zj=0 z j = 0 就可以了(這樣的話 σ′(zj)=1/4 σ ′ ( z j ) = 1 / 4 )。是以,比如我們要想 z1=w1a0+b1=0 z 1 = w 1 a 0 + b 1 = 0 ,使 b1=−100∗a0 b 1 = − 100 ∗ a 0 就可以了。這樣初始化參數後,得到 wjσ′(zj)=100∗14=25 w j σ ′ ( z j ) = 100 ∗ 1 4 = 25 .我們得到了一個梯度會爆炸的網絡。

梯度不穩定問題:這裡的基本問題不是梯度消失或則梯度爆炸問題,而是前面網絡層的梯度是後面網絡層中一些項目的乘積的形式。當存在多層的時候,從本質上就會造成不穩定的問題。要使所有層按同樣的速度學習的唯一的辦法就是所有這些相乘的項能平衡。事實上,沒有一些機制或則底層的原因,這種平衡很難發生。簡單來說,真正的問題是神經網絡的梯度不穩定問題。是以如果我們用标準的基于梯度的學習算法,不同的層趨向于以不同的速度學習。

梯度消失的普遍性:我們已經知道,深度網絡中,前面的網絡層中容易出現梯度消失或則梯度爆炸的問題。事實上,使用sigmoid神經元的時候,梯度消失比較常見。為什麼呢?我們再次考慮乘積項 |wσ′(z)| | w σ ′ ( z ) | .要想避免梯度消失問題,需要滿足 |wσ′(z)|>1 | w σ ′ ( z ) | > 1 。你可能會認為故意 w w 值比較大的話這個條件很容易滿足。其實不然。原因是σ′(z)σ′(z)也依賴于 w w :σ′(z)=σ′(wa+b)σ′(z)=σ′(wa+b),其中a是輸入。是以當 w w 比較大的時候,我們需要小心不要同時使σ′(wa+b)σ′(wa+b)變小了。這是一個相當苛刻的限制條件。原因是當我們增大 w w 時,wa+bwa+b是增大的。觀察函數 σ′(z) σ ′ ( z ) 發現,這會使 σ′(wa+b) σ ′ ( w a + b ) 變小的。是以,通常情況下,梯度會消失。

更複雜網絡中的梯度不穩定問題

我們已經學習過了簡單網絡的情況,每一層隻包含一個神經元。更複雜的深度網絡中情況又是怎樣的呢?

神經網絡與深度學習(五):深度網絡訓練難點

事實上,情況一樣。一個包含 L L 層的神經網絡中,ll層的梯度滿足下面的公式:

δl=∑′(zl)(wl+1)T∑′(zl+1)(wl+2)T...∑′(zL)∇aC(124) δ l = ∑ ′ ( z l ) ( w l + 1 ) T ∑ ′ ( z l + 1 ) ( w l + 2 ) T . . . ∑ ′ ( z L ) ∇ a C ( 124 )

其中, ∑′(zl) ∑ ′ ( z l ) 是一個對角矩陣,每一項表示連接配接到 l l 層的神經元的權重輸入。wlwl表示對應層的權重矩陣。 ∇aC ∇ a C 表示損失函數C關于輸出激活值的偏導數。

這個公式比前面的公式要複雜很多。但是,本質的形式還是很相似的。由很多形式為 (wj)T∑′(zj) ( w j ) T ∑ ′ ( z j ) 的項組成。

深度網絡的其他障礙

本章中,我們主要關注了梯度消失的問題,更廣泛的說,應該是梯度不穩定問題。這隻是深度網絡的一個障礙。很多正在進行的研究目标在于更好的了解深度學習中的挑戰。這裡我不準備總結所有這些工作。這裡我會簡單的提及一些論文,讓你們了解到人們經常遇到的問題。

第一例子,2010年Glorot和Bengio發現sigmoid激活函數會導緻最後一層隐藏層的輸出在0附近飽和,導緻學習變慢的問題。他們建議使用一些替換的激活函數。

第二個例子,2013年Sutskever, Martens, Dahl 和 Hinton研究了随機權重初始化和動量梯度下降對深度學習的影響。

這些例子提示我們,”什麼使得深度網絡很難訓練”是一個很複雜的問題。本章我我們關注了梯度不穩定的問題。上面兩個例子說明,結果跟所用的激活函數、權重初始化的方式、甚至梯度下降的具體實作形式都有關系。當然網絡的結構,其他超參的取值也很重要。是以,原因是多方面的,跟很多因素有關系。對這些關系的了解是正在研究的主題。這些看起來很悲觀。但是好消息是,下一章中,我們開發出了幾種方法,某種程度上克服了或則是繞過了這些障礙。

繼續閱讀