1. 程式人生 > >淺讀Caffe: Blobs, Layers, and Nets

淺讀Caffe: Blobs, Layers, and Nets

Preface

今天下午把Caffe Tutorial中的Blobs, Layers, and Nets: anatomy of a Caffe model這一節閱讀了一遍。先在這裡進行大概的總結(現在意識到了總結的用處),以後隨著深度的進行慢慢加深。

首先,我想在這裡引用甘宇飛對caffe優缺點的總結

優點:
1. 速度快。Google Protocol Buffer資料標準為Caffe提升了效率。
2. 學術論文采用此模型較多。不確定是不是最多,但接觸到的不少論文都與Caffe有關(R-CNN,DSN,最近還有人用Caffe實現LSTM)

缺點:
1. 曾更新過重要函式介面。有人反映,偶爾會出現介面變換的情況,自己很久前寫的程式碼可能過了一段時間就不能和新版本很好地相容了。(現在更新速度放緩,介面逐步趨於穩定)
2. 對於某些研究方向來說的人並不適合,這個需要對Caffe的結構有一定了解。

確實,我目前看的Semantic Image Segmentation相關的Paper,幾乎都是用caffe實現的。所以,我目前著重於caffe。也玩過Tensorflow,不過速度似乎好慢。
OK,言歸正傳。

Blob

Blob是caffe中基本的資料結構,用來儲存與交流資料。並且它可以在CPU與GPU之間同步資料,提供了統一的儲存介面來處理資料。
像影象資料(batches of images)、神經網路引數(model parameters)以及神經網路進行Back propagation運算進行學習時產生的導數資料(derivatives for optimization),都可以用Blob結構來儲存與交流。

Blob結構從數學上來說,是一個N維陣列,按照C-contiguous方式來儲存。
這裡的C-contiguous fashion,我google了一下,指的就是記憶體儲存是連續的,不間斷的儲存的。具體的解釋見下面兩個網址:
1. What is the difference between contiguous and non-contiguous arrays?
2. C Contiguous Memory
具體的來講,上面的N維陣列中的N,是4。例如對於一批如下影象資料:

影象的數量number: N
影象的通道數channel: K
影象的高度height: H
影象的寬度width: W

於是其Blob資料結構為:N* K * H * W。當然,實際物理儲存上,是按照行佔優(row-major)方式儲存的。
因此,對於(n, k, h, w)的位置,其實體記憶體地址即為:((n×K+k)×H+h)×W+w

Blob儲存的資料分為兩類:datadiff,前者指的是我們在網路間正常交流的資料,如影象畫素資料之類的;後者指的是Back propagation進行學習時,運算得到的梯度資料。
由於這些資料可以在CPU上計算、也可以在GPU上運算,因此,要想獲取這些資料分別有兩種方式。拿在CPU上運算的data資料舉例:

const Dtype* cpu_data() const; //不可改變資料值
Dtype* mutable_cpu_data(); //可以改變資料值

這在原始碼中:~/caffe/include/caffe/blob.hpp 中,體現如下:

這裡寫圖片描述

這樣設計的原因是,caffe為了在CPU與GPU之間同步資料時,隱藏同步的細節以及儘可能減小資料傳輸的量,於是使用了SyncedMem類。這裡的一個建議是,如果不需要改變資料的值,儘可能的使用const訪問的方式。

還有就是,Tutorial上提到一點,對於純粹應用的人;來說應該沒多大關係。我還是看了一下,寫的是當實際操作中,有GPU存在的時候,一開始資料已經從硬碟讀到CPU中,此時系統核心會呼叫GPU來計算,同時,CPU中不會將資料傳送到下一個網路中了,“為了保持高層的表現效能略過低層的細節資訊”,這句話的意思我不太懂,原句是:

ignoring low-level details while maintaining a high level of performance

最後所有的網路層都有GPU的實現,所有的中間資料以及計算的梯度資料都會儲存在GPU中。這部分不是太懂,可能涉及到作業系統的知識,等弄懂了再來細細補充~

Layer computation and connections

在Blob之後,就是關鍵的Layer層了,這是組成神經網路模型的基礎,也是進行計算求解的基礎。
Layers層中要進行許多運算:

  1. convolve filters:卷積層,進行卷積
  2. pool:池化層,進行池化
  3. take inner products:進行內積運算
  4. apply nonlinearities like rectified linear, sigmoid:進行非線性對映,如ReLU函式(非線性校正單元)、Sigmoid函式
  5. normalize:歸一化
  6. load data:載入資料
  7. compute losses like softmax and hinge:計算損失函式,如softmax、hinge

在Tutorial中Layer這個頁面中,詳細地講解了Layer中的不同的Layer、其間的運算細節。

所有的Layer層都可以由底層得到輸入資料,進行計算,再向前輸出計算資料。
每一層定義了3種重要的計算:setup(初始化)、forward(向前傳播)、backward(向後傳播)。
1. Setup:在神經網路一開始初始化的時候,對本層的網路進行初始化以及初始化其連線。
2. Forward:從當前這層網路的下一層得到輸入資料,經過計算(網路間的權值,進行加權計算),得到運算結果並送往下一神經網路層。
3. Backward:得到由上一神經網路層計算的梯度輸出結果,在本層對其進行梯度計算,傳輸給下一層進行計算。這裡我多說一句,實際上,梯度下降運用到的一個數學理論就是求導中的鏈式求導法則(chain rule)。正因為這個法則,所以造成了後向傳播容易造成了著名的Vanishing gradient problem(梯度消失)以及gradient explosion(梯度爆炸)問題。

在caffe中,Forward與Backward各有兩種實現版本,一種是用於CPU計算,另一種是用於GPU計算。如果你不用GPU的實現版本,神經網路層的計算會用CPU的版本,CPU版本就類似於一種備用吧。caffe在CPU與GPU計算之間的切換十分的靈活方便,GPU計算更快,僅在CPU與GPU之間傳輸資料與複製資料時需要額外的消費。

Net definition and operation

caffe中的神經網路是由一系列連線的Layer組成的 a directed acyclic graph(DAG,有向無環圖) 。
caffe會在進行前向傳播forward與後向傳播backward的時候,對DAG中的所有層進行記錄(bookkeeping),以確保正確。一個典型的網路是從底端的讀入資料層(data layer)開始,以要進行特定任務(如影象分類與重建)的損失層(losslLayer)結束。

caffe是由一個純文字模組化語言來定義描述神經網路層與它們之間的聯絡的。如下一個簡單的邏輯迴歸分類器:
這裡寫圖片描述
其純文字描述為:

name:"LogReg"
layer{
    name:"mnist"
    type:"Data"
    top:"data"
    top:"label"
    data_param{
        source:"Input_leveldb"
        batch_size:64
    }
}
layer{
    name:"ip"
    type:"InnerProduct"
    bottom:"data"
    top:"ip"
    inner_product_param{
        num_output:2
    }
}
layer{
    name:"loss"
    type:"SoftmaxWithLoss"
    bottom:"ip"
    bottom:"label"
    top:"loss"
}

這裡要說明一下的是,像上面的這幅圖片,是caffe裡面自帶的畫圖工具實現的。就是/cafferoot/python/draw_net.py這個python檔案,怎麼執行呢?是這樣的,首先需要自定義好純文字描述網路結構的檔案,如這裡的LogReg.prototxt,之後就可以如下輸入命令:

$ python draw_net.py /home/chenxp/programtest/LogReg.prototxt /home/chenxp/test.png --rankdir BT

以上命令中,/home/chenxp/programtest/LogReg.prototxt是你寫好的網路結構的檔案,/home/chenxp/test.png是輸出圖片的路徑以及圖片名,最後的--rankdir BT是指定輸出網路的方向,預設是LR,即從左到右,我指定的是BT,意思是從下往上繪製神經網路結構圖。

模組的初始化是由Net::Init()函式來進行的,初始化做兩件事:
1. 創造Blob資料塊與Layer層,初步搭起網路結構圖的大致架構;
2. 呼叫神經網路層的SetUp()初始化函式。
除了以上這兩件“大事”,初始化工作瀏覽網路架構,驗證正確性,在初始化的時候,網路會在終端裡打印出初始化期間的日誌資訊(擷取自Tutorial):
這裡寫圖片描述

注意到這裡網路的構建過程是與裝置無關的(device agnostic),之前提到過,在神經網路模型定義的時候,Blob與Layer層隱藏了實現了細節。在網路構建完成後,通過定義在caffe::mode()的轉換函式來決定網路是用CPU跑還是GPU跑,通過Caffe::set_mode()來設定。神經網路層通過CPU計算得到的結果與通過GPU計算得到的結果是一樣的(由計算機的數值誤差決定,但是可以通過測試來預防避免)。

Conclusion

今天上午看了一會兒SVM、CRF方面的,最後還是想,把最近研究的Fully Convolutional Network研究透,準備自己著手訓練一組資料,先試試看。因為不知怎麼的,我測試FCN-32s Fully Convolutional Semantic Segmentation on PASCAL-Context的時候,當stride是32的時候,即fcn-32s-pascalcontext.caffemodel,可以測試出結果,雖然不是很好:
這裡寫圖片描述

但是,當我用fcn-16s-pascalcontext.caffemodel以及其他stride的caffemodel時,基本出不了結果。但是我看Github上還有有人跑出良好的結果的,我想是不是需要自己訓練一下。所以,這兩天把caffe好好研究一下,目標可以自己寫出eval.pydeploy.prototxt這些檔案,部署自己的caffe~
今天看的其實還沒到原始碼部分,caffe的原始碼寫的很規範,很棒,一定要看看,所以這一頁會補上原始碼部分的分析,稍後~^_^

相關推薦

Caffe: Blobs, Layers, and Nets

Preface 今天下午把Caffe Tutorial中的Blobs, Layers, and Nets: anatomy of a Caffe model這一節閱讀了一遍。先在這裡進行大概的總結(現在意識到了總結的用處),以後隨著深度的進行慢慢加深。 首先

caffe中train_val.prototxt和deploy.prototxt文件的區別

image pixel proto form 準確率 .proto 應用 網絡 基礎 本文以CaffeNet為例: 1. train_val.prototxt 首先,train_val.prototxt文件是網絡配置文件。該文件是在訓練的時候用的。 2.dep

head first servlet and jsp有感(1)(轉)

上下 first 例如 端口 求和 ftp服務 運行 表單 app 一.web服務器:接收客戶請求,然後向客戶返回一些結果,註意web服務器在硬件上指物理主機,在軟件上指web服務器應用軟件,例如tomcat,jboss那種 web客戶,一般指瀏覽器(b/s模式)

caffe源碼(未完待續)

樣本 源碼解析 單元 最小 size 傳遞 strong 統一 news caffe源碼閱讀雜記 準備 一些參考網頁 Neural Networks and Deep Learning TUTORIAL ON DEEP LEARNING FOR VISION Deep

jdk原始碼-Integer

public final class Integer extends Number implements Comparable<Integer>   Integer 由final修飾了,所以該類不能夠被繼承,同時 Integer 繼承了Number類,因此可以將Integer轉換成

caffe loss layers

1.Softmax 型別(type):SoftmaxWithLoss(廣義線性迴歸分析損失層) Softmax Loss Layer計算的是輸入的多項式迴歸損失(multinomial logistic loss of the softmax of its inpu

jdk原始碼-ArrayList

  一、ArrayList概述   首先我們來說一下ArrayList是什麼?它解決了什麼問題?ArrayList其實是一個數組,但是有區別於一般的陣列,它是一個可以動態改變大小的動態陣列。ArrayList的關鍵特性也是這個動態的特性了,ArrayList的設計初衷就是為了解決Java陣列長度不可變的問題

Vue MVVM Dep/Observer/Watcher

Dep class: Dep static target: Watcher id: number // 當前 dep 的 uid sups: [Watcher, ...] // sups 是依賴的 Watcher 的集合 __proto__: { addSub(sub: Watcher) // 新增 W

Java集合&Spring原始碼

記錄自己現在知道的,以後瞭解了更多的話,再繼續補上來 Java集合類 Collection 介面 說明:是List,set 的父類。定義了集合初始模樣。集合只儲存物件。 Jdk8文件,內部方法定義有: List介面 說明:有序集合,可重複,繼承Collection。常用實現類ArrayList,L

caffe中train_val.prototxt和deploy.prototxt檔案的區別

在剛開始學習的時候,覺得train_val.prototxt檔案和deploy.prototxt檔案很相似,然後當時想嘗試利用deploy.prototxt還原出train_val.prototxt檔案,所以就進行了一下對比,水平有限,可能很多地方說的不到位,希望大神們指點批

real time localization and 3D reconstruction筆記

       首先,我們提出了從視訊流中估計相機運動和三維結構的完整方法使用區域性束調整來解釋我們的增量方法:我們建議僅使用限制在最後一個攝像機和這些攝像機觀察到的3D點的一組引數來優化3D結構的末端。在第二部分中,我們提供實際資料的實驗和結果,並與GPS定位

jdk原始碼-HashSet

  通過閱讀原始碼發現,HashSet底層的實現原始碼其實就是呼叫HashMap的方法實現的,所以如果你閱讀過HashMap或對HashMap比較熟悉的話,那麼閱讀HashSet就很輕鬆,也很容易理解了。我之前也寫了一篇關於hashMap原始碼閱讀的文章,可以點選這裡檢視。   使用過HashSet的都清楚它

對R語言因子的

啊啊啊啊啊好煩啊什麼是因子!!不同領域中的對因子的解釋是不同的!結果一百度,什麼樣的定義都有!好醉!加上R語言這個關鍵詞才找得到定義!可是,還是很難懂啊啊啊!後來經過我無限掙扎(原諒我笨),我才終於貌似懂了那麼一點點,接下來我會用比較簡單的例子去闡述!希望你能聽懂! 故事開

iOS開發之執行時程式設計(Runtime Programming)

  什麼是執行時(Objective-C runtime)?       簡單的來說,Objective-C runtime是一個實現 Objective-C語言的庫。物件可以用C語言的結構體表示,而方法(methods) 可以用C函式實現。       事實上,他們也差不

elastic-job總結所用設計模式

最近在研讀開源分散式定時任務框架elastic-job原始碼,基本清晰該框架邏輯架構和設計理念,現總結研讀過程中使用到的設計模式。 1. 單例模式               設計模式中最基本也是最常用的一種,在es-job中使用如下: @NoArgsConstructor

Handlebars模板引擎中的each巢狀及原始碼

Handlebars模板引擎作為時下最流行的模板引擎之一,已然在開發中為我們提供了無數便利。作為一款無語義的模板引擎,Handlebars只提供極少的helper函式,還原模板引擎的本身,也許這正是他在效率上略勝一籌的原因,這裡有一個網友測試,表明Handlebars在萬行

菜鳥caffe原始碼(一):protoc.exe的使用

caffe感覺都是別人玩剩下的東西,但是結合目前專案和以後對工作的設想,caffe原始碼還是有很好的學習價值。 參考入門書籍《深度學習21天實戰caffe-趙永科》 學習protobuffer相關知識,瞭解如何讀取proto.txt等相關引數檔案。 路線下載protobu

LLVM學習日誌6——另一個簡單例子ModuleMaker,呼叫LLVM的API及函式

發現LLVM的呼叫還是看不太懂,先來學個小例子。 對了,剛發現,在llvm的examples中有各種例子的原始碼可以看,包括之前那個Kaleidoscope 這個ModuleMaker 照例讀原始碼 第一句是定義context,到現在我還不知道具體有什麼用,看文件說L

NHibernate原始碼 1

曾經瞭解過Hibernate, 印象很深,是個很不錯得O/R Mapping FW. 在http://nhibernate.sourceforge.net/上有個從Java移植過來得.NET版本--NHibernate(以下稱NH),不過目前還處於PreAlpha Buil

MyBaitis 原始碼

Mybatis 架構 怎麼看原始碼 下載原始碼 (通過maven下載,或者github下載) 解壓原始碼