卷積神經網路(CNN)反向傳播演算法

劉建平Pinard發表於2017-03-03

    在卷積神經網路(CNN)前向傳播演算法中,我們對CNN的前向傳播演算法做了總結,基於CNN前向傳播演算法的基礎,我們下面就對CNN的反向傳播演算法做一個總結。在閱讀本文前,建議先研究DNN的反向傳播演算法:深度神經網路(DNN)反向傳播演算法(BP)

1. 回顧DNN的反向傳播演算法

    我們首先回顧DNN的反向傳播演算法。在DNN中,我們是首先計算出輸出層的$\delta^L$:$$\delta^L = \frac{\partial J(W,b)}{\partial z^L} = \frac{\partial J(W,b)}{\partial a^L}\odot \sigma^{'}(z^L)$$

    利用數學歸納法,用$\delta^{l+1}$的值一步步的向前求出第l層的$\delta^l$,表示式為:$$\delta^{l} = \delta^{l+1}\frac{\partial z^{l+1}}{\partial z^{l}} = (W^{l+1})^T\delta^{l+1}\odot \sigma^{'}(z^l)$$

    有了$\delta^l$的表示式,從而求出$W,b$的梯度表示式:$$\frac{\partial J(W,b)}{\partial W^l} = \frac{\partial J(W,b,x,y)}{\partial z^l} \frac{\partial z^l}{\partial W^l} = \delta^{l}(a^{l-1})^T$$$$\frac{\partial J(W,b,x,y)}{\partial b^l} = \frac{\partial J(W,b)}{\partial z^l} \frac{\partial z^l}{\partial b^l} = \delta^{l}$$

    有了$W,b$梯度表示式,就可以用梯度下降法來優化$W,b$,求出最終的所有$W,b$的值。

    現在我們想把同樣的思想用到CNN中,很明顯,CNN有些不同的地方,不能直接去套用DNN的反向傳播演算法的公式。

2. CNN的反向傳播演算法思想

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

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

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

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

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

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

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

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

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

    我們首先解決上面的問題2,如果已知池化層的$\delta^l$,推匯出上一隱藏層的$\delta^{l-1}$。

    在前向傳播演算法時,池化層一般我們會用MAX或者Average對輸入進行池化,池化的區域大小已知。現在我們反過來,要從縮小後的誤差$\delta^l$,還原前一次較大區域對應的誤差。

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

    用一個例子可以很方便的表示:假設我們的池化區域大小是2x2。$\delta^l$的第k個子矩陣為:$$\delta_k^l =
\left( \begin{array}{ccc}
2& 8 \\
4& 6 \end{array} \right)$$

    由於池化區域為2x2,我們先講$\delta_k^l$做還原,即變成:$$
\left( \begin{array}{ccc}
0&0&0&0 \\ 0&2& 8&0 \\ 0&4&6&0 \\
0&0&0&0 \end{array} \right)$$

     如果是MAX,假設我們之前在前向傳播時記錄的最大值位置分別是左上,右下,右上,左下,則轉換後的矩陣為:$$
\left( \begin{array}{ccc}
2&0&0&0 \\ 0&0& 0&8 \\ 0&4&0&0 \\
0&0&6&0 \end{array} \right)$$

    如果是Average,則進行平均:轉換後的矩陣為:$$
\left( \begin{array}{ccc}
0.5&0.5&2&2 \\ 0.5&0.5&2&2 \\ 1&1&1.5&1.5 \\
1&1&1.5&1.5 \end{array} \right)$$

    這樣我們就得到了上一層 $\frac{\partial J(W,b)}{\partial a_k^{l-1}} $的值,要得到$\delta_k^{l-1}$:$$\delta_k^{l-1} = \frac{\partial J(W,b)}{\partial a_k^{l-1}} \frac{\partial  a_k^{l-1}}{\partial z_k^{l-1}} = upsample(\delta_k^l) \odot \sigma^{'}(z_k^{l-1})$$

    其中,upsample函式完成了池化誤差矩陣放大與誤差重新分配的邏輯。

    我們概括下,對於張量$\delta^{l-1}$,我們有:$$\delta^{l-1} =  upsample(\delta^l) \odot \sigma^{'}(z^{l-1})$$

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

    對於卷積層的反向傳播,我們首先回憶下卷積層的前向傳播公式:$$  a^l= \sigma(z^l) = \sigma(a^{l-1}*W^l +b^l) $$

    其中$n\_in$為上一隱藏層的輸入子矩陣個數。

    在DNN中,我們知道$\delta^{l-1}$和$\delta^{l}$的遞推關係為:$$\delta^{l} = \frac{\partial J(W,b)}{\partial z^l} = \frac{\partial J(W,b)}{\partial z^{l+1}}\frac{\partial z^{l+1}}{\partial z^{l}} = \delta^{l+1}\frac{\partial z^{l+1}}{\partial z^{l}}$$

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

    注意到$z^{l}$和$z^{l-1}$的關係為:$$z^l = a^{l-1}*W^l +b^l =\sigma(z^{l-1})*W^l +b^l  $$

    因此我們有:$$\delta^{l-1} =  \delta^{l}\frac{\partial z^{l}}{\partial z^{l-1}} = \delta^{l}*rot180(W^{l}) \odot  \sigma^{'}(z^{l-1}) $$

    這裡的式子其實和DNN的類似,區別在於對於含有卷積的式子求導時,卷積核被旋轉了180度。即式子中的$rot180()$,翻轉180度的意思是上下翻轉一次,接著左右翻轉一次。在DNN中這裡只是矩陣的轉置。那麼為什麼呢?由於這裡都是張量,直接推演引數太多了。我們以一個簡單的例子說明為啥這裡求導後卷積核要翻轉。

    假設我們$l-1$層的輸出$a^{l-1}$是一個3x3矩陣,第$l$層的卷積核$W^l$是一個2x2矩陣,採用1畫素的步幅,則輸出$z^{l}$是一個2x2的矩陣。我們簡化$b^l都是0$,則有$$a^{l-1}*W^l = z^{l}$$

    我們列出$a,W,z$的矩陣表示式如下:$$
\left( \begin{array}{ccc}
a_{11}&a_{12}&a_{13} \\ a_{21}&a_{22}&a_{23}\\
a_{31}&a_{32}&a_{33} \end{array} \right)    *  \left( \begin{array}{ccc}
w_{11}&w_{12}\\
w_{21}&w_{22} \end{array} \right) = \left( \begin{array}{ccc}
z_{11}&z_{12}\\
z_{21}&z_{22} \end{array} \right)$$

    利用卷積的定義,很容易得出:$$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_{23}w_{12} + a_{32}w_{21} +   a_{33}w_{22} $$

    接著我們模擬反向求導:$$\nabla a^{l-1} = \frac{\partial J(W,b)}{\partial a^{l-1}} = \frac{\partial J(W,b)}{\partial z^{l}} \frac{\partial z^{l}}{\partial a^{l-1}} = \delta^{l} \frac{\partial z^{l}}{\partial a^{l-1}}$$

    從上式可以看出,對於$a^{l-1}$的梯度誤差$\nabla a^{l-1}$,等於第$l$層的梯度誤差乘以$\frac{\partial z^{l}}{\partial a^{l-1}}$,而$\frac{\partial z^{l}}{\partial a^{l-1}}$對應上面的例子中相關聯的$w$的值。假設我們的$z$矩陣對應的反向傳播誤差是$\delta_{11}, \delta_{12}, \delta_{21}, \delta_{22}$組成的2x2矩陣,則利用上面梯度的式子和4個等式,我們可以分別寫出$\nabla a^{l-1}$的9個標量的梯度。

    比如對於$a_{11}$的梯度,由於在4個等式中$a_{11}$只和$z_{11}$有乘積關係,從而我們有:$$ \nabla a_{11} = \delta_{11}w_{11}$$

    對於$a_{12}$的梯度,由於在4個等式中$a_{12}$和$z_{12},z_{11}$有乘積關係,從而我們有:$$ \nabla a_{12} = \delta_{11}w_{12} + \delta_{12}w_{11}$$

    同樣的道理我們得到:$$ \nabla a_{13} = \delta_{12}w_{12} $$$$\nabla a_{21} = \delta_{11}w_{21} + \delta_{21}w_{11}$$$$\nabla a_{22} = \delta_{11}w_{22} + \delta_{12}w_{21} + \delta_{21}w_{12} + \delta_{22}w_{11}  $$$$ \nabla a_{23} = \delta_{12}w_{22} + \delta_{22}w_{12}$$$$ \nabla a_{31} = \delta_{21}w_{21}$$$$ \nabla a_{32} = \delta_{21}w_{22} + \delta_{22}w_{21}$$$$ \nabla a_{33} = \delta_{22}w_{22} $$  

    這上面9個式子其實可以用一個矩陣卷積的形式表示,即:$$
\left( \begin{array}{ccc}
0&0&0&0 \\ 0&\delta_{11}& \delta_{12}&0 \\ 0&\delta_{21}&\delta_{22}&0 \\
0&0&0&0 \end{array} \right) * \left( \begin{array}{ccc}
w_{22}&w_{21}\\
w_{12}&w_{11} \end{array} \right)  = \left( \begin{array}{ccc}
\nabla a_{11}&\nabla a_{12}&\nabla a_{13} \\ \nabla a_{21}&\nabla a_{22}&\nabla a_{23}\\
\nabla a_{31}&\nabla a_{32}&\nabla a_{33} \end{array} \right)$$

     為了符合梯度計算,我們在誤差矩陣周圍填充了一圈0,此時我們將卷積核翻轉後和反向傳播的梯度誤差進行卷積,就得到了前一次的梯度誤差。這個例子直觀的介紹了為什麼對含有卷積的式子反向傳播時,卷積核要翻轉180度的原因。

    以上就是卷積層的誤差反向傳播過程。

5. 已知卷積層的$\delta^l$,推導該層的$W,b$的梯度    

    好了,我們現在已經可以遞推出每一層的梯度誤差$\delta^l$了,對於全連線層,可以按DNN的反向傳播演算法求該層$W,b$的梯度,而池化層並沒有$W,b$,也不用求$W,b$的梯度。只有卷積層的$W,b$需要求出。

    注意到卷積層$z$和$W,b$的關係為:$$z^l = a^{l-1}*W^l +b$$

    因此我們有:$$\frac{\partial J(W,b)}{\partial W^{l}} = \frac{\partial J(W,b)}{\partial z^{l}}\frac{\partial z^{l}}{\partial W^{l}} =a^{l-1} *\delta^l$$

    注意到此時卷積核並沒有反轉,主要是此時是層內的求導,而不是反向傳播到上一層的求導。具體過程我們可以分析一下。

    和第4節一樣的一個簡化的例子,這裡輸入是矩陣,不是張量,那麼對於第l層,某個個卷積核矩陣W的導數可以表示如下:$$\frac{\partial J(W,b)}{\partial W_{pq}^{l}} = \sum\limits_i\sum\limits_j(\delta_{ij}^la_{i+p-1,j+q-1}^{l-1})$$

    假設我們輸入$a$是4x4的矩陣,卷積核$W$是3x3的矩陣,輸出$z$是2x2的矩陣,那麼反向傳播的$z$的梯度誤差$\delta$也是2x2的矩陣。

    那麼根據上面的式子,我們有:$$\frac{\partial J(W,b)}{\partial W_{11}^{l}} = a_{11}\delta_{11} + a_{12}\delta_{12} + a_{21}\delta_{21} +  a_{22}\delta_{22}$$

$$\frac{\partial J(W,b)}{\partial W_{12}^{l}} = a_{12}\delta_{11} + a_{13}\delta_{12} + a_{22}\delta_{21} +  a_{23}\delta_{22}$$

$$\frac{\partial J(W,b)}{\partial W_{13}^{l}} = a_{13}\delta_{11} + a_{14}\delta_{12} + a_{23}\delta_{21} +  a_{24}\delta_{22}$$

$$\frac{\partial J(W,b)}{\partial W_{21}^{l}} = a_{21}\delta_{11} + a_{22}\delta_{12} + a_{31}\delta_{21} +  a_{32}\delta_{22}$$

    最終我們可以一共得到9個式子。整理成矩陣形式後可得:

$$\frac{\partial J(W,b)}{\partial W^{l}} =\left( \begin{array}{ccc} a_{11}&a_{12}&a_{13}&a_{14} \\ a_{21}&a_{22}&a_{23}&a_{24} \\ a_{31}&a_{32}&a_{33}&a_{34} \\
a_{41}&a_{42}&a_{43}&a_{44} \end{array} \right) * \left( \begin{array}{ccc}
\delta_{11}& \delta_{12} \\ \delta_{21}&\delta_{22} \end{array} \right)  $$

    從而可以清楚的看到這次我們為什麼沒有反轉的原因。

    而對於b,則稍微有些特殊,因為$\delta^l$是高維張量,而$b$只是一個向量,不能像DNN那樣直接和$\delta^l$相等。通常的做法是將$\delta^l$的各個子矩陣的項分別求和,得到一個誤差向量,即為$b$的梯度:$$\frac{\partial J(W,b)}{\partial b^{l}} = \sum\limits_{u,v}(\delta^l)_{u,v}$$

6. CNN反向傳播演算法總結

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

    輸入:m個圖片樣本,CNN模型的層數L和所有隱藏層的型別,對於卷積層,要定義卷積核的大小K,卷積核子矩陣的維度F,填充大小P,步幅S。對於池化層,要定義池化區域大小k和池化標準(MAX或Average),對於全連線層,要定義全連線層的啟用函式(輸出層除外)和各層的神經元個數。梯度迭代引數迭代步長$\alpha$,最大迭代次數MAX與停止迭代閾值$\epsilon$

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

    1) 初始化各隱藏層與輸出層的各$W,b$的值為一個隨機值。

      2)for iter to 1 to MAX:

    2-1) for i =1 to m:

      a) 將CNN輸入$a^1$設定為$x_i$對應的張量

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

      b-1) 如果當前是全連線層:則有$a^{i,l} = \sigma(z^{i,l}) = \sigma(W^la^{i,l-1} + b^{l})$

      b-2) 如果當前是卷積層:則有$a^{i,l} = \sigma(z^{i,l}) = \sigma(W^l*a^{i,l-1} + b^{l})$

      b-3) 如果當前是池化層:則有$ a^{i,l}= pool(a^{i,l-1})$, 這裡的pool指按照池化區域大小k和池化標準將輸入張量縮小的過程。

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

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

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

      d-1)  如果當前是全連線層:$\delta^{i,l} =  (W^{l+1})^T\delta^{i,l+1}\odot \sigma^{'}(z^{i,l})$

      d-2) 如果當前是卷積層:$\delta^{i,l} = \delta^{i,l+1}*rot180(W^{l+1}) \odot  \sigma^{'}(z^{i,l}) $

      d-3) 如果當前是池化層:$\delta^{i,l} =  upsample(\delta^{i,l+1}) \odot \sigma^{'}(z^{i,l})$

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

      2-2-1) 如果當前是全連線層:$W^l = W^l -\alpha \sum\limits_{i=1}^m \delta^{i,l}(a^{i, l-1})^T $, $b^l = b^l -\alpha \sum\limits_{i=1}^m \delta^{i,l}$

      2-2-2) 如果當前是卷積層,對於每一個卷積核有:$W^l = W^l -\alpha \sum\limits_{i=1}^m \delta^{i,l}*a^{i, l-1} $, $b^l = b^l -\alpha \sum\limits_{i=1}^m \sum\limits_{u,v}(\delta^{i,l})_{u,v}$

    2-3) 如果所有$W,b$的變化值都小於停止迭代閾值$\epsilon$,則跳出迭代迴圈到步驟3。

    3) 輸出各隱藏層與輸出層的線性關係係數矩陣$W$和偏倚向量$b$。

 

(歡迎轉載,轉載請註明出處。歡迎溝通交流: liujianping-ok@163.com) 

參考資料:

1) Neural Networks and Deep Learning by By Michael Nielsen

2) Deep Learning, book by Ian Goodfellow, Yoshua Bengio, and Aaron Courville

3) UFLDL Tutorial

4)CS231n Convolutional Neural Networks for Visual Recognition, Stanford

相關文章