天天看點

深度學習(四)-前饋神經網絡

  在前饋神經網絡中,各神經元分别屬于不同的層。每一層的神經元可以接收前一層神經元的信号,并産生信号輸出到下一層。第 0 層叫輸入層,最後一層叫輸出層,其它中間層叫做隐藏層,相鄰兩層的神經元之間為全連接配接關系,也稱為全連接配接神經網絡( F N N FNN FNN),表現形式如下圖所示。

深度學習(四)-前饋神經網絡

  我們用下面的記号來描述一個前饋神經網絡:

     L L L:表示神經網絡的層數

     m ( l ) m^{(l)} m(l):表示第 l l l 層神經元的個數

     f l ( ⋅ ) f_l(·) fl​(⋅):表示 l l l 層神經元的激活函數

     W ( l ) W^{(l)} W(l):表示 l − 1 l−1 l−1 層到第 l l l 層的權重矩陣

     b ( l ) b^{(l)} b(l):表示 l − 1 l−1 l−1 層到第 l l l 層的偏置

     z ( l ) z^{(l)} z(l):表示 l l l 層神經元的淨輸入

     a ( l ) a^{(l)} a(l):表示 l l l 層神經元的輸出

  前饋神經網絡通過下面公式進行資訊傳播:

z ( l ) = W ( l ) ∗ a ( l − 1 ) + b ( l ) z^{(l)} = W ^{(l)} * a^{(l−1)} + b^{(l)} z(l)=W(l)∗a(l−1)+b(l)

a ( l ) = f l ( z ( l ) ) a^{(l)} = f_l(z^{(l)}) a(l)=fl​(z(l))

  上面兩式也可以得到:

z ( l ) = W ( l ) ∗ f l − 1 ( z ( l − 1 ) ) + b ( l ) z^{(l)} = W^{(l)}* f_{l−1}(z^{(l−1)}) + b^{(l)} z(l)=W(l)∗fl−1​(z(l−1))+b(l)

  或者

a ( l ) = f l ( W ( l ) ∗ a ( l − 1 ) + b ( l ) ) a^{(l)} = f_l(W^{(l)}*a^{(l−1)} + b^{(l)}) a(l)=fl​(W(l)∗a(l−1)+b(l))

  這樣,前饋神經網絡可以通過逐層的資訊傳遞,得到網絡最後的輸出 a ( l ) a^{(l)} a(l)。整個網絡可以看作一個複合函數 ϕ ( x ; W , b ) ϕ(x; W, b) ϕ(x;W,b),将向量 x x x 作為第1層的輸入 a ( 0 ) a(0) a(0),将第 L L L 層的輸出 a ( L ) a(L) a(L) 作為整個函數的輸出。

x = a ( 0 ) → z ( 1 ) → a ( 1 ) → z ( 2 ) → ⋅ ⋅ ⋅ → a ( L − 1 ) → z ( L ) → a ( L ) = φ ( x ; W , b ) ) x = a(0) → z(1) → a(1) → z(2) → · · · → a(L−1) → z(L) → a(L) = φ(x; W, b)) x=a(0)→z(1)→a(1)→z(2)→⋅⋅⋅→a(L−1)→z(L)→a(L)=φ(x;W,b))

  其中 W , b W, b W,b 表示網絡中所有層的連接配接權重和偏置。

1. 反向傳播算法

  上面簡單的介紹了前饋神經網絡,我們發現一個神經網絡的輸出好壞是由參數 W , b W,b W,b 決定的,那麼訓練神經網絡的過程其實就是不斷的更新參數來得到最好的結果,在前面的pytorch學習(一)-線性回歸中使用了損失函數 f f f 來控制模型訓練的結果,其本質就是需要計算出 f f f 的梯度 ∇ f \nabla f ∇f,反向傳播算法就是一個有效地求解梯度的算法。

1.1 鍊式法則

  假設有一個函數 f ( x , y , z ) = ( x + y ) z f(x,y,z)=(x+y)z f(x,y,z)=(x+y)z,我們需要對其求微分,當然很多人一眼就可以看出 f ( x , y , z ) f(x,y,z) f(x,y,z) 對 x x x, y y y, z z z 的微分,但是如果函數複雜呢,是以我們換一種方式,假設 q = x + y q=x+y q=x+y, 那麼可以求得微分:

∂ f ∂ q = z ; ∂ f ∂ z = q ; ∂ q ∂ x = 1 ; ∂ q ∂ y = 1 \frac{{\partial f}}{{\partial q}} = z;\frac{{\partial f}}{{\partial z}} = q;\frac{{\partial q}}{{\partial x}} = 1;\frac{{\partial q}}{{\partial y}} = 1 ∂q∂f​=z;∂z∂f​=q;∂x∂q​=1;∂y∂q​=1

  但是我們關心的是 ∂ f ∂ x , ∂ f ∂ y , ∂ q ∂ z \frac{{\partial f}}{{\partial x}},\frac{{\partial f}}{{\partial y}},\frac{{\partial q}}{{\partial z}} ∂x∂f​,∂y∂f​,∂z∂q​,是以可以得到:

∂ f ∂ x = ∂ f ∂ q ∂ q ∂ x \frac{{\partial f}}{{\partial x}} = \frac{{\partial f}}{{\partial q}}\frac{{\partial q}}{{\partial x}} ∂x∂f​=∂q∂f​∂x∂q​

∂ f ∂ y = ∂ f ∂ q ∂ q ∂ y \frac{{\partial f}}{{\partial y}} = \frac{{\partial f}}{{\partial q}}\frac{{\partial q}}{{\partial y}} ∂y∂f​=∂q∂f​∂y∂q​

∂ f ∂ z = q \frac{{\partial f}}{{\partial z}} = q ∂z∂f​=q

  從上面我們可以看出,如果需要對函數的元素求導,那麼可以一層一層求導,然後将結果乘起來,這就是鍊式法則,同時也是反向傳播算法的核心。

1.2 反向傳播算法

  給定一個樣本 ( x , y ) (x, y) (x,y),将其輸入到神經網絡模型中,得到網絡輸出為 y ′ y' y′。假設損失函數為 L ( y , y ′ ) L(y, y') L(y,y′),要進行

參數學習就需要計算損失函數關于每個參數的導數。對第 l l l 層中的參數權重 W ( l ) W^{(l)} W(l) 和偏置 b ( l ) b^{(l)} b(l) 計算偏導數。

∂ L ( y , y ′ ) ∂ W i j ( l ) = ∂ L ( y , y ′ ) ∂ z l ( ∂ z l ∂ W i j ( l ) ) \frac{{\partial L(y,y')}}{{\partial W_{ij}^{(l)}}} = \frac{{\partial L(y,y')}}{{\partial {z^l}}}(\frac{{\partial {z^l}}}{{\partial W_{ij}^{(l)}}}) ∂Wij(l)​∂L(y,y′)​=∂zl∂L(y,y′)​(∂Wij(l)​∂zl​)

∂ L ( y , y ′ ) ∂ b ( l ) = ∂ L ( y , y ′ ) ∂ z l ( ∂ z l ∂ b ( l ) ) \frac{{\partial L(y,y')}}{{\partial {b^{(l)}}}} = \frac{{\partial L(y,y')}}{{\partial {z^l}}}(\frac{{\partial {z^l}}}{{\partial {b^{(l)}}}}) ∂b(l)∂L(y,y′)​=∂zl∂L(y,y′)​(∂b(l)∂zl​)

  其中 ∂ L ( y , y ′ ) ∂ z l \frac{{\partial L(y,y')}}{{\partial {z^l}}} ∂zl∂L(y,y′)​為目标函數關于第 l l l 層的神經元 z ( l ) z^{(l)} z(l) 的偏導數,稱為誤差項,是以需要計算三個偏導數,分别為 ∂ L ( y , y ′ ) ∂ z l \frac{{\partial L(y,y')}}{{\partial {z^l}}} ∂zl∂L(y,y′)​, ( ∂ z l ∂ W i j ( l ) ) (\frac{{\partial {z^l}}}{{\partial W_{ij}^{(l)}}}) (∂Wij(l)​∂zl​), ( ∂ z l ∂ b ( l ) ) (\frac{{\partial {z^l}}}{{\partial {b^{(l)}}}}) (∂b(l)∂zl​),可以得到:

∂ z l ∂ W i j ( l ) = ∂ ( W ( l ) a ( l − 1 ) + b ( l ) ) ∂ W i j ( l ) \frac{{\partial {z^l}}}{{\partial W_{ij}^{(l)}}} = \frac{{\partial ({W^{(l)}}{a^{(l - 1)}} + {b^{(l)}})}}{{\partial W_{ij}^{(l)}}} ∂Wij(l)​∂zl​=∂Wij(l)​∂(W(l)a(l−1)+b(l))​

∂ z l ∂ b ( l ) = ∂ ( W ( l ) a ( l − 1 ) + b ( l ) ) ∂ b ( l ) \frac{{\partial {z^l}}}{{\partial {b^{(l)}}}} = \frac{{\partial ({W^{(l)}}{a^{(l - 1)}} + {b^{(l)}})}}{{\partial {b^{(l)}}}} ∂b(l)∂zl​=∂b(l)∂(W(l)a(l−1)+b(l))​

  是以權重矩陣 W ( l ) W^(l) W(l) 的第 i i i 行為 a j ( l − 1 ) a_j^{(l - 1)} aj(l−1)​,偏置為 1。

  因為 z ( l + 1 ) = W ( l + 1 ) a ( l ) + b ( l + 1 ) z^{(l+1)} = W ^{(l+1)}a^{(l)} + b^{(l+1)} z(l+1)=W(l+1)a(l)+b(l+1), 且 a ( l ) = f l ( z ( l ) ) a^{(l)} = f_l(z^{(l)}) a(l)=fl​(z(l)),同時 f l ( ⋅ ) fl(·) fl(⋅) 為按位計算的函數,得到:

∂ z ( l + 1 ) ∂ a l = ( W ( l + 1 ) ) T \frac{{\partial {z^{(l + 1)}}}}{{\partial {a^l}}}=(W^{(l+1)})^T ∂al∂z(l+1)​=(W(l+1))T

∂ a l ∂ z l = d i a g ( f l ′ ( z ( l ) ) ) \frac{{\partial {a^l}}}{{\partial {z^l}}}=diag(f_l'(z^{(l)})) ∂zl∂al​=diag(fl′​(z(l)))

= ∂ L ( y l , y l ′ ) ∂ z l = ∂ ( y l − y l ′ ) ∂ z l = ∂ ( y l − W l a ( l − 1 ) + b l ) ∂ z l = ∂ ( y l − W l f l − 1 ( z ( l − 1 ) ) + b l ) ∂ z l =\frac{{\partial L({y_l},{y_l}')}}{{\partial {z^l}}} = \frac{{\partial ({y_l} - {y_l}')}}{{\partial {z^l}}} = \frac{{\partial ({y_l} - {W^l}{a^{(l - 1)}} + {b^l})}}{{\partial {z^l}}} = \frac{{\partial ({y_l} - {W^l}{f_{l - 1}}({z^{(l - 1)}}) + {b^l})}}{{\partial {z^l}}} =∂zl∂L(yl​,yl​′)​=∂zl∂(yl​−yl​′)​=∂zl∂(yl​−Wla(l−1)+bl)​=∂zl∂(yl​−Wlfl−1​(z(l−1))+bl)​

= > ∂ L ( y , y ′ ) ∂ z l = ∂ L ( y , y ′ ) ∂ z l + 1 ∂ z ( l + 1 ) ∂ a l ∂ a l ∂ z l =>\frac{{\partial L(y,y')}}{{\partial {z^l}}} = \frac{{\partial L(y,y')}}{{\partial {z^{l + 1}}}}\frac{{\partial {z^{(l + 1)}}}}{{\partial {a^l}}}\frac{{\partial {a^l}}}{{\partial {z^l}}} =>∂zl∂L(y,y′)​=∂zl+1∂L(y,y′)​∂al∂z(l+1)​∂zl∂al​

  其中 d i a g ( x ) diag(x) diag(x) 為對角矩陣,其對角線元素為 x x x,⊙ 是向量的點積運算符,表示每個元素相乘。我們用 δ l \delta^l δl來定義第 l l l 層神經元的誤差項,那麼 :

δ l = d i a g ( f l ′ ( z ( l ) ) ) ⋅ ( W ( l + 1 ) ) T ⋅ δ ( l + 1 ) = f l ′ ( z ( l ) ) ⊙ ( ( W ( l + 1 ) ) T ⋅ δ ( l + 1 ) ) \delta^l= diag(f_l'(z^{(l)})) · (W^{(l+1)})^T · δ^{(l+1)}=f_l'(z^{(l)})\odot ((W^{(l+1)})^T · δ^{(l+1)}) δl=diag(fl′​(z(l)))⋅(W(l+1))T⋅δ(l+1)=fl′​(z(l))⊙((W(l+1))T⋅δ(l+1))

  從上式可以看到,第 l l l 層的誤差項可以通過第 l + 1 l+1 l+1 層的誤差項計算得到,這就是誤差的反向傳播。反向傳播算法的含義是:第 l l l 層的一個神經元的誤差項是所有與該神經元相連的第 l + 1 l+1 l+1 層的神經元的誤差項的權重和,然後再乘上該神經元激活函數的梯度。計算出三個偏導之後,重新算出參數的梯度:

∂ L ( y , y ′ ) ∂ W i j ( l ) = δ i ( l ) ∏ i ( a j ( l − 1 ) ) T = δ i ( l ) a j ( l − 1 ) = > ∂ L ( y , y ′ ) ∂ W ( l ) = δ ( l ) ( a ( l − 1 ) ) T \frac{{\partial L(y,y')}}{{\partial W_{ij}^{(l)}}} = \delta _i^{(l)}\prod\nolimits_i {{{(a_j^{(l - 1)})}^T}} = \delta _i^{(l)}a_j^{(l - 1)} = > \frac{{\partial L(y,y')}}{{\partial W_{}^{(l)}}} = \delta _{}^{(l)}{(a_{}^{(l - 1)})^T} ∂Wij(l)​∂L(y,y′)​=δi(l)​∏i​(aj(l−1)​)T=δi(l)​aj(l−1)​=>∂W(l)​∂L(y,y′)​=δ(l)​(a(l−1)​)T

∂ L ( y , y ′ ) ∂ b ( l ) = δ ( l ) \frac{{\partial L(y,y')}}{{\partial b_{}^{(l)}}} = \delta _{}^{(l)} ∂b(l)​∂L(y,y′)​=δ(l)​

2. 自動梯度計算

  神經網絡的參數主要通過梯度下降來進行優化的。當确定了風險函數以及網絡結構後,我們就可以手動用鍊式法則來計算風險函數對每個參數的梯度,并用代碼進行實作。但是手動求導并轉換為計算機程式的過程非常瑣碎并容易出錯,導緻實作神經網絡變得十分低效。目前,幾乎所有的主流深度學習架構都包含了自動梯度計算的功能,即我們可以隻考慮網絡結構并用代碼實作,其梯度可以自動進行計算,無需人工幹預。這樣開發的效率就大大提高了,常見的梯度計算有三類:數值微分、符号微分、自動微分。想深究的同學可以看看邱錫鵬老師《神經網絡與深度學習》第二張第4.5小結,講述的很清楚。

3. 梯度優化

  深度學習中主要使用的梯度下降的方法, P y t o r c h Pytorch Pytorch 中有封裝 t o r c h . o p t i m torch.optim torch.optim 子產品來優化梯度,我這裡下降梯度都用 1e-1 代替,具體使用具體設定。主要有以下幾種:

3.1 SGD

  随機梯度下降法是梯度下降法的一個小變形,就是每次使用一批資料進行梯度的計算,而不是計算全部資料的梯度。因為現在深度學習的資料量都特别大, 是以每次都計算所有資料的梯度是不現實的,這樣會導緻運算時間特别長,同時每次都計算全部的梯度還失去了一些随機性, 容易陷入局部誤差,是以使用随機梯度下降法可能每次都不是朝着真正最小的方向.但是這樣反而容易跳出局部極小點。

   p y t o r c h pytorch pytorch 表示為: t o r c h . o p t i m . S G D ( p a r a m e t e r s , 1 e − 1 ) torch.optim.SGD(parameters, 1e-1) torch.optim.SGD(parameters,1e−1)

3.2 Momentum

  在随機梯度下降的同時,增加動量,其計算基于前面梯度,也就是說參數更新不僅僅基于目前的梯度,也基于之前的梯度

   p y t o r c h pytorch pytorch 表示為: t o r c h . o p t i m . S G D ( p a r a m e t e r s , 1 e − 1 , m o m e n t u m = 0.9 ) torch.optim.SGD(parameters, 1e-1, momentum=0.9) torch.optim.SGD(parameters,1e−1,momentum=0.9)

3.3 Adagrad

  自适應學習率,表現形式為:

w t − η ∑ i = 0 t ( g i ) 2 + ε g t − > w t + 1 {w^t} - \frac{\eta }{{\sqrt {\sum\nolimits_{i = 0}^t {{{({g^i})}^2} + \varepsilon } } }}{g^t} - > {w^{t + 1}} wt−∑i=0t​(gi)2+ε

​η​gt−>wt+1

  我們可以看到學習率在不斷變小, 且受每次計算出來的梯度影響 ,對于梯度比較大的參數,它的學習率就會變得相對更小 ,裡面的根号特别重要,沒有這個根号算法表現非常差。同時 ε \varepsilon ε 是一個平滑參數,通常設定為 1e-4~1e-8,這是為了避免分母為 0。但是自适應學習率在某些情況下一直遞減的學習率并不好,這樣會造成學習過早停止。

   p y t o r c h pytorch pytorch 表示為: t o r c h . o p t i m . A d a g r a d ( p a r a m e t e r s , 1 e − 1 ) torch.optim.Adagrad(parameters, 1e-1) torch.optim.Adagrad(parameters,1e−1)

3.4 RMSprop

c a c h e t = α ∗ c a c h e t − 1 + ( 1 − α ) ( g t ) 2 cach{e^t} = \alpha *cach{e^{t - 1}} + (1 - \alpha ){({g^t})^2} cachet=α∗cachet−1+(1−α)(gt)2

w t − η c a c h e t + ε g t − > w t + 1 {w^t} - \frac{\eta }{{\sqrt {cach{e^t} + \varepsilon } }}{g^t} - > {w^{t + 1}} wt−cachet+ε

​η​gt−>wt+1

   R M S p r o p RMSprop RMSprop 這裡相比較 A d a g r a d Adagrad Adagrad 多了一個衰減 α \alpha α, 這樣就不再會将前面所有的梯度平方求和,而是通過一個衰減率将其變小,使用了一種滑動平均的方式,越靠前面的梯度對自适應的學習率影響越小,這樣就能更加有效地避免 A d a g r a d Adagrad Adagrad 學習率一直遞減太多的問題,能夠更快地收斂 。

   p y t o r c h pytorch pytorch 表示為: t o r c h . o p t i m . R M S p r o p ( p a r a m e t e r s , 1 e − 1 ) torch.optim.RMSprop(parameters, 1e-1) torch.optim.RMSprop(parameters,1e−1)

3.5 Adam

  這是一種綜合型的學習方法,可以看成是 R M S p r o p RMSprop RMSprop 加上 M o m e n t u m Momentum Momentum 的學習方法,達到比 R M S P r o p RMSProp RMSProp 更好的效果。

   p y t o r c h pytorch pytorch 表示為: t o r c h . o p t i m . A d a m ( p a r a m e t e r s , 1 e − 1 ) torch.optim.Adam(parameters, 1e-1) torch.optim.Adam(parameters,1e−1)

參考

  1. 邱錫鵬:《神經網絡與深度學習》 https://nndl.github.io/
  2. 廖星宇:《深度學習之pytorch》

繼續閱讀