以上为Caffe代码架构的一个总体介绍,希望能借此帮助社区的小伙伴找到打开定制化Caffe大门的钥匙。本文作者希望借此抛砖引玉,与更多期望了解Caffe和深度学习框架底层实现的同行交流。

信任社区中许多小伙伴和我相同运用了很长时刻的Caffe深度学习结构,也十分希望从代码层次了解Caffe的完结然后完结新功用的定制。本文将从全体架构和底层完结的视角,对Caffe源码进行解析。

Caffe整体架构

Caffe结构主要有五个组件,Blob,Solver,Net,Layer,Proto,其结构图如下图1所示。Solver担任深度网络的练习,每个Solver中包括一个练习网络目标和一个测验网络目标。每个网络则由若干个Layer构成。每个Layer的输入和输出Feature map表明为Input Blob和Output Blob。Blob是Caffe实践存储数据的结构,是一个不定维的矩阵,在Caffe中一般用来表明一个拉直的四维矩阵,四个维度别离对应Batch Size(N),Feature Map的通道数(C),Feature Map高度(H)和宽度(W)。Proto则根据Google的Protobuf开源项目,是一种相似XML的数据交换格局,用户只需要按格局界说目标的数据成员,能够在多种语言中完结目标的序列化与反序列化,在Caffe中用于网络模型的结构界说、存储和读取。

深度学习结构Caffe源码解析  框架 Caffe 源码 第1张

图1 Caffe源码整体架构图

Blob解析

下面介绍Caffe中的根本数据存储类Blob。Blob运用SyncedMemory类进行数据存储,数据成员 data_指向实践存储数据的内存或显存块,shape_存储了当时blob的维度信息,diff_这个保存了反向传递时分的梯度信息。在Blob中其实不是只要num,channel,height,width这种四维办法,它是一个不定维度的数据结构,将数据翻开存储,而维度独自存在一个vector 类型的shape_变量中,这样每个维度都能够恣意改变。

来一同看看Blob的要害函数,data_at这个函数能够读取的存储在此类中的数据,diff_at能够用来读取反向传回来的差错。顺便给个提示,尽量运用data_at(const vector& index)来查找数据。Reshape函数能够修正blob的存储巨细,count用来回来存储数据的数量。BlobProto类担任了将Blob数据进行打包序列化到Caffe的模型中。

工厂形式阐明

接下来介绍一种规划形式Factory Pattern,Caffe 中Solver和Layer目标的创立均运用了此形式,首先看工厂形式的UML的类图:

深度学习结构Caffe源码解析  框架 Caffe 源码 第2张

图2 工厂形式UML类图

好像Factory生成同一功用可是不同类型产品相同,这些产品完结了相同Operation,许多人看了工厂形式的代码,会发生这样的疑问为何不new一个出来呢,这样new一个出来好像也没什么问题吧。试想如下状况,由于代码重构类的称号改了,或许结构函数参数改变(添加或削减参数)。而你代码中又有N处new了这个类。假如你又没用工厂,就只能一个一个找来改。工厂形式的效果便是让运用者削减对产品自身的了解,下降运用难度。假如用工厂,只需要修正工厂类的创立详细目标办法的完结,而其他代码不会受到影响。

举个比方,写代码少不得饿了要加班去吃夜宵,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,尽管口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说“来四个鸡翅”就行了。麦当劳和肯德基便是出产鸡翅的Factory。

Solver解析

接下来切回正题,咱们看看Solver这个优化目标在Caffe中是怎样完结的。SolverRegistry这个类便是咱们看到的上面的factory类,担任给咱们一个优化算法的产品,外部只需要把数据和网络结构界说好,它就能够自己优化了。

Solver* CreateSolver(const SolverParameter& param)这个函数便是工厂形式下的CreateProduct的操作, Caffe中这个SolverRegistry工厂类能够提供给咱们6种产品(优化算法):

深度学习结构Caffe源码解析  框架 Caffe 源码 第3张

这六种产品的功用都是完结网络的参数更新,仅仅完结办法不相同。那咱们来看看他们的运用流程吧。当然这些产品相似上面Product类中的Operation,每一个Solver都会承继Solve和Step函数,而每个Solver中独有的仅仅是ApplyUpdate这个函数里边履行的内容不相同,接口是共同的,这也和咱们之前说的工厂出产出来的产品相同功用相同,细节上有差异,比方大多数电饭煲都有烧饭的功用,可是每一种电饭煲烧饭的加热办法或许不同,有底盘加热的还有立体加热的等。接下里咱们看看Solver中的要害函数。

Solver中Solve函数的流程图如下:

深度学习结构Caffe源码解析  框架 Caffe 源码 第4张

图3 Solver类Solve办法流程图

Solver类中Step函数流程图:

深度学习结构Caffe源码解析  框架 Caffe 源码 第5张

图4 Solver类Step办法流程图

Solver中要害的便是调用Sovle函数和Step函数的流程,你只需要对照Solver类中两个函数的详细完结,看懂上面两个流程图就能够了解Caffe练习履行的进程了。

Net类解析

分析过Solver之后咱们来分析下Net类的一些要害操作。这个是咱们运用Proto创立出来的深度网络目标,这个类担任了深度网络的前向和反向传递。以下是Net类的初始化办法NetInit函数调用流程:

深度学习结构Caffe源码解析  框架 Caffe 源码 第6张

图5 Net类NetInit办法流程图

Net的类中的要害函数简略分析

• ForwardBackward:按顺序调用了Forward和Backward。

• ForwardFromTo(int start, int end):履行从start层到end层的前向传递,选用简略的for循环调用。

• BackwardFromTo(int start, int end):和前面的ForwardFromTo函数相似,调用从start层到end层的反向传递。

• ToProto函数完结网络的序列化到文件,循环调用了每个层的ToProto函数。

Layer解析

Layer是Net的根本组成单元,例如一个卷积层或一个Pooling层。本末节将介绍Layer类的完结。

Layer的承继结构

深度学习结构Caffe源码解析  框架 Caffe 源码 第7张

图6 Layer层的承继结构

Layer的创立

与Solver的创立办法很像,Layer的创立运用的也是工厂形式,这儿简略阐明下几个宏函数:

REGISTER_LAYER_CREATOR担任将创立层的函数放入LayerRegistry。

深度学习结构Caffe源码解析  框架 Caffe 源码 第8张

咱们来看看大多数层创立的函数的生成宏REGISTER_LAYER_CLASS,能够看到宏函数比较简略的,将类型作为函数称号的一部分,这样就能够发生出一个创立函数,并将创立函数放入LayerRegistry。

深度学习结构Caffe源码解析  框架 Caffe 源码 第9张

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

这段代码在split_layer.cpp文件中

深度学习结构Caffe源码解析  框架 Caffe 源码 第10张

REGISTER_LAYER_CLASS(Split)。

这样咱们将type替换过今后给咱们做个典范,参阅下面的代码。

深度学习结构Caffe源码解析  框架 Caffe 源码 第11张

当然这儿的创立函数好像是直接调用,没有涉及到咱们之前工厂形式的一些问题。一切的层的类都是这样吗?当然不是,咱们仔细观察卷积类。

深度学习结构Caffe源码解析  框架 Caffe 源码 第12张

卷积层怎样没有创立函数呢,当然不是,卷积的层的创立函数在LayerFactory.cpp中,截图给咱们看下,详细代码如下:

深度学习结构Caffe源码解析  框架 Caffe 源码 第13张

这样两种类型的Layer的创立函数都有了对应的声明。这儿直接阐明除了有cudnn完结的层,其他层都是选用***种办法完结的创立函数,而带有cudnn完结的层都选用的第二种办法完结的创立函数。

Layer的初始化

介绍完创立咱们看看层里边的几个函数都是什么时分被调用的。

要害函数Setup此函数在之前的流程图中的NetInit时分被调用,代码如下:

深度学习结构Caffe源码解析  框架 Caffe 源码 第14张

这样整个Layer初始化的进程中,CheckBlobCounts被***调用,然后接下来是LayerSetUp,后边才是Reshape,***才是SetLossWeights。这样Layer初始化的生命周期咱们就有了了解。

Layer的其他函数的介绍

Layer的Forward函数和Backward函数完结了网络的前向和反向传递,这两个函数在自己完结新的层必需要完结。其间Backward会修正bottom中blob的diff_,这样就完结了差错的方向传导。

Protobuf介绍

Caffe中的Caffe.proto文件担任了整个Caffe网络的构建,又担任了Caffemodel的存储和读取。下面用一个比方介绍Protobuf的工作办法:

运用protobuffer东西存储512维度图画特征:

• message 编写:新建txt文件后缀名改为proto,编写自己的message如下,并放入解压的protobuff的文件夹里;

深度学习结构Caffe源码解析  框架 Caffe 源码 第15张

其间,dwFaceFeatSize表明特征点数量;pfFaceFeat表明人脸特征。

• 翻开windows指令窗口(cmd.exe)—->cd空格,把protobuff的文件途径复制粘贴进去——>enter;

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

• 能够看到文件夹里边生成“ .pb.h”和“.pb.cpp”两个文件,阐明成功了

深度学习结构Caffe源码解析  框架 Caffe 源码 第16张

• 下面能够和自己的代码整合了:

• 新建你自己的工程,把“ .pb.h”和“.pb.cpp”两个文件添加到自己的工程里,并写上#include” *.pb.h”

• 依照配库的教程把库装备下就能够了

VS下Protobuf的配库办法:

解决方案—->右击工程名—->特点

(1)c/c++—>惯例—>附加包括目录—>

($your protobuffer include path)\protobuffer

(2)c/c++—>链接器–>惯例—>附加库目录–>

($your protobuffer lib path)\protobuffer

(3) c/c++—>链接器–>输入—>附加依靠项–>

libprotobufd.lib;(带d的为debug形式)

或libprotobuf.lib;(不带d,为release形式)

运用protobuf进行打包的办法如下代码:

深度学习结构Caffe源码解析  框架 Caffe 源码 第17张

Caffe的模型序列化

BlobProto其实便是Blob序列化成Proto的类,Caffe模型文件运用了该类。Net调用每个层的Toproto办法,每个层的Toproto办法调用了Blob类的ToProto办法,这样完好的模型就被都序列化到proto里边了。***只要将这个proto承继于message类的目标序列化到文件就完结了模型写入文件。Caffe打包模型的时分就仅仅简略调用了WriteProtoToBinaryFile这个函数,而这个函数里边的内容如下:

深度学习结构Caffe源码解析  框架 Caffe 源码 第18张

Proto.txt的简略阐明

Caffe网络的构建和Solver的参数界说均由此类型文件完结。Net构建进程中调用ReadProtoFromTextFile将一切的网络参数读入。然后调用上面的流程进行整个Caffe网络的构建。这个文件决议了怎样运用存在caffe model中的每个blob是用来做什么的,假如没有了这个文件caffe的模型文件将无法运用,由于模型中只存储了各式各样的blob数据,里边只要float值,而怎样切分这些数据是由prototxt文件决议的。

Caffe的架构在结构上选用了反射机制去动态创立层来构建Net,Protobuf本质上界说了graph,反射机制是由宏合作map结构构成的,然后运用工厂形式去完结各式各样层的创立,当然差异于一般界说装备选用xml或许json,该项意图写法选用了proto文件对组件进行拼装。

总结

以上为Caffe代码架构的一个整体介绍,希望能借此协助社区的小伙伴找到翻开定制化Caffe大门的钥匙。本文作者希望借此抛砖引玉,与更多希望了解Caffe和深度学习结构底层完结的同行沟通。

转载请说明出处
知优网 » 深度学习结构Caffe源码解析

发表评论

您需要后才能发表评论