建議安裝scitools套裝的understand對(duì)源碼進(jìn)行閱讀??梢詫?duì)整個(gè)工程的代碼進(jìn)行解析后以整個(gè)工程都可以快速地jump to definition。以及可以對(duì)整體代碼進(jìn)行更近一步的解析。反正無(wú)比好用,墻裂推薦。
Overview

我們今天主要講一下layers的源碼
layers

我們發(fā)現(xiàn)每一種layer都分成.cpp和.cu兩種。其實(shí)很好理解,.cpp的是cpu版本的,.cu是cuda版本的。


我們先來(lái)看看INSTANTIATE_CLASS(ConvolutionLayer);這個(gè)宏操作干了什么

簡(jiǎn)要介紹一下這個(gè)宏操作涉及的##(concatenate)和template specialization.
宏操作##
簡(jiǎn)單來(lái)說(shuō)就是把signal的字符鏈接起來(lái)
舉個(gè)例子
#define cat(a, b) a##b
辣么
printf("%d\n", cat(a,1));
就等價(jià)于
printf("%d\n", a1);
template instantiation
我們使用template的時(shí)候?qū)嶋H上是implicitly實(shí)例化了template的一個(gè)class,然而我們也有explicit version.
類似于
template class SampleClass<int>;
注意區(qū)別于template specialization.(模板類/函數(shù)特化是定義在規(guī)定了特定typename的template的定義)
好吧其實(shí)這些都沒(méi)什么卵用。我們其實(shí)更在乎Forward和Backward。
總所周知,CNN主要有一個(gè)end to end的過(guò)程,遵循bp網(wǎng)絡(luò)的定義,有forward也有backward。我們來(lái)簡(jiǎn)單看看這個(gè)forward和backward的過(guò)程應(yīng)該怎么寫
CPU version
forward

計(jì)算forward的被分成了兩個(gè)部分。實(shí)際上就是
o = w*i + b
第一部分的w*i對(duì)應(yīng)的就是
this->forward_cpu_gemm(bottom_data + n * this->bottom_dim_,
weight, top_data + n * this->top_dim_);
第二部分(bias)對(duì)應(yīng)的就是
if (this->bias_term_) {
const Dtype* bias = this->blobs_[1]->cpu_data();
this->forward_cpu_bias(top_data + n * this->top_dim_, bias);
}
出于好奇我們?cè)龠M(jìn)一步看看這兩個(gè)函數(shù)是怎么做的

首先介紹一下什么是im2col
http://www.zhihu.com/question/28385679
相當(dāng)于把運(yùn)算分解成兩部,首先第一步把矩陣變成一個(gè)一個(gè)的col,然后再相乘。特別的當(dāng)矩陣是1x1的時(shí)候或者需要skip im2col的時(shí)候(后面一個(gè)什么鬼我還不太清楚,總之一般情況下先理解第一個(gè))不需要im2col(廢話)。
為什么要這么做呢?
相當(dāng)于卷積被分解成了
o = col2im(w*im2col(i)) + b)
為什么要這么做呢?
好求導(dǎo)??!
可以參考
http://zhangliliang.com/2015/02/11/about-caffe-code-convolutional-layer/
(啥時(shí)候才能趕上人家的水平。。。。
至于細(xì)節(jié)部分,我想講講我在閱讀中有困難的地方,那就是維數(shù)的問(wèn)題。在conv_layer.cpp部分中,其實(shí)只是用到了batch_size那一個(gè)維度以及之前和多少個(gè)前面的層連接。沒(méi)有涉及到后面三維ChannelxWeightxHeight。
而在后面的部分,使用了im2col把WxH兩個(gè)維度壓成一個(gè)維度V, 于是就有了CxV的一個(gè)矩陣。convolution網(wǎng)絡(luò)層的參數(shù)大小是C_bottom(上一層channel數(shù))xC_top(輸出channel數(shù)),正好對(duì)應(yīng)一個(gè)矩陣乘法。
接下來(lái)forward部分的代碼屬于很好理解但是文字不好表述的部分(各種offset以及矩陣乘法函數(shù)的各種參數(shù)等等)。所以就不贅述了。
backward

結(jié)構(gòu)和forward類似。由于backward的原因應(yīng)該考慮top的size。

有了上面所說(shuō)的,其實(shí)這一步也是通過(guò)im2col把卷積變成全連接層的形式,類似于普通o=ai+b進(jìn)行求導(dǎo)。
GPU version
外層的套路和CPU version幾乎是一樣的



Titan X 3000多個(gè)核心呢。。。??斓蔑w起來(lái),一般Caffe的網(wǎng)絡(luò)GPU都是CPU的30倍左右。