Caffe学习笔记(一):Caffe架构及其模型解析

时间:2023-03-04 15:35:02

Caffe学习笔记(一):Caffe架构及其模型解析

写在前面:关于caffe平台如何快速搭建以及如何在caffe上进行训练与预测,请参见前面的文章《caffe平台快速搭建:caffe+window7+vs2013》、《Windows平台上Caffe的训练与学习方法(以数据库CIFAR-10为例)》。

本文主要介绍Caffe的总体框架,并对caffe模型进行解析,主要是本人的学习笔记,参考了各种资料,例如:《Caffe官方教程中译本》,网址:http://caffe.berkeleyvision.org/等等。

1、Caffe架构

Caffe是一个深度学习框架,该框架主要包括五大组件:blobs/layers/nets、solver/proto。

其中,blobs/layers/nets使得Caffe构成基于自己的模型架构,即一种模块化的模型,简单来说就是caffe通过逐层(layer-by-layer)的方式定义了一个网络nets,网络从数据输入层到损失层自下而上定义整个模型,而Blobs只是caffe中处理和传递实际数据的数据封装包;

而solver/proto中的Solver负责深度网络的训练,主要目的就是协调模型的优化,每个Solver中包含一个训练网络对象和一个测试网络对象。Solver优化一个模型的方法是:首先通过调用前传来获得输出和损失,然后通过调用反传产生模型的梯度,将梯度和权值更新后相结合来最小化损失。

而proto则基于Google的Protobuf开源项目,是一种类似XML的数据交换格式,用户只需要按格式定义对象的数据成员,可以在多种语言中实现对象的序列化与反序列化,在Caffe中用于网络模型的结构定义、存储和读取。

blobs/layers/nets与solver/proto的区别与联系可以总结为:caffe通过layers的方式定义nets,而贯穿所有nets的结构就是caffe框架或者模型,对于layers而言,输入的就是blobs这种数据封装包格式的实际数据,当采用该框架进行训练时,也就是solver调优模型,则需要proto这种用于网络模型的结构定义、存储和读取,换句话说,模型格式用protobuf语言定义在caffe.proto文件中。

Caffe学习笔记(一):Caffe架构及其模型解析

2、Caffe模型解析:Blobs、Layers, and Nets

blobs、layers与nets之间的关系可以总结为:caffe使用blobs结构来存储、交换和处理网络中正向和反向迭代时的数据(值)和导数信息(梯度),blobs是caffe的标准数组结构,他提供了一个统一的内存接口,layer是caffe模型和计算的基本单元,net则是一系列layers和其连接的集合,blobs详细描述了信息是如何在layer和net中存储和交换的。

下面对blob/layer/net分别介绍。

2.1、blobs

Blob是Caffe中处理和传递实际数据的数据封装包,并且在 CPU与GPU之间具有同步处理能力。从数学意义上说,blob是按C风格连续存储的N维数组。为了便于优化,blobs提供统一的内存接口来存储某种类型的数据,例如批量图像数据、模型参数以及用来进行优化的导数。

对于批量图像数据来说,blob常规的维数为图像数量N *通道数K *图像高度H *图像宽度W。Blob按行为主(row-major)进行存储,所以一个4维blob中,坐标为(n, k, h, w)的值的物理位置为((n * K + k) * H + h) * W + w,这也使得最后面/最右边的维度更新最快。

对于blob中的数据,我们关心的是values(值)和gradients(梯度),所以一个blob单元存储了两块数据——data和diff。前者是我们在网络中传送的普通数据,后者是通过网络计算得到的梯度。 而且,由于数据既可存储在CPU上,也可存储在GPU上,因而有两种数据访问方式:静态方式,不改变数值;动态方式,改变数值。之所以这么设计是因为blob使用了一个SyncedMem类来同步CPU和GPU上的数值,以隐藏同步的细节和最小化传送数据。一个经验准则是,如果不想改变数值,就一直使用常量调用,而且绝不要在自定义类中存储指针。每次操作blob时,调用相应的函数来获取它的指针,因为SyncedMem需要用这种方式来确定何时需要复制数据。

实际上,使用GPU时,Caffe中CPU代码先从磁盘中加载数据到blob,同时请求分配一个GPU设备核(device kernel)以使用GPU进行计算,再将计算好的blob数据送入下一层,这样既实现了高效运算,又忽略了底层细节。只要所有layers均有GPU实现,这种情况下所有的中间数据和梯度都会保留在GPU上。

2.2、layers

Layer是Caffe模型的本质内容和执行计算的基本单元。Layer可以进行很多运算,如:convolve(卷积)、pool(池化)、inner product(内积),rectified-linear和sigmoid等非线性运算,元素级的数据变换,normalize(归一化)、load data(数据加载)、softmax和hinge等losses(损失计算)。可在Caffe的layer catalogue(层目录)中查看所有操作,其囊括了绝大部分目前最前沿的深度学习任务所需要的层类型。

一个layer通过bottom(底部)连接层接收数据,通过top(顶部)连接层输出数据。 每一个layer都定义了3种重要的运算:setup(初始化设置),forward(前向传播),backward(反向传播)。

总的来说,Layer承担了网络的两个核心操作:forward pass(前向传播)——接收输入并计算输出;backward pass(反向传播)——接收关于输出的梯度,计算相对于参数和输入的梯度并反向传播给在它前面的层。由此组成了每个layer的前向和反向通道。

由于Caffe网络的组合性和其代码的模块化,自定义layer是很容易的。只要定义好layer的setup(初始化设置)、forward(前向通道)和backward(反向通道),就可将layer纳入到网络中。

2.3、nets

Caffe模型是端到端的机器学习引擎。

准确的说,Net是由一系列层组成的有向无环(DAG)计算图,Caffe保留了计算图中所有的中间值以确保前向和反向迭代的准确性。一个典型的Net开始于data layer——从磁盘中加载数据,终止于loss layer——计算如分类和重构这些任务的目标函数。

Net由一系列层和它们之间的相互连接构成,用的是一种文本建模语言。

Net::Init()进行模型的初始化。初始化主要实现两个操作:创建blobs和layers以搭建整个网络DAG图,以及调用layers的SetUp()函数。初始化时也会做另一些记录,例如确认整个网络结构的正确与否等。另外,初始化期间,Net会打印其初始化日志到INFO信息中。网络构建完之后,通过设置Caffe::mode()函数中的Caffe::set_mode(),即可实现在CPU或GPU上的运行,实验已经证明采用CPU或GPU计算得到的结果相同。

模型是利用文本protocol buffer(prototxt)语言定义的,学习好的模型会被序列化地存储在二进制protocol buffer (binaryproto) .caffemodel文件中。 模型格式用protobuf语言定义在caffe.proto文件中。

3、总结

上面只是简单地从理论模型层面上对caffe架构以及模型进行介绍,更深入地理解必须结合caffe源码做进一步地分析,个人建议:在阅读caffe源码的同时回过头来理解这些稍微理论性的知识,不仅有助于源码的理解,更加有助于caffe整体设计思想的深入了解。