DL基本知識(二)反向傳播推導&python實現

事先聲明一下,這篇博客的適用人羣是對於卷積神經網絡的基本結構和每個模塊都基本瞭解的同學。當然,如果各位大神看到我這篇博客有什麼不對的地方請大家積極指出哈,我一定好好改正,畢竟學習是一個不斷改進的過程。

關鍵字: 神經網絡、矩陣求導、鏈式法則、python

之前學習反向傳播的時候,對於矩陣的求導、鏈式法則以及正則化的求導過程有些疑惑,我覺得是一個不錯的機會來徹底搞清楚。

這裏先開一個小差,我自己特別不喜歡推公式,因爲推了幾篇公式之後,編程實現就是這麼幾行,感覺超級不爽,。。。廢話少說,下面開始進入主題。

下面是這篇博客的內容:

  • 自定義神經網絡搭建過程
  • 反向傳播過程中矩陣求導
  • 反向傳播過程中激活函數求導
  • BONUS 反向傳播過程中的正則化
  • 總結

自定義神經網絡搭建過程

首先交代下整個神經網絡的搭建過程。整個神經網絡由三層組成:輸入層,隱藏層和輸出層組成。

  • 輸入層

    輸入的每條樣本的維度爲[1, 500], 每個樣本的每一維都是從[-10,10]的區間內選取的隨機整數。

  • 隱藏層

    隱藏層的維度爲[500,3],每一維都是[0,1]之間均勻分佈的隨機浮點數。隱藏層輸出之後會經過sigmoid激活函數。

  • 輸出層

    輸出層的維度爲[3,3],每一維都是[0,1]之間均勻分佈的隨機浮點數。輸出層輸出之後會經過sigmoid激活函數。

  • 標籤

    每個數據的標籤是一個維度爲[1,3]的向量,每個樣本的每一維都是從[0, 1]的區間內選取的隨機整數。因而從標籤的形式可以看出,這個任務是一個多target分類任務。

  • 損失函數

    輸出層與標籤之間進行均方損失函數計算(這裏說明的是,分類問題不應該是這麼做,應該用分類問題特有的損失函數,這裏只是爲了方便起見)。

  • 網絡整體結構圖

    上述整個神經網絡模型的示意圖如下所示:
    nn_plot

反向傳播過程中矩陣求導

先從最簡單的說起,就是最簡單的affine layer(全連接層)的反向傳播,在這一層中的前向傳播如下公式,xx是這層的輸入,ww是這層的參數,bb是這層的偏置, outout是這層的輸入,
out=xw+bout = x * w + b

這裏爲了簡便,省略了偏置項(bb),下圖展示了反向傳播過程中的計算流程,這裏展示的是輸入層和隱藏層矩陣相乘之後的反向傳播狀態。
bp
其中d_loss_input_layer代表的是輸入層的梯度,d_loss_hidden_layer_w代表的是隱藏層權重矩陣的梯度,d_loss_hidden_layer_before_activation代表的是隱藏層輸入到激活函數之前的結果的梯度。

根據矩陣求導的鏈式法則可得(其中{xyz}\{x\rightarrow y\rightarrow z\}代表的含義是由x推出y,再由y推出z,×\times代表的含義是矩陣相乘),
zx=(yx)T×zy    {xyz} \frac{\partial z}{\partial x}=(\frac{\partial y}{\partial x})^T\times \frac{\partial z}{\partial y} \ \ \ \ \{x\rightarrow y\rightarrow z\}
可得如下公式,
lossinput_layer=(hidden_layer_before_activationinput_layer)T×losshidden_layer_before_activationlosshidden_layer_w=(hidden_layer_before_activationhidden_layer_w)T×losshidden_layer_before_activation \frac{\partial loss}{\partial input\_layer}=(\frac{\partial hidden\_layer\_before\_activation}{\partial input\_layer})^T\times\frac{\partial loss}{\partial hidden\_layer\_before\_activation} \\ \frac{\partial loss}{\partial hidden\_layer\_w }=(\frac{\partial hidden\_layer\_before\_activation}{\partial hidden\_layer\_w})^T\times\frac{\partial loss}{\partial hidden\_layer\_before\_activation}
而反向傳播過程中要解決的核心問題是權重矩陣的參數更新問題,因而這裏只關注d_loss_hidden_layer_w的計算,又根據矩陣求導的法則
βTxx=β \frac{\partial \beta ^Tx}{\partial x}=\beta
可得
hidden_layer_before_activationhidden_layer_w=input_layerT \frac{\partial hidden\_layer\_before\_activation}{\partial hidden\_layer\_w}=input\_layer^T


losshidden_layer_w=input_layerT×losshidden_layer_before_activation \frac{\partial loss}{\partial hidden\_layer\_w }=input\_layer^T\times\frac{\partial loss}{\partial hidden\_layer\_before\_activation}
這樣只需要知道losshidden_layer_before_activation\frac{\partial loss}{\partial hidden\_layer\_before\_activation},就能夠將隱藏層的權重矩陣的梯度求解出來,而該結果又是通過鏈式法則的前端傳遞過來的,因而需要計算前面的結果,這裏才能夠知道,具體計算結果這裏就不再贅述,因爲這裏重點講的是矩陣求導的過程。

反向傳播過程中激活函數求導

激活函數的意義是爲神經網絡的計算添加非線性,這樣神經網絡就能夠擬合更加複雜的曲線,不過這不是本文的重點,大家有興趣的可以參考其他博客。這裏重點介紹的是激活函數再反向傳播中是如何求導的,這裏以sigmoid函數爲例來詳細介紹。首先給出的是該種情況下反向傳播的過程示意圖,其中d_sigmoid代表的是sigmoid函數的求導函數。
在這裏插入圖片描述
由於這裏在前向計算時是逐位點乘的,因而這裏不涉及矩陣求導,但是這裏依然存在鏈式法則,因而計算公式如下,
losshidden_layer_before_activation=d_sigmoid(hidden_layer_before_activation)losshidden_layer \frac{\partial loss}{\partial hidden\_layer\_before\_activation}= \\ d\_sigmoid(hidden\_layer\_before\_activation)*\frac{\partial loss}{\partial hidden\_layer}
這裏值得注意的是,上面公式中*代表的是矩陣的逐位點乘,而不是矩陣相乘。

到此,反向傳播過程中激活函數求導講述完畢。上述過程的完整代碼可以參考我的github repo, 每一步都是手工計算,過程中只利用了numpy函數庫,個人認爲可以較爲清晰的解答簡單神經網絡前向和反向傳播過程中的細節問題。大家如果有興趣,可以一起維護這個repo~

BONUS 反向傳播過程中的正則化

正則化的基本思想是通過限制參數的野蠻生長而誕生的技術,說白了就是抑制過擬合,讓模型的泛化能力更強。具體的做法是在計算損失時加入了權重矩陣的正則項,這樣如果權重矩陣每個元素的取值太大的話,會導致整體的損失變大,因而爲了使損失變小,在學習過程中會抑制參數變得很大,這裏所說的"很大"指的是絕對值很大或者平方項很大,分別對應了l1正則項和l2正則項。因而下文會講述這兩個正則項的求導過程以及兩個正則化項在實際運用時對結果的影響。

  • l1正則項
    反向傳播的計算公式如下所示:
    losswl1={1    if w>01  if w<0 \frac{\partial loss}{\partial w}_{l1}=\left\{\begin{matrix} 1 \ \ \ \ if \ w > 0\\ -1 \ \ if \ w < 0 \end{matrix}\right.

  • l2正則項
    反向傳播的計算公式如下所示:
    losswl2=w \frac{\partial loss}{\partial w}_{l2}=w

  • 實際應用

    將正則項運用到第一節所搭建的神經網絡中,分別對比了不加正則項、l1正則項和l2正則項之間的訓練和驗證損失的差異,示意圖如下所示:
    在這裏插入圖片描述
    可以看出,添加了正則項之後,驗證集能夠更快地收斂,而對於數值特徵,上述示意圖顯示的不是特別明顯,這裏截取了訓練過程中訓練loss和驗證loss的數值結果,如下所示(到1600次迭代時基本已經收斂),

    不加正則項:
    iteration 1600, train loss: 0.3432821160251056, valid_loss: 2.5690724565021563

    l1正則項:
    iteration 1600, train loss: 0.20726140239368068, valid_loss: 0.019843994548783522

    l2正則項:
    iteration 1600, train loss: 1.09977712566086, valid_loss: 0.21506450810326314

    這裏可以明顯地看出,不加正則項收斂時,訓練loss會很低,但是驗證loss比較大,而l1和l2正好相反,經過添加正則項的操作之後,驗證loss更低,這就能說明添加正則項確實比不添加正則項的效果要好。而在這裏爲何l1比l2的效果要好,目前樓主還沒有想到一個比較好的答案,等大段時間了可以好好想一下,或者大家可以一起來想一下~

總結

手動實現神經網絡,可以消除之前對神經網絡反向傳播計算的恐懼,並且對矩陣求導以及鏈式法則有了一個更加深刻的認識,希望以後能夠在這個領域由更多的見解,也希望大家如果對該博客有什麼異議,一定提出來,共同學習,共同提高~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章