《神經網路的梯度推導與程式碼驗證》之CNN的前向傳播和反向梯度推導

SumwaiLiu發表於2020-09-03

FNN(DNN)的前向傳播,反向梯度推導以及程式碼驗證中,我們不僅總結了FNN(DNN)這種神經網路結構的前向傳播和反向梯度求導公式,還通過tensorflow的自動求微分工具驗證了其準確性。在本篇章,我們將專門針對CNN這種網路結構進行前向傳播介紹和反向梯度推導。更多相關內容請見《神經網路的梯度推導與程式碼驗證》系列介紹

 

注意:

 

目錄

  • 3.1 CNN的前向傳播
    • 3.1.1 CNN輸入層前向傳播到卷積層
    • 3.1.2 隱藏層前向傳播到卷積層
    • 3.1.3 隱藏層前向傳播到池化層
    • 3.1.4 隱藏層前向傳播到全連線層
    • 3.1.5 CNN前向傳播演算法小結
  • 3.2 CNN的反向梯度推導
    • 3.2.1 已知池化層的$\delta^{l}$,推導前一隱藏層的$\delta^{l-1}$
    • 3.2.2 已知卷積層的$\delta^{l}$,推導前一隱藏層的$\delta^{l-1}$
    • 3.2.3 已知卷積層的$\delta^{l}$,推導該層的$W$,$b$的梯度
    • 3.2.4 CNN反向梯度求導總結
  • 參考資料

 


 

3.1 CNN的前向傳播

CNN大致的結構如下,包括輸出層,若干的卷積層+ReLU啟用函式,若干的池化層,DNN全連線層,以及最後的用Softmax啟用函式的輸出層。這裡我們用一個彩色的汽車樣本的影像識別再從感官上回顧下CNN的結構。圖中的CONV即為卷積層,POOL即為池化層,而FC即為FNN全連線層,包括了Softmax啟用函式。

 

從上圖可以看出,要理順CNN的前向傳播演算法,重點是輸入層的前向傳播,卷積層的前向傳播以及池化層的前向傳播。而FNN全連線層和用Softmax啟用函式的輸出層的前向和反向傳播在講FNN時已經介紹過了。

 

3.1.1 CNN輸入層前向傳播到卷積層

輸入層的前向傳播是CNN前向傳播演算法的第一步。一般輸入層的下一層都是卷積層,因此我們標題是輸入層前向傳播到卷積層。

 

我們這裡還是以影像識別為例。

 

先考慮最簡單的,樣本都是二維的黑白圖片。這樣輸入層$\boldsymbol{X}$就是一個矩陣,矩陣的值等於圖片的各個畫素位置的值。這時和卷積層相連的卷積核$\boldsymbol{W}$就也是矩陣。

 

如果樣本都是有RGB的彩色圖片,這樣輸入 就是3個矩陣,即分別對應R,G和B的矩陣,或者說是一個張量。這時和卷積層相連的卷積核 就也是張量,對應的最後一維的維度為3。即每個卷積核都是3個子矩陣組成。

 

同樣的方法,對於3D的彩色圖片之類的樣本,我們的輸入$\boldsymbol{X}$可以是4維,5維的張量,那麼對應的卷積核$\boldsymbol{W}$也是個高維的張量。不管維度多高,對於我們的輸入,前向傳播的過程可以表示為:

$\boldsymbol{a}^{2} = \sigma\left( \boldsymbol{z}^{2} \right) = \sigma\left( {\boldsymbol{a}^{1}*\boldsymbol{W}^{2} + \boldsymbol{b}^{2}} \right)$

其中,上標代表層數,星號代表卷積,而$\boldsymbol{b}$代表我們的bias,$\sigma$為啟用函式,這裡一般都是ReLU。和DNN的前向傳播比較一下,其實形式非常的像,只是我們這兒是張量的卷積,而不是矩陣的乘法。同時由於$\boldsymbol{W}$是張量,那麼同樣的位置,$\boldsymbol{W}$引數的個數就比DNN多很多了。

 

為了簡化我們的描述,本文後面如果沒有特殊說明,我們都預設輸入是3維的張量,即用RBG可以表示的彩色圖片。

 

這裡需要我們自己定義的CNN模型引數有:

1)一般我們的卷積核不止一個,比如有K個,那麼我們輸入層的輸出,或者說第二層卷積層的對應的輸入就K個。

2)卷積核中每個子矩陣的的大小,一般我們都用子矩陣為方陣的卷積核,比如FxF的子矩陣。

3) 填充padding(以下簡稱P),我們卷積的時候,為了可以更好的識別邊緣,一般都會在輸入矩陣在周圍加上若干圈的0再進行卷積,加多少圈則P為多少。

4) 步幅stride(以下簡稱S),即在卷積過程中每次移動的畫素距離大小。

 

3.1.2 隱藏層前向傳播到卷積層

現在我們再來看隱藏層前向傳播到卷積層時的前向傳播演算法。

 

假設隱藏層的輸出是M個矩陣對應的三維張量,則輸出到卷積層的卷積核也是M個子矩陣對應的三維張量。這時表示式和輸入層的很像:

$\boldsymbol{a}^{l} = \sigma\left( \boldsymbol{z}^{l} \right) = \sigma\left( {\boldsymbol{a}^{l - 1}*\boldsymbol{W}^{l} + \boldsymbol{b}^{l}} \right)$

也可以寫成M個子矩陣子矩陣卷積後對應位置相加的形式,即:

$\boldsymbol{a}^{l} = \sigma\left( \boldsymbol{z}^{l} \right) = \sigma\left( {\sum\limits_{k = 1}^{M}\boldsymbol{z}_{k}^{l}} \right) = \sigma\left( {\sum\limits_{k - 1}^{M}{\boldsymbol{a}_{\boldsymbol{k}}^{\boldsymbol{l} - 1}*\boldsymbol{W}_{k}^{l} + \boldsymbol{b}^{l}}} \right)$

 

和上一節3.1.1唯一的區別僅僅在於,這裡的輸入是隱藏層來的,而不是我們輸入的原始圖片樣本形成的矩陣。

 

需要我們定義的CNN模型引數也和上一節一樣,這裡我們需要定義卷積核的個數K,卷積核子矩陣的維度F,填充大小P以及步幅S。

 

3.1.3 隱藏層前向傳播到池化層

池化層的處理邏輯是比較簡單的,我們的目的就是對輸入的矩陣進行縮小概括。比如輸入的若干矩陣是N x N維的,而我們的池化大小是k x k的區域,則輸出的矩陣都是  x  維的。

這裡需要需要我們定義的CNN模型引數是:

1) 池化區域的大小k

2) 池化的標準,一般是MAX或者Average。

 

3.1.4 隱藏層前向傳播到全連線層

由於全連線層就是普通的DNN模型結構,因此我們可以直接使用DNN的前向傳播演算法邏輯,即:

$\boldsymbol{a}^{l} = \sigma\left( \boldsymbol{z}^{l} \right) = \sigma\left( {\boldsymbol{W}^{\boldsymbol{l}}\boldsymbol{a}^{\boldsymbol{l} - 1} + \boldsymbol{b}^{l}} \right)$

這裡的啟用函式一般是sigmoid或者tanh。

 

經過了若干全連線層之後,最後的一層為Softmax輸出層。此時輸出層和普通的全連線層唯一的區別是,啟用函式是softmax函式。這裡需要需要我們定義的CNN模型引數是:

1) 全連線層的啟用函式

2) 全連線層各層神經元的個數

 

3.1.5 CNN前向傳播小結

我們現在總結下CNN的前向傳播演算法。

 

輸入:1個圖片樣本,CNN模型的層數L和所有隱藏層的型別。

  • 對於卷積層,要定義卷積核的大小K,卷積核子矩陣的維度F,填充大小P,步幅S。
  • 對於池化層,要定義池化區域大小k和池化標準(MAX或Average)。
  • 對於全連線層,要定義全連線層的啟用函式(輸出層除外)和各層的神經元個數。

輸出:CNN模型的輸出$\boldsymbol{a}^{L}$

1)根據輸入層的填充大小P,填充原始圖片的邊緣,得到輸入張量$\boldsymbol{a}^{l}$

2)初始化所有隱藏層的引數$\boldsymbol{W}$,$\boldsymbol{b}$

3)for $l=2$ to $L-1$:

  • 如果第$l$層是卷積層,則輸出為

$\boldsymbol{a}^{l} = ReLU\left( \boldsymbol{z}^{l} \right) = ReLU\left( {\boldsymbol{a}^{l - 1}*\boldsymbol{W}^{l} + \boldsymbol{b}^{l}} \right)$

  • 如果第$l$層是池化層,則輸出為

$\boldsymbol{a}^{l} = \boldsymbol{z}^{l} = pooling\left( \boldsymbol{a}^{l - 1} \right)$

這裡的$pooling\left( ~ \right)$指按照池化區域大小k和池化標準將輸入張量縮小的過程。

  • 如果第$l$層是全連線層,則輸出為

$\boldsymbol{a}^{l} = \sigma\left( \boldsymbol{z}^{l} \right) = \sigma\left( {\boldsymbol{W}^{\boldsymbol{l}}\boldsymbol{a}^{\boldsymbol{l} - 1} + \boldsymbol{b}^{l}} \right)$

4) 對於輸出層第L層:

$\boldsymbol{a}^{L} = softmax\left( \boldsymbol{z}^{L} \right) = softmax\left( {\boldsymbol{W}^{\boldsymbol{L}}\boldsymbol{a}^{\boldsymbol{L} - 1} + \boldsymbol{b}^{L}} \right)$

 

以上就是CNN前向傳播演算法的過程總結。有了CNN前向傳播演算法的基礎,我們後面再來理解CNN的反向傳播演算法就簡單多了。

 


 

3.2 CNN的反向梯度推導

與推導DNN時候類似,我們定義$\boldsymbol{\delta}^{l} = \frac{\partial l}{\partial\boldsymbol{z}^{\boldsymbol{l}}}$

要套用DNN的反向傳播演算法到CNN,有幾個問題需要解決:

1)池化層沒有啟用函式,這個問題倒比較好解決,我們可以令池化層的啟用函式為$\sigma\left( \boldsymbol{z} \right) = \boldsymbol{z}$,即啟用後就是自己本身。這樣池化層啟用函式的導數為1。

2)池化層在前向傳播的時候,對輸入進行了壓縮,那麼我們現在需要向前反向推導$\boldsymbol{\delta}^{l - 1}$,這個推導方法和DNN完全不同。

3)卷積層是通過張量卷積,或者說若干個矩陣卷積求和而得的當前層的輸出,這和DNN很不相同,DNN的全連線層是直接進行矩陣乘法得到當前層的輸出。這樣在卷積層反向傳播的時候,$\boldsymbol{\delta}^{l - 1}$的遞推計算方法肯定有所不同。

4)對於卷積層,由於$\boldsymbol{W}$使用的運算是卷積,那麼從$\boldsymbol{\delta}^{l }$推匯出該層的所有卷積核的$\boldsymbol{W}$和$\boldsymbol{b}$的方式也不同。

 

從上面可以看出,問題1比較好解決,但是問題2,3,4就需要好好的動一番腦筋了,而問題2,3,4也是解決CNN反向傳播演算法的關鍵所在。另外大家要注意到的是,DNN中的$\boldsymbol{a}^{\boldsymbol{l}}$$\boldsymbol{z}^{\boldsymbol{l}}$都只是一個向量,而CNN中的$\boldsymbol{a}^{\boldsymbol{l}}$$\boldsymbol{z}^{\boldsymbol{l}}$都是一個張量,這個張量是一般三維的,即由若干個輸入的子矩陣組成。

 

下面我們就針對問題2,3,4來一步步研究CNN的反向傳播演算法。

 

在推導過程中,需要注意的是,由於卷積層可以有多個卷積核,各個卷積核的處理方法是完全相同且獨立的,為了簡化演算法公式的複雜度,我們下面提到卷積核都是卷積層中若干卷積核中的一個。

 

因為CNN前傳的順序一般是卷積-池化,所以BP推導的時候,我們先看池化的BP推導,然後在看卷積的BP推導。

 

3.2.1 已知池化層的$\delta^{l}$,推導前一隱藏層的$\delta^{l-1}$

我們先搬出池化層的計算公式:

$\boldsymbol{a}^{l} = \boldsymbol{z}^{l} = pooling\left( \boldsymbol{a}^{l - 1} \right) = pooling\left( {\sigma\left( \boldsymbol{z}^{l - 1} \right)} \right)$ 

其中$size\left( \boldsymbol{z}^{l} \right) < size\left( \boldsymbol{a}^{l - 1} \right) = size\left( \boldsymbol{z}^{l - 1} \right)$,即$size\left( \boldsymbol{\delta}^{l} \right) < size\left( \boldsymbol{\delta}^{l - 1} \right)$

先分析下這個$pooling{()}$是在做什麼。在前向傳播演算法時,池化層一般我們會用MAX或者Average對輸入進行池化,池化的區域大小是已知的。

 

現在我們反過來,要從縮小後的誤差$\boldsymbol{\delta}^{\boldsymbol{l}}$,還原前一次較大區域對應的誤差$\boldsymbol{\delta}^{\boldsymbol{l-1}}$。

 

在反向傳播時,我們首先會把$\boldsymbol{\delta}^{\boldsymbol{l}}$的所有子矩陣矩陣大小還原成池化之前的大小。

 

如果是MAX,則把$\boldsymbol{\delta}^{\boldsymbol{l}}$的所有子矩陣的各個池化局域的值放在之前做前向傳播演算法得到最大值的位置。如果是Average,則把$\boldsymbol{\delta}^{\boldsymbol{l}}$的所有子矩陣的各個池化局域的值取平均後放在還原後的子矩陣位置。這個過程一般叫做upsample

 

下面以$\boldsymbol{\delta}^{\boldsymbol{l}}$的其中一個子矩陣為例:

假設我們的池化區域大小是2 x 2。$\boldsymbol{\delta}^{\boldsymbol{l}}$的第k各子矩陣為$\boldsymbol{\delta}_{k}^{l} = \left\lbrack \begin{array}{ll} 2 & 8 \\ 4 & 6 \\ \end{array} \right\rbrack$($\boldsymbol{\delta}^{\boldsymbol{l}}$子矩陣數等於前一層卷積層的卷積核數)。

 

由於池化區域為2x2,我們先將$\boldsymbol{\delta}^{\boldsymbol{l}}$做還原,即變成:

$\left\lbrack \begin{array}{ll} \begin{array}{ll} 0 & 0 \\ 0 & 2 \\ \end{array} & \begin{array}{ll} 0 & 0 \\ 8 & 0 \\ \end{array} \\ \begin{array}{ll} 0 & 4 \\ 0 & 0 \\ \end{array} & \begin{array}{ll} 6 & 0 \\ 0 & 0 \\ \end{array} \\ \end{array} \right\rbrack$

 

如果是MAX,假設我們之前在前向傳播時記錄的最大值位置分別是左上,右下,右上,左下,則轉換後的矩陣,即$\frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}}$為:

$\left\lbrack \begin{array}{ll} \begin{array}{ll} 2 & 0 \\ 0 & 0 \\ \end{array} & \begin{array}{ll} 0 & 0 \\ 0 & 8 \\ \end{array} \\ \begin{array}{ll} 0 & 4 \\ 0 & 0 \\ \end{array} & \begin{array}{ll} 0 & 0 \\ 6 & 0 \\ \end{array} \\ \end{array} \right\rbrack$

如果是Average,則進行平均:轉換後的矩陣,即${\partial\boldsymbol{a}_{k}^{l - 1}}$為:

$\left\lbrack \begin{array}{ll} \begin{array}{ll} 0.5 & 0.5 \\ 0.5 & 0.5 \\ \end{array} & \begin{array}{ll} 2 & 2 \\ 2 & 2 \\ \end{array} \\ \begin{array}{ll} 1 & 1 \\ 1 & 1 \\ \end{array} & \begin{array}{ll} 1.5 & 1.5 \\ 1.5 & 1.5 \\ \end{array} \\ \end{array} \right\rbrack$

於是我們得到了$\boldsymbol{\delta}_{k}^{l}$與$\frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}}$的關係如下:

$\frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}} = upsample\left( \boldsymbol{\delta}_{k}^{l} \right)$

 

接下來是個錯誤演示:

我們想通過求$\frac{\partial\boldsymbol{a}_{k}^{l - 1}}{\partial\boldsymbol{z}_{k}^{l - 1}}$,從而得到$\boldsymbol{\delta}_{k}^{l - 1} = \frac{\partial l}{\partial\boldsymbol{z}_{k}^{l - 1}} = \left( \frac{\boldsymbol{a}_{k}^{l - 1}}{\boldsymbol{z}_{k}^{l - 1}} \right)^{T}\frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}}$

,但這個式子是不對的注意,因為$\frac{\partial\boldsymbol{a}_{k}^{l - 1}}{\partial\boldsymbol{z}_{k}^{l - 1}}$是矩陣對矩陣的導數,所以並不適用向量對向量的鏈式法則。

 

於是我們繼續追本溯源,鏈式法則是從何而來?源頭仍然是微分。我們直接從微分的角度入手建立複合法則,從而繞過求$\frac{\partial\boldsymbol{a}_{k}^{l - 1}}{\partial\boldsymbol{z}_{k}^{l - 1}}$的過程基於$\frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}}$往下做微分求得$\frac{\partial l}{\partial\boldsymbol{z}_{k}^{l - 1}}$。

 

正確的解法是用複合微分來接解問題:

我們已知$\frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}}$,$\boldsymbol{a}_{k}^{l - 1} = \sigma\left( \boldsymbol{z}_{k}^{l - 1} \right)$,求$\frac{\partial l}{\partial\boldsymbol{z}_{k}^{l - 1}}$

解:

已知$\frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}}$這意味著,有微分等式$dl = tr\left( {\left( \frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}} \right)^{T}d\boldsymbol{a}_{k}^{l - 1}} \right)$成立。

我們把$d\boldsymbol{a}_{k}^{l - 1}$又看成是一個微分問題,基於$\boldsymbol{a}_{k}^{l - 1} = \sigma\left( \boldsymbol{z}_{k}^{l - 1} \right)$套娃式地求其微分變換:

$tr\left( {\left( \frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}} \right)^{T}d\boldsymbol{a}_{k}^{l - 1}} \right) = tr\left( {\left( \frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}} \right)^{T}d\sigma\left( \boldsymbol{z}_{k}^{l - 1} \right)} \right) = tr\left( {\left( \frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}} \right)^{T}\left( {\sigma^{'}\left( \boldsymbol{z}_{k}^{l - 1} \right) \odot d\boldsymbol{z}_{k}^{l - 1}} \right)} \right) = tr\left( {\left( {\frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}} \odot \sigma^{'}\left( \boldsymbol{z}_{k}^{l - 1} \right)} \right)^{T}d\boldsymbol{z}_{k}^{l - 1}} \right)$

於是,我們得到$dl = tr\left( {\left( {\frac{\partial l}{\partial\mathbf{a}_{k}^{l - 1}} \odot \sigma^{'}\left( \mathbf{z}_{k}^{l - 1} \right)} \right)^{T}d\mathbf{z}_{k}^{l - 1}} \right)$的結論,所以

$\boldsymbol{\delta}_{k}^{l - 1} = \frac{\partial l}{\partial\boldsymbol{a}_{k}^{l - 1}} \odot \sigma^{'}\left( \boldsymbol{z}_{k}^{l - 1} \right) = upsample\left( \boldsymbol{\delta}_{k}^{l} \right) \odot \sigma^{'}\left( \boldsymbol{z}_{k}^{l - 1} \right)$

 

至此,我們已經知道誤差逆著經過$pooling$層會發生什麼了,經過前梯度矩陣為$\boldsymbol{\delta}_{k}^{l}$,經過後梯度矩陣變成了$\boldsymbol{\delta}_{k}^{l - 1} = upsample\left( \boldsymbol{\delta}_{k}^{l} \right) \odot \sigma^{'}\left( \boldsymbol{z}_{k}^{l - 1} \right)$

 

3.2.2 已知卷積層的$\delta^{l}$,推導前一隱藏層的$\delta^{l-1}$

接下來我們要看看誤差逆著經過卷積層會發生什麼事情。

 

我們首先回憶下卷積層的前向傳播公式:

$\boldsymbol{a}^{l} = \sigma\left( \boldsymbol{z}^{l} \right) = \sigma\left( {\boldsymbol{a}^{l - 1}*\boldsymbol{W}^{l} + \boldsymbol{b}^{l}} \right)$

因此要推匯出$\boldsymbol{\delta}^{l - 1}$和$\boldsymbol{\delta}^{l}$的遞推關係,必須計算$\frac{\partial\boldsymbol{z}^{l}}{\partial\boldsymbol{z}^{l - 1}}$。

注意:這裡實際上只推導了$\boldsymbol{\delta}^{l}$梯度矩陣反向經過某個卷積核中的某個子矩陣$\boldsymbol{W}^{l}$所得到的上$\boldsymbol{\delta}^{l - 1}$梯度矩陣。假設前傳流程如下:

 

 

那麼在反向傳播時,我們所討論的是:

 

 

 

下面正式開始。

 

我們注意到:

 $\boldsymbol{z}^{l} = \boldsymbol{a}^{l - 1}*\boldsymbol{W}^{l} + \boldsymbol{b}^{l} = \sigma\left( \boldsymbol{z}^{l - 1} \right)*\boldsymbol{W}^{l} + \boldsymbol{b}^{l}$

這裡先給出下面這個等式,然後說明怎麼是得到:

 $\boldsymbol{\delta}^{l - 1} = \left( \frac{\partial\boldsymbol{z}^{l}}{\partial\boldsymbol{z}^{l - 1}} \right)^{T}\boldsymbol{\delta}^{l} = \boldsymbol{\delta}^{l}*rot180\left( \boldsymbol{W}^{l} \right) \odot \sigma^{'}\left( \boldsymbol{z}^{l - 1} \right)$

對比DNN中的$\boldsymbol{\delta}^{l - 1} = \left( \boldsymbol{W}^{l} \right)^{T}\delta^{l} \odot \sigma^{'}\left( \boldsymbol{z}^{l - 1} \right)$兩者還是挺相似的。

 

證明$\boldsymbol{\delta}^{l - 1} = \left( \frac{\partial\boldsymbol{z}^{l}}{\partial\boldsymbol{z}^{l - 1}} \right)^{T}\boldsymbol{\delta}^{l} = \boldsymbol{\delta}^{l}*rot180\left( \boldsymbol{W}^{l} \right) \odot \sigma^{'}\left( \boldsymbol{z}^{l - 1} \right)$:

首先給出二維卷積公式:

 $\boldsymbol{C}\left( {i,j} \right) = \left( {\boldsymbol{X}*\boldsymbol{W}} \right)\left( {i,j} \right){\sum\limits_{m}{\sum\limits_{n}{w\left( {m,n} \right)x\left( {i - m,j - m} \right)}}}$

 在CNN中,雖然我們也是說卷積,但是我們的卷積公式和嚴格意義數學中的定義稍有不同,比如對於二維的卷積,定義為:

$\boldsymbol{C}\left( {i,j} \right) = \left( {\boldsymbol{X}*\boldsymbol{W}} \right)\left( {i,j} \right){\sum\limits_{m}{\sum\limits_{n}{w\left( {m,n} \right)x\left( {i + m,j + m} \right)}}}$

數學上和CNN上的卷積操作的區別是,卷積核在前者需要翻轉180度。

根據CNN中的二維卷積定義,對$\boldsymbol{z}^{l} = \boldsymbol{a}^{l - 1}*\boldsymbol{W}^{l} + \boldsymbol{b}^{l} = \sigma\left( \boldsymbol{z}^{l - 1} \right)*\boldsymbol{W}^{l} + \boldsymbol{b}^{l}$進行元素級的展開,我們得到:

 $z_{x,y}^{l} = \left( {\boldsymbol{a}^{l - 1}*\boldsymbol{W}^{l}} \right)_{x,y} + b_{x,y}^{l} = {\sum\limits_{m}{\sum\limits_{n}{w_{m,n}^{l}\sigma\left( z_{x + m,y + n}^{l - 1} \right)}}}{+ b}_{x,y}^{l}$

由1.7.3(詳情見《神經網路的梯度推導與程式碼驗證》之數學基礎篇:矩陣微分與求導)的標量對多個矩陣的鏈式求導法則$\frac{\partial z}{\partial x_{ij}} = {\sum\limits_{k}{\sum\limits_{l}{\frac{\partial z}{\partial Y_{kl}}\frac{\partial Y_{kl}}{\partial X_{ij}}}}}$可得$\boldsymbol{\delta}^{l}$中的元素$\delta_{x,y}^{l}$

滿足以下式子:

$\delta_{x,y}^{l - 1} = \frac{\partial l}{\partial z_{x,y}^{l - 1}} = {\sum\limits_{k}{\sum\limits_{l}{\frac{\partial l}{\partial z_{k,l}^{l}}\frac{\partial z_{k,l}^{l}}{z_{x,y}^{l - 1}}}}}$

聯立上面兩個等式,我們可以展開$z_{k,l}^{l}$從而得到:

$\delta_{x,y}^{l - 1} = \frac{\partial l}{\partial z_{x,y}^{l - 1}} = {\sum\limits_{k}{\sum\limits_{l}{\frac{\partial l}{\partial z_{k,l}^{l}}\frac{\partial z_{k,l}^{l}}{z_{x,y}^{l - 1}}}}} = {\sum\limits_{k}{\sum\limits_{l}{\delta_{k,l}^{l}\frac{\partial z_{k,l}^{l}}{{\partial z}_{x,y}^{l - 1}} = {\sum\limits_{k}{\sum\limits_{l}{\delta_{k,l}^{l}\frac{\partial\left( {{\sum\limits_{m}{\sum\limits_{n}{w_{m,n}^{l}\sigma\left( z_{k + m,l + n}^{l - 1} \right) +}}}b_{x,y}^{l}} \right)}{\partial z_{x,y}^{l - 1}}}}}}}}$

上式看著挺噁心的,但仔細分析$\frac{\partial\left( {{\sum\limits_{m}{\sum\limits_{n}{w_{m,n}^{l}\sigma\left( z_{k + m,l + n}^{l - 1} \right) +}}}b_{x,y}^{l}} \right)}{\partial z_{x,y}^{l - 1}}$可以發現雖然分子是個mn項的累加,但因為要對$z_{x,y}^{l - 1}$進行偏微分,所以顯然最後保留下來的,只有同時滿足$x = k + m$,$y = ~l + n$兩個約束的項。所以有:

$\delta_{x,y}^{l - 1} = {\sum\limits_{k}{\sum\limits_{l}{\delta_{k,l}^{l}\frac{\partial\left( {{\sum\limits_{m}{\sum\limits_{n}{w_{m,n}^{l}\sigma\left( z_{k + m,l + n}^{l - 1} \right) +}}}b_{x,y}^{l}} \right)}{\partial z_{x,y}^{l - 1}}}}} = {\sum\limits_{k}{\sum\limits_{l}{\delta_{k,l}^{l}\frac{\partial\left( {w_{x - k,y - l}^{l}\sigma\left( z_{x,y}^{l - 1} \right)} \right)}{\partial z_{x,y}^{l - 1}}}}} = {\sum\limits_{k}{\sum\limits_{l}{\delta_{k,l}^{l}w_{x - k,y - l}^{l}\sigma^{'}\left( z_{x,y}^{l - 1} \right) =}}}\sigma^{'}\left( z_{x,y}^{l - 1} \right){\sum\limits_{k}{\sum\limits_{l}{\delta_{k,l}^{l}w_{x - k,y - l}^{l}}}}$

觀察$\sum\limits_{k}{\sum\limits_{l}{\delta_{k,l}^{l}w_{x - k,y - l}^{l}}}$這一項可以發現,這就是一般數學上的卷積運算,如果我們統一用CNN上的卷積定義來表示這一項,根據之前所提到的,兩種卷積操作的區別是卷積核相差個rot180操作,所以有:

$\boldsymbol{\delta}^{l - 1} = \boldsymbol{\delta}^{l}*rot180\left( \boldsymbol{W}^{l} \right) \odot \sigma^{'}\left( \boldsymbol{z}^{l - 1} \right)$

注意到$\boldsymbol{\delta}^{l - 1}$與$\boldsymbol{\delta}^{l}$的尺寸是不同的,從$l - 1$層到$l$層進行的卷積操作叫“valid convolution” (更多不同的卷積模式可參考:https://www.cnblogs.com/itmorn/p/11179448.html),如下圖所示:

 

所以$\boldsymbol{\delta}^{l - 1}$的尺寸要小於$\boldsymbol{\delta}^{l}$,而如今誤差要逆著反傳回去,顯然不是做“valid convolution”因為這樣只會讓尺寸更小。所以我們要做的是“full convolution”,一種直觀的解釋是,feature map經過valid convolution後尺寸會縮小,而對於同樣大小的卷積核和步長,如果接下來使用full convolution的話就能讓尺寸恢復成原來的大小。

 

我們先以一個簡單的例子說明為啥這裡卷積核要翻轉,為啥相對於前傳的valid convolution,反傳要做full convolution。

 

假設第$l - 1$層的輸出$\boldsymbol{a}^{l - 1}$是一個3 x 3的矩陣,第$l$層的卷積核$\boldsymbol{W}^{l}$是一個2 x 2的矩陣,採用1畫素的步幅,啟用函式用的是線性函式,輸出的$\boldsymbol{z}^{l}$是一個2 x 2的矩陣。我們簡化$\boldsymbol{b}^{l}$成都是0,則有:

$\boldsymbol{z}^{l} = conv2D\left( {\boldsymbol{a}^{l - 1},\boldsymbol{W}^{l},'valid'} \right)$

對上述式子展開,進行元素級分析:

$\left\lbrack \begin{array}{ll} z_{11} & z_{12} \\ z_{21} & z_{22} \\ \end{array} \right\rbrack = \left\lbrack \begin{array}{lll} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \\ \end{array} \right\rbrack*\left\lbrack \begin{array}{l} \begin{array}{ll} w_{11} & w_{12} \\ \end{array} \\ \begin{array}{ll} w_{21} & w_{22} \\ \end{array} \\ \end{array} \right\rbrack$

其中卷積符號代表CNN中的卷積操作,利用該定義,我們得到:

$z_{11} = a_{11}w_{11} + a_{12}w_{12} + a_{21}w_{21} + a_{22}w_{22}$

$z_{12} = a_{12}w_{11} + a_{13}w_{12} + a_{22}w_{21} + a_{23}w_{22}$

$z_{21} = a_{21}w_{11} + a_{22}w_{12} + a_{31}w_{21} + a_{32}w_{22}$

$z_{22} = a_{22}w_{11} + a_{13}w_{12} + a_{32}w_{21} + a_{33}w_{22}$

接著我們模擬反向求導:

根據鏈式法則:$\frac{\partial l}{\partial a_{x,y}^{l - 1}} = {\sum\limits_{k}{\sum\limits_{l}{\frac{\partial l}{\partial z_{k,l}^{l}}\frac{\partial z_{k,l}^{l}}{a_{x,y}^{l - 1}}}}}$我們得到:

$\frac{\partial l}{\partial a_{11}^{l - 1}} = {\sum\limits_{k}{\sum\limits_{l}{\frac{\partial l}{\partial z_{k,l}^{l}}\frac{\partial z_{k,l}^{l}}{a_{x,y}^{l - 1}}}}} = \frac{\partial l}{\partial z_{11}^{l}}\frac{\partial z_{11}^{l}}{a_{11}^{l - 1}} + \frac{\partial l}{\partial z_{12}^{l}}\frac{\partial z_{12}^{l}}{a_{11}^{l - 1}} + \frac{\partial l}{\partial z_{21}^{l}}\frac{\partial z_{21}^{l}}{a_{11}^{l - 1}} + \frac{\partial l}{\partial z_{22}^{l}}\frac{\partial z_{22}^{l}}{a_{11}^{l - 1}}$

對$z$展開後我們得到:

$\frac{\partial l}{\partial a_{11}^{l - 1}} = \frac{\partial l}{\partial z_{11}^{l}}w_{11} = \delta_{11}^{l}w_{11}$

同理,我們可以得到:

$\frac{\partial l}{\partial a_{12}^{l - 1}} = \delta_{11}^{l}w_{12} + \delta_{12}^{l}w_{11}$

$\frac{\partial l}{\partial a_{13}^{l - 1}} = \delta_{12}^{l}w_{12}$

$\frac{\partial l}{\partial a_{21}^{l - 1}} = \delta_{11}^{l}w_{21} + \delta_{21}^{l}w_{11}$

$\frac{\partial l}{\partial a_{22}^{l - 1}} = \delta_{11}^{l}w_{22} + \delta_{12}^{l}w_{21} + \delta_{21}^{l}w_{12} + \delta_{22}^{l}w_{11}$

$\frac{\partial l}{\partial a_{23}^{l - 1}} = \delta_{12}^{l}w_{22} + \delta_{22}^{l}w_{12}$

$\frac{\partial l}{\partial a_{31}^{l - 1}} = \delta_{21}^{l}w_{21}$

$\frac{\partial l}{\partial a_{32}^{l - 1}} = \delta_{21}^{l}w_{22} + \delta_{22}^{l}w_{21}$

$\frac{\partial l}{\partial a_{33}^{l - 1}} = \delta_{22}^{l}w_{22}$

這上面9個式子其實可以用一個矩陣卷積的形式表示,即:

$\left\lbrack \begin{array}{ll} \begin{array}{ll} 0 & 0 \\ 0 & \delta_{11}^{l} \\ \end{array} & \begin{array}{ll} 0 & 0 \\ \delta_{12}^{l} & 0 \\ \end{array} \\ \begin{array}{ll} 0 & \delta_{21}^{l} \\ 0 & 0 \\ \end{array} & \begin{array}{ll} \delta_{22}^{l} & 0 \\ 0 & 0 \\ \end{array} \\ \end{array} \right\rbrack*\left\lbrack \begin{array}{ll} w_{22} & w_{21} \\ w_{12} & w_{11} \\ \end{array} \right\rbrack = \left\lbrack \begin{array}{lll} \frac{\partial l}{\partial a_{11}^{l - 1}} & \frac{\partial l}{\partial a_{12}^{l - 1}} & \frac{\partial l}{\partial a_{13}^{l - 1}} \\ \frac{\partial l}{\partial a_{21}^{l - 1}} & \frac{\partial l}{\partial a_{22}^{l - 1}} & \frac{\partial l}{\partial a_{23}^{l - 1}} \\ \frac{\partial l}{\partial a_{31}^{l - 1}} & \frac{\partial l}{\partial a_{32}^{l - 1}} & \frac{\partial l}{\partial a_{33}^{l - 1}} \\ \end{array} \right\rbrack$

可以看到$\delta$周圍都包圍著0,這叫做full模式的卷積運算,因為只有這樣才能讓$\boldsymbol{\delta}^{l}$矩陣擴充套件到$\frac{\partial l}{\partial\boldsymbol{a}^{l - 1}}$的大小。而且我們還能發現,現在的卷積核跟前向傳播時候的卷積核對比確實是發生了180度旋轉,即:

$\frac{\partial l}{\partial\boldsymbol{a}^{l - 1}} = conv2D\left( {\boldsymbol{\delta}^{l},rot180\left( \boldsymbol{W}^{l} \right),'full'} \right)$

一個結論是如果前向傳播是valid模式的卷積運算,那麼反向傳播就需要做full模式的卷積操作。

 

接著讓我們再看一個更通用的例子2:

假設第$l - 1$層的輸出$\boldsymbol{a}^{l - 1}$是一個5 x 5的矩陣,第$l$層的卷積核$\boldsymbol{W}^{l}$是一個3x3的矩陣,採用2畫素的步幅,啟用函式用的是線性函式,輸出的$\boldsymbol{z}^{l}$是一個2 x 2的矩陣。我們簡化$\boldsymbol{b}^{l}$成都是0,則有:

$\boldsymbol{z}^{l} = conv2D\left( {\boldsymbol{a}^{l - 1},\boldsymbol{W}^{l},^{'}valid^{'},~stride = 2} \right)$

對上述式子展開,進行元素級分析:

$\left\lbrack \begin{array}{ll} z_{11} & z_{12} \\ z_{21} & z_{22} \\ \end{array} \right\rbrack = \left\lbrack \begin{array}{ll} \begin{array}{lll} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \\ \end{array} & \begin{array}{ll} a_{14} & a_{15} \\ a_{24} & a_{25} \\ a_{34} & a_{35} \\ \end{array} \\ \begin{array}{lll} a_{41} & a_{42} & a_{43} \\ a_{51} & a_{52} & a_{53} \\ \end{array} & \begin{array}{ll} a_{44} & a_{45} \\ a_{54} & a_{55} \\ \end{array} \\ \end{array} \right\rbrack*\left\lbrack \begin{array}{ll} \begin{array}{l} w_{11} \\ w_{21} \\ \end{array} & \begin{array}{l} \begin{array}{ll} w_{12} & w_{13} \\ \end{array} \\ \begin{array}{ll} w_{22} & w_{23} \\ \end{array} \\ \end{array} \\ w_{31} & \begin{array}{ll} w_{32} & w_{33} \\ \end{array} \\ \end{array} \right\rbrack$

 

其中卷積符號代表CNN中的卷積操作,利用該定義,我們得到:

$z_{11} = a_{11}w_{11} + a_{12}w_{12} + a_{13}w_{13} + a_{21}w_{21} + a_{22}w_{22} + a_{23}w_{23} + a_{31}w_{31} + a_{32}w_{32} + a_{33}w_{33}$

$z_{12} = a_{13}w_{11} + a_{14}w_{12} + a_{15}w_{13} + a_{23}w_{21} + a_{24}w_{22} + a_{25}w_{23} + a_{33}w_{31} + a_{34}w_{32} + a_{35}w_{33}$

$z_{21} = a_{31}w_{11} + a_{32}w_{12} + a_{33}w_{13} + a_{41}w_{21} + a_{42}w_{22} + a_{43}w_{23} + a_{51}w_{31} + a_{52}w_{32} + a_{53}w_{33}$

$z_{22} = a_{33}w_{11} + a_{34}w_{12} + a_{35}w_{13} + a_{43}w_{21} + a_{44}w_{22} + a_{45}w_{23} + a_{53}w_{31} + a_{54}w_{32} + a_{55}w_{33}$

 

接著我們模擬反向求導過程:

根據鏈式法則:$\frac{\partial l}{\partial a_{x,y}^{l - 1}} = {\sum\limits_{k}{\sum\limits_{l}{\frac{\partial l}{\partial z_{k,l}^{l}}\frac{\partial z_{k,l}^{l}}{a_{x,y}^{l - 1}}}}}$,我們得到:

$\frac{\partial l}{\partial a_{11}^{l - 1}} = {\sum\limits_{k}{\sum\limits_{l}{\frac{\partial l}{\partial z_{k,l}^{l}}\frac{\partial z_{k,l}^{l}}{a_{x,y}^{l - 1}}}}} = \frac{\partial l}{\partial z_{11}^{l}}\frac{\partial z_{11}^{l}}{a_{11}^{l - 1}} + \frac{\partial l}{\partial z_{12}^{l}}\frac{\partial z_{12}^{l}}{a_{11}^{l - 1}} + \frac{\partial l}{\partial z_{21}^{l}}\frac{\partial z_{21}^{l}}{a_{11}^{l - 1}} + \frac{\partial l}{\partial z_{22}^{l}}\frac{\partial z_{22}^{l}}{a_{11}^{l - 1}}$

於是我們得到:

$\frac{\partial l}{\partial a_{11}^{l - 1}} = \frac{\partial l}{\partial z_{11}^{l}}w_{11} = \delta_{11}w_{11}$

同理,我們可以得到(同一個$\frac{\partial l}{\partial a_{xy}^{l - 1}}$的下標規律是$\delta$的下標$\pm 1$則$w$的下標$\mp 2$):

$\frac{\partial l}{\partial a_{12}^{l - 1}} = \delta_{11}w_{12}$

$\frac{\partial l}{\partial a_{13}^{l - 1}} = \delta_{11}w_{13} + \delta_{12}w_{11}$

$\frac{\partial l}{\partial a_{14}^{l - 1}} = \delta_{12}w_{12}$

...其他的$\frac{\partial l}{\partial a_{xy}^{l - 1}}$以此類推。

 

實際我們可以用下面這個卷積運算來表示上面這些海量的偏導數:

$\left\lbrack \begin{array}{lll} \begin{array}{ll} 0 & 0 \\ 0 & 0 \\ \end{array} & \begin{array}{lll} 0 & 0 & 0 \\ 0 & 0 & 0 \\ \end{array} & \begin{array}{ll} 0 & 0 \\ 0 & 0 \\ \end{array} \\ \begin{array}{ll} 0 & 0 \\ 0 & 0 \\ \end{array} & \begin{array}{lll} \delta_{11} & 0 & \delta_{12} \\ 0 & 0 & 0 \\ \delta_{21} & 0 & \delta_{22} \\ \end{array} & \begin{array}{ll} 0 & 0 \\ 0 & 0 \\ \end{array} \\ \begin{array}{ll} 0 & 0 \\ 0 & 0 \\ \end{array} & \begin{array}{lll} 0 & 0 & 0 \\ 0 & 0 & 0 \\ \end{array} & \begin{array}{ll} 0 & 0 \\ 0 & 0 \\ \end{array} \\ \end{array} \right\rbrack*\left\lbrack \begin{array}{ll} \begin{array}{l} w_{33} \\ w_{23} \\ \end{array} & \begin{array}{l} \begin{array}{ll} w_{32} & w_{31} \\ \end{array} \\ \begin{array}{ll} w_{22} & w_{21} \\ \end{array} \\ \end{array} \\ w_{13} & \begin{array}{ll} w_{12} & w_{11} \\ \end{array} \\ \end{array} \right\rbrack = \left\lbrack \begin{array}{lll} \frac{\partial l}{\partial a_{11}^{l - 1}} & \cdots & \frac{\partial l}{\partial a_{15}^{l - 1}} \\ \vdots & \ddots & \vdots \\ \frac{\partial l}{\partial a_{51}^{l - 1}} & \cdots & \frac{\partial l}{\partial a_{51}^{l - 1}} \\ \end{array} \right\rbrack$

 

由上式可知,在例子二中卷積核確實也旋轉了180度。但是跟第一個例子相比,這裡的$\delta_{ij}$是散開了的。分析其原因,我認為解釋是這樣的:從我們的數學推導過程來看,我們是在預設stride=1的情況下推導的,而緊接著所舉的例子1也是在stride=1的情況證明推導的正確性,所以自然也是沒什麼問題。而在例子2中,stride=2了,如果我們不讓$\delta_{ij}$散開,那麼最後左邊這個矩陣與卷積核進行卷積之後是無法得到右邊矩陣的那種尺寸的。

 

那麼當stride>1時,$\delta_{ij}$需要散得多開呢?

 

如果我們想讓stride>1時和stride=1時的結果能得到統一,我認為我們可以將stride>1的情況視為是stride=1的特殊情況,例如,stride=2的話,兩個矩陣先按照stride=1那樣進行卷積,在位移不能被2整除的地方,卷積結果就輸出0。這樣我們就得到下面這個計算模式:

$conv2D\left( {\boldsymbol{a}^{l - 1},\boldsymbol{W}^{l},^{'}valid^{'},~stride = 2} \right) = \left\lbrack \begin{array}{lll} z_{11} & 0 & z_{12} \\ 0 & 0 & 0 \\ z_{21} & 0 & z_{22} \\ \end{array} \right\rbrack = \boldsymbol{z}^{l}$

然後loss $l$對矩陣$\boldsymbol{z}^{l}$的導數,即$\boldsymbol{\delta}^{l}$,它跟$rot180\left( \boldsymbol{W}^{l} \right)$進行stride=1的full模式的卷積運算最終結果就是例子2的結果了,即:

$\frac{\partial l}{\partial\boldsymbol{a}^{l - 1}} = conv2D\left( {\left\lbrack \begin{array}{lll} \delta_{11} & 0 & \delta_{12} \\ 0 & 0 & 0 \\ \delta_{21} & 0 & \delta_{22} \\ \end{array} \right\rbrack,rot180\left( \boldsymbol{W}^{l} \right),'full'} \right)$

 

分析上面這個結果不禁讓人思考深度學習框架裡的conv函式是怎麼實現的。出於方便進行梯度反向計算的目的,前向傳播的任何stride>1的卷積操作,都應當看成是特殊的stride=1的卷積會更好,即stride>1的輸出等於是對在stride=1下卷積得到的特徵圖的做subsampling,前一段時間在網上搜一些Conv2DTranspose相關的資料的時候也看到過這種說法,貌似conv函式的stride=2就是基於stride=1的特徵圖做下采樣得到的。

 

回到正題,求得$\frac{\partial l}{\partial\boldsymbol{a}^{l - 1}}$進一步求$\frac{\partial l}{\partial\boldsymbol{z}^{l - 1}}$就非常簡單了:

因為$dl = \left( \frac{\partial l}{\partial\boldsymbol{a}^{l - 1}} \right)^{T}d\boldsymbol{a}^{l - 1}$,$\boldsymbol{a}^{l - 1} = \sigma\left( \boldsymbol{z}^{l - 1} \right)$

所以通過鏈式(套娃)法則有:

 $dl = \left( \frac{\partial l}{\partial\boldsymbol{a}^{l - 1}} \right)^{T}d\boldsymbol{a}^{l - 1} = \left( \frac{\partial l}{\partial\boldsymbol{a}^{l - 1}} \right)^{T}d\sigma\left( \boldsymbol{z}^{l - 1} \right) = \left( \frac{\partial l}{\partial\boldsymbol{a}^{l - 1}} \right)^{T}diag\left( {\sigma^{'}\left( \boldsymbol{z}^{l - 1} \right)} \right)d\boldsymbol{z}^{l - 1} = \left( {diag\left( {\sigma^{'}\left( \boldsymbol{z}^{l - 1} \right)} \right)\frac{\partial l}{\partial\boldsymbol{a}^{l - 1}}} \right)^{T}d\boldsymbol{z}^{l - 1} = \left( {\frac{\partial l}{\partial\boldsymbol{a}^{l - 1}} \odot \sigma^{'}\left( \boldsymbol{z}^{l - 1} \right)} \right)^{T}d\boldsymbol{z}^{l - 1}$

 所以求出$\frac{\partial l}{\partial\boldsymbol{z}^{l - 1}} = \frac{\partial l}{\partial\boldsymbol{a}^{l - 1}} \odot \sigma^{'}\left( \boldsymbol{z}^{l - 1} \right)$,這就是本小節開頭那個待說明的結論:

 $\boldsymbol{\delta}^{l - 1} = \left( \frac{\partial\boldsymbol{z}^{l}}{\partial\boldsymbol{z}^{l - 1}} \right)^{T}\boldsymbol{\delta}^{l} = \boldsymbol{\delta}^{l}*rot180\left( \boldsymbol{W}^{l} \right) \odot \sigma^{'}\left( \boldsymbol{z}^{l - 1} \right)$

 

3.2.3 已知卷積層的$\delta^{l}$,推導該層的$W$,$b$的梯度

我們現在已經可以遞推出每一層的梯度誤差$\boldsymbol{\delta}^{\boldsymbol{l}}$了,對於全連線層,如何求$\boldsymbol{W}$和$\boldsymbol{b}$這個問題已經討論過了,而池化層是沒有$\boldsymbol{W}$和$\boldsymbol{b}$,所以就剩下卷積層的$\boldsymbol{W}$和$\boldsymbol{b}$了。

 

所以我們把目光放到卷積層的$\boldsymbol{W}$和$\boldsymbol{b}$上:

 

類似於上一小節的分析思路,我們先根據鏈式法則寫出下面這個等式:

 $\frac{\partial l}{\partial w_{x,y}^{l - 1}} = {\sum\limits_{k}{\sum\limits_{l}{\frac{\partial l}{\partial z_{k,l}^{l}}\frac{\partial z_{k,l}^{l}}{w_{x,y}^{l - 1}}}}}$

然後對$z_{k,l}^{l}$進行展開,得到:

 $\frac{\partial l}{\partial w_{x,y}^{l}} = {\sum\limits_{k}{\sum\limits_{l}{\frac{\partial l}{\partial z_{k,l}^{l}}\frac{\partial z_{k,l}^{l}}{w_{x,y}^{l}}}}} = {\sum\limits_{k}{\sum\limits_{l}{\delta_{k,l}^{l}\frac{\partial\left( {{\sum\limits_{m}{\sum\limits_{n}{w_{m,n}^{l}\sigma\left( z_{k + m,l + n}^{l - 1} \right) +}}}b_{x,y}^{l}} \right)}{\partial w_{x,y}^{l}}}}}$

類似地,我們進一步得到:

$\frac{\partial l}{\partial\boldsymbol{W}^{l}} = {\sum\limits_{k}{\sum\limits_{l}\delta_{k,l}^{l}}}\sigma\left( z_{k + x,l + y}^{l - 1} \right) = conv2D\left( {\sigma\left( \boldsymbol{z}^{l - 1} \right),\boldsymbol{\delta}^{l}~,'valid'} \right)$

 

需要注意的是,對於stride>1的情況,如果要求$\frac{\partial\boldsymbol{l}}{\partial\boldsymbol{W}^{\boldsymbol{l}}}$$\frac{\partial\boldsymbol{l}}{\partial\boldsymbol{b}^{\boldsymbol{l}}}$,我們需要將其$\boldsymbol{\delta}^{\boldsymbol{l}}$

視為是stride=1的特殊情況,只有在stride=1和stride>1兩種情況下卷積核位置重疊的地方是有值的,其他位置都是0。

 

之所以是valid模式而不是前面反向傳播那樣用full,是因為這裡$\sigma\left( z_{k + x,l + y}^{l - 1} \right)$的尺寸比$\frac{\partial l}{\partial w_{x,y}^{l - 1}}$大,所以不可能是full的。

 

類似地,對於$\frac{\partial l}{\partial b_{x,y}^{l}}$我們有:

$\frac{\partial l}{\partial b_{x,y}^{l}} = {\sum\limits_{k}{\sum\limits_{l}{\frac{\partial l}{\partial z_{k,l}^{l}}\frac{\partial z_{k,l}^{l}}{b_{x,y}^{l}}}}} = {\sum\limits_{k}{\sum\limits_{l}{\delta_{k,l}^{l}\frac{\partial\left( {{\sum\limits_{m}{\sum\limits_{n}{w_{m,n}^{l}\sigma\left( z_{k + m,l + n}^{l - 1} \right) +}}}b_{x,y}^{l}} \right)}{\partial b_{x,y}^{l}}}}} = {\sum\limits_{k}{\sum\limits_{l}\delta_{k,l}^{l}}}$

 

因為每張feature map的bias都是靠廣播來擴散到所有元素上的,所以顯然所有$\frac{\partial l}{\partial b_{x,y}^{l}}$都一樣:

$\frac{\partial l}{\partial b^{l}} = \frac{\partial l}{\partial b_{x,y}^{l}} = {\sum\limits_{k}{\sum\limits_{l}\delta_{k,l}^{l}}}$

 

3.2.4 CNN反向梯度求導總結

現在我們總結下CNN的反向傳播演算法,以最基本的批量梯度下降法為例來描述反向傳播演算法。

 

輸入:m個圖片樣本,CNN模型的層數L和所有隱藏層的型別。

  • 對於卷積層,要定義卷積核的大小K,卷積核子矩陣的維度F,填充大小P,步幅S。

  • 對於池化層,要定義池化區域大小k和池化標準(MAX或Average)。

  • 對於全連線層,要定義全連線層的啟用函式(輸出層除外)和各層的神經元個數。
  • 梯度迭代引數迭代步長$\alpha$,最大迭代次數MAX與停止迭代閾值$\epsilon$。

輸出:CNN模型各隱藏層與輸出層的$\boldsymbol{W}$,$\boldsymbol{b}$

1)初始化各隱藏層與輸出層的各$\boldsymbol{W}$,$\boldsymbol{b}$的值為隨機值。

2)for iter from 1 to MAX:

2-1)for i =1 to m:

a)將CNN輸入$\boldsymbol{a}^{1}$設定為$\boldsymbol{x}_{i}$對應的張量

b)for $l=2$ to L-1,根據下面3中情況進行前向傳播計算

  • 如果當前是全連線層:有$\boldsymbol{a}^{i,l} = \sigma\left( \boldsymbol{z}^{i,l} \right) = \sigma\left( {\boldsymbol{W}^{l}\boldsymbol{a}^{i,l - 1} + b^{l}} \right)$
  • 如果當前是卷積層:則有$\boldsymbol{a}^{i,l} = \sigma\left( \boldsymbol{z}^{i,l} \right) = \sigma\left( {conv2D\left( {\boldsymbol{W}^{l}{,\boldsymbol{a}}^{i,l - 1},\boldsymbol{'}valid\boldsymbol{'}} \right)} \right)$
  • 如果當前是池化層:則有$\boldsymbol{a}^{i,l} = pool\left( \boldsymbol{a}^{i,l - 1} \right)$

c)對於輸出層(即第L層):$\boldsymbol{a}^{i,L} = softmax\left( \boldsymbol{z}^{i,L} \right) = softmax\left( {\boldsymbol{W}^{L}\boldsymbol{a}^{i,L - 1} + b^{L}} \right)$

d)通過損失函式計算輸出層的$\boldsymbol{\delta}^{i,L}$

e)for $l=L-1$ to 2,根據下面3種情況進行反向傳播計算:

  • 如果當前是全連線層:$\boldsymbol{\delta}^{i,l} = \left( \boldsymbol{W}^{l + 1} \right)^{T}\boldsymbol{\delta}^{i,l + 1} \odot \sigma^{'}\left( \boldsymbol{z}^{i,l} \right)$
  • 如果當前是卷積層:$\boldsymbol{\delta}^{i,l} = conv2D\left( {\boldsymbol{\delta}^{i,l + 1},rot180\left( \boldsymbol{W}^{l + 1} \right)~} \right) \odot \sigma^{'}\left( \boldsymbol{z}^{i,l} \right)$
  • 如果當前是池化層:$\boldsymbol{\delta}^{i,l} = upsample\left( \boldsymbol{\delta}_{k}^{l + 1} \right) \odot \sigma^{'}\left( \boldsymbol{z}_{k}^{l} \right)$

2-2)for $l=2$ to L,根據下面2種情況更新第$l$層的$\boldsymbol{W}$,$\boldsymbol{b}$

  • 如果當前是全連線層:$\boldsymbol{W}^{l} = \boldsymbol{W}^{l} - \alpha{\sum\limits_{i = 1}^{m}{\boldsymbol{\delta}^{i,l}\left( \boldsymbol{a}^{i,l - 1} \right)^{T}}}$,$\boldsymbol{b}^{l} = \boldsymbol{b}^{l} - \alpha{\sum\limits_{i = 1}^{m}\boldsymbol{\delta}^{i,l}}$
  • 如果當前是卷積層,對於每個卷積核的每個子矩陣執行:$\boldsymbol{W}^{l} = \boldsymbol{W}^{l} - \alpha{\sum\limits_{i = 1}^{m}{\boldsymbol{\delta}^{i,l}*\left( \boldsymbol{a}^{i,l - 1} \right)^{T}}}$,$b^{l} = b^{l} - \alpha{\sum\limits_{i = 1}^{m}{\sum\limits_{u,v}\left( \boldsymbol{\delta}^{i,l} \right)_{u,v}}}$

2-3)如果所有$\boldsymbol{W}$,$\boldsymbol{b}$的變化值都小於$\epsilon$,則停止迭代。

3)輸出各隱藏層與輸出層的線性關係係數矩陣和偏置,$\boldsymbol{W}$,$\boldsymbol{b}$

 


 

 參考資料

(歡迎轉載,轉載請註明出處。歡迎留言或溝通交流: lxwalyw@gmail.com)

相關文章