初识caffe代码<一>——整体层次介绍

来源:互联网 发布:众划算在淘宝算违规吗 编辑:程序博客网 时间:2024/06/14 08:38

代码层次

(四个类复杂性由低到高):
- Blob:是基础的数据结构,是用来保存学习到的参数以及网络传输过程中产生数据的类。
- Layer:是网络的基本单元,由此派生出了各种层类。修改这部分的人主要是研究特征表达方向的。
- Net:是网络的搭建,将Layer所派生出层类组合成网络。
- Solver:是Net的求解,修改这部分人主要会是研究DL求解方向的。


一、Blob

caffe支持CUDA,在数据级别上也做了一些优化,重要的是对protocolbuffer(Google 公司内部的混合语言数据标准,是一种轻便高效的结构化数据存储格式,简称Protobuf)所定义的数据结构的继承,Caffe因此可以在尽可能小的内存占用下获得很高的效率,但是牺牲了一些代码可读性
在更高一级的Layer中Blob用下面的形式表示学习到的参数:
vector<shared_ptr<Blob<Dtype>>>blobs_;
这里使用的是一个Blob容器,某些Layer包含多组学习参数,比如多个卷积核的卷积层。以及Layer所传递的数据形式,后面还有涉及:

vector<Blob<Dtype>*> &bottom;vector<Blob<Dtype>*> *top;

二、Layer

1、5大Layer派生类型
Caffe十分强调网络层次性,也就是说卷积操作,非线性变换(ReLU等),Pooling,权值连接等。全部都由某一种Layer来表示。

具体分为5大类Layer:

  • NeuronLayer类定义于neuron_layers.hpp中,其派生类主要是元素级别的运算(eg. Dropout运算,激活函数ReLU,Sigmoid等),运算均为同址计算(in-place computation,返回值覆盖原值而占用新的内存)
  • LossLayer类定义于loss_layers.hpp中,其派生类会产生loss,只有这些层才能够产生loss
  • 数据层定义于data_layer.hpp中,作为网络的最底层,主要实现数据格式的转换
  • 数据表达层(转的作者自己分的类)定义于vision_layers.hpp,实现特征表达功能,更具体地说包含卷积操作,Pooling操作,他们基本都会产生新的内存占用(Pooling相对较小)
  • 网络连接层和激活函数(转的作者分类)定义于common_layers.hpp,Caffe提供了单个层与多个层的连接,并在这个头文件里声明。这里包含了常用的全连接层InnerProductLayer类。

2、Layer的重要成员函数
在Layer内部,数据主要有两种传递方式,正向传导(Forward)和反向传导(Backward)。
Forward和Backward有CPU和GPU(部分有)两种实现。Caffe中所有的Layer都要用这两种方法传递数据。

vitural void Forward(const vector<Blob<Dtype>*> &bottom,vector<Blob<Dtype>*> *top) = 0;virtual void Backward(const vector<Blob<Dtype>*> &top,const vector<Blob> &propagate_down,vector<Blob<Dtype>*> *bottom) = 0;

ps:Bottom来表示输入,Top表示输出。前一层Layer的top是后一层layer的bottom。

Layer类派生出来的层类通过这实现这两个虚函数,产生了各种各样功能的层类。Forward是从根据bottom计算top的过程,Backward则相反,根据top计算bottom。注意:这里为什么用一个包含Blob的容器(vector),对于大多数Layer来说输入和输出都个连接只有一个Layer,然而对于某些Layer存在一对多的情况,比如LossLayer和某些连接层,在网络结构定义文件(*.proto)中每一层的参数bootom和top数目就决定了vector中元素数目。

layers {   bottom:"decode1neuron"  //该层底下连接的第一个Layer   bottom:"flatdata"  //该层底下连接的第二个Layer   top:"12_error"  //该层顶上连接的一个Layer   name:"loss"  //该层的名字   type:EUCLIDEAN_LOSS  //该层的类型   loss_weight:0}

caffe结构是自底向上
3、Layer的重要成员变量
loss
vector<Dtype> loss_;
每一层又有一个loss_值,只不过大多数Layer都是0,只有LossLayer才可能产生非0的loss_。计算loss是会把所有层的loss_相加。
learnable parameters

vector<shared_ptr<Blob<Dtype>>>blobs_; 

前面提到过的,Layer学习到的参数。

三、Net

Net用容器的形式将多个Layer有序地放在一起,其自身实现的功能主要是对逐层Layer进行初始化,以及提供Update()地接口(更新网络参数),本身不能对参数进行有效学习过程。

vector<shared_ptr<Layer<Dtype>>> layers_;

同样Net也有它自己的

vector<Blob<Dtype>*>& Forward(const vector<Blob<Dtype>> &bottom,Dtype* loss = NULL);void Net<Dtype>::Backward();

他们是对整个网络的前向和反向传导,各调用一次就可以计算出网络的loss。

四、Solver

这个类中包含一个Net的指针,主要是实现了训练模型参数所采用的优化算法,它所派生的类就可以对整个网络进行训练

shared_ptr<Net<Dtype>> net_;

不同的模型训练方法通过重载函数ComputeUpdateValue()实现计算update参数的核心功能

virtual void ComputeUpdateValue() = 0;

最后当进行整个网络训练过程(也就是运行caffe训练某个模型时),实际上是在运行caffe.cpp中的train函数,而这个函数实际上是实例化一个Solver的对象,初始化后调用了Solver中的Solve()方法。而这个Solve()函数主要是在迭代运行下面的这两个函数,就是刚才介绍的那几个函数。

ComputeUpdateValue();net_->Update();

Layer部分代码最多,反映出caffe比较重视丰富网络单元的类型,但caffe的代码结构高度层次化,使得某些研究以及应用(比如研究类似非逐层连接的神经网络这种复杂的网络连接方式)难以在该平台实现,这也是caffe的不足。
caffe基本数据单元都用Blob,使得数据在内存的存储变得十分高效,紧凑,从而提升了整体训练能力,但可读性不便。如forward参数也是直接用Blob而不是设计一个新类来增加可读性。所以说性能的提升是以可读性为代价的。

作者:知乎用户
链接:https://www.zhihu.com/question/27982282/answer/39350629
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。