参考自《21天实战caffe》及知乎:深度学习caffe的代码怎么读?
caffe是由伯克利视觉和学习中心(BVLC)开发的基于C++/CUDA/python实现的深度学习框架。
一. 特点:
- 实现卷积神经网络架构(CNN)
- 速度快,采用google的ProtoBuffer数据格式,提高效率
- 完全开源,由C++语言编写
- caffe提供了一整套工具集,可用于训练、预测、数据预处理等。
- caffe自带一系列参考模型和快速教程
二. 代码结构:
如上图为caffe的数据结构,一个CNN模型由Net表示,Net由多个Layer组成,Layer输入输出数据由Blob数据结构保存。
Blob,Layer,Net,Solver这几个大类,自下而上,环环相扣,贯穿了整个caffe的结构。
- Blob:是基础的数据结构、存储单元,是用来保存学习到的参数以及网络传输过程中产生数据的类。
- Layer:是网络的基本计算单元,由此派生出了各种层类。修改这部分的人主要是研究特征表达方向的。
- Net:是网络的搭建,代表一个完整CNN,将Layer所派生出层类组合成网络。Solver:是Net的求解,修改这部分人主要会是研究DL求解方向的。
三. 具体代码结构
- Blob
- Blob类型描述
Caffe内部采用的数据类型主要是对protocol buffer所定义的数据结构的继承,因此可以在尽可能小的内存占用下获得很高的效率,虽然追求性能的同时Caffe也会牺牲了一些代码可读性。
Blob在内存中表示4维数组,维度从低到高为(width_,height_,channels_,num_),可分别表示图像的宽和高、颜色通道、图像为第几帧。Blob存储数据或权值(data)和权值增量(diff)。
Blob为模板类。声明在 include/caffe/blob.hpp,使用时需包含该头文件 #include<caffe/blob.hpp> 并使用命名空间caffe。类的实现在 src/caffe/proto/caffe.proto。
BlobProto对象可以进行磁盘与内存中数据的交互。
- Blob重要成员函数和变量
shared_ptr<SyncedMemory> data_; //数据 shared_ptr<SyncedMemory> diff_;//梯度
void Blob<Dtype>::Reshape(const int num, const int channels, const int height,const int width); //重新修改Blob形状,根据形状申请动态内存数据和梯度
inline int count(int start_axis, int end_axis) const; //计算Blob需要的基本数据单元的数量
- Layer
- Layer类型描述
Layer至少有一个输入Blob(Bottom Blob)和一个输出Blob(Top Blob),部分Layer带有权值(weight)和偏执项(Bias),有两个运算方向:前向传播(Forward)和反向传播(Backward)。其中前向传播对输入Blob进行处理得到输出Blob,反向传播计算则对输出Blob的diff进行某种处理,得到输入Blob的diff。
Layer为抽象类,不能直接创建Layer对象,其大部分函数都只有虚函数,函数的真正实现在其派生类中。
头文件 include/caffe/layer.hpp 源文件src/caffe/layer.cppBlob重要成员函数和变量
- Layer重要成员函数和变量
vector<Dtype> loss_ //每一层都会有一个loss值,但只有LossLayer才会产生非0的loss vector<shared_ptr<Blob<Dtype> > > blobs_ ;//Layer所学习的参数,包括权值和偏差
virtual void Forward(const vector<Blob<Dtype>*> &bottom,vector<Blob<Dtype>*> *top) = 0;// Layer内部数据正向传播,从bottom到top方向
virtual void Backward(const vector<Blob<Dtype>*> &top,const vector<bool> &propagate_down,vector<Blob<Dtype>*> *bottom) = 0;
//Layer内部梯度反向传播,从top到bottom方向
在Layer内部,数据主要有两种传递方式,Forward和Backward,分别有CPU和GPU(部分有)两种实现。
Layer函数:
layers { bottom: "decode1neuron" // 该层底下连接的第一个Layer bottom: "flatdata" // 该层底下连接的第二个Layer top: "l2_error" // 该层顶上连接的一个Layer name: "loss" // 该层的名字 type: EUCLIDEAN_LOSS // 该层的类型 loss_weight: 0 }
- Net
- Net类型描述
Net用容器的形式将多个Layer有序地放在一起,其自身实现的功能主要是对逐层Layer进行初始化,以及提供Update( )的接口(更新网络参数),本身不能对参数进行有效地学习过程。
- Net的重要成员函数和变量
vector<shared_ptr<Layer<Dtype> > > layers_ ;//构成该net的layers
void Init(const NetParameter& param); //根据NetParameter进行net初始化,简单的来说就是先把网络中所有层的bottom Blobs&top Blobs(无重复)实例化,并从输入层开始,逐层地进行Setup的工作,从而完成了整个网络的搭建,为后面的数据前后传输打下基础。
vector<Blob<Dtype>*>& Forward(const vector<Blob<Dtype>* > & bottom,Dtype* loss = NULL); void Net<Dtype>::Backward(); //是对整个网络的前向和反向传导,各调用一次就可以计算出网络的loss了。
- Solver
- Solver的类型描述
Solver类中包含一个Net的指针,主要是实现了训练模型参数所采用的优化算法,根据优化算法的不同会派生不同的类,而基于这些子类就可以对网络进行正常的训练过程。
- Solver的重要成员函数和变量
shared_ptr<Net<Dtype> > net_ ;//net对象
virtual void ComputeUpdateValue() = 0;//不同的模型训练方法通过重载函数ComputeUpdateValue( )实现计算update参数的核心功能
ComputeUpdateValue(); net_->Update();
caffemodel为训练好的模型,权重文件。
solverstate为求解器状态文件,存放训练的中间过程,可暂停后继续训练