翻譯自 http://neuralnetworksanddeeplearning.com/chap3.html ,《neural networks and deep learning》的第三章內容。原作者寫的非常淺顯易懂,英文好的朋友推薦直接讀原作,文章也有別人翻譯過,但是想加深自己的理解,就自己也嘗試翻譯了,水平有限,難免有疏漏,謹慎閱讀。
當一個高爾夫球手在初次學習打高爾夫時,他通常會花費大量的時間學習基礎的揮桿動作。他們會逐漸的學習其他的擊球方式,學習怎么樣切球,怎么樣打出曲線球,并在學習訓練過程中不斷的修正他們的基礎揮桿動作。我們到目前為止在研究的“反向傳播”算法就跟高爾夫球學習中的揮桿動作一樣,它是神經網絡訓練中的大部分基礎工作。在這一章中,我將會介紹一些能夠提升“反向傳播”算法效率的技術,通過這些技術可以優化神經網絡的學習效率。
我們在這一章中提出的優化技術包括:“交叉熵”損失函數;四種能夠提高模型泛化能力的正則化方法(L1和L2正則化,dropout and artificial expansion of the training data));一種更好的初始化神經網絡中各節點權重的方法;神經網絡中的超參數設置方法。我也會稍微提到一些其他的方法。這四個部分之間內容都是相互獨立的,所以你也可以直接挑選你感興趣的部分,跳過那些你已經很了解或者不感興趣的部分。我們也會給出一些技術實現的代碼,并使用這些技術實現方法改善我們在第一章中提到的手寫識別問題。
由于神經網絡的中涉及的技術非常多,我們這一章只會研究其中的一些常用方法。我們希望通過深入研究少數幾個最重要的方法,來加強對神經網絡學習理論的認識。掌握這幾個最重要的技術理論及方法,不僅僅能夠優化神經網絡的表現,并且有助于幫你解決你在學習神經網絡中可能遇到的其他問題。這些技術會有助于你快速學習其他相關技術,為你奠定理論基礎。
交叉熵
無論做什么,當我們發現自己做得不好,總是會令人感到沮喪的。很久之前,我第一次給一位聽眾演奏鋼琴的時候,我非常緊張,在演奏時,我比琴譜低了一個八度。我感到很困惑,甚至無法完成整個演奏,直到別人指出了我的錯誤,那真是非常尷尬的經歷。相比這個不愉快的經歷,我們發現當我們被別人明確的指出錯誤根源時,我們反而能獲得更大的進步。你能想象,我在下一次給別人演奏時,就能正確的演奏出琴譜了!相反,如果沒有人指出我們的錯誤,我們學習的效率往往就比較低。
在神經網絡訓練中,我們也期望神經網絡也能夠從錯誤中獲得進步。在神經網絡訓練過程中,這能實現嗎?為了回答這個問題,我們來看一個簡單的例子。我們用只有一個輸入的單個神經元作為示例:
我們假定這個神經元訓練完成后,具備的功能是:當輸入為1時,它的輸出是0。這個假定只是為了方便我們演示神經元的訓練過程,有助于清晰的表述怎樣以梯度下降的方式來獲取權重w和偏移b的過程。下面我們將具體的討論這個神經元是怎樣學習的。
首先,我們初始化權重w=0.6,b=0.9。通常情況下,有一些常用的方法來初始化這些變量的取值,在這里我并沒有采用這些方法,只是簡單的指定了變量的初始值。當我指定了初始值之后,這個神經元的輸出是0.82(激活函數采用sigmoid函數)。我們期望的輸出是0,當前的輸出0.82與期望值明顯有較大偏差,因此這個神經元還需要進一步訓練,獲取更好的W和b。點擊下圖中右下方的“Run”按鈕,你可以看到這個神經元是如何完成訓練,逐漸的接近期望值0。(注意,這并不是一個預先處理過的動畫圖片,是通過瀏覽器計算梯度之后,js程序使用這個梯度更新權重w和偏移b,最終展示給你了結果。)這個示例中的設置學習率η=0.15,確保訓練的過程比較慢,這樣我們可以清晰的可視化該過程。我們也可以更改設置加快訓練過程,使訓練在數秒內完成。在這個訓練過程中,我們使用的損失函數是我們在第一章介紹過的平方損失函數。我們會在后面簡短的介紹下這個損失函數,如果你還是對該函數有疑問,則可以重新閱讀第一章中的該內容。(注意,你可以重復點擊“Run”按鈕,重復觀看該訓練過程)。
補圖,js效果(文章頭部有原文鏈接,可至原文觀看)
正像你所看到的這樣,通過快速的更改權重w和偏移b,神經元輸出的誤差漸漸變小,最終該神經元給出的輸出值是0.09.它并不是完全等于我們的期望輸出值0,但是0.09也已經是非常接近這個期望了。假設我們初始化權重w=b=2.0,那么神經元初始輸出值是0.98,這是一個非常糟糕的輸出。你可以點擊下面示例中的“Run”按鈕,來觀察一下這個神經元是如何學習的。
補圖,js效果(文章頭部有原文鏈接,可至原文觀看)
雖然我們在這兩個例子中使用了同樣的學習率(η=0.15),但是我們發現第二例子的學習速度要更慢一些。事實上,第一個示例在差不多150次迭代的時候,權重w和偏移b基本上就不再改變了,神經元的輸出也更快的接近期望值0.
這個神經元的學習過程和人類的學習過程并不相同。我在本章內容的開端曾說過,我們經常能夠從嚴重的錯誤中獲得更高的學習效率。但是神經元從嚴重錯誤中學習進步卻比較困難,相比簡單的錯誤,神經元反而能學習的更快。經過人們的研究發現,這種現象并不是僅僅在我們這個簡單神經元訓練中出現,在其他神經網絡的訓練中也經常出現。那么為什么神經元不能從錯誤中獲得更高的學習效率呢?是否能發掘一種方法來避免這種現象出現?
更進一步的探尋這個問題,我們發現這個神經元在學習訓練過程中,是以損失函數對權重W和偏移b的偏導數決定的方向不斷更改W和b的取值,即?C/?w和?C/?b。所以我們說“學習效率低”實際上與說偏導數太小是等價的。那么問題的根源就是為什么這兩個偏導數比較小,那我們先來計算一下這兩個偏導數看看真實的情況是什么樣子的。我們在這個示例中使用的是平方損失函數,定義如下所示
在該表達式中,a是神經元在輸入x=1時的輸出值,y=0是我們的期望輸出值。但實際上,這個表達式是W和b的函數,其中a=σ(z),而z=wx+b。(σ是sigmoid激活函數。)應用導數鏈式規則可得到兩個偏導數如下所示:
在上式中,我們最后將y=0和x=1分別代入該表達式。我們再接下來看看上式中的σ′(z)。σ函數如下圖所示
通過上面這張函數圖像,可知當神經元的輸出取值接近1的時候,曲線變的非常平,σ′(z)取值也就非常小。上面的等式(55)和(56)這時的取值就是非常小。這就是學習速度變慢的根本原因所在。隨后我們將看到在一般的神經網絡中,學習速度變慢也是由這個原因引起的,我們的這個簡單示例并不是特例。
交叉熵損失函數簡介
我們應該如何應對學習速度慢的問題?經過上面的分析證明,我們可以通過將平方損失函數替換成一個其他類型的損失函數來避免這個問題。為了能更明白的解釋交叉熵函數,我們會對上面那個單神經元的示例進行一些擴展。我們假定我們要訓練的神經元具備多個變量輸入,x1,x2,….,每個變量對應的權重為w1,w2,…,該神經元偏移為b
這個神經元的輸出值是a=σ(z),其中z=∑jwjxj+b.我們將這個神經元的交叉熵函數定義如下
在上式中的n代表訓練樣本數,對所有的樣本輸入x,神經元輸出a和標簽y按上式進行累加求和。
我們很難從直觀上觀察出這個函數表達式對解決學習速度降低問題是否有效。實際上,我們甚至不確定這個函數表達的含義跟我們理解的“損失”含義是否一致。因此,讓我們先明確一下這個函數能被用來做損失函數的原因。
交叉熵函數能夠被用來做損失函數的原因有兩個。第一,函數是非負的,也就是說該函數取值C>0。(注意:由于a=σ(z)是sigmoid函數的取值,所以00。)第二,當神經元的輸出跟我們期望輸出越接近,交叉熵函數的取值越接近0。為什么呢?由于訓練樣本中y=0,如果神經元輸出值a≈0,此時神經元的輸出與期望輸出非常接近,而交叉熵函數中的ylna=0,并且(1-y)ln(1-a)≈0,累加所有項之后則有C≈0,即可說明當神經元的輸出跟我們期望輸出越接近,交叉熵函數的取值越接近0。同理,如果y=1,神經元的輸出a≈1,交叉熵函數取值也接近0。
綜上可知,交叉熵函數是一個取值大于0,并且當神經元的輸出與y越接近,其取值就越接近0,這恰恰就是我們選擇損失函數的標準(注:平方損失函數也可以簡單的推導出這兩條特性),所以理論上交叉熵函數是可以用作損失函數的。
下一個問題,交叉熵函數能避免學習速度降低的問題嗎?我們先計算交叉熵函數的對W和b的偏導數,令a=σ(z),同時利用鏈式求導規則,可以得到下面的表達式
對上面的表達式做一些基礎運算,就可以得到下面的表達式
其中σ(z)=1/(1+e-z),對其求導可知σ′(z)=σ(z)(1-σ(z))。我希望你能在下面的練習章節中自己推到這個等式,現在我們就直接使用該等式。當我們把σ′(z)代入等式(60),就可以將其簡化成下面的表達式
這是一個非常漂亮的表達式。通過該表達式可知,學習速度依賴于(σ(z)-y)的取值。(σ(z)-y)在一定程度上反映了錯誤的程度,也就是說錯誤越大,神經元每次改變w和b的幅度越大,學習速度就越快,這似乎與我們的直覺更加接近(對比作者鋼琴演奏的例子)。同時,這個函數也可以避免像表達式(55)那樣出現由于σ′(z)平滑而帶來的學習速度降低的問題。當我們使用交叉熵函數作為損失函數時,我們不再需要計算σ′(z),也就不再需要擔心它的取值太小帶來的問題。正是由于我們使用了交叉熵函數,它使我們完全避免了這個問題,你也許會認為這是一個很神奇的事情。其實這并不是一個很神奇的事情,我們一會就會讓你了解到,選擇交叉熵函數確實是由于它具備這一特性。
我們以同樣的方式計算偏移b的偏導數,我不會再給出詳細的證明步驟,你可以自己驗證下面的表達式
同樣,對比表達式(56),這再次避免了σ′(z)帶來的學習速度降低的問題
練習
證明表達式:σ′(z)= σ(z)(1-σ(z))
讓我們回到最開始的單神經元簡單示例中,看看當我們使用交叉熵函數替換平方損失函數后都發生了些什么。我們首先看一下,在平方函數表現較好的情況下,交叉熵函數的表現。在下圖中,我們使用交叉熵函數替換了平方損失函數,初始化權重w=0.6,權重b=0.9,點擊下方的“Run”按鈕,可以觀察訓練過程:
補圖,js效果(文章頭部有原文鏈接,可至原文觀看)
不出意外,采用交叉熵函數的神經元學習的過程表現良好,與采用平方損失函數的神經元學習過程類似。接下來我們將權重w和偏移b都設置成2.0,采用平方損失函數的神經元訓練過程并不理想(可觀察上面示例),我們看一下采用交叉熵函數的神經元訓練效果如何,如下圖所示:
補圖,js效果(文章頭部有原文鏈接,可至原文觀看)
通過上圖可知,采用交叉熵函數的神經元訓練過程非常迅速,并且正向我們預期那樣得到了很好的效果。如果你仔細觀察的話,你會發現采用交叉熵函數的訓練的曲線在初始階段要比平方損失函數曲線更加陡峭。曲線的坡度比較大,說明了交叉熵函數正像我們預期的那樣從錯誤中學習的更快。
在這兩個例子中,我并沒有像平方損失函數示例中那樣指明學習率的取值。在平方損失函數中,我們將η設置為0.15。我們也應該在交叉熵損失函數中采用相同的值嗎?事實上,損失函數不同,很難準確的定義相同的學習率,就像蘋果和橘子的對比一樣。在這幾個例子中,我們設置學習率的標準是可以讓我們更容易的看清楚神經元的學習過程。假如你仍舊好奇,我們可以公布我們在交叉熵損失函數中采用的學習率:η=0.005。
你可能會認為學習率的改變會使上述幾個示例失去了對比意義。當你在隨機初始化設置學習率參數時,誰知道神經元學習速度會有多快呢?這種想法忽略了問題的重點。這幾張圖的重點不是神經元訓練的絕對速度對比,而是神經元的學習速度是怎樣變化的。在對比示例中,采用平方損失函數要比采用交叉熵損失函數,隨著神經元在逐漸接近正確值的過程中,神經元從錯誤中學習的速度要慢很多。這是不依賴于學習率參數的設置的。
我們已經研究了交叉熵函數對單個神經元的作用。我們可以輕易的將交叉熵函數應用推廣到多層神經網絡的多個神經元中。我們假設y=y1,y2,…是神經元的期望輸出值,這些神經元位于最終的輸出層,而aL1,aL2,..是輸出層的實際輸出。我們可以定義交叉熵函數如下
這個表達式跟我們表達式(57)非常相似,不同的地方是我們對所有的輸出神經元進行了累加求和。我不會通過求導再證明這個表達式在避免學習速度下降方面的作用,從表面上看它在多層神經網絡上應該是有效的。假如你對這個感興趣,你可以自己通過求導驗證。
我們應該在什么時候采用交叉熵函數替換平方損失函數呢?事實上,在采用sigmoid函數作為激活函數的神經網絡中,交叉熵函數基本上總是更好的選擇。讓我們看看原因是什么,當我們在建立神經網絡時,我們會隨機初始化權重和偏移。這些隨機選擇的初始值會對某些輸入給出錯誤的輸出,也就是說神經元在應該輸出0的時候,錯誤的輸出了1,或者相反的情況也有可能,這種情況基本上不可避免的總會出現。如果我們采用平方損失函數,神經元會學習速度比較慢。由于權重會持續從訓練樣本中學習,因此甚至可能會出現無法最終收斂,這顯然不是我們想要的。
練習
l一個關于交叉熵函數可能會混淆的點是y和a在函數中的位置。你有可能會將?[ylna+(1?y)ln(1?a)]記成?[alny+(1?a)ln(1?y)]。想想第二個表達式當y=0或者y=1會發生什么?這些情況是否會影響第一個表達式?想想為什么。
l在本章節開始的示例中,我們假設交叉熵函數輸出值很小,并且對于所有的訓練樣本都有σ(z)≈y。這個假設依賴于y只能取值0或者1。在分類問題時,這種建設是沒有問題的,但是對其他問題(如回歸問題)y可能取值位于0和1之間。事實是當σ(z)=y時,交叉熵函數會取到最小值(注:對表達式63中的變量a求偏導,可知最小值點為a=y,即σ(z)=y,將a=y代入表達式63,即可得到下面的表達式),該最小值為:
表達式?[ylny+(1?y)ln(1?y)]有時候也被稱為二元熵
問題
l在多層多神經元網絡中,交叉熵函數是否有效性。
按照我們提到的計算方法,平方損失函數對輸出層權重的偏導數是:
當神經元處于最后的收斂階段時,σ′(zLj)會讓學習的速度快速下降。對于交叉熵函數來說,對于單個輸入x,其輸出誤差δL是
因此,在采用交叉熵函數的神經網絡的輸出層,損失函數對輸出層權重的偏導數是
σ′(zLj)也消失了,所以交叉熵函數能夠避免學習速度下降的問題。交叉熵函數并不僅僅在單個神經元中生效,在更復雜的多層多個神經元網絡中也能起到效果。對于偏差b的證明也是類似的過程,如果你對這一證明過程抱有疑問,你可以自己利用公式推導出這一結果。
l如果神經網絡的輸出層采用線性激活函數,則可以使用平方損失函數。
假定在多層神經網絡結構的輸出層采用線性激活函數,也就是說不采用sigmoid函數激活,輸出層激活規則aLj=zLj。在這種情況下,采用平方損失函數的輸出誤差δL為
跟前面的處理過程類似,計算平方損失函數對輸出層權重w和偏移b的偏導數如下
這說明如果激活函數是線性函數,平方損失函數并不會造成學習速度的下降。事實上,在采用線性激活函數的情況下,平方損失函數是一個很合適的選擇。
將交叉熵函數應用到手寫數字識別
未完....