深度学习caffe的代码怎么读?
生活随笔
收集整理的這篇文章主要介紹了
深度学习caffe的代码怎么读?
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
知乎用戶?,Caffe / Torch7 / CNN 知乎用戶、任逸風(fēng)、陳文?等人贊同 我是從Torch7轉(zhuǎn)移到Caffe的人,僅供參考,當(dāng)你閱讀前你應(yīng)該具備一些有關(guān)DL的基礎(chǔ)知識,本文集中寫Caffe代碼結(jié)構(gòu)而非介紹DL知識。
我是去年底開始看Caffe代碼的,看代碼的時(shí)間加在一起也不到一個(gè)月,也算半個(gè)新手,我的回答是從新手角度作一個(gè)入門階段的經(jīng)驗(yàn)分享。
本文只涉及Caffe結(jié)構(gòu)的相關(guān)問題,不涉及具體實(shí)現(xiàn)技巧等細(xì)節(jié)。
==============================================================
1. 初識Caffe
1.1. Caffe相對與其他DL框架的優(yōu)點(diǎn)和缺點(diǎn):
優(yōu)點(diǎn):
回答里面有人說熟悉Blob,Layer,Net,Solver這樣的幾大類,我比較贊同。我基本是從這個(gè)順序開始學(xué)習(xí)的,這四個(gè)類復(fù)雜性從低到高,貫穿了整個(gè)Caffe。把他們分為三個(gè)層次介紹。
==============================================================
2. Caffe進(jìn)階
2.1. Blob:
Caffe支持CUDA,在數(shù)據(jù)級別上也做了一些優(yōu)化,這部分最重要的是知道它主要是對protocol buffer所定義的數(shù)據(jù)結(jié)構(gòu)的繼承,Caffe也因此可以在盡可能小的內(nèi)存占用下獲得很高的效率。(追求性能的同時(shí)Caffe也犧牲了一些代碼可讀性)
在更高一級的Layer中Blob用下面的形式表示學(xué)習(xí)到的參數(shù):
vector<shared_ptr<Blob<Dtype> > > blobs_; 這里使用的是一個(gè)Blob的容器是因?yàn)槟承㎜ayer包含多組學(xué)習(xí)參數(shù),比如多個(gè)卷積核的卷積層。
以及Layer所傳遞的數(shù)據(jù)形式,后面還會涉及到這里:
vector<Blob<Dtype>*> ⊥ vector<Blob<Dtype>*> *top 2.2. Layer:
2.2.1. 5大Layer派生類型
Caffe十分強(qiáng)調(diào)網(wǎng)絡(luò)的層次性,也就是說卷積操作,非線性變換(ReLU等),Pooling,權(quán)值連接等全部都由某一種Layer來表示。具體來說分為5大類Layer
在Layer內(nèi)部,數(shù)據(jù)主要有兩種傳遞方式,正向傳導(dǎo)(Forward)和反向傳導(dǎo)(Backward)。Forward和Backward有CPU和GPU(部分有)兩種實(shí)現(xiàn)。Caffe中所有的Layer都要用這兩種方法傳遞數(shù)據(jù)。
virtual void Forward(const vector<Blob<Dtype>*> &bottom, vector<Blob<Dtype>*> *top) = 0; virtual void Backward(const vector<Blob<Dtype>*> &top,const vector<bool> &propagate_down, vector<Blob<Dtype>*> *bottom) = 0; Layer類派生出來的層類通過這實(shí)現(xiàn)這兩個(gè)虛函數(shù),產(chǎn)生了各式各樣功能的層類。Forward是從根據(jù)bottom計(jì)算top的過程,Backward則相反(根據(jù)top計(jì)算bottom)。注意這里為什么用了一個(gè)包含Blob的容器(vector),對于大多數(shù)Layer來說輸入和輸出都各連接只有一個(gè)Layer,然而對于某些Layer存在一對多的情況,比如LossLayer和某些連接層。在網(wǎng)路結(jié)構(gòu)定義文件(*.proto)中每一層的參數(shù)bottom和top數(shù)目就決定了vector中元素?cái)?shù)目。
layers {bottom: "decode1neuron" // 該層底下連接的第一個(gè)Layerbottom: "flatdata" // 該層底下連接的第二個(gè)Layertop: "l2_error" // 該層頂上連接的一個(gè)Layername: "loss" // 該層的名字type: EUCLIDEAN_LOSS // 該層的類型loss_weight: 0 } 2.2.3. Layer的重要成員變量
loss
vector<Dtype> loss_; 每一層又有一個(gè)loss_值,只不多大多數(shù)Layer都是0,只有LossLayer才可能產(chǎn)生非0的loss_。計(jì)算loss是會把所有層的loss_相加。
learnable parameters
vector<shared_ptr<Blob<Dtype> > > blobs_; 前面提到過的,Layer學(xué)習(xí)到的參數(shù)。
2.3. Net:
Net用容器的形式將多個(gè)Layer有序地放在一起,其自身實(shí)現(xiàn)的功能主要是對逐層Layer進(jìn)行初始化,以及提供Update( )的接口(更新網(wǎng)絡(luò)參數(shù)),本身不能對參數(shù)進(jìn)行有效地學(xué)習(xí)過程。
vector<shared_ptr<Layer<Dtype> > > layers_; 同樣Net也有它自己的
vector<Blob<Dtype>*>& Forward(const vector<Blob<Dtype>* > & bottom,Dtype* loss = NULL); void Net<Dtype>::Backward(); 他們是對整個(gè)網(wǎng)絡(luò)的前向和方向傳導(dǎo),各調(diào)用一次就可以計(jì)算出網(wǎng)絡(luò)的loss了。
2.4. Solver
這個(gè)類中包含一個(gè)Net的指針,主要是實(shí)現(xiàn)了訓(xùn)練模型參數(shù)所采用的優(yōu)化算法,它所派生的類就可以對整個(gè)網(wǎng)絡(luò)進(jìn)行訓(xùn)練了。
shared_ptr<Net<Dtype> > net_; 不同的模型訓(xùn)練方法通過重載函數(shù)ComputeUpdateValue( )實(shí)現(xiàn)計(jì)算update參數(shù)的核心功能
virtual void ComputeUpdateValue() = 0; 最后當(dāng)進(jìn)行整個(gè)網(wǎng)絡(luò)訓(xùn)練過程(也就是你運(yùn)行Caffe訓(xùn)練某個(gè)模型)的時(shí)候,實(shí)際上是在運(yùn)行caffe.cpp中的train( )函數(shù),而這個(gè)函數(shù)實(shí)際上是實(shí)例化一個(gè)Solver對象,初始化后調(diào)用了Solver中的Solve( )方法。而這個(gè)Solve( )函數(shù)主要就是在迭代運(yùn)行下面這兩個(gè)函數(shù),就是剛才介紹的哪幾個(gè)函數(shù)。
ComputeUpdateValue(); net_->Update();
==============================================================
至此,從底層到頂層對Caffe的主要結(jié)構(gòu)都應(yīng)該有了大致的概念。為了集中重點(diǎn)介紹Caffe的代碼結(jié)構(gòu),文中略去了大量Caffe相關(guān)的實(shí)現(xiàn)細(xì)節(jié)和技巧,比如Layer和Net的參數(shù)如何初始化,proto文件的定義,基于cblas的卷積等操作的實(shí)現(xiàn)(cblas實(shí)現(xiàn)卷積這一點(diǎn)我的個(gè)人主頁GanYuFei中的《Caffe學(xué)習(xí)筆記5-BLAS與boost::thread加速》有介紹)等等就不一一列舉了。
整體來看Layer部分代碼最多,也反映出Caffe比較重視豐富網(wǎng)絡(luò)單元的類型,然而由于Caffe的代碼結(jié)構(gòu)高度層次化,使得某些研究以及應(yīng)用(比如研究類似非逐層連接的神經(jīng)網(wǎng)絡(luò)這種復(fù)雜的網(wǎng)絡(luò)連接方式)難以在該平臺實(shí)現(xiàn)。這也就是一開始說的一個(gè)不足。
另外,Caffe基本數(shù)據(jù)單元都用Blob,使得數(shù)據(jù)在內(nèi)存中的存儲變得十分高效,緊湊,從而提升了整體訓(xùn)練能力,而同時(shí)帶來的問題是我們看見的一些可讀性上的不便,比如forward的參數(shù)也是直接用Blob而不是設(shè)計(jì)一個(gè)新類以增強(qiáng)可讀性。所以說性能的提升是以可讀性為代價(jià)的。
最后一點(diǎn)也是最重要的一點(diǎn),我從Caffe學(xué)到了很多。第一次看的C++項(xiàng)目就看到這么好的代碼,實(shí)在是受益匪淺,在這里也感謝作者賈揚(yáng)清等人的貢獻(xiàn)。
甘宇飛更新于2/13/2015 編輯于 2015-02-13?36 條評論?感謝? 分享 ?收藏???沒有幫助???舉報(bào)???作者保留權(quán)利 更多回答 Gein Chen?,Deep Learning/Linux/Vimer yuncheng lu、愛吃麻辣菠蘿、張小璐?等人贊同 樓上的大神回答的都很好了,非常感謝。這里我想說一下我自己學(xué)習(xí)caffe的方式,限于時(shí)間篇幅,并不想深入到具體的實(shí)現(xiàn)細(xì)節(jié),只是從大的方向上談?wù)?#xff0c;因?yàn)橹v清楚一個(gè)細(xì)節(jié)都是一篇博客的篇幅了。
1.學(xué)習(xí)程序的第一步,先讓程序跑起來,看看結(jié)果,這樣就會有直觀的感受。
Caffe的官網(wǎng)上Caffe | Deep Learning Framework?提供了很多的examples,你可以很容易地開始訓(xùn)練一些已有的經(jīng)典模型,如LeNet。我建議先從?LeNet MNIST Tutorial開始,因?yàn)閿?shù)據(jù)集很小,網(wǎng)絡(luò)也很小但很經(jīng)典,用很少的時(shí)間就可以跑起來了。當(dāng)你看到terminal刷拉拉的一行行輸出,看到不斷減少的loss和不斷上升的accuracy,訓(xùn)練結(jié)束你得到了99+%的準(zhǔn)確率,感覺好厲害的樣子。你可以多跑跑幾個(gè)例子,熟悉一下環(huán)境和接口。
2.單步調(diào)試,跟著Caffe在網(wǎng)絡(luò)里流動
當(dāng)玩了幾天之后,你對Caffe的接口有點(diǎn)熟悉了,對已有的例子也玩膩了,你開始想看看具體是怎么實(shí)現(xiàn)的了。我覺得最好的方法是通過單步調(diào)試的方式跟著程序一步一步的在網(wǎng)絡(luò)里前向傳播,然后再被當(dāng)成誤差信息傳回來。
Caffe就像一個(gè)你平常編程中Project,你可以使用IDE或者GDB去調(diào)試它,這里我們不細(xì)說調(diào)試的過程。你可以先跟蹤前向傳播的過程,無非就是從高層次到低層次的調(diào)用Forward函數(shù), Solver->Net->Layer->Specific Layer (Convolution等...).后向傳播也類似,但因?yàn)槟銓affe里面的各種變量運(yùn)算不熟悉,當(dāng)你跟蹤完前向傳播時(shí)可能已經(jīng)頭暈眼花了,還是休息一下,消化一下整個(gè)前向傳播的流程。
剛剛開始你沒有必要對每個(gè)Layer的計(jì)算細(xì)節(jié)都那么較真,大概知道程序的運(yùn)算流程就好,這樣你才可以比較快的對Caffe有個(gè)大體的把握。
3.個(gè)性化定制Caffe
到這里,你已經(jīng)可以說自己有用過Caffe了,但是還不能算入門,因?yàn)槟氵€不知道怎么修改源碼,滿足自己特定的需求。我們很多時(shí)候都需要自己定義新的層來完成特定的運(yùn)算,這時(shí)你需要在Caffe里添加新的層。
你一開肯定無從下手,腦子一片空白。幸運(yùn)的是Caffe github上的Wiki?Development · BVLC/caffe Wiki · GitHub已經(jīng)有了教程了,而且這是最接近latest Caffe的源碼結(jié)構(gòu)的教程,你在網(wǎng)上搜到的Blog很多是有點(diǎn)過時(shí)的,因?yàn)镃affe最近又重構(gòu)了代碼。你可以跟著它的指導(dǎo)去添加自己的層。
雖然你已經(jīng)知道要在哪里添加自己的東西了,但你遇到最核心的問題是如何寫下面這四個(gè)函數(shù)。
4.理解并實(shí)現(xiàn)Backpropagation
這個(gè)我覺得是與平臺無關(guān)的,不管你是使用Caffe、Torch 7,還是Theano,你都需要深刻理解并掌握的。因?yàn)槲冶容^笨,花了好長時(shí)間才能夠適應(yīng)推導(dǎo)中的各種符號。其實(shí)也不難,就是誤差順著Chain rule法則流回到前面的層。我不打算自己推導(dǎo)后向傳播的過程,因?yàn)槲抑牢覜]有辦法將它表達(dá)得很好,而且網(wǎng)上已經(jīng)有很多非常好的教程了。下面是我覺得比較好的學(xué)習(xí)步驟吧。
先說個(gè)大概,知道了神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu),forward跟backward是怎樣的一個(gè)過程,基本上就知道了caffe的結(jié)構(gòu)了。按照神經(jīng)網(wǎng)絡(luò)的運(yùn)行過程看Caffe就好了。
既然說神經(jīng)網(wǎng)絡(luò),那么就得有一個(gè)網(wǎng)絡(luò)出來,caffe里面就用Net這個(gè)類來記錄這個(gè)網(wǎng)絡(luò)。
那么網(wǎng)絡(luò)是由很多個(gè)layer構(gòu)成,自然而然就會有Layer這個(gè)類,為了統(tǒng)一管理這些類,自然而然就想要抽象,那么Layer這個(gè)抽象類作為一個(gè)最基本的單元出現(xiàn)了,接下來就會有實(shí)現(xiàn)各種功能的layer出現(xiàn),如:Convolution/ReLU/Softmax等。
Layer間需要連接啊,Layer需要有輸入輸出啊,caffe里面用Bottom來表示輸入,Top表示輸出,前一層Layer的top是后一層layer的bottom,這樣,連接搞掂了,輸入輸出也搞掂了。
網(wǎng)絡(luò)搞掂了,layer搞掂了,那就要搞個(gè)求解算法啊,那么Solver這個(gè)類就出現(xiàn)了,這個(gè)就是用來求解網(wǎng)絡(luò)的。
就醬紫,有時(shí)間再寫得詳細(xì)一點(diǎn)。反正就這么一句話:按照神經(jīng)網(wǎng)絡(luò)的運(yùn)行過程看Caffe就好了。
from:?http://www.zhihu.com/question/27982282/answer/39350629 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
我是去年底開始看Caffe代碼的,看代碼的時(shí)間加在一起也不到一個(gè)月,也算半個(gè)新手,我的回答是從新手角度作一個(gè)入門階段的經(jīng)驗(yàn)分享。
本文只涉及Caffe結(jié)構(gòu)的相關(guān)問題,不涉及具體實(shí)現(xiàn)技巧等細(xì)節(jié)。
==============================================================
1. 初識Caffe
1.1. Caffe相對與其他DL框架的優(yōu)點(diǎn)和缺點(diǎn):
優(yōu)點(diǎn):
- 速度快。Google Protocol Buffer數(shù)據(jù)標(biāo)準(zhǔn)為Caffe提升了效率。
- 學(xué)術(shù)論文采用此模型較多。不確定是不是最多,但接觸到的不少論文都與Caffe有關(guān)(R-CNN,DSN,最近還有人用Caffe實(shí)現(xiàn)LSTM)
- 曾更新過重要函數(shù)接口。有人反映,偶爾會出現(xiàn)接口變換的情況,自己很久前寫的代碼可能過了一段時(shí)間就不能和新版本很好地兼容了。(現(xiàn)在更新速度放緩,接口逐步趨于穩(wěn)定,感謝 評論區(qū)王峰的建議)
- 對于某些研究方向來說的人并不適合。這個(gè)需要對Caffe的結(jié)構(gòu)有一定了解,(后面提到)。
回答里面有人說熟悉Blob,Layer,Net,Solver這樣的幾大類,我比較贊同。我基本是從這個(gè)順序開始學(xué)習(xí)的,這四個(gè)類復(fù)雜性從低到高,貫穿了整個(gè)Caffe。把他們分為三個(gè)層次介紹。
- Blob:是基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),是用來保存學(xué)習(xí)到的參數(shù)以及網(wǎng)絡(luò)傳輸過程中產(chǎn)生數(shù)據(jù)的類。
- Layer:是網(wǎng)絡(luò)的基本單元,由此派生出了各種層類。修改這部分的人主要是研究特征表達(dá)方向的。
- Net:是網(wǎng)絡(luò)的搭建,將Layer所派生出層類組合成網(wǎng)絡(luò)。Solver:是Net的求解,修改這部分人主要會是研究DL求解方向的。
==============================================================
2. Caffe進(jìn)階
2.1. Blob:
Caffe支持CUDA,在數(shù)據(jù)級別上也做了一些優(yōu)化,這部分最重要的是知道它主要是對protocol buffer所定義的數(shù)據(jù)結(jié)構(gòu)的繼承,Caffe也因此可以在盡可能小的內(nèi)存占用下獲得很高的效率。(追求性能的同時(shí)Caffe也犧牲了一些代碼可讀性)
在更高一級的Layer中Blob用下面的形式表示學(xué)習(xí)到的參數(shù):
vector<shared_ptr<Blob<Dtype> > > blobs_; 這里使用的是一個(gè)Blob的容器是因?yàn)槟承㎜ayer包含多組學(xué)習(xí)參數(shù),比如多個(gè)卷積核的卷積層。
以及Layer所傳遞的數(shù)據(jù)形式,后面還會涉及到這里:
vector<Blob<Dtype>*> ⊥ vector<Blob<Dtype>*> *top 2.2. Layer:
2.2.1. 5大Layer派生類型
Caffe十分強(qiáng)調(diào)網(wǎng)絡(luò)的層次性,也就是說卷積操作,非線性變換(ReLU等),Pooling,權(quán)值連接等全部都由某一種Layer來表示。具體來說分為5大類Layer
- NeuronLayer類?定義于neuron_layers.hpp中,其派生類主要是元素級別的運(yùn)算(比如Dropout運(yùn)算,激活函數(shù)ReLu,Sigmoid等),運(yùn)算均為同址計(jì)算(in-place computation,返回值覆蓋原值而占用新的內(nèi)存)。
- LossLayer類?定義于loss_layers.hpp中,其派生類會產(chǎn)生loss,只有這些層能夠產(chǎn)生loss。
- 數(shù)據(jù)層?定義于data_layer.hpp中,作為網(wǎng)絡(luò)的最底層,主要實(shí)現(xiàn)數(shù)據(jù)格式的轉(zhuǎn)換。
- 特征表達(dá)層(我自己分的類)定義于vision_layers.hpp(為什么叫vision這個(gè)名字,我目前還不清楚),實(shí)現(xiàn)特征表達(dá)功能,更具體地說包含卷積操作,Pooling操作,他們基本都會產(chǎn)生新的內(nèi)存占用(Pooling相對較小)。
- 網(wǎng)絡(luò)連接層和激活函數(shù)(我自己分的類)定義于common_layers.hpp,Caffe提供了單個(gè)層與多個(gè)層的連接,并在這個(gè)頭文件中聲明。這里還包括了常用的全連接層InnerProductLayer類。
在Layer內(nèi)部,數(shù)據(jù)主要有兩種傳遞方式,正向傳導(dǎo)(Forward)和反向傳導(dǎo)(Backward)。Forward和Backward有CPU和GPU(部分有)兩種實(shí)現(xiàn)。Caffe中所有的Layer都要用這兩種方法傳遞數(shù)據(jù)。
virtual void Forward(const vector<Blob<Dtype>*> &bottom, vector<Blob<Dtype>*> *top) = 0; virtual void Backward(const vector<Blob<Dtype>*> &top,const vector<bool> &propagate_down, vector<Blob<Dtype>*> *bottom) = 0; Layer類派生出來的層類通過這實(shí)現(xiàn)這兩個(gè)虛函數(shù),產(chǎn)生了各式各樣功能的層類。Forward是從根據(jù)bottom計(jì)算top的過程,Backward則相反(根據(jù)top計(jì)算bottom)。注意這里為什么用了一個(gè)包含Blob的容器(vector),對于大多數(shù)Layer來說輸入和輸出都各連接只有一個(gè)Layer,然而對于某些Layer存在一對多的情況,比如LossLayer和某些連接層。在網(wǎng)路結(jié)構(gòu)定義文件(*.proto)中每一層的參數(shù)bottom和top數(shù)目就決定了vector中元素?cái)?shù)目。
layers {bottom: "decode1neuron" // 該層底下連接的第一個(gè)Layerbottom: "flatdata" // 該層底下連接的第二個(gè)Layertop: "l2_error" // 該層頂上連接的一個(gè)Layername: "loss" // 該層的名字type: EUCLIDEAN_LOSS // 該層的類型loss_weight: 0 } 2.2.3. Layer的重要成員變量
loss
vector<Dtype> loss_; 每一層又有一個(gè)loss_值,只不多大多數(shù)Layer都是0,只有LossLayer才可能產(chǎn)生非0的loss_。計(jì)算loss是會把所有層的loss_相加。
learnable parameters
vector<shared_ptr<Blob<Dtype> > > blobs_; 前面提到過的,Layer學(xué)習(xí)到的參數(shù)。
2.3. Net:
Net用容器的形式將多個(gè)Layer有序地放在一起,其自身實(shí)現(xiàn)的功能主要是對逐層Layer進(jìn)行初始化,以及提供Update( )的接口(更新網(wǎng)絡(luò)參數(shù)),本身不能對參數(shù)進(jìn)行有效地學(xué)習(xí)過程。
vector<shared_ptr<Layer<Dtype> > > layers_; 同樣Net也有它自己的
vector<Blob<Dtype>*>& Forward(const vector<Blob<Dtype>* > & bottom,Dtype* loss = NULL); void Net<Dtype>::Backward(); 他們是對整個(gè)網(wǎng)絡(luò)的前向和方向傳導(dǎo),各調(diào)用一次就可以計(jì)算出網(wǎng)絡(luò)的loss了。
2.4. Solver
這個(gè)類中包含一個(gè)Net的指針,主要是實(shí)現(xiàn)了訓(xùn)練模型參數(shù)所采用的優(yōu)化算法,它所派生的類就可以對整個(gè)網(wǎng)絡(luò)進(jìn)行訓(xùn)練了。
shared_ptr<Net<Dtype> > net_; 不同的模型訓(xùn)練方法通過重載函數(shù)ComputeUpdateValue( )實(shí)現(xiàn)計(jì)算update參數(shù)的核心功能
virtual void ComputeUpdateValue() = 0; 最后當(dāng)進(jìn)行整個(gè)網(wǎng)絡(luò)訓(xùn)練過程(也就是你運(yùn)行Caffe訓(xùn)練某個(gè)模型)的時(shí)候,實(shí)際上是在運(yùn)行caffe.cpp中的train( )函數(shù),而這個(gè)函數(shù)實(shí)際上是實(shí)例化一個(gè)Solver對象,初始化后調(diào)用了Solver中的Solve( )方法。而這個(gè)Solve( )函數(shù)主要就是在迭代運(yùn)行下面這兩個(gè)函數(shù),就是剛才介紹的哪幾個(gè)函數(shù)。
ComputeUpdateValue(); net_->Update();
==============================================================
至此,從底層到頂層對Caffe的主要結(jié)構(gòu)都應(yīng)該有了大致的概念。為了集中重點(diǎn)介紹Caffe的代碼結(jié)構(gòu),文中略去了大量Caffe相關(guān)的實(shí)現(xiàn)細(xì)節(jié)和技巧,比如Layer和Net的參數(shù)如何初始化,proto文件的定義,基于cblas的卷積等操作的實(shí)現(xiàn)(cblas實(shí)現(xiàn)卷積這一點(diǎn)我的個(gè)人主頁GanYuFei中的《Caffe學(xué)習(xí)筆記5-BLAS與boost::thread加速》有介紹)等等就不一一列舉了。
整體來看Layer部分代碼最多,也反映出Caffe比較重視豐富網(wǎng)絡(luò)單元的類型,然而由于Caffe的代碼結(jié)構(gòu)高度層次化,使得某些研究以及應(yīng)用(比如研究類似非逐層連接的神經(jīng)網(wǎng)絡(luò)這種復(fù)雜的網(wǎng)絡(luò)連接方式)難以在該平臺實(shí)現(xiàn)。這也就是一開始說的一個(gè)不足。
另外,Caffe基本數(shù)據(jù)單元都用Blob,使得數(shù)據(jù)在內(nèi)存中的存儲變得十分高效,緊湊,從而提升了整體訓(xùn)練能力,而同時(shí)帶來的問題是我們看見的一些可讀性上的不便,比如forward的參數(shù)也是直接用Blob而不是設(shè)計(jì)一個(gè)新類以增強(qiáng)可讀性。所以說性能的提升是以可讀性為代價(jià)的。
最后一點(diǎn)也是最重要的一點(diǎn),我從Caffe學(xué)到了很多。第一次看的C++項(xiàng)目就看到這么好的代碼,實(shí)在是受益匪淺,在這里也感謝作者賈揚(yáng)清等人的貢獻(xiàn)。
甘宇飛更新于2/13/2015 編輯于 2015-02-13?36 條評論?感謝? 分享 ?收藏???沒有幫助???舉報(bào)???作者保留權(quán)利 更多回答 Gein Chen?,Deep Learning/Linux/Vimer yuncheng lu、愛吃麻辣菠蘿、張小璐?等人贊同 樓上的大神回答的都很好了,非常感謝。這里我想說一下我自己學(xué)習(xí)caffe的方式,限于時(shí)間篇幅,并不想深入到具體的實(shí)現(xiàn)細(xì)節(jié),只是從大的方向上談?wù)?#xff0c;因?yàn)橹v清楚一個(gè)細(xì)節(jié)都是一篇博客的篇幅了。
1.學(xué)習(xí)程序的第一步,先讓程序跑起來,看看結(jié)果,這樣就會有直觀的感受。
Caffe的官網(wǎng)上Caffe | Deep Learning Framework?提供了很多的examples,你可以很容易地開始訓(xùn)練一些已有的經(jīng)典模型,如LeNet。我建議先從?LeNet MNIST Tutorial開始,因?yàn)閿?shù)據(jù)集很小,網(wǎng)絡(luò)也很小但很經(jīng)典,用很少的時(shí)間就可以跑起來了。當(dāng)你看到terminal刷拉拉的一行行輸出,看到不斷減少的loss和不斷上升的accuracy,訓(xùn)練結(jié)束你得到了99+%的準(zhǔn)確率,感覺好厲害的樣子。你可以多跑跑幾個(gè)例子,熟悉一下環(huán)境和接口。
2.單步調(diào)試,跟著Caffe在網(wǎng)絡(luò)里流動
當(dāng)玩了幾天之后,你對Caffe的接口有點(diǎn)熟悉了,對已有的例子也玩膩了,你開始想看看具體是怎么實(shí)現(xiàn)的了。我覺得最好的方法是通過單步調(diào)試的方式跟著程序一步一步的在網(wǎng)絡(luò)里前向傳播,然后再被當(dāng)成誤差信息傳回來。
Caffe就像一個(gè)你平常編程中Project,你可以使用IDE或者GDB去調(diào)試它,這里我們不細(xì)說調(diào)試的過程。你可以先跟蹤前向傳播的過程,無非就是從高層次到低層次的調(diào)用Forward函數(shù), Solver->Net->Layer->Specific Layer (Convolution等...).后向傳播也類似,但因?yàn)槟銓affe里面的各種變量運(yùn)算不熟悉,當(dāng)你跟蹤完前向傳播時(shí)可能已經(jīng)頭暈眼花了,還是休息一下,消化一下整個(gè)前向傳播的流程。
剛剛開始你沒有必要對每個(gè)Layer的計(jì)算細(xì)節(jié)都那么較真,大概知道程序的運(yùn)算流程就好,這樣你才可以比較快的對Caffe有個(gè)大體的把握。
3.個(gè)性化定制Caffe
到這里,你已經(jīng)可以說自己有用過Caffe了,但是還不能算入門,因?yàn)槟氵€不知道怎么修改源碼,滿足自己特定的需求。我們很多時(shí)候都需要自己定義新的層來完成特定的運(yùn)算,這時(shí)你需要在Caffe里添加新的層。
你一開肯定無從下手,腦子一片空白。幸運(yùn)的是Caffe github上的Wiki?Development · BVLC/caffe Wiki · GitHub已經(jīng)有了教程了,而且這是最接近latest Caffe的源碼結(jié)構(gòu)的教程,你在網(wǎng)上搜到的Blog很多是有點(diǎn)過時(shí)的,因?yàn)镃affe最近又重構(gòu)了代碼。你可以跟著它的指導(dǎo)去添加自己的層。
雖然你已經(jīng)知道要在哪里添加自己的東西了,但你遇到最核心的問題是如何寫下面這四個(gè)函數(shù)。
- forward_cpu()
- forward_gpu()
- backward_cpu()
- backward_gpu()
4.理解并實(shí)現(xiàn)Backpropagation
這個(gè)我覺得是與平臺無關(guān)的,不管你是使用Caffe、Torch 7,還是Theano,你都需要深刻理解并掌握的。因?yàn)槲冶容^笨,花了好長時(shí)間才能夠適應(yīng)推導(dǎo)中的各種符號。其實(shí)也不難,就是誤差順著Chain rule法則流回到前面的層。我不打算自己推導(dǎo)后向傳播的過程,因?yàn)槲抑牢覜]有辦法將它表達(dá)得很好,而且網(wǎng)上已經(jīng)有很多非常好的教程了。下面是我覺得比較好的學(xué)習(xí)步驟吧。
- 從淺層的神經(jīng)網(wǎng)絡(luò)(所謂的全連接層)的后向傳播開始,因?yàn)檫@個(gè)比較簡單,而且現(xiàn)在我們常說的CNN和LSTM的梯度計(jì)算也最終會回歸到這里。
- 第一個(gè)必看的是Ng深入淺出的Ufldl教程UFLDL Tutorial,還有中文版的,這對不喜歡看英語的同學(xué)是個(gè)好消息。當(dāng)然你看一遍不理解,再看一遍,忘了,再看,讀個(gè)幾遍你才會對推導(dǎo)過程和數(shù)學(xué)符號熟悉。我頭腦不大行,來來回回看了好多次。
- 當(dāng)然,Ufldl的教程有點(diǎn)短,我還發(fā)現(xiàn)了一個(gè)講得更細(xì)膩清晰的教程,?Michael Nielsen寫的Neural networks and deep learning。它講得實(shí)在太好了,以至于把我的任督二脈打通了。在Ufldl的基礎(chǔ)上讀這個(gè),你應(yīng)該可以很快掌握全連接層的反向傳播。
- 最后在拿出standford大牛karpathy的一篇博客Hacker's guide to Neural Networks,這里用了具體的編程例子手把手教你算梯度,并不是推導(dǎo)后向傳播公式的,是關(guān)于通用梯度計(jì)算的。用心去體會一下。
- 這時(shí)你躍躍欲試,回去查看Caffe源碼里Convolution層的實(shí)現(xiàn),但發(fā)現(xiàn)自己好像沒看懂。雖說卷積層和全連接層的推導(dǎo)大同小異,但思維上還是有個(gè)gap的。我建議你先去看看Caffe如何實(shí)現(xiàn)卷積的,Caffe作者賈揚(yáng)清大牛在知乎上的回答在 Caffe 中如何計(jì)算卷積?讓我茅塞頓開。重點(diǎn)理解im2col和col2im.
- 這時(shí)你知道了Convolution的前向傳播,還差一點(diǎn)就可以弄明白后向傳播怎么實(shí)現(xiàn)了。我建議你死磕Caffe中Convolution層的計(jì)算過程,把每一步都搞清楚,經(jīng)過痛苦的過程之后你會對反向傳播有了新的體會的。在這之后,你應(yīng)該有能力添加自己的層了。再補(bǔ)充一個(gè)完整的添加新的層的教程Making a Caffe Layer ? Computer Vision Enthusiast。這篇教程從頭開始實(shí)現(xiàn)了一個(gè)Angle To Sine Cosine Layer,包含了梯度推導(dǎo),前向與后向傳播的CPU和GPU函數(shù),非常棒的一個(gè)教程。
- 最后,建議學(xué)習(xí)一下基本的GPU Cuda編程,雖然Caffe中已經(jīng)把Cuda函數(shù)封裝起來了,用起來很方便,但有時(shí)還是需要使用kernel函數(shù)等Cuda接口的函數(shù)。這里有一個(gè)入門的視頻教程,講得挺不錯的NVIDIA CUDA初級教程視頻。
第二個(gè)回答,講得還是一樣的亂,謝謝觀看。
發(fā)布于 2016-01-06?21 條評論?感謝? 分享 ?收藏???沒有幫助???舉報(bào)???作者保留權(quán)利 41贊同 反對,不會顯示你的姓名 米八?,人臉檢測/關(guān)鍵點(diǎn)定位/識別 吳昊、白世明、知乎用戶?等人贊同 其實(shí)關(guān)于怎么用caffe,我一直想寫篇文章,因?yàn)榻o太多人講過怎么用了,也幫很多人基于caffe寫過代碼。14年初因?yàn)橼sNIPS,開始用caffe,大概用了有一年半了。先說個(gè)大概,知道了神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu),forward跟backward是怎樣的一個(gè)過程,基本上就知道了caffe的結(jié)構(gòu)了。按照神經(jīng)網(wǎng)絡(luò)的運(yùn)行過程看Caffe就好了。
既然說神經(jīng)網(wǎng)絡(luò),那么就得有一個(gè)網(wǎng)絡(luò)出來,caffe里面就用Net這個(gè)類來記錄這個(gè)網(wǎng)絡(luò)。
那么網(wǎng)絡(luò)是由很多個(gè)layer構(gòu)成,自然而然就會有Layer這個(gè)類,為了統(tǒng)一管理這些類,自然而然就想要抽象,那么Layer這個(gè)抽象類作為一個(gè)最基本的單元出現(xiàn)了,接下來就會有實(shí)現(xiàn)各種功能的layer出現(xiàn),如:Convolution/ReLU/Softmax等。
Layer間需要連接啊,Layer需要有輸入輸出啊,caffe里面用Bottom來表示輸入,Top表示輸出,前一層Layer的top是后一層layer的bottom,這樣,連接搞掂了,輸入輸出也搞掂了。
網(wǎng)絡(luò)搞掂了,layer搞掂了,那就要搞個(gè)求解算法啊,那么Solver這個(gè)類就出現(xiàn)了,這個(gè)就是用來求解網(wǎng)絡(luò)的。
就醬紫,有時(shí)間再寫得詳細(xì)一點(diǎn)。反正就這么一句話:按照神經(jīng)網(wǎng)絡(luò)的運(yùn)行過程看Caffe就好了。
from:?http://www.zhihu.com/question/27982282/answer/39350629 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的深度学习caffe的代码怎么读?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Caffe —— Deep learni
- 下一篇: 为什么深度学习几乎成了计算机视觉研究的标