詳解神經網絡的前向傳播和反向傳播(從頭推導)


詳解神經網絡的前向傳播和反向傳播
本篇博客是對Michael Nielsen所著的《Neural Network and Deep Learning》第2章內容的解讀,有興趣的朋友可以直接閱讀原文Neural Network and Deep Learning。

  對神經網絡有些了解的人可能都知道,神經網絡其實就是一個輸入XX到輸出YY的映射函數:f(X)=Yf(X)=Y,函數的系數就是我們所要訓練的網絡參數WW,只要函數系數確定下來,對於任何輸入xixi我們就能得到一個與之對應的輸出yiyi,至於yiyi是否符合我們預期,這就屬於如何提高模型性能方面的問題了,本文不做討論。

  那么問題來了,現在我們手中只有訓練集的輸入XX和輸出YY,我們應該如何調整網絡參數WW使網絡實際的輸出f(X)=Y^f(X)=Y^與訓練集的YY盡可能接近?

  在開始正式講解之前,讓我們先對反向傳播過程有一個直觀上的印象。反向傳播算法的核心是代價函數CC對網絡中參數(各層的權重ww和偏置bb)的偏導表達式∂C∂w∂C∂w和∂C∂b∂C∂b。這些表達式描述了代價函數值CC隨權重ww或偏置bb變化而變化的程度。到這里,BP算法的思路就很容易理解了:如果當前代價函數值距離預期值較遠,那么我們通過調整ww和bb的值使新的代價函數值更接近預期值(和預期值相差越大,則ww和bb調整的幅度就越大)。一直重復該過程,直到最終的代價函數值在誤差范圍內,則算法停止。

  BP算法可以告訴我們神經網絡在每次迭代中,網絡的參數是如何變化的,理解這個過程對於我們分析網絡性能或優化過程是非常有幫助的,所以還是盡可能搞透這個點。我也是之前大致看過,然后發現看一些進階知識還是需要BP的推導過程作為支撐,所以才重新整理出這么一篇博客。

前向傳播過程
  在開始反向傳播之前,先提一下前向傳播過程,即網絡如何根據輸入XX得到輸出YY的。這個很容易理解,粗略看一下即可,這里主要是為了統一后面的符號表達。


記wljkwjkl為第l−1l−1層第kk個神經元到第ll層第jj個神經元的權重,bljbjl為第ll層第jj個神經元的偏置,aljajl為第ll層第jj個神經元的激活值(激活函數的輸出)。不難看出,aljajl的值取決於上一層神經元的激活:
alj=σ(∑kwljkal−1k+blj)(1)
(1)ajl=σ(∑kwjklakl−1+bjl)
將上式重寫為矩陣形式:
al=σ(wlal−1+bl)(2)
(2)al=σ(wlal−1+bl)
為了方便表示,記 zl=wlal−1+blzl=wlal−1+bl為每一層的權重輸入, (2)(2)式則變為 al=σ(zl)al=σ(zl)。
  利用 (2)(2)式一層層計算網絡的激活值,最終能夠根據輸入 XX得到相應的輸出Y^Y^。
反向傳播過程
  反向傳播過程中要計算∂C∂w∂C∂w和∂C∂b∂C∂b,我們先對代價函數做兩個假設,以二次損失函數為例:
C=12n∑x∥y(x)−aL(x)∥2(3)
(3)C=12n∑x‖y(x)−aL(x)‖2
其中 nn為訓練樣本xx的總數, y=y(x)y=y(x)為期望的輸出,即ground truth, LL為網絡的層數,aL(x)aL(x)為網絡的輸出向量。
假設1:總的代價函數可以表示為單個樣本的代價函數之和的平均:
C=1n∑xCx  Cx=12∥y−aL∥2(4)
(4)C=1n∑xCx  Cx=12‖y−aL‖2

  這個假設的意義在於,因為反向傳播過程中我們只能計算單個訓練樣本的 ∂Cx∂w∂Cx∂w和 ∂Cx∂b∂Cx∂b,在這個假設下,我們可以通過計算所有樣本的平均來得到總體的 ∂C∂w∂C∂w和 ∂C∂b∂C∂b
假設2:代價函數可以表達為網絡輸出的函數 costC=C(aL)costC=C(aL),比如單個樣本 xx的二次代價函數可以寫為:
Cx=12∥y−aL∥2=12∑j(yj−aLj)2(5)
(5)Cx=12‖y−aL‖2=12∑j(yj−ajL)2
反向傳播的四個基本方程
  權重ww和偏置bb的改變如何影響代價函數CC是理解反向傳播的關鍵。最終,這意味着我們需要計算出每個∂C∂wljk∂C∂wjkl和∂C∂blj∂C∂bjl,在討論基本方程之前,我們引入誤差δδ的概念,δljδjl表示第ll層第jj個單元的誤差。關於誤差的理解,《Neural Network and Deep Learning》書中給了一個比較形象的例子。


  如上圖所示,假設有個小惡魔在第ll層第jj個單元搗蛋,他讓這個神經元的權重輸出變化了ΔzljΔzjl,那么這個神經元的激活輸出為σ(zlj+Δzlj)σ(zjl+Δzjl),然后這個誤差向后逐層傳播下去,導致最終的代價函數變化了∂C∂zljΔzlj∂C∂zjlΔzjl。現在這個小惡魔改過自新,它想幫助我們盡可能減小代價函數的值(使網絡輸出更符合預期)。假設∂C∂zlj∂C∂zjl一開始是個很大的正值或者負值,小惡魔通過選擇一個和∂C∂zlj∂C∂zjl方向相反的ΔzljΔzjl使代價函數更小(這就是我們熟知的梯度下降法)。隨着迭代的進行,∂C∂zlj∂C∂zjl會逐漸趨向於0,那么ΔzljΔzjl對於代價函數的改進效果就微乎其微了,這時小惡魔就一臉驕傲的告訴你:“俺已經找到了最優解了(局部最優)”。這啟發我們可以用∂C∂zlj∂C∂zjl來衡量神經元的誤差:
δlj=∂C∂zlj
δjl=∂C∂zjl
下面就來看看四個基本方程是怎么來的。
  
1. 輸出層的誤差方程
δLj=∂C∂zLj=∂C∂aLj∂aLj∂zLj=∂C∂aLjσ′(zLj)(BP1)
(BP1)δjL=∂C∂zjL=∂C∂ajL∂ajL∂zjL=∂C∂ajLσ′(zjL)
如果上面的東西你看明白了,這個方程應該不難理解,等式右邊第一項 ∂C∂aLj∂C∂ajL衡量了代價函數隨網絡最終輸出的變化快慢,而第二項 σ′(zLj)σ′(zjL)則衡量了激活函數輸出隨 zLjzjL的變化快慢。當激活函數飽和,即 σ′(zLj)≈0σ′(zjL)≈0時,無論 ∂C∂aLj∂C∂ajL多大,最終 δLj≈0δjL≈0,輸出神經元進入飽和區,停止學習。
  (BP1)方程中兩項都很容易計算,如果代價函數為二次代價函數 C=12∑j(yj−aLj)2C=12∑j(yj−ajL)2,則 ∂C∂aLj=aLj−yj∂C∂ajL=ajL−yj,同理,對激活函數 σ(z)σ(z)求 zLjzjL的偏導即可求得 σ′(zLj)σ′(zjL)。將(BP1)重寫為矩陣形式:
δL=∇aC⊙σ′(zL)(BP1a)
(BP1a)δL=∇aC⊙σ′(zL)
⊙⊙為Hadamard積,即矩陣的點積。
2. 誤差傳遞方程
δl=((wl+1)Tδl+1)⊙σ′(zl)(BP2)
(BP2)δl=((wl+1)Tδl+1)⊙σ′(zl)
這個方程說明我們可以通過第 l+1l+1層的誤差 δl+1δl+1計算第 ll層的誤差δlδl,結合(BP1)和(BP2)兩個方程,我們現在可以計算網絡中任意一層的誤差了,先計算 δLδL,然后計算 δL−1δL−1, δL−2δL−2,…,直到輸入層。
證明過程如下:
δlj=∂C∂zlj=∑k∂C∂zl+1k∂zl+1k∂zlj=∑kδl+1k∂zl+1k∂zlj
δjl=∂C∂zjl=∑k∂C∂zkl+1∂zkl+1∂zjl=∑kδkl+1∂zkl+1∂zjl
因為 zl+1k=∑jwl+1kjalj+bl+1k=∑jwl+1kjσ(zlj)+bl+1kzkl+1=∑jwkjl+1ajl+bkl+1=∑jwkjl+1σ(zjl)+bkl+1,所以 ∂zl+1k∂zlj=wl+1kjσ′(zlj)∂zkl+1∂zjl=wkjl+1σ′(zjl),因此可以得到(BP2),
δlj=∑kwl+1kjδl+1kσ′(zlj)
δjl=∑kwkjl+1δkl+1σ′(zjl)

3. 代價函數對偏置的改變率
∂C∂blj=∂C∂zlj∂zlj∂blj=∂C∂zlj=δlj(BP3)
(BP3)∂C∂bjl=∂C∂zjl∂zjl∂bjl=∂C∂zjl=δjl
這里因為 zlj=∑kwljkal−1k+bljzjl=∑kwjklakl−1+bjl所以 ∂zLj∂bLj=1∂zjL∂bjL=1
4. 代價函數對權重的改變率
∂C∂wljk=∂C∂zlj∂zLj∂wljk=∂C∂zljal−1k=al−1kδlj(BP4)
(BP4)∂C∂wjkl=∂C∂zjl∂zjL∂wjkl=∂C∂zjlakl−1=akl−1δjl
可以簡寫為
∂C∂w=ainδout(6)
(6)∂C∂w=ainδout
,不難發現,當上一層激活輸出接近0的時候,無論返回的誤差有多大, ∂C∂w∂C∂w的改變都很小,這也就解釋了為什么神經元飽和不利於訓練。
  從上面的推導我們不難發現,當輸入神經元沒有被激活,或者輸出神經元處於飽和狀態,權重和偏置會學習的非常慢,這不是我們想要的效果。這也說明了為什么我們平時總是說激活函數的選擇非常重要。

  當我計算得到∂C∂wljk∂C∂wjkl和∂C∂blj∂C∂bjl后,就能愉悅地使用梯度下降法對參數進行一輪輪更新了,直到最后模型收斂。

反向傳播為什么快
  回答這個問題前,我們先看一下普通方法怎么求梯度。以計算權重為例,我們將代價函數看成是權重的函數C=C(w)C=C(w),假設現在網絡中有100萬個參數,我們可以利用微分的定義式來計算代價函數對其中某個權重wjwj的偏導:
∂C∂wj≈C(w+εej→)−C(w)ε(7)
(7)∂C∂wj≈C(w+εej→)−C(w)ε
然后我們算一下,為了計算 ∂C∂wj∂C∂wj,我們需要從頭到尾完整進行一次前向傳播才能得到最終 C(w+εej→)C(w+εej→)的值,要計算100萬個參數的偏導就需要前向傳播100萬次,而且這還只是一次迭代,想想是不是特別可怕?
  再反觀反向傳播算法,如方程(BP4)所示,我們只要知道 al−1kakl−1和 δljδjl就能計算出偏導 ∂C∂wljk∂C∂wjkl。激活函數值 al−1kakl−1在一次前向傳播后就能全部得到,然后利用(BP1)和(PB2)可以計算出 δljδjl,反向傳播和前向傳播計算量相當,所以總共只需2次前向傳播的計算量就能計算出所有的 ∂C∂wljk∂C∂wjkl。這比使用微分定義式求偏導的計算量少了不止一點半點,簡直是質的飛躍。
————————————————
版權聲明:本文為CSDN博主「Maples丶丶」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_16137569/article/details/81449209


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM