自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深度學(xué)習(xí)框架Caffe源碼解析

大數(shù)據(jù)
以上為Caffe代碼架構(gòu)的一個(gè)總體介紹,希望能借此幫助社區(qū)的小伙伴找到打開(kāi)定制化Caffe大門(mén)的鑰匙。本文作者希望借此拋磚引玉,與更多期望了解Caffe和深度學(xué)習(xí)框架底層實(shí)現(xiàn)的同行交流。

相信社區(qū)中很多小伙伴和我一樣使用了很長(zhǎng)時(shí)間的Caffe深度學(xué)習(xí)框架,也非常希望從代碼層次理解Caffe的實(shí)現(xiàn)從而實(shí)現(xiàn)新功能的定制。本文將從整體架構(gòu)和底層實(shí)現(xiàn)的視角,對(duì)Caffe源碼進(jìn)行解析。

Caffe總體架構(gòu)

Caffe框架主要有五個(gè)組件,Blob,Solver,Net,Layer,Proto,其結(jié)構(gòu)圖如下圖1所示。Solver負(fù)責(zé)深度網(wǎng)絡(luò)的訓(xùn)練,每個(gè)Solver中包含一個(gè)訓(xùn)練網(wǎng)絡(luò)對(duì)象和一個(gè)測(cè)試網(wǎng)絡(luò)對(duì)象。每個(gè)網(wǎng)絡(luò)則由若干個(gè)Layer構(gòu)成。每個(gè)Layer的輸入和輸出Feature map表示為Input Blob和Output Blob。Blob是Caffe實(shí)際存儲(chǔ)數(shù)據(jù)的結(jié)構(gòu),是一個(gè)不定維的矩陣,在Caffe中一般用來(lái)表示一個(gè)拉直的四維矩陣,四個(gè)維度分別對(duì)應(yīng)Batch Size(N),F(xiàn)eature Map的通道數(shù)(C),Feature Map高度(H)和寬度(W)。Proto則基于Google的Protobuf開(kāi)源項(xiàng)目,是一種類(lèi)似XML的數(shù)據(jù)交換格式,用戶(hù)只需要按格式定義對(duì)象的數(shù)據(jù)成員,可以在多種語(yǔ)言中實(shí)現(xiàn)對(duì)象的序列化與反序列化,在Caffe中用于網(wǎng)絡(luò)模型的結(jié)構(gòu)定義、存儲(chǔ)和讀取。

圖1 Caffe源碼總體架構(gòu)圖

Blob解析

下面介紹Caffe中的基本數(shù)據(jù)存儲(chǔ)類(lèi)Blob。Blob使用SyncedMemory類(lèi)進(jìn)行數(shù)據(jù)存儲(chǔ),數(shù)據(jù)成員 data_指向?qū)嶋H存儲(chǔ)數(shù)據(jù)的內(nèi)存或顯存塊,shape_存儲(chǔ)了當(dāng)前blob的維度信息,diff_這個(gè)保存了反向傳遞時(shí)候的梯度信息。在Blob中其實(shí)不是只有num,channel,height,width這種四維形式,它是一個(gè)不定維度的數(shù)據(jù)結(jié)構(gòu),將數(shù)據(jù)展開(kāi)存儲(chǔ),而維度單獨(dú)存在一個(gè)vector 類(lèi)型的shape_變量中,這樣每個(gè)維度都可以任意變化。

來(lái)一起看看Blob的關(guān)鍵函數(shù),data_at這個(gè)函數(shù)可以讀取的存儲(chǔ)在此類(lèi)中的數(shù)據(jù),diff_at可以用來(lái)讀取反向傳回來(lái)的誤差。順便給個(gè)提示,盡量使用data_at(const vector& index)來(lái)查找數(shù)據(jù)。Reshape函數(shù)可以修改blob的存儲(chǔ)大小,count用來(lái)返回存儲(chǔ)數(shù)據(jù)的數(shù)量。BlobProto類(lèi)負(fù)責(zé)了將Blob數(shù)據(jù)進(jìn)行打包序列化到Caffe的模型中。

工廠(chǎng)模式說(shuō)明

接下來(lái)介紹一種設(shè)計(jì)模式Factory Pattern,Caffe 中Solver和Layer對(duì)象的創(chuàng)建均使用了此模式,首先看工廠(chǎng)模式的UML的類(lèi)圖:

圖2 工廠(chǎng)模式UML類(lèi)圖

如同F(xiàn)actory生成同一功能但是不同型號(hào)產(chǎn)品一樣,這些產(chǎn)品實(shí)現(xiàn)了同樣Operation,很多人看了工廠(chǎng)模式的代碼,會(huì)產(chǎn)生這樣的疑問(wèn)為何不new一個(gè)出來(lái)呢,這樣new一個(gè)出來(lái)似乎也沒(méi)什么問(wèn)題吧。試想如下情況,由于代碼重構(gòu)類(lèi)的名稱(chēng)改了,或者構(gòu)造函數(shù)參數(shù)變化(增加或減少參數(shù))。而你代碼中又有N處new了這個(gè)類(lèi)。如果你又沒(méi)用工廠(chǎng),就只能一個(gè)一個(gè)找來(lái)改。工廠(chǎng)模式的作用就是讓使用者減少對(duì)產(chǎn)品本身的了解,降低使用難度。如果用工廠(chǎng),只需要修改工廠(chǎng)類(lèi)的創(chuàng)建具體對(duì)象方法的實(shí)現(xiàn),而其他代碼不會(huì)受到影響。

舉個(gè)例子,寫(xiě)代碼少不得餓了要加班去吃夜宵,麥當(dāng)勞的雞翅和肯德基的雞翅都是MM愛(ài)吃的東西,雖然口味有所不同,但不管你帶MM去麥當(dāng)勞或肯德基,只管向服務(wù)員說(shuō)“來(lái)四個(gè)雞翅”就行了。麥當(dāng)勞和肯德基就是生產(chǎn)雞翅的Factory。

Solver解析

接下來(lái)切回正題,我們看看Solver這個(gè)優(yōu)化對(duì)象在Caffe中是如何實(shí)現(xiàn)的。SolverRegistry這個(gè)類(lèi)就是我們看到的上面的factory類(lèi),負(fù)責(zé)給我們一個(gè)優(yōu)化算法的產(chǎn)品,外部只需要把數(shù)據(jù)和網(wǎng)絡(luò)結(jié)構(gòu)定義好,它就可以自己優(yōu)化了。

Solver* CreateSolver(const SolverParameter& param)這個(gè)函數(shù)就是工廠(chǎng)模式下的CreateProduct的操作, Caffe中這個(gè)SolverRegistry工廠(chǎng)類(lèi)可以提供給我們6種產(chǎn)品(優(yōu)化算法):

這六種產(chǎn)品的功能都是實(shí)現(xiàn)網(wǎng)絡(luò)的參數(shù)更新,只是實(shí)現(xiàn)方式不一樣。那我們來(lái)看看他們的使用流程吧。當(dāng)然這些產(chǎn)品類(lèi)似上面Product類(lèi)中的Operation,每一個(gè)Solver都會(huì)繼承Solve和Step函數(shù),而每個(gè)Solver中獨(dú)有的僅僅是ApplyUpdate這個(gè)函數(shù)里面執(zhí)行的內(nèi)容不一樣,接口是一致的,這也和我們之前說(shuō)的工廠(chǎng)生產(chǎn)出來(lái)的產(chǎn)品一樣功能一樣,細(xì)節(jié)上有差異,比如大多數(shù)電飯煲都有煮飯的功能,但是每一種電飯煲煮飯的加熱方式可能不同,有底盤(pán)加熱的還有立體加熱的等。接下里我們看看Solver中的關(guān)鍵函數(shù)。

Solver中Solve函數(shù)的流程圖如下:

圖3 Solver類(lèi)Solve方法流程圖

Solver類(lèi)中Step函數(shù)流程圖:

圖4 Solver類(lèi)Step方法流程圖

Solver中關(guān)鍵的就是調(diào)用Sovle函數(shù)和Step函數(shù)的流程,你只需要對(duì)照Solver類(lèi)中兩個(gè)函數(shù)的具體實(shí)現(xiàn),看懂上面兩個(gè)流程圖就可以理解Caffe訓(xùn)練執(zhí)行的過(guò)程了。

Net類(lèi)解析

分析過(guò)Solver之后我們來(lái)分析下Net類(lèi)的一些關(guān)鍵操作。這個(gè)是我們使用Proto創(chuàng)建出來(lái)的深度網(wǎng)絡(luò)對(duì)象,這個(gè)類(lèi)負(fù)責(zé)了深度網(wǎng)絡(luò)的前向和反向傳遞。以下是Net類(lèi)的初始化方法NetInit函數(shù)調(diào)用流程:

圖5 Net類(lèi)NetInit方法流程圖

Net的類(lèi)中的關(guān)鍵函數(shù)簡(jiǎn)單剖析

• ForwardBackward:按順序調(diào)用了Forward和Backward。

• ForwardFromTo(int start, int end):執(zhí)行從start層到end層的前向傳遞,采用簡(jiǎn)單的for循環(huán)調(diào)用。

• BackwardFromTo(int start, int end):和前面的ForwardFromTo函數(shù)類(lèi)似,調(diào)用從start層到end層的反向傳遞。

• ToProto函數(shù)完成網(wǎng)絡(luò)的序列化到文件,循環(huán)調(diào)用了每個(gè)層的ToProto函數(shù)。

Layer解析

Layer是Net的基本組成單元,例如一個(gè)卷積層或一個(gè)Pooling層。本小節(jié)將介紹Layer類(lèi)的實(shí)現(xiàn)。

Layer的繼承結(jié)構(gòu)

圖6 Layer層的繼承結(jié)構(gòu)

Layer的創(chuàng)建

與Solver的創(chuàng)建方式很像,Layer的創(chuàng)建使用的也是工廠(chǎng)模式,這里簡(jiǎn)單說(shuō)明下幾個(gè)宏函數(shù):

REGISTER_LAYER_CREATOR負(fù)責(zé)將創(chuàng)建層的函數(shù)放入LayerRegistry。

我們來(lái)看看大多數(shù)層創(chuàng)建的函數(shù)的生成宏REGISTER_LAYER_CLASS,可以看到宏函數(shù)比較簡(jiǎn)單的,將類(lèi)型作為函數(shù)名稱(chēng)的一部分,這樣就可以產(chǎn)生出一個(gè)創(chuàng)建函數(shù),并將創(chuàng)建函數(shù)放入LayerRegistry。

REGISTER_LAYER_CREATOR(type, Creator_##type##Layer)

這段代碼在split_layer.cpp文件中

REGISTER_LAYER_CLASS(Split)。

這樣我們將type替換過(guò)以后給大家做個(gè)范例,參考下面的代碼。

當(dāng)然這里的創(chuàng)建函數(shù)好像是直接調(diào)用,沒(méi)有涉及到我們之前工廠(chǎng)模式的一些問(wèn)題。所有的層的類(lèi)都是這樣嗎?當(dāng)然不是,我們仔細(xì)觀(guān)察卷積類(lèi)。

卷積層怎么沒(méi)有創(chuàng)建函數(shù)呢,當(dāng)然不是,卷積的層的創(chuàng)建函數(shù)在LayerFactory.cpp中,截圖給大家看下,具體代碼如下:

這樣兩種類(lèi)型的Layer的創(chuàng)建函數(shù)都有了對(duì)應(yīng)的聲明。這里直接說(shuō)明除了有cudnn實(shí)現(xiàn)的層,其他層都是采用***種方式實(shí)現(xiàn)的創(chuàng)建函數(shù),而帶有cudnn實(shí)現(xiàn)的層都采用的第二種方式實(shí)現(xiàn)的創(chuàng)建函數(shù)。

Layer的初始化

介紹完創(chuàng)建我們看看層里面的幾個(gè)函數(shù)都是什么時(shí)候被調(diào)用的。

關(guān)鍵函數(shù)Setup此函數(shù)在之前的流程圖中的NetInit時(shí)候被調(diào)用,代碼如下:

這樣整個(gè)Layer初始化的過(guò)程中,CheckBlobCounts被***調(diào)用,然后接下來(lái)是LayerSetUp,后面才是Reshape,***才是SetLossWeights。這樣Layer初始化的生命周期大家就有了了解。

Layer的其他函數(shù)的介紹

Layer的Forward函數(shù)和Backward函數(shù)完成了網(wǎng)絡(luò)的前向和反向傳遞,這兩個(gè)函數(shù)在自己實(shí)現(xiàn)新的層必須要實(shí)現(xiàn)。其中Backward會(huì)修改bottom中blob的diff_,這樣就完成了誤差的方向傳導(dǎo)。

Protobuf介紹

Caffe中的Caffe.proto文件負(fù)責(zé)了整個(gè)Caffe網(wǎng)絡(luò)的構(gòu)建,又負(fù)責(zé)了Caffemodel的存儲(chǔ)和讀取。下面用一個(gè)例子介紹Protobuf的工作方式:

利用protobuffer工具存儲(chǔ)512維度圖像特征:

• message 編寫(xiě):新建txt文件后綴名改為proto,編寫(xiě)自己的message如下,并放入解壓的protobuff的文件夾里;

其中,dwFaceFeatSize表示特征點(diǎn)數(shù)量;pfFaceFeat表示人臉特征。

• 打開(kāi)windows命令窗口(cmd.exe)—->cd空格,把protobuff的文件路徑復(fù)制粘貼進(jìn)去——>enter;

• 輸入指令protoc *.proto –cpp_out=. ———>enter

• 可以看到文件夾里面生成“ .pb.h”和“.pb.cpp”兩個(gè)文件,說(shuō)明成功了

• 下面可以和自己的代碼整合了:

• 新建你自己的工程,把“ .pb.h”和“.pb.cpp”兩個(gè)文件添加到自己的工程里,并寫(xiě)上#include” *.pb.h”

• 按照配庫(kù)的教程把庫(kù)配置下就可以了

VS下Protobuf的配庫(kù)方法:

解決方案—->右擊工程名—->屬性

(1)c/c++—>常規(guī)—>附加包含目錄—>

($your protobuffer include path)\protobuffer

(2)c/c++—>鏈接器–>常規(guī)—>附加庫(kù)目錄–>

($your protobuffer lib path)\protobuffer

(3) c/c++—>鏈接器–>輸入—>附加依賴(lài)項(xiàng)–>

libprotobufd.lib;(帶d的為debug模式)

或libprotobuf.lib;(不帶d,為release模式)

使用protobuf進(jìn)行打包的方法如下代碼:

Caffe的模型序列化

BlobProto其實(shí)就是Blob序列化成Proto的類(lèi),Caffe模型文件使用了該類(lèi)。Net調(diào)用每個(gè)層的Toproto方法,每個(gè)層的Toproto方法調(diào)用了Blob類(lèi)的ToProto方法,這樣完整的模型就被都序列化到proto里面了。***只要將這個(gè)proto繼承于message類(lèi)的對(duì)象序列化到文件就完成了模型寫(xiě)入文件。Caffe打包模型的時(shí)候就只是簡(jiǎn)單調(diào)用了WriteProtoToBinaryFile這個(gè)函數(shù),而這個(gè)函數(shù)里面的內(nèi)容如下:

Proto.txt的簡(jiǎn)單說(shuō)明

Caffe網(wǎng)絡(luò)的構(gòu)建和Solver的參數(shù)定義均由此類(lèi)型文件完成。Net構(gòu)建過(guò)程中調(diào)用ReadProtoFromTextFile將所有的網(wǎng)絡(luò)參數(shù)讀入。然后調(diào)用上面的流程進(jìn)行整個(gè)caffe網(wǎng)絡(luò)的構(gòu)建。這個(gè)文件決定了怎樣使用存在caffe model中的每個(gè)blob是用來(lái)做什么的,如果沒(méi)有了這個(gè)文件caffe的模型文件將無(wú)法使用,因?yàn)槟P椭兄淮鎯?chǔ)了各種各樣的blob數(shù)據(jù),里面只有float值,而怎樣切分這些數(shù)據(jù)是由prototxt文件決定的。

Caffe的架構(gòu)在框架上采用了反射機(jī)制去動(dòng)態(tài)創(chuàng)建層來(lái)構(gòu)建Net,Protobuf本質(zhì)上定義了graph,反射機(jī)制是由宏配合map結(jié)構(gòu)形成的,然后使用工廠(chǎng)模式去實(shí)現(xiàn)各種各樣層的創(chuàng)建,當(dāng)然區(qū)別于一般定義配置采用xml或者json,該項(xiàng)目的寫(xiě)法采用了proto文件對(duì)組件進(jìn)行組裝。

總結(jié)

以上為Caffe代碼架構(gòu)的一個(gè)總體介紹,希望能借此幫助社區(qū)的小伙伴找到打開(kāi)定制化Caffe大門(mén)的鑰匙。本文作者希望借此拋磚引玉,與更多期望了解Caffe和深度學(xué)習(xí)框架底層實(shí)現(xiàn)的同行交流。

責(zé)任編輯:武曉燕 來(lái)源: 網(wǎng)絡(luò)大數(shù)據(jù)
相關(guān)推薦

2019-03-06 09:55:54

Python 開(kāi)發(fā)編程語(yǔ)言

2017-04-25 18:03:11

Caffe深度學(xué)習(xí)框架

2017-02-21 10:00:44

大數(shù)據(jù)深度學(xué)習(xí)框架對(duì)比

2018-03-09 22:56:52

PaddlePaddl

2012-11-06 11:07:59

jQueryJSjQuery框架

2024-01-18 08:31:22

go實(shí)現(xiàn)gorm框架

2022-12-07 08:02:43

Spring流程IOC

2013-03-05 09:16:33

MySQLInnodb

2021-11-05 12:59:51

深度學(xué)習(xí)PytorchTenso

2024-09-11 09:25:03

Tomcat組件PREP

2023-06-27 16:42:18

Tinygrad深度學(xué)習(xí)工具

2020-08-28 17:54:31

深度學(xué)習(xí)框架

2021-11-27 05:03:09

框架深度學(xué)習(xí)

2022-11-25 07:35:57

PyTorchPython學(xué)習(xí)框架

2015-09-11 09:17:55

JavaJava HashMa

2021-09-16 15:08:08

鴻蒙HarmonyOS應(yīng)用

2022-04-17 23:09:07

深度學(xué)習(xí)人工智能芯片

2011-08-31 15:59:10

LUAWeb 開(kāi)發(fā)

2024-06-13 09:12:38

2017-04-10 18:00:11

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)