caffe中forward過程總結(1)

2021-08-04 04:15:31 字數 3525 閱讀 3411

感謝作者總結!

caffe中最重要的兩個部分就是forward和backward的過程,farward是根據輸入資料正向**輸入屬於哪一類;backward是根據輸出的結果求得代價函式,然後根據代價函式反向求去其相對於各層網路引數的梯度的過程。我們先對farward過程做一下總結。

caffe中有兩個過程會設計到farward,test和train,這裡我們以train訓練過程為例。

int train() caffe.cpp line 181:

這是train的入口函式,train函式裡的操作這裡我們掠過,我們主要進入訓練的主體函式solver->solve()函式(line 253)。void solver::solve()函式是訓練網路的入口函式,而我們的訓練的主體函式就是在line 293的step()函式。

訓練主體函式void solver::step():

進入這個函式之後,我們首先就要進行迭代的迴圈,以lenet網路訓練為例,由於lenet是採用stochastic的訓練方式,所以就必須進行多次迭代,當然每次迭代迴圈又會採用多個樣本(batch)進行訓練。在迴圈體內,程式就回進入forward過程了。程式如下:

for(

inti = 0; i 

loss /= param_.iter_size(); 

3. forward過程:

在進入net_->forwardbackward()函式(net.hpp line 85)之後,程式會先進入forward函式:forward(&loss),然後再會進入backward()函式。forward過程是一層一層來進行的。在net資料結構體中有乙個儲存有每層layer指標的vector,forward過程就回根據這個vector在每層layer中進行迴圈。當前層的forward就是由當前層輸入通過卷積或是矩陣運算或者別的運算求輸出,得到的輸出作為下一層的輸入,然後繼續下一層的forward過程。forward在每層的迴圈過程如下:

for(

inti = start; i <= end; ++i)   

}  

4.每層的forward過程:

由於每層的作用不一樣,所以每層的forward過程也是不一樣的,這裡我們以lenet為例,介紹幾個重要的層的forward操作。

a.卷積層void convolutionlayer::forward_cpu(const vector*>& bottom, const                                  vector*>& top):

bottom代表輸入的資料集合,top代表輸出的資料集合,這兩個資料結構是blob結構,關於blob結構,在另一篇總結中有總結。卷             積的具體計算過程這裡我深究。由於訓練是以batch為基本單位,在lenet中乙個batch是含有64個樣本,當前類下的this->num_表                示就是乙個batch中含有的樣本數量,所以卷積也要根據樣本數量進行迴圈,程式如下:

for(int

n = 0; n 

this

->num_; ++n)   

}  

程式首先會用weight矩陣和輸入bottom向乘,對應的就是forward_cpu_gemm()函式;然後就是對bias進行處理,bias程式會根據情況決定是否對bias進行scale,即放大還是縮小。我們首先進入forward_cpu_gemm()函式:這個函式就是進行卷積運算的主要函式,caffe中的卷積運算是用blas庫完成的,blas庫只是完成矩陣操作,具體到卷積時怎麼構造矩陣是caffe本身的程式做的。我們先來看一下caffe是怎麼構造卷積矩陣的。

以lenet為例,在該層卷積之前,輸入資料是28×28的,該層的卷積核是5x5,那麼最後卷積的輸出應該是24x24。但是當前卷積層有20個卷積核,而且我現在想只呼叫一次blas的矩陣函式,就能完成20個卷積核對28x28影象的全部卷積函式。caffe是這樣處理的,如下圖所示

程式先把20個不同的卷積核放在乙個矩陣裡,矩陣的每一行表示每個卷積核的所有係數,即每個卷積核都是按行展開了;然後對於輸入畫素,該卷積層只有一張輸入畫素,程式會把每個卷積核的不同位置上的25個畫素拍成一列,對於5x5卷積核卷積28x28的,最後輸出是24x24的尺寸,我們就要為每個卷積核構造576列資料,分別對應不同位置上的25個對應的畫素;最後的輸出就會變成20x576,其中20表示20個卷積核,576表示每個卷積核的輸出尺寸,即24x24。

每個卷積核的bias只有乙個值,但是對於每個卷積核在影象上的不同位置,我們可能要對其進行scale操作,這就需要576個scale係數,最後輸出是20x576,然後和weight卷積後的結果相加就可以得出最終的結果了。

為什麼要這樣設計,我理解的是,是為了一次卷積運算就可以把20個卷積核對影象的卷積操作一次計算出來。上面只是第一層卷積層,後面卷積層的處理和這相似,但由於輸入資料的個數不一樣,矩陣構造的過程又有稍微不同。

b.pooling層void poolinglayer::forward_cpu(const vector*>& bottom, const vector*>& top):

pooling層的作用就是下取樣,這裡採用的是poolmethid_max方式,即在pooling核的區域選擇出最大的值作為當前區域的值,pooling層的運算比較簡單,這裡不再深究。

c.2級卷積層void convolutionlayer::forward_cpu(const vector*>& bottom, const vector*>& top):

經過下取樣之後,影象尺寸變成12x12,但是有20個12x12的影象資料,因為對應有20個卷積核,這一層又需要構造卷積矩陣,我們這裡權值相乘的矩陣的構造,如下圖所示:

首先第乙個矩陣同樣表示權值矩陣,50表示這一層有50個卷積核,500=25×20,這一層的卷積核是5x5,然後這一層的輸入有20個不同的12x12的影象,所以500就表示每個卷積核分別和20個不同的輸入的對應的位置相乘,然後再把所有的結果相加,從這我們可以看出,這一層的每乙個卷積核都是和所有的資料相連線的;第二個矩陣表示輸入矩陣,同樣由於卷積核的大小是5x5,輸入尺寸是12x12,所以輸出的結果是8x8,即乙個卷積核在乙個資料上卷積了64次,所以對於每一幅輸入影象,我們都要構造64個對應的數,而又因為輸入是有20張影象的,所以每一次卷積都會設計25x20個資料,所以輸入矩陣有500行,64列;輸出矩陣自然就是50x64,50對應卷積核的個數,64對應每個卷積核的輸出。

d.2級pooling層void poolinglayer::forward_cpu(const vector*>& bottom, const vector*>& top):

這也只是乙個下取樣層,對輸入8x8的影象進行下取樣,輸出就變成4x4個,都是有50個。

以上就是caffe中forward過程的和卷積層相關的forward具體過程,在卷積層後還有innerproduct層以及求取代價函式層,這在另一篇有總結。

caffe中forward過程總結 2

前面 總結的是caffe有和卷積有關的forward過程,下面我們總結一下卷積之後和全連線網路inner product layer有關的forward過程。第一層inner product void innerproductlayer forward cpu const vector bottom...

caffe中forward過程總結(2)

感謝作者總結 第一層inner product void innerproductlayer forward cpu const vector bottom,const vector top 這層的輸入是50x4x4,總共有800個輸入,而輸出的寬度是500,所以該層有500個神經元分別與輸入進行全...

caffe中backward過程總結

感謝樓主總結!backward是利用代價函式求取關於網路中每個引數梯度的過程,為後面更新網路引數做準備。求取梯度的過程也是乙個矩陣運算的過程,後面會有詳細介紹,本身求取梯度的過程並不是很複雜,而且網路中的各層求取梯度的過程都是相似的。下面就按照backward的執行順序,從最後一層向前介紹caffe...