深度學習之CNN的推導

轉載:http://blog.csdn.net/zouxy09/article/details/9993371php

 本文的論文來自:html

Notes on Convolutional Neural Networks, Jake Bouvrie。git

         這個主要是CNN的推導和實現的一些筆記,再看懂這個筆記以前,最好具備CNN的一些基礎。這裏也先列出一個資料供參考:github

[1] Deep Learning(深度學習)學習筆記整理系列之(七)算法

[2] LeNet-5, convolutional neural networks網絡

[3]卷積神經網絡架構

[4] Neural Network for Recognition of Handwritten Digitsapp

[5] Deep learning:三十八(Stacked CNN簡單介紹)dom

[6] Gradient-based learning applied to document recognition.函數

[7]Imagenet classification with deep convolutional neural networks.

[8] UFLDL中的「卷積特徵提取」和「池化」。

        另外,這裏有個matlab的Deep Learning的toolbox,裏面包含了CNN的代碼,在下一個博文中,我將會詳細註釋這個代碼。這個筆記對這個代碼的理解很是重要。

         下面是本身對其中的一些知識點的理解:

 

《Notes on Convolutional Neural Networks》

1、介紹

         這個文檔討論的是CNNs的推導和實現。CNN架構的鏈接比權值要多不少,這實際上就隱含着實現了某種形式的規則化。這種特別的網絡假定了咱們但願經過數據驅動的方式學習到一些濾波器,做爲提取輸入的特徵的一種方法。

         本文中,咱們先對訓練全鏈接網絡的經典BP算法作一個描述,而後推導2D CNN網絡的卷積層和子採樣層的BP權值更新方法。在推導過程當中,咱們更強調實現的效率,因此會給出一些Matlab代碼。最後,咱們轉向討論如何自動地學習組合前一層的特徵maps,特別地,咱們還學習特徵maps的稀疏組合。

 

2、全鏈接的反向傳播算法

         典型的CNN中,開始幾層都是卷積和下采樣的交替,而後在最後一些層(靠近輸出層的),都是全鏈接的一維網絡。這時候咱們已經將全部兩維2D的特徵maps轉化爲全鏈接的一維網絡的輸入。這樣,當你準備好將最終的2D特徵maps輸入到1D網絡中時,一個很是方便的方法就是把全部輸出的特徵maps鏈接成一個長的輸入向量。而後咱們回到BP算法的討論。(更詳細的基礎推導能夠參考UFLDL中「反向傳導算法」)。

2.一、Feedforward Pass前向傳播

         在下面的推導中,咱們採用平方偏差代價函數。咱們討論的是多類問題,共c類,共N個訓練樣本。

         這裏表示第n個樣本對應的標籤的第k維。表示第n個樣本對應的網絡輸出的第k個輸出。對於多類問題,輸出通常組織爲「one-of-c」的形式,也就是隻有該輸入對應的類的輸出節點輸出爲正,其餘類的位或者節點爲0或者負數,這個取決於你輸出層的激活函數。sigmoid就是0,tanh就是-1.

         由於在所有訓練集上的偏差只是每一個訓練樣本的偏差的總和,因此這裏咱們先考慮對於一個樣本的BP。對於第n個樣本的偏差,表示爲:

       傳統的全鏈接神經網絡中,咱們須要根據BP規則計算代價函數E關於網絡每個權值的偏導數。咱們用l來表示當前層,那麼當前層的輸出能夠表示爲:

       輸出激活函數f(.)能夠有不少種,通常是sigmoid函數或者雙曲線正切函數。sigmoid將輸出壓縮到[0, 1],因此最後的輸出平均值通常趨於0 。因此若是將咱們的訓練數據歸一化爲零均值和方差爲1,能夠在梯度降低的過程當中增長收斂性。對於歸一化的數據集來講,雙曲線正切函數也是不錯的選擇。

 

2.二、Backpropagation Pass反向傳播

         反向傳播回來的偏差能夠看作是每一個神經元的基的靈敏度sensitivities(靈敏度的意思就是咱們的基b變化多少,偏差會變化多少,也就是偏差對基的變化率,也就是導數了),定義以下:(第二個等號是根據求導的鏈式法則獲得的)

         由於∂u/∂b=1,因此∂E/∂b=∂E/∂u=δ,也就是說bias基的靈敏度∂E/∂b=δ和偏差E對一個節點所有輸入u的導數∂E/∂u是相等的。這個導數就是讓高層偏差反向傳播到底層的神來之筆。反向傳播就是用下面這條關係式:(下面這條式子表達的就是第l層的靈敏度,就是)

 公式(1)

         這裏的「◦」表示每一個元素相乘。輸出層的神經元的靈敏度是不同的:

         最後,對每一個神經元運用delta(即δ)規則進行權值更新。具體來講就是,對一個給定的神經元,獲得它的輸入,而後用這個神經元的delta(即δ)來進行縮放。用向量的形式表述就是,對於第l層,偏差對於該層每個權值(組合爲矩陣)的導數是該層的輸入(等於上一層的輸出)與該層的靈敏度(該層每一個神經元的δ組合成一個向量的形式)的叉乘。而後獲得的偏導數乘以一個負學習率就是該層的神經元的權值的更新了:

 公式(2)

         對於bias基的更新表達式差很少。實際上,對於每個權值(W)ij都有一個特定的學習率ηIj

 

3、Convolutional Neural Networks 卷積神經網絡

3.一、Convolution Layers 卷積層

         咱們如今關注網絡中卷積層的BP更新。在一個卷積層,上一層的特徵maps被一個可學習的卷積核進行卷積,而後經過一個激活函數,就能夠獲得輸出特徵map。每個輸出map多是組合卷積多個輸入maps的值:

       這裏Mj表示選擇的輸入maps的集合,那麼到底選擇哪些輸入maps呢?有選擇一對的或者三個的。但下面咱們會討論如何去自動選擇須要組合的特徵maps。每個輸出map會給一個額外的偏置b,可是對於一個特定的輸出map,卷積每一個輸入maps的卷積核是不同的。也就是說,若是輸出特徵map j和輸出特徵map k都是從輸入map i中卷積求和獲得,那麼對應的卷積核是不同的。

3.1.一、Computing the Gradients梯度計算

         咱們假定每一個卷積層l都會接一個下采樣層l+1 。對於BP來講,根據上文咱們知道,要想求得層l的每一個神經元對應的權值的權值更新,就須要先求層l的每個神經節點的靈敏度δ(也就是權值更新的公式(2))。爲了求這個靈敏度咱們就須要先對下一層的節點(鏈接到當前層l的感興趣節點的第l+1層的節點)的靈敏度求和(獲得δl+1),而後乘以這些鏈接對應的權值(鏈接第l層感興趣節點和第l+1層節點的權值)W。再乘以當前層l的該神經元節點的輸入u的激活函數f的導數值(也就是那個靈敏度反向傳播的公式(1)的δl的求解),這樣就能夠獲得當前層l每一個神經節點對應的靈敏度δl了。

      然而,由於下采樣的存在,採樣層的一個像素(神經元節點)對應的靈敏度δ對應於卷積層(上一層)的輸出map的一塊像素(採樣窗口大小)。所以,層l中的一個map的每一個節點只與l+1層中相應map的一個節點鏈接。

     爲了有效計算層l的靈敏度,咱們須要上採樣upsample 這個下采樣downsample層對應的靈敏度map(特徵map中每一個像素對應一個靈敏度,因此也組成一個map),這樣才使得這個靈敏度map大小與卷積層的map大小一致,而後再將層l的map的激活值的偏導數與從第l+1層的上採樣獲得的靈敏度map逐元素相乘(也就是公式(1))。

        在下采樣層map的權值都取一個相同值β,並且是一個常數。因此咱們只須要將上一個步驟獲得的結果乘以一個β就能夠完成第l層靈敏度δ的計算。

       咱們能夠對卷積層中每個特徵map j重複相同的計算過程。但很明顯須要匹配相應的子採樣層的map(參考公式(1)):

        up(.)表示一個上採樣操做。若是下采樣的採樣因子是n的話,它簡單的將每一個像素水平和垂直方向上拷貝n次。這樣就能夠恢復原來的大小了。實際上,這個函數能夠用Kronecker乘積來實現:

       好,到這裏,對於一個給定的map,咱們就能夠計算獲得其靈敏度map了。而後咱們就能夠經過簡單的對層l中的靈敏度map中全部節點進行求和快速的計算bias基的梯度了:

 公式(3)

       最後,對卷積核的權值的梯度就能夠用BP算法來計算了(公式(2))。另外,不少鏈接的權值是共享的,所以,對於一個給定的權值,咱們須要對全部與該權值有聯繫(權值共享的鏈接)的鏈接對該點求梯度,而後對這些梯度進行求和,就像上面對bias基的梯度計算同樣:

       這裏,中的在卷積的時候與逐元素相乘的patch,輸出卷積map的(u, v)位置的值是由上一層的(u, v)位置的patch與卷積核k_ij逐元素相乘的結果。

      咋一看,好像咱們須要煞費苦心地記住輸出map(和對應的靈敏度map)每一個像素對應於輸入map的哪一個patch。但實際上,在Matlab中,能夠經過一個代碼就實現。對於上面的公式,能夠用Matlab的卷積函數來實現:

       咱們先對delta靈敏度map進行旋轉,這樣就能夠進行互相關計算,而不是卷積(在卷積的數學定義中,特徵矩陣(卷積核)在傳遞給conv2時須要先翻轉(flipped)一下。也就是顛倒下特徵矩陣的行和列)。而後把輸出反旋轉回來,這樣咱們在前向傳播進行卷積的時候,卷積核纔是咱們想要的方向。

 

3.二、Sub-sampling Layers 子採樣層

         對於子採樣層來講,有N個輸入maps,就有N個輸出maps,只是每一個輸出map都變小了。

        down(.)表示一個下采樣函數。典型的操做通常是對輸入圖像的不一樣nxn的塊的全部像素進行求和。這樣輸出圖像在兩個維度上都縮小了n倍。每一個輸出map都對應一個屬於本身的乘性偏置β和一個加性偏置b。

 

3.2.一、Computing the Gradients 梯度計算

         這裏最困難的是計算靈敏度map。一旦咱們獲得這個了,那咱們惟一須要更新的偏置參數β和b就能夠垂手可得了(公式(3))。若是下一個卷積層與這個子採樣層是全鏈接的,那麼就能夠經過BP來計算子採樣層的靈敏度maps。

         咱們須要計算卷積核的梯度,因此咱們必須找到輸入map中哪一個patch對應輸出map的哪一個像素。這裏,就是必須找到當前層的靈敏度map中哪一個patch對應與下一層的靈敏度map的給定像素,這樣才能夠利用公式(1)那樣的δ遞推,也就是靈敏度反向傳播回來。另外,須要乘以輸入patch與輸出像素之間鏈接的權值,這個權值實際上就是卷積核的權值(已旋轉的)。

      在這以前,咱們須要先將核旋轉一下,讓卷積函數能夠實施互相關計算。另外,咱們須要對卷積邊界進行處理,但在Matlab裏面,就比較容易處理。Matlab中全卷積會對缺乏的輸入像素補0 。

      到這裏,咱們就能夠對b和β計算梯度了。首先,加性基b的計算和上面卷積層的同樣,對靈敏度map中全部元素加起來就能夠了:

       而對於乘性偏置β,由於涉及到了在前向傳播過程當中下采樣map的計算,因此咱們最好在前向的過程當中保存好這些maps,這樣在反向的計算中就不用從新計算了。咱們定義:

這樣,對β的梯度就能夠用下面的方式計算:

 

3.三、Learning Combinations of Feature Maps 學習特徵map的組合

         大部分時候,經過卷積多個輸入maps,而後再對這些卷積值求和獲得一個輸出map,這樣的效果每每是比較好的。在一些文獻中,通常是人工選擇哪些輸入maps去組合獲得一個輸出map。但咱們這裏嘗試去讓CNN在訓練的過程當中學習這些組合,也就是讓網絡本身學習挑選哪些輸入maps來計算獲得輸出map纔是最好的。咱們用αij表示在獲得第j個輸出map的其中第i個輸入map的權值或者貢獻。這樣,第j個輸出map能夠表示爲:

         須要知足約束:

         這些對變量αij的約束能夠經過將變量αij表示爲一個組無約束的隱含權值cij的softmax函數來增強。(由於softmax的因變量是自變量的指數函數,他們的變化率會不一樣)。

         由於對於一個固定的j來講,每組權值cij都是和其餘組的權值獨立的,因此爲了方面描述,咱們把下標j去掉,只考慮一個map的更新,其餘map的更新是同樣的過程,只是map的索引j不一樣而已。

         Softmax函數的導數表示爲:

        這裏的δ是Kronecker delta。對於偏差對於第l層變量αi的導數爲:

         最後就能夠經過鏈式規則去求得代價函數關於權值ci的偏導數了:

 

3.3.一、Enforcing Sparse Combinations 增強稀疏性組合

         爲了限制αi是稀疏的,也就是限制一個輸出map只與某些而不是所有的輸入maps相連。咱們在總體代價函數裏增長稀疏約束項Ω(α)。對於單個樣本,重寫代價函數爲:

而後尋找這個規則化約束項對權值ci求導的貢獻。規則化項Ω(α)對αi求導是:

         而後,經過鏈式法則,對ci的求導是:

         因此,權值ci最後的梯度是:

 

3.四、Making it Fast with MATLAB

        CNN的訓練主要是在卷積層和子採樣層的交互上,其主要的計算瓶頸是:

1)前向傳播過程:下采樣每一個卷積層的maps;

2)反向傳播過程:上採樣高層子採樣層的靈敏度map,以匹配底層的卷積層輸出maps的大小;

3)sigmoid的運用和求導。

         對於第一和第二個問題,咱們考慮的是如何用Matlab內置的圖像處理函數去實現上採樣和下采樣的操做。對於上採樣,imresize函數能夠搞定,但須要很大的開銷。一個比較快速的版本是使用Kronecker乘積函數kron。經過一個全一矩陣ones來和咱們須要上採樣的矩陣進行Kronecker乘積,就能夠實現上採樣的效果。對於前向傳播過程當中的下采樣,imresize並無提供在縮小圖像的過程當中還計算nxn塊內像素的和的功能,因此無法用。一個比較好和快速的方法是用一個全一的卷積核來卷積圖像,而後簡單的經過標準的索引方法來採樣最後卷積結果。例如,若是下采樣的域是2x2的,那麼咱們能夠用2x2的元素全是1的卷積核來卷積圖像。而後再卷積後的圖像中,咱們每一個2個點採集一次數據,y=x(1:2:end,1:2:end),這樣就能夠獲得了兩倍下采樣,同時執行求和的效果。

         對於第三個問題,實際上有些人覺得Matlab中對sigmoid函數進行inline的定義會更快,其實否則,Matlab與C/C++等等語言不同,Matlab的inline反而比普通的函數定義更非時間。因此,咱們能夠直接在代碼中使用計算sigmoid函數及其導數的真實代碼。

相關文章
相關標籤/搜索