原文链接:https://www.zhihu.com/question/27982282

1.Caffe代码层次。
回答里面有人说熟悉Blob,Layer,Net,Solver这样的几大类,我比较赞同。我基本是从这个顺序开始学习的,这四个类复杂性从低到高,贯穿了整个Caffe。把他们分为三个层次介绍。

  • Blob:作为数据传输的媒介,无论是网络权重参数,还是输入数据,都是转化为Blob数据结构来存储
  • Layer:作为网络的基础单元,神经网络中层与层间的数据节点、前后传递都在该数据结构中被实现,层类种类丰富,比如常用的卷积层、全连接层、pooling层等等,大大地增加了网络的多样性
  • Net:作为网络的整体骨架,决定了网络中的层次数目以及各个层的类别等信息
  • Solver:作为网络的求解策略,涉及到求解优化问题的策略选择以及参数确定方面,修改这个模块的话一般都会是研究DL的优化求解的方向。
1. Blob:
1.1. Blob的类型描述
Caffe内部采用的数据类型主要是对protocol buffer所定义的数据结构的继承,因此可以在尽可能小的内存占用下获得很高的效率,虽然追求性能的同时Caffe也会牺牲了一些代码可读性。
直观来说,可以把Blob看成一个有4维的结构体(包含数据和梯度),而实际上,它们只是一维的指针而已,其4维结构通过shape属性得以计算出来。
1.2. 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的形状(4维),并根据形状来申请动态内存存储数据和梯度。

inline int count(int start_axis, int end_axis) const

计算Blob所需要的基本数据单元的数量。

在更高一级的Layer中Blob用下面的形式表示学习到的参数:

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

这里使用的是一个Blob的容器是因为某些Layer包含多组学习参数,比如多个卷积核的卷积层。
以及Layer所传递的数据形式,后面还会涉及到这里:

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

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

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

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

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

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

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

2.2.3. Layer的重要成员变量
loss

vector<Dtype> loss_;

每一层又有一个loss_值,只不多大多数Layer都是0,只有LossLayer才可能产生非0的loss_。计算loss是会把所有层的loss_相加。
learnable parameters

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

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

 

2.3. 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了。
2.4. Solver
这个类中包含一个Net的指针,主要是实现了训练模型参数所采用的优化算法,它所派生的类就可以对整个网络进行训练了。

shared_ptr<Net<Dtype> > net_;

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

virtual void ComputeUpdateValue() = 0;

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

ComputeUpdateValue();
net_->Update();

==============================================================

至此,从底层到顶层对Caffe的主要结构都应该有了大致的概念。为了集中重点介绍Caffe的代码结构,文中略去了大量Caffe相关的实现细节和技巧,比如Layer和Net的参数如何初始化,proto文件的定义,基于cblas的卷积等操作的实现(cblas实现卷积这一点我的个人主页GanYuFei中的《Caffe学习笔记5-BLAS与boost::thread加速》有介绍)等等就不一一列举了。

整体来看Layer部分代码最多,也反映出Caffe比较重视丰富网络单元的类型,然而由于Caffe的代码结构高度层次化,使得某些研究以及应用(比如研究类似非逐层连接的神经网络这种复杂的网络连接方式)难以在该平台实现。这也就是一开始说的一个不足。

另外,Caffe基本数据单元都用Blob,使得数据在内存中的存储变得十分高效,紧凑,从而提升了整体训练能力,而同时带来的问题是我们看见的一些可读性上的不便,比如forward的参数也是直接用Blob而不是设计一个新类以增强可读性。所以说性能的提升是以可读性为代价的。
最后一点也是最重要的一点,我从Caffe学到了很多。第一次看的C++项目就看到这么好的代码,实在是受益匪浅,在这里也感谢作者贾扬清等人的贡献。

 
Net中有必要认识的几个名字:
 
这里再补充几点:
1.使用Linux 的grep指令来快速追踪某个关键字:在caffe根目录下输入: grep -n -H -R "REGISTER_LAYER_CREATOR"(举例),其中-n 显示行号 -H显示文件名 -R递归查找每个子目录

    

caffe源码阅读(1)_整体框架和简介(摘录)的更多相关文章

  1. Caffe源码阅读(1) 全连接层

    Caffe源码阅读(1) 全连接层 发表于 2014-09-15   |   今天看全连接层的实现.主要看的是https://github.com/BVLC/caffe/blob/master/src ...

  2. caffe源码阅读

    参考网址:https://www.cnblogs.com/louyihang-loves-baiyan/p/5149628.html 1.caffe代码层次熟悉blob,layer,net,solve ...

  3. (转) Spring源码阅读 之 Spring整体架构

    标签(空格分隔): Spring 声明:本文系转载,原地地址:spring framework 4 源码阅读 Spring骨架 Spring的骨架,也是Spring的核心包.主要包含三个内容 cont ...

  4. caffe源码阅读(1)-数据流Blob

    Blob是Caffe中层之间数据流通的单位,各个layer之间的数据通过Blob传递.在看Blob源码之前,先看一下CPU和GPU内存之间的数据同步类SyncedMemory:使用GPU运算时,数据要 ...

  5. [Go] gocron源码阅读-go语言web框架Macaron

    gocron源码中使用的是马卡龙框架,下面这个就是安装这个框架,和一般的MVC框架很像go get gopkg.in/macaron.v1git clone https://github.com/go ...

  6. caffe源码阅读(一)convert_imageset.cpp注释

    PS:本系列为本人初步学习caffe所记,由于理解尚浅,其中多有不足之处和错误之处,有待改正. 一.实现方法 首先,将文件名与它对应的标签用 std::pair 存储起来,其中first存储文件名,s ...

  7. caffe源码阅读(3)-Datalayer

    DataLayer是把数据从文件导入到网络的层,从网络定义prototxt文件可以看一下数据层定义 layer { name: "data" type: "Data&qu ...

  8. caffe源码阅读(2)-Layer

    神经网络是由层组成的,深度神经网络就是层数多了.layer对应神经网络的层.数据以Blob的形式,在不同的layer之间流动.caffe定义的神经网络已protobuf形式定义.例如: layer { ...

  9. caffe 源码阅读

    bvlc:Berkeley Vision and Learning Center. 1. 目录结构 models(四个文件夹均有四个文件构成,deploy.prototxt, readme.md, s ...

随机推荐

  1. 【ZOJ2278】Fight for Food(dp)

    BUPT2017 wintertraining(16) #4 F ZOJ - 2278 题意 给定一个10*10以内的地图,和p(P<=30000)只老鼠,给定其出现位置和时间T(T<=1 ...

  2. [USACO 2018 Open Contest]作业总结

    t1-Out of Sorts 题目大意 将最大的数冒泡排序到最后需要多少次操作. 分析 排序后判断距离. ac代码 #include<bits/stdc++.h> #define N 1 ...

  3. Android 手势&触摸事件

    在刚开始学Android的时候,就觉得Google的文档不咋样,在研究手势时,更加的感觉Google的文档写得实在是太差了.很多常量,属性和方法,居然连个描述都没有. 没有描述也就罢了,但是OnGes ...

  4. Java关键字synchronized详解

    Java多线程thread互联网制造  synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程A每次运行到这个方法时,都要检查有没有其它正在用这个方法的线程B(或者C D等),有的话 ...

  5. 上下文管理协议with_open,__enter__和__exit__(三十八)

    在操作文件对象的时候可以这么写 with open('a.txt') as f: '代码块' 上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__ent ...

  6. php redis在windows下的部署

    1.下载php扩展 下载地址:https://github.com/phpredis/phpredis/downloads 2.将下载php扩展redis放到php的ext目录下,然后在php.ini ...

  7. js动画最佳实现——requestAnimationFrame

    我们经常用setInterval来实现动画,其实这种做法不是太好,因为不同浏览器的刷新频率也不一样(一般认为设置16为最佳,按每秒60帧算,1000/60≍16.67) var dis = 0,tim ...

  8. 20190311 Windows安装ZooKeeper

    1. 说明 记录过程中踩过的坑 1.1. 环境 本机环境:Win10 ZooKeeper版本:3.4.6 2. 安装 2.1. 下载 官网下载网址 2.2. 修改配置文件 复制conf目录下的zoo_ ...

  9. Hadoop基础-Hdfs各个组件的运行原理介绍

    Hadoop基础-Hdfs各个组件的运行原理介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.NameNode工作原理(默认端口号:50070) 1>.什么是NameN ...

  10. 第一模块:python基础语法

    Python基础[day01]:python介绍发展史(一) Python基础[day01]:Hello World程序(二) Python基础[day01]:表达式if ...else语句(三) P ...