日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

CNN 反向传播推导

發(fā)布時間:2025/3/17 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CNN 反向传播推导 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

CNN卷積神經(jīng)網(wǎng)絡(luò)推導(dǎo)和實現(xiàn)

本文的論文來自:

Notes on Convolutional Neural Networks, Jake Bouvrie。

這個主要是CNN的推導(dǎo)和實現(xiàn)的一些筆記,再看懂這個筆記之前,最好具有CNN的一些基礎(chǔ)。這里也先列出一個資料供參考:

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

[2] LeNet-5, convolutional neural networks

[3]卷積神經(jīng)網(wǎng)絡(luò)

[4] Neural Network for Recognition of Handwritten Digits

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

[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》

一、介紹

這個文檔討論的是CNNs的推導(dǎo)和實現(xiàn)。CNN架構(gòu)的連接比權(quán)值要多很多,這實際上就隱含著實現(xiàn)了某種形式的規(guī)則化。這種特別的網(wǎng)絡(luò)假定了我們希望通過數(shù)據(jù)驅(qū)動的方式學(xué)習到一些濾波器,作為提取輸入的特征的一種方法。

本文中,我們先對訓(xùn)練全連接網(wǎng)絡(luò)的經(jīng)典BP算法做一個描述,然后推導(dǎo)2D CNN網(wǎng)絡(luò)的卷積層和子采樣層的BP權(quán)值更新方法。在推導(dǎo)過程中,我們更強調(diào)實現(xiàn)的效率,所以會給出一些Matlab代碼。最后,我們轉(zhuǎn)向討論如何自動地學(xué)習組合前一層的特征maps,特別地,我們還學(xué)習特征maps的稀疏組合。

二、全連接的反向傳播算法

典型的CNN中,開始幾層都是卷積和下采樣的交替,然后在最后一些層(靠近輸出層的),都是全連接的一維網(wǎng)絡(luò)。這時候我們已經(jīng)將所有兩維2D的特征maps轉(zhuǎn)化為全連接的一維網(wǎng)絡(luò)的輸入。這樣,當你準備好將最終的2D特征maps輸入到1D網(wǎng)絡(luò)中時,一個非常方便的方法就是把所有輸出的特征maps連接成一個長的輸入向量。然后我們回到BP算法的討論。(更詳細的基礎(chǔ)推導(dǎo)可以參考UFLDL中“反向傳導(dǎo)算法”)。

2.1、Feedforward Pass前向傳播

在下面的推導(dǎo)中,我們采用平方誤差代價函數(shù)。我們討論的是多類問題,共c類,共N個訓(xùn)練樣本。

這里表示第n個樣本對應(yīng)的標簽的第k維。表示第n個樣本對應(yīng)的網(wǎng)絡(luò)輸出的第k個輸出。對于多類問題,輸出一般組織為“one-of-c”的形式,也就是只有該輸入對應(yīng)的類的輸出節(jié)點輸出為正,其他類的位或者節(jié)點為0或者負數(shù),這個取決于你輸出層的激活函數(shù)。sigmoid就是0,tanh就是-1.

因為在全部訓(xùn)練集上的誤差只是每個訓(xùn)練樣本的誤差的總和,所以這里我們先考慮對于一個樣本的BP。對于第n個樣本的誤差,表示為:

傳統(tǒng)的全連接神經(jīng)網(wǎng)絡(luò)中,我們需要根據(jù)BP規(guī)則計算代價函數(shù)E關(guān)于網(wǎng)絡(luò)每一個權(quán)值的偏導(dǎo)數(shù)。我們用l來表示當前層,那么當前層的輸出可以表示為:

輸出激活函數(shù)f(.)可以有很多種,一般是sigmoid函數(shù)或者雙曲線正切函數(shù)。sigmoid將輸出壓縮到[0, 1],所以最后的輸出平均值一般趨于0 。所以如果將我們的訓(xùn)練數(shù)據(jù)歸一化為零均值和方差為1,可以在梯度下降的過程中增加收斂性。對于歸一化的數(shù)據(jù)集來說,雙曲線正切函數(shù)也是不錯的選擇。

2.2、Backpropagation Pass反向傳播

反向傳播回來的誤差可以看做是每個神經(jīng)元的基的靈敏度sensitivities(靈敏度的意思就是我們的基b變化多少,誤差會變化多少,也就是誤差對基的變化率,也就是導(dǎo)數(shù)了),定義如下:(第二個等號是根據(jù)求導(dǎo)的鏈式法則得到的)

因為?u/?b=1,所以?E/?b=?E/?u=δ,也就是說bias基的靈敏度?E/?b=δ和誤差E對一個節(jié)點全部輸入u的導(dǎo)數(shù)?E/?u是相等的。這個導(dǎo)數(shù)就是讓高層誤差反向傳播到底層的神來之筆。反向傳播就是用下面這條關(guān)系式:(下面這條式子表達的就是第l層的靈敏度,就是)

公式(1)

這里的“?”表示每個元素相乘。輸出層的神經(jīng)元的靈敏度是不一樣的:

最后,對每個神經(jīng)元運用delta(即δ)規(guī)則進行權(quán)值更新。具體來說就是,對一個給定的神經(jīng)元,得到它的輸入,然后用這個神經(jīng)元的delta(即δ)來進行縮放。用向量的形式表述就是,對于第l層,誤差對于該層每一個權(quán)值(組合為矩陣)的導(dǎo)數(shù)是該層的輸入(等于上一層的輸出)與該層的靈敏度(該層每個神經(jīng)元的δ組合成一個向量的形式)的叉乘。然后得到的偏導(dǎo)數(shù)乘以一個負學(xué)習率就是該層的神經(jīng)元的權(quán)值的更新了:

公式(2)

對于bias基的更新表達式差不多。實際上,對于每一個權(quán)值(W)ij都有一個特定的學(xué)習率ηIj

三、Convolutional Neural Networks 卷積神經(jīng)網(wǎng)絡(luò)

3.1、Convolution Layers 卷積層

我們現(xiàn)在關(guān)注網(wǎng)絡(luò)中卷積層的BP更新。在一個卷積層,上一層的特征maps被一個可學(xué)習的卷積核進行卷積,然后通過一個激活函數(shù),就可以得到輸出特征map。每一個輸出map可能是組合卷積多個輸入maps的值:

這里Mj表示選擇的輸入maps的集合,那么到底選擇哪些輸入maps呢?有選擇一對的或者三個的。但下面我們會討論如何去自動選擇需要組合的特征maps。每一個輸出map會給一個額外的偏置b,但是對于一個特定的輸出map,卷積每個輸入maps的卷積核是不一樣的。也就是說,如果輸出特征map j和輸出特征map k都是從輸入map i中卷積求和得到,那么對應(yīng)的卷積核是不一樣的。

3.1.1、Computing the Gradients梯度計算

我們假定每個卷積層l都會接一個下采樣層l+1 。對于BP來說,根據(jù)上文我們知道,要想求得層l的每個神經(jīng)元對應(yīng)的權(quán)值的權(quán)值更新,就需要先求層l的每一個神經(jīng)節(jié)點的靈敏度δ(也就是權(quán)值更新的公式(2))。為了求這個靈敏度我們就需要先對下一層的節(jié)點(連接到當前層l的感興趣節(jié)點的第l+1層的節(jié)點)的靈敏度求和(得到δl+1),然后乘以這些連接對應(yīng)的權(quán)值(連接第l層感興趣節(jié)點和第l+1層節(jié)點的權(quán)值)W。再乘以當前層l的該神經(jīng)元節(jié)點的輸入u的激活函數(shù)f的導(dǎo)數(shù)值(也就是那個靈敏度反向傳播的公式(1)的δl的求解),這樣就可以得到當前層l每個神經(jīng)節(jié)點對應(yīng)的靈敏度δl了。

然而,因為下采樣的存在,采樣層的一個像素(神經(jīng)元節(jié)點)對應(yīng)的靈敏度δ對應(yīng)于卷積層(上一層)的輸出map的一塊像素(采樣窗口大小)。因此,層l中的一個map的每個節(jié)點只與l+1層中相應(yīng)map的一個節(jié)點連接。

為了有效計算層l的靈敏度,我們需要上采樣upsample 這個下采樣downsample層對應(yīng)的靈敏度map(特征map中每個像素對應(yīng)一個靈敏度,所以也組成一個map),這樣才使得這個靈敏度map大小與卷積層的map大小一致,然后再將層l的map的激活值的偏導(dǎo)數(shù)與從第l+1層的上采樣得到的靈敏度map逐元素相乘(也就是公式(1))。

在下采樣層map的權(quán)值都取一個相同值β,而且是一個常數(shù)。所以我們只需要將上一個步驟得到的結(jié)果乘以一個β就可以完成第l層靈敏度δ的計算。

我們可以對卷積層中每一個特征map j重復(fù)相同的計算過程。但很明顯需要匹配相應(yīng)的子采樣層的map(參考公式(1)):

up(.)表示一個上采樣操作。如果下采樣的采樣因子是n的話,它簡單的將每個像素水平和垂直方向上拷貝n次。這樣就可以恢復(fù)原來的大小了。實際上,這個函數(shù)可以用Kronecker乘積來實現(xiàn):

好,到這里,對于一個給定的map,我們就可以計算得到其靈敏度map了。然后我們就可以通過簡單的對層l中的靈敏度map中所有節(jié)點進行求和快速的計算bias基的梯度了:

公式(3)

最后,對卷積核的權(quán)值的梯度就可以用BP算法來計算了(公式(2))。另外,很多連接的權(quán)值是共享的,因此,對于一個給定的權(quán)值,我們需要對所有與該權(quán)值有聯(lián)系(權(quán)值共享的連接)的連接對該點求梯度,然后對這些梯度進行求和,就像上面對bias基的梯度計算一樣:

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

咋一看,好像我們需要煞費苦心地記住輸出map(和對應(yīng)的靈敏度map)每個像素對應(yīng)于輸入map的哪個patch。但實際上,在Matlab中,可以通過一個代碼就實現(xiàn)。對于上面的公式,可以用Matlab的卷積函數(shù)來實現(xiàn):

我們先對delta靈敏度map進行旋轉(zhuǎn),這樣就可以進行互相關(guān)計算,而不是卷積(在卷積的數(shù)學(xué)定義中,特征矩陣(卷積核)在傳遞給conv2時需要先翻轉(zhuǎn)(flipped)一下。也就是顛倒下特征矩陣的行和列)。然后把輸出反旋轉(zhuǎn)回來,這樣我們在前向傳播進行卷積的時候,卷積核才是我們想要的方向。

3.2、Sub-sampling Layers 子采樣層

對于子采樣層來說,有N個輸入maps,就有N個輸出maps,只是每個輸出map都變小了。

down(.)表示一個下采樣函數(shù)。典型的操作一般是對輸入圖像的不同nxn的塊的所有像素進行求和。這樣輸出圖像在兩個維度上都縮小了n倍。每個輸出map都對應(yīng)一個屬于自己的乘性偏置β和一個加性偏置b。

3.2.1、Computing the Gradients 梯度計算

這里最困難的是計算靈敏度map。一旦我們得到這個了,那我們唯一需要更新的偏置參數(shù)β和b就可以輕而易舉了(公式(3))。如果下一個卷積層與這個子采樣層是全連接的,那么就可以通過BP來計算子采樣層的靈敏度maps。

我們需要計算卷積核的梯度,所以我們必須找到輸入map中哪個patch對應(yīng)輸出map的哪個像素。這里,就是必須找到當前層的靈敏度map中哪個patch對應(yīng)與下一層的靈敏度map的給定像素,這樣才可以利用公式(1)那樣的δ遞推,也就是靈敏度反向傳播回來。另外,需要乘以輸入patch與輸出像素之間連接的權(quán)值,這個權(quán)值實際上就是卷積核的權(quán)值(已旋轉(zhuǎn)的)。

在這之前,我們需要先將核旋轉(zhuǎn)一下,讓卷積函數(shù)可以實施互相關(guān)計算。另外,我們需要對卷積邊界進行處理,但在Matlab里面,就比較容易處理。Matlab中全卷積會對缺少的輸入像素補0 。

到這里,我們就可以對b和β計算梯度了。首先,加性基b的計算和上面卷積層的一樣,對靈敏度map中所有元素加起來就可以了:

而對于乘性偏置β,因為涉及到了在前向傳播過程中下采樣map的計算,所以我們最好在前向的過程中保存好這些maps,這樣在反向的計算中就不用重新計算了。我們定義:

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

3.3、Learning Combinations of Feature Maps 學(xué)習特征map的組合

大部分時候,通過卷積多個輸入maps,然后再對這些卷積值求和得到一個輸出map,這樣的效果往往是比較好的。在一些文獻中,一般是人工選擇哪些輸入maps去組合得到一個輸出map。但我們這里嘗試去讓CNN在訓(xùn)練的過程中學(xué)習這些組合,也就是讓網(wǎng)絡(luò)自己學(xué)習挑選哪些輸入maps來計算得到輸出map才是最好的。我們用αij表示在得到第j個輸出map的其中第i個輸入map的權(quán)值或者貢獻。這樣,第j個輸出map可以表示為:

需要滿足約束:

這些對變量αij的約束可以通過將變量αij表示為一個組無約束的隱含權(quán)值cij的softmax函數(shù)來加強。(因為softmax的因變量是自變量的指數(shù)函數(shù),他們的變化率會不同)。

因為對于一個固定的j來說,每組權(quán)值cij都是和其他組的權(quán)值獨立的,所以為了方面描述,我們把下標j去掉,只考慮一個map的更新,其他map的更新是一樣的過程,只是map的索引j不同而已。

Softmax函數(shù)的導(dǎo)數(shù)表示為:

這里的δ是Kronecker delta。對于誤差對于第l層變量αi的導(dǎo)數(shù)為:

最后就可以通過鏈式規(guī)則去求得代價函數(shù)關(guān)于權(quán)值ci的偏導(dǎo)數(shù)了:

3.3.1、Enforcing Sparse Combinations 加強稀疏性組合

為了限制αi是稀疏的,也就是限制一個輸出map只與某些而不是全部的輸入maps相連。我們在整體代價函數(shù)里增加稀疏約束項?(α)。對于單個樣本,重寫代價函數(shù)為:

然后尋找這個規(guī)則化約束項對權(quán)值ci求導(dǎo)的貢獻。規(guī)則化項?(α)對αi求導(dǎo)是:

然后,通過鏈式法則,對ci的求導(dǎo)是:

所以,權(quán)值ci最后的梯度是:

3.4、Making it Fast with MATLAB

CNN的訓(xùn)練主要是在卷積層和子采樣層的交互上,其主要的計算瓶頸是:

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

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

3)sigmoid的運用和求導(dǎo)。

對于第一和第二個問題,我們考慮的是如何用Matlab內(nèi)置的圖像處理函數(shù)去實現(xiàn)上采樣和下采樣的操作。對于上采樣,imresize函數(shù)可以搞定,但需要很大的開銷。一個比較快速的版本是使用Kronecker乘積函數(shù)kron。通過一個全一矩陣ones來和我們需要上采樣的矩陣進行Kronecker乘積,就可以實現(xiàn)上采樣的效果。對于前向傳播過程中的下采樣,imresize并沒有提供在縮小圖像的過程中還計算nxn塊內(nèi)像素的和的功能,所以沒法用。一個比較好和快速的方法是用一個全一的卷積核來卷積圖像,然后簡單的通過標準的索引方法來采樣最后卷積結(jié)果。例如,如果下采樣的域是2x2的,那么我們可以用2x2的元素全是1的卷積核來卷積圖像。然后再卷積后的圖像中,我們每個2個點采集一次數(shù)據(jù),y=x(1:2:end,1:2:end),這樣就可以得到了兩倍下采樣,同時執(zhí)行求和的效果。

對于第三個問題,實際上有些人以為Matlab中對sigmoid函數(shù)進行inline的定義會更快,其實不然,Matlab與C/C++等等語言不一樣,Matlab的inline反而比普通的函數(shù)定義更非時間。所以,我們可以直接在代碼中使用計算sigmoid函數(shù)及其導(dǎo)數(shù)的真實代碼。

轉(zhuǎn)載至:https://blog.csdn.net/zouxy09/article/details/9993371

第二部分

卷積神經(jīng)網(wǎng)絡(luò)的反向傳播:

首先回顧一下一般的前饋神經(jīng)網(wǎng)絡(luò)的反向傳播:

詳細內(nèi)容可參看:神經(jīng)網(wǎng)絡(luò)基礎(chǔ)和反向傳播推導(dǎo)

1,CNN的前向傳播

a)對于卷積層,卷積核與輸入矩陣對應(yīng)位置求積再求和,作為輸出矩陣對應(yīng)位置的值。如果輸入矩陣inputX為M*N大小,卷積核為a*b大小,那么輸出Y為(M-a+1)*(N-b+1)大小。

b)對于池化層,按照池化標準把輸入張量縮小。
c)對于全連接層,按照普通網(wǎng)絡(luò)的前向傳播計算。

2,CNN反向傳播的不同之處:

首先要注意的是,一般神經(jīng)網(wǎng)絡(luò)中每一層輸入輸出a,z都只是一個向量,而CNN中的a,z是一個三維張量,即由若干個輸入的子矩陣組成。其次:

  • 池化層沒有激活函數(shù)。這個問題倒比較好解決,我們可以令池化層的激活函數(shù)為σ(z)=z,即激活后就是自己本身。這樣池化層激活函數(shù)的導(dǎo)數(shù)為1。
  • 池化層在前向傳播的時候,對輸入進行了壓縮,那么我們向前反向推導(dǎo)上一層的誤差時,需要做upsample處理
  • 卷積層是通過張量卷積,或者說若干個矩陣卷積求和而得到當前層的輸出,這和一般的網(wǎng)絡(luò)直接進行矩陣乘法得到當前層的輸出不同。這樣在卷積層反向傳播的時候,上一層誤差的遞推計算方法肯定有所不同。
  • 對于卷積層,由于W使用的運算是卷積,那么由該層誤差推導(dǎo)出該層的所有卷積核的W,b的方式也不同。
  • 由于卷積層可以有多個卷積核,各個卷積核的處理方法是完全相同且獨立的,為了簡化算法公式的復(fù)雜度,我們下面提到卷積核都是卷積層中若干卷積核中的一個。接下來看具體的CNN反向傳播步驟。

    3,已知池化層的誤差,反向推導(dǎo)上一隱藏層的誤差

    在前向傳播時,池化層我們會用MAX或者Average對輸入進行池化,池化的區(qū)域大小已知。現(xiàn)在我們反過來,要從縮小后區(qū)域的誤差,還原前一層較大區(qū)域的誤差。這個過程叫做upsample。假設(shè)我們的池化區(qū)域大小是2x2。第l層誤差的第k個子矩陣δlk為:

    如果池化區(qū)域表示為a*a大小,那么我們把上述矩陣上下左右各擴展a-1行和列進行還原

    如果是MAX,假設(shè)我們之前在前向傳播時記錄的最大值位置分別是左上,右下,右上,左下,則轉(zhuǎn)換后的矩陣為:

    如果是Average,則進行平均,轉(zhuǎn)換后的矩陣為:

    上邊這個矩陣就是誤差矩陣經(jīng)過upsample之后的矩陣,那么,由后一層誤差推導(dǎo)出前一層誤差的公式為:

    上式和普通網(wǎng)絡(luò)的反向推導(dǎo)誤差很類似:

    可以看到,只有第一項不同。

    4,已知卷積層的誤差,反向推導(dǎo)上一隱藏層的誤差

    公式如下:

    我們再看一次普通網(wǎng)絡(luò)的反向推導(dǎo)誤差的公式:

    可以看到區(qū)別在于,下一層的權(quán)重w的轉(zhuǎn)置操作,變成了旋轉(zhuǎn)180度的操作,也就是上下翻轉(zhuǎn)一次,左右再翻轉(zhuǎn)一次,這其實就是“卷積”一詞的意義(我們可簡單理解為數(shù)學(xué)上的trick),可參考下圖,Q是下一層的誤差,周圍補0方便計算,W是180度翻轉(zhuǎn)后的卷積核,P是W和Q做卷積的結(jié)果:

    5,已知卷積層的誤差,推導(dǎo)該層的W,b的梯度

    經(jīng)過以上各步驟,我們已經(jīng)算出每一層的誤差了,那么:
    a)對于全連接層,可以按照普通網(wǎng)絡(luò)的反向傳播算法求該層W,b的梯度。
    b)對于池化層,它并沒有W,b,也不用求W,b的梯度。
    c)只有卷積層的W,b需要求出,先看w:

    再對比一下普通網(wǎng)絡(luò)的求w梯度的公式,發(fā)現(xiàn)區(qū)別在于,對前一層的輸出做翻轉(zhuǎn)180度的操作:

    而對于b,則稍微有些特殊,因為在CNN中,誤差δ是三維張量,而b只是一個向量,不能像普通網(wǎng)絡(luò)中那樣直接和誤差δ相等。通常的做法是將誤差δ的各個子矩陣的項分別求和,得到一個誤差向量,即為b的梯度:



    本文內(nèi)容來自:
    1,Michael Nielsen的《Neural Networks and Deep Learning》中文翻譯
    2,http://www.cnblogs.com/pinard/p/6494810.html
    3,http://blog.csdn.net/yunpiao123456/article/details/52437794

    總結(jié)

    以上是生活随笔為你收集整理的CNN 反向传播推导的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。