初识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>*> ⊥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
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 初识caffe代码<一>——整体层次介绍
- Caffe代码阅读——层次结构
- Caffe学习总结(一)——初识caffe
- Caffe代码结构初识
- Horizon 源码阅读(一)—— Horizon 整体介绍
- Horizon 源码阅读(一)—— Horizon 整体介绍
- JEM 代码解析——整体框架(一)
- levelDB—整体架构介绍
- Caffe学习笔记1:初识caffe篇(caffe介绍)
- 小读spring ioc源码(一)——整体介绍
- 质量体系——CMMI及整体介绍
- Redis源码研究—代码整体架构
- UICollectionView(一)——整体总结
- UICollectionView(一)——整体总结
- UICollectionView(一)——整体总结
- Caffe代码与架构介绍
- caffe源码剖析(一)--整体目录结构
- Volley框架解析(一)-----整体介绍
- sqlite3数据库ubuntu移植&arm开发板移植
- 数据结构之二叉树(数组)
- el表达式与ognl表达式区别?
- 【数据库优化】优化SQL查询:如何写出高性能SQL语句
- 重新开始学习.NET之二–继承和实现多态的几种方法
- 初识caffe代码<一>——整体层次介绍
- eclipse创建maven项目
- 文章标题
- C#dataGridView中设置ComboBox
- 内存对齐
- C++之失控指针、迷途指针、野指针、悬浮指针及空指针[转]
- Shell 小脚本集合----持续更新
- 通用类型的两路归并算法实现(一)-Java中int型归并排序的实现
- 树的实现机制