caffe data层_【caffe教程1】 caffe代码导论

news/2024/7/7 20:22:51 标签: caffe data层

本文首发于公众号《有三AI》

[caffe解读] caffe从数学公式到代码实现1-导论​mp.weixin.qq.com
e9297f264a52a7ee38515e94cb31e35a.png
我这个系列caffe代码解读跟大部分人的思路不一样,一般读caffe代码思路是按照caffe的层级结构来,blob到layer到net各自分层来读,但我想提供一个另外的思路,从数学公式到代码实现。

从每一个文件背后具体的数学含义来读,这对于我们非数学系或者数学基础不是很好的工程人员来说,是比较适合的。

那么,我会采取什么样的形式呢,就是,layer definition,caffe layer,caffe test layer的格式,举个例子来说,比如softmax,那我就打算从softmax的数学定义,caffe softmax层的实现,caffe softmax test layer的实现。一定要加上test layer,因为当我们自己实现某些类时,往往需要梯度反向求导,这时候最好自己写test来验证自己的代码是否正确。

好了,下面就开始吧。当然,现在这是第一篇,所以我们还是不可避免先打下基础,先要阅读下面的内容,对caffe的代码有基本的了解。这是include/caffe下面的代码list。

blob.hpp
caffe.hpp
common.hpp
data_transformer.hpp
filler.hpp
internal_thread.hpp
layer.hpp
layer_factory.hpp
net.hpp
parallel.hpp
sgd_solvers.hpp
solver.hpp
solver_factory.hpp
syncedmem.hpp

一个一个来。

1 blob.hpp&cpp

blob是caffe中的基础数据单元,一个blob是一个四维张量,(N,C,H,W),N是batch size大小,C是channel,H,W分别是图像宽高,由于caffe擅长于做图像,所以这个定义天然适合图像。故一个256*256的rgb图像,blob size是(1,3,256,256)。

blob.hpp,需要注意的就是下面的变量和函数

5ba5af9a3dafc33fee2d2f9ab7f08e0f.png

其中data_存储数据,diff_存储梯度,shape_分别是blob_的尺度,count_是所有数据数目,即N*C*H*W。

以后要访问这些数据,就会用到下面的函数,其中cpu_data是只读,mutable_cpt_data是可写,gpu类似。

8b45d4c4523ff10e190ae79ef2da13ff.png

上面还有一个疑问,那就是初次见到SyncedMemory类会不知道它是做什么的,它主要负责在GPU或者CPU上分配内存以及保持数据的同步作用。

可参考下面资料。

http://blog.csdn.net/xizero00/article/details/51001206

http://www.cnblogs.com/korbin/p/5606770.html

由于展开是另一个篇幅,因此我们不过多停留在此,知道blob是通过这样的方式存取即可

2 caffe.hpp,common.hpp,internal_thread.hpp, parallel.hpp, syncedmem.hpp,solver_factory.hpp,layer_factory.hpp,sgd_solvers.hpp

把这几个放这里,是因为其中一些是gpu编程和内存等较为底层的编程的,看起来比较费劲,我们一般的应用其实也不需要对此有太深了解,大家会用即可。另外还有sovler这个类大家仔细读读即可。

caffe.hpp包含其他基础hpp。

internal_thread.hpp,与线程有关的变量函数。

parallel.hpp,与并行有关的变量函数。

syncedmem.hpp,内存分配和Caffe的底层数据的切换

solver_factory.hpp,layer_factory.hpp,顾名思义,分别是caffe solver的工厂类模板定义和普通layer的模板定义。

举例拿sovler来多说几句,solver_factory.hpp,其中solver指的是优化方法,由于caffe优化采用的就是梯度下降的方法,包括SGD,NesterovSolver,RMSPropSolver,AdamSolver等通通都定义在sgd_solvers.hpp中。

工厂设计模型,简单了解如下

http://developer.51cto.com/art/201107/277728.htm

http://alanse7en.github.io/caffedai-ma-jie-xi-4/

深入了解需要自己去看,从代码的角度来看就是解决重复造轮子的问题,减少重复代码,在caffe的面试中经常会问到噢。

看下它的代码,重要变量两个

typedef Solver<Dtype>* (*Creator)(const
SolverParameter&);

typedef std::map<string, Creator>
CreatorRegistry;

重要函数两个个,

static CreatorRegistry& Registry() { static CreatorRegistry*
g_registry_ = new CreatorRegistry();
   return *g_registry_;
}
static Solver<Dtype>* CreateSolver(const
SolverParameter& param) {
   const string& type = param.type();
   CreatorRegistry& registry = Registry();
   CHECK_EQ(registry.count(type), 1) << "Unknown solver type: " << type
       << " (known types: " << SolverTypeListString() << ")";
   return registry[type](param);
 }

其中需要注意的是,SolverParameter是一个配置参数不说,CreatorRegistry就是我们以后自定义层需要知道的,需要知道registry是一个map,存储的就是字符串以及对应的以函数指针形式存储的Creator类型的函数,而注册都会在cpp中进行,以后详解。

common.hpp,是一些与io有关的函数与变量,cpu与gpu模式设定变量Brew
mode_;函数set_mode,setDevice,以及与随机数有关的函数变量shared_ptr<RNG>
random_generator_;

3 datatransform.hpp

这是很重要的一个文件,当我们自定义数据层的时候会用到,它的作用就是从磁盘中读取数据塞进caffe定义的变量内存中。从它的头文件就可以看出,它依赖于blob,common,以及caffe.pb.h

#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/proto/caffe.pb.h"

caffe.pb.h中就包含了序列化的变量。

datatransform.hpp中的变量如下:

shared_ptr<Caffe::RNG> rng_;
Phase phase_;
Blob<Dtype> data_mean_;
vector<Dtype> mean_values_;

可见存储了常见的mean_value。

datatransform.hpp中的的核心是重载的transform函数,它可以按照不同的输入来载入数据,我们平常在caffe内部做的随机crop,flip等等操作都在这里完成,具体大家可以去研究源码,静下心看非常简单。

void Transform(const vector<Datum> & datum_vector,Blob<Dtype>* transformed_blob);
void Transform(const vector<cv::Mat> & mat_vector, Blob<Dtype>*
transformed_blob);
void Transform(const cv::Mat& cv_img, Blob<Dtype>* transformed_blob);
4 filler.hpp

它没有对应的cpp,所有实现都在hpp中,因为很简单,它就是对权重初始化的,其中包含,constantfiller,Gaussianfiller,XavierFiller,MSRAFiller等等,相信大家都比较熟了。

5 solver.hpp

这就是caffe 迭代求解优化的函数定义,其中重要变量loss就在这里,这就是训练caffe时显示出的loss的来源

vector<Dtype> losses_;
 Dtype smoothed_loss_;
 SolverParameter param_;

迭代优化的函数,

virtual void Solve(const char* resume_file = NULL);
inline void Solve(const string resume_file) { Solve(resume_file.c_str()); }
void Step(int iters);
6 layer.hpp

这就是一个层的定义了,想必大家很有兴趣,那具体都有什么呢?

我们首先看变量,

LayerParameter layer_param_;
 vector<Dtype> loss_;

然后看重要函数

LayerSetUp,用于layer初始化,一般是定义一些shape,初始化一些变量。

virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {}

Forward,Backward的cpu和gpu版本,除了数据层外始终成对存在的前向和反向函数,forward是基于bottom计算top,backward则是基于top计算bottom,很好理解。

virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) = 0;
virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
   Fackward_cpu(bottom,top);
 }
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) = 0;
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
   Backward_cpu(top, propagate_down, bottom);
 }
7 net.hpp

这是最大的一个hpp了,也是最高层的,就是整个网络的定义。

看看重要变量:

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

layers_就是所有层,layer_names_;存储了名字,以后在我们inference的时候会需要经常用到。

vector<float> params_lr_;
 vector<bool> has_params_lr_;

上面是每一层学习率的参数,在我们想要固定某些层不让其学习,或者调整不同层的学习率时,会非常重要。其实还有很多重要变量如,

vector<Dtype> blob_loss_weights_;
Phase phase_;

都是经常接触的,不一一描述了大家自己看代码。

下面是一个重载的重要函数,

void CopyTrainedLayersFrom(const
NetParameter& param);
void CopyTrainedLayersFrom(const string
trained_filename);
void CopyTrainedLayersFromBinaryProto(const string
trained_filename);
void CopyTrainedLayersFromHDF5(const string
trained_filename);

它是重要的初始化网络的方法,可以实现不同形式输入的初始化,在inference时会经常使用的。

好了,基础就这么多,并没有非常细致的讲述而只是对重要内容进行介绍,在开始下面的文章之前,一定要熟读上面的这些hpp和对应cpp文件,对它有什么是什么,熟练于胸。

欢迎关注我们超过12个深度学习开源框架使用的教程和对应的开源项目
【完结】给新手的12大深度学习开源框架快速入门项目​mp.weixin.qq.com
31142a0fbcf0f3894b651b2036803e70.png
https://github.com/longpeng2008/yousan.ai​github.com

http://www.niftyadmin.cn/n/1108695.html

相关文章

Excel 2016新增函数之TEXTJOIN

Excel 2016新增函数之TEXTJOIN在2016年1月功能更新中&#xff0c;EXCEL 2016新增几个常用重要函数&#xff0c;主要有&#xff1a;ifs,switch,maxifs,minifs,concat,textjoin等。注意&#xff0c;要能使用上述函数&#xff0c;Office的版本很重要&#xff0c;并不是所有的Offic…

力扣——体育馆的人流量

X 市建了一个新的体育馆&#xff0c;每日人流量信息被记录在这三列信息中&#xff1a;序号(id)、日期 (date)、 人流量 (people)。 请编写一个查询语句&#xff0c;找出高峰期时段&#xff0c;要求连续三天及以上&#xff0c;并且每天人流量均不少于100。 例如&#xff0c;表 s…

eCos内核API与内核实现的衔接

mingdu.zheng <at> gmail <dot> comhttp://blog.csdn.net/zoomdy/article/details/8884815 eCos内核API是以C函数以及C结构体的形式提供的&#xff0c;eCos的内核是使用C类实现的&#xff0c; kernel/.../src/common/kapi.cxx 将C类实现衔接到C函数及C结构体&#…

python注释码_python编码与代码注释

一、内容编码显然ASCII码无法将世界上的各种文字和符号全部表示&#xff0c;所以&#xff0c;就需要新出一种可以代表所有字符和符号的编码&#xff0c;即&#xff1a;UnicodeUnicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。Unicode 是为了解决传统的字符编码…

学科实践活动感悟50字_学科实践活动感想

最近我们开展了学科实践活动。在这项活动中&#xff0c;我学会了许多新知识和新方法。比如&#xff0c;语文实践活动中&#xff0c;我知道了如何表达&#xff0c;如何选择素材等。在数学实践活动中&#xff0c;我明白了一道题不一定只有一种解法&#xff0c;可能有很多做法&…

eCos的HAL接口采用宏定义形式的优势

mingdu.zheng <at> gmail <dot> comhttp://blog.csdn.net/zoomdy/article/details/8884820 eCos的HAL接口为eCos其它组件提供访问硬件的统一接口&#xff0c;所有的HAL接口都是以宏定义的形式提供的&#xff0c; 采用宏定义的形式有如下优势&#xff1a; 1. 实现接…

nginx安装和遇到的问题

nginx安装步骤和遇到的问题 tar -xvf nginx-1.15.1.tar.gz cd nginx-1.15.1 ./configrue make make install 在configure中可能遇到的问题&#xff1a; (1) ./configure: error: the HTTP rewrite module requires the PCRE library. You can either disable the module by us…

关于同步、异步与阻塞、非阻塞的理解

1、前言 前一段时间出去面试&#xff0c;被问到同步、异步与阻塞、非阻塞的区别。我一时半会没有想出来&#xff0c;作为一个工作三年的人来说&#xff0c;实在很惭愧。我当时理解同步、异步属于两个进程中间的协作关系&#xff0c;例如使用浏览器访问一个网站&#xff0c;需要…