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


    在卷積神經網絡(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} = (\frac{\partial z^{l+1}}{\partial z^{l}})^T\delta^{l+1} = (W^{l+1})^T\delta^{l+1}\odot \sigma^{'}(z^l)$$

    有了$\delta^l$的表達式,從而求出$W,b$的梯度表達式:$$\frac{\partial J(W,b)}{\partial W^l}  = \delta^{l}(a^{l-1})^T$$$$\frac{\partial J(W,b,x,y)}{\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  a_k^{l-1}}{\partial z_k^{l-1}})^T\frac{\partial J(W,b)}{\partial a_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 z^{l+1}}{\partial z^{l}})^T \frac{\partial J(W,b)}{\partial z^{l+1}} =(\frac{\partial z^{l+1}}{\partial z^{l}})^T\delta^{l+1}$$

    因此要推導出$\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} =  (\frac{\partial z^{l}}{\partial z^{l-1}})^T\delta^{l} = \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 z^{l}}{\partial a^{l-1}})^T\frac{\partial J(W,b)}{\partial z^{l}} =(\frac{\partial z^{l}}{\partial a^{l-1}})^T \delta^{l} $$

    從上式可以看出,對於$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}}=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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2024 CODEPRJ.COM