反向傳播神經網絡推導中給出了複雜的BP公式。從頭看這篇多年的博客的公式,我都有點被繞暈了。現在在這裏我可以從矩陣計算的角度去演示一個全連接神經網絡的計算過程,這樣更簡潔明瞭。
如上圖,是一個簡單的分類全連接神經網絡,每一根線表示權重相乘。如果沒看透這個計算關係,那麼我們很容易這樣設計程序:每一個節點都製作一個class類,每個類節點要與其他類節點有連接關係,要傳遞數據,要計算梯度誤差。這樣做出來的神經網絡靈活性很強,但是真的是太複雜了!不靠譜!
假設我們只研究兩層數據之間的關係,每根線代表一個權重乘法。設權重爲w1ij ,前一層數據是x1i ,後一層數據爲x2j ,那麼後一層每一個數據就是x2i=∑ix1iw1ij+b1i 。爲了形象表示數據從左向右傳遞的過程,我寫成
[x11x12...]⎡⎣⎢⎢w11jw12j...⎤⎦⎥⎥+b11
如果我們擴展計算整個全連接層,就可以得到簡單的矩陣計算:
[x11x12...]⎡⎣⎢w111w121...w112w122......⎤⎦⎥+[b11b12...]=[x21x22...]→X1W1+B1=X2
所以,一個全連接層,實際上就是一個矩陣乘法和一個矩陣加法,數據都是向量,權重參數可以用矩陣表示,計算過程能夠編碼爲一個layer類,即一個神經網絡層。相應的,激活層其實就是對數據向量,逐個元素進行計算,即
Activation(X2)=[f(x21)f(x22)...]
這兩種操作都可以向量化,在GPU中跑的飛快;CPU使用MKL和BLAS庫也可以大大加速計算。
下面關鍵就是如何計算梯度來修正權重,梯度下降法的定義是
θnew=θold−∂F∂θ 。矩陣求導的公式(注意上標2並不是平方,是序號)是:
∂X2∂W1=(X1)T∂E∂B1=I
設損失函數爲E。
好了,假設我隨便做一個神經網絡,包含一層全連接層
fc1:Xfc1=XinputWfc1+Bfc1
,一層sigmoid激活層
sig:Xsig=sigmoid(Xfc1)
,一層全連接層,最後只輸出一個結果
fc2:y=Xfc2=XsigWfc2+Bfc2
,損失函數是Euclidean損失函數
E=12∑(y′i−yi)2 ,求和是因爲我們可能一次性計算一個批次的數據,即一個batch,把多次計算的誤差全部加起來。
輸出層誤差梯度爲:
δ4=∂E∂Xfc2=∑(y′i−yi)
fc2層要計算W、B的梯度,和一個向上傳遞的梯度:
δ3=∂E∂Wfc2=∂E∂Xfc2∂Xfc2∂Wfc2=XTsig∑(y′i−yi)=XTsigδ4∂E∂Bfc2=∑(y′i−yi)=δ4δup3=δ4WTfc2
sig層不包含W、B,只上傳梯度:
δup2=∂Xsig∂Xfc1δup3=Xsig.∗(1−Xsig).∗δup3
.*是元素相乘。這只是一個過渡層。
fc1層函數梯度:
δ1=∂E∂Wfc1=∂E∂Xfc2∂Xfc2∂Xsig∂Xsig∂Xfc1∂Xfc1∂Wfc1=XTinputδup2∂E∂Bfc1=∂E∂Xfc2∂Xfc2∂Xsig∂Xsig∂Xfc1∂Xfc1∂Bfc1=δup2
歸納總結一下:
* 設當前層序號爲n,輸入數據爲
Xn ,下一層向上傳遞的梯度爲
δupn+1 ,則當前層W更新梯度爲
XTnδupn+1 ,B更新梯度爲
δupn+1 ,向上傳遞的梯度爲
δupn+1WTn
* 如果當前層不包含W,B,例如激活層,則上傳向上傳遞梯度即可
* 輸出層的梯度由損失函數定義。