禁止轉載
問題
常見的標量版反向傳播公式從推導上易於理解,但對代碼實現不友好
所以這裏用向量化的形式寫出反向傳播。 具體要求:
- 向量化寫法,避免出現∑,只採用矩陣的四則運算和逐元素運算
- 帶有L2正則項
- 直接寫一個batch,避免一個一個樣本的寫
- 多分類交叉熵損失
說明
- 上述這些要求的優勢在於可以直接轉化爲向量化的計算代碼
- 在pytorch、numpy等框架中,向量化的計算比用循環累加要快非常多
- 本文參考了矩陣求導術-上,強推!本文采用的符號規範與之一致,如果沒有看過直接看本文也沒有問題
網絡結構
- 網絡結構必須定義明確,說明清楚
- 輸入數據爲X,Y
- 網絡一共三層,結構爲:
fc1:X→F1relu:F1→G1fc2:G1→F2
- 輸入層維度爲D,隱層維度爲H,輸出層維度爲C. 所以每一層的參數形狀爲
W1∈RH×DW2∈RC×Hb1∈RH×1b2∈RC×1
- 記一次batch樣本數爲N,所以輸入層、隱層、類別標註的形狀爲
X∈RD×NF1,G1∈RH×NF2,Y∈RC×N
這裏Y採用了one-hot編碼
- 我用了列向量寫法,如果你習慣於行向量,那麼可以參考我貼在文末的手稿
前向傳播
F1=W1X+b111×N(1)
G1=max(0,F1)(2)
F2=W2G1+b211×N(3)
其中1a×b表示形狀爲a×b的全1矩陣
記L1爲經驗損失項
L1=[ln(11×CeF2)−11×C(F2⊙Y)]1N×1(4)
其中“⊙”表示逐元素乘法,要求參與運算的兩個矩陣維度相同
本文所有的指數函數e⋅和對數函數ln(⋅)都爲逐元素函數
取均值的操作N1L1放到了後文引入,爲了方便求導書寫
式(4)的正確性稍加解釋:
對於樣本i,L1i=−ln∑y=1CeF2yieF2yii=ln(∑y=1CeF2yi)−F2yii=ln(11×CeF2⋅i)−11×C(F2⋅i⊙Y⋅i).
其中yi∈{1,2,...,N},表示樣本i的類別。只要注意到Y⋅i是one-hot編碼,該推導不難成立
由L1=∑i=1NL1i,得式(4),可以自行驗證
[
- 一段冗筆,可以不看:
如果記Y^爲經過softmax後的網絡輸出,Y^∈RC×N,那麼
Y^=eF2⊙1C×CeF21
其中A1表示把A逐元素取倒數,L1又可寫成
L1=−ln(11×C(Y^⊙Y))1N×1
這樣L1就避免了直接使用F2,但是該式到式(4)的正確性不易看出,該式也不利於後續求導
不過這兩式易於構建計算圖,方便代碼實現
後續推導仍然使用式(4)
]
記L2表示正則損失項,L21爲W1的損失,L22爲W2的損失
L2=L21+L22=11×H(W1⊙W1)1D×1+11×C(W2⊙W2)1H×1(5)
L=N1L1+λL2(6)
式(1)~式(6)完整介紹了前向傳播的向量化寫法
下一節將介紹反向傳播的向量化寫法,高潮要來了呀,準備好
反向傳播
首先簡單介紹兩個知識點
- Jacobian辨識:如果df=tr(AdX),那麼∂X∂f=AT
即如果想求∂X∂f,只要能把df寫成tr(AdX)的形式,那麼就能把∂X∂f辨識出來,爲AT
- 跡的一些性質,很重要,這些技巧後文會用
- 矩陣乘法/逐元素乘法交換:tr{AT(B⊙C)}=tr{(A⊙B)TC}
- 輪換對稱性:tr{AB}=tr{BA}
- 轉置跡不變:tr{A}=tr{AT}
- 微分內提:dtr{A}=tr{dA}
另外,我們記A1表示把A逐元素取倒數
開始吧
經驗損失項
dL=N1dL1+λdL2(7)
dL1=[d[ln(11×CeF2)]−11×C(dF2⊙Y)]1N×1=[d[(11×CeF2)]⊙11×CeF21−11×C(dF2⊙Y)]1N×1=[(11×C(eF2⊙dF2))⊙11×CeF21−11×C(dF2⊙Y)]1N×1=tr{[(11×C(eF2⊙dF2))⊙11×CeF21−11×C(dF2⊙Y)]1N×1}=tr{[(11×C(eF2⊙dF2))⊙11×CeF21]1N×1}−tr{11×C(dF2⊙Y)1N×1}=tr{1N×1[(11×C(eF2⊙dF2))⊙11×CeF21]}−tr{1N×C(dF2⊙Y)}=tr{[11×N⊙(11×C(eF2⊙dF2))]T11×CeF21}−tr{(1C×N⊙dF2)TY)}=tr{[11×C(eF2⊙dF2)]T11×CeF21}−tr{dF2TY}=tr{(dF2T⊙eF2T)(1C×111×CeF21)}−tr{dF2TY}=tr{dF2T[eF2⊙(1C×111×CeF21)]}−tr{dF2TY}=tr{[eF2⊙(1C×111×CeF21)−Y]TdF2}
一波推導,Jacobian辨識得
∂F2∂L1=eF2⊙(1C×111×CeF21)−Y(8)
接下來,開始反向傳播,由式(3)
dL1=tr{∂F2∂L1TdF2}=tr{∂F2∂L1T(dW2G1+W2dG1+db211×N)}=tr{G1∂F2∂L1TdW2}+tr{∂F2∂L1TW2dG1}+tr{11×N∂F2∂L1Tdb2}
Jacobian辨識得
∂W2∂L1=∂F2∂L1G1T(9)
∂b2∂L1=∂F2∂L11N×1(10)
∂G1∂L1=W2T∂F2∂L1(11)
式(9)和式(10)給出了經驗損失項關於W2和b2的參數更新公式
我們繼續反向傳播,由式(2)
dL1=tr{∂G1∂L1dG1}+...(G1無關項)=tr{∂G1∂L1[I(F1>0)⊙dF1]}+...=tr{[∂G1∂L1T⊙I(F1>0)]TdF1}+...
Jacobian辨識得
∂F1∂L1=∂G1∂L1⊙I(F1>0)(12)
由式(1)
dL1=tr{∂F1∂L1TdF1}+...(F1無關項)=tr{∂F1∂L1T(dW1X+db111×N)}+...=tr{X∂F1∂L1TdW1}+tr{11×N∂F1∂L1Tdb1}+...
Jacobian辨識得
∂W1∂L1=∂F1∂L1XT(13)
∂b1∂L1=∂F1∂L11N×1(14)
式(13)和式(14)給出了經驗損失項關於W1和b1的參數更新公式。注意這兩式和W2,b2更新公式(9)和(10)之間的相似性。更多層反向傳播公式是可以歸納出來的
正則損失項
對於L2
dL21=11×H(W1⊙dW1)1D×1+11×H(dW1⊙W1)1D×1=2tr{11×H(W1⊙dW1)1D×1}=2tr{1D×H(W1⊙dW1)}=2tr{(1H×D⊙W1)TdW1)}=tr{2W1TdW1}
由Jacobian辨識得
∂W1∂L21=2W1(15)
同理
∂W2∂L21=2W2(16)
可以看出L2參數項對參數的影響與用標量寫法推導是一致的
L1參數項的向量化推導類似
後記
- 寫了一天……
- 矩陣求導是非常強大的工具,而且求出來的表達式可以直接轉化成代碼實現
- 類似的方法可以推導SVM合頁損失、Logistic迴歸、線性迴歸等的參數更新公式,可以留作練習(想起來之前面試讓我求最小二乘的梯度,我想推向量寫法,沒推出來就很氣,無奈勉強寫了標量寫法)
- 上述方法始終保持了標量對矩陣求導,反向傳播即是把矩陣微分不斷打開的過程
- 在矩陣求導術(下)中,給出了一種矩陣對矩陣求導的技法,似乎是可以寫出另一種鏈式法則,這裏我存有一個疑問:
如果輸出結果爲標量(例如loss),是否用矩陣求導術(上)的方法更爲方便?因爲(下)中方法要先把矩陣拍開,而後再合上?
- 我用手稿寫了一份行向量的版本,僅供參考