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

layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
......
}

就是定义了一个卷积层,bottom是其前一层,而top是其后一层。前向传播计算过程就是获取bottom的输出(Blob),当做输入,通过计算(Forward),输出Blob给下一层top;每一层还有一个反向传播Backforward。不同的层实现的前向传播和反向传播不相同,但是它们都有同一个基类class Layer

成员变量

先看一下Layer的成员变量,这些成员变量都是层的基本变量,不同的层都需要这些变量,这些成员变量访问权限为protected

LayerParameter layer_param_;
/** The phase: TRAIN or TEST */
Phase phase_;
/** The vector that stores the learnable parameters as a set of blobs. */
vector<shared_ptr<Blob<Dtype> > > blobs_;
/** Vector indicating whether to compute the diff of each param blob. */
vector<bool> param_propagate_down_; /** The vector that indicates whether each top blob has a non-zero weight in
* the objective function. */
vector<Dtype> loss_;

layer_param_类型为LayerParameter,具体定义在caffe_root/src/caffe/protocaffe.proto中,描述了层的一些信息,例如是测试还是训练,其bottom和top等。

phase_是枚举变量,指明这一层是训练还是测试。

blobs_是容器,其容器内元素类型为指向Blob的智能指针,存储内容为权重w和偏置b,即这一层需要训练的参数。

param_propagate_down_是保存bool类型的容易,即是否要计算Blob的梯度diff

loss_是容器,标志着top blob是否有非零权重

还有2个private访问权限的变量:

bool is_shared_;//标记layer是否被nets共享

/** The mutex for sequential forward if this layer is shared */
shared_ptr<boost::mutex> forward_mutex_;//如果layer被共享,使用前要加锁

layer可以被网络共享,如果共享,使用layer时,需要给layer加锁。

初始化过程

layer构造函数需要LayerParameter类型参数,这个参数往往定义在网络的protobuf中。通过构造函数来初始化,给blobs_分配空间,随后从Layerparameter中填充分配的内存。

    explicit Layer(const LayerParameter& param)
: layer_param_(param), is_shared_(false) {
// Set phase and copy blobs (if there are any).
phase_ = param.phase();
if (layer_param_.blobs_size() > 0) {
blobs_.resize(layer_param_.blobs_size());
for (int i = 0; i < layer_param_.blobs_size(); ++i) {
blobs_[i].reset(new Blob<Dtype>());
blobs_[i]->FromProto(layer_param_.blobs(i));
}
}
}

之后调用SetUp函数,这个函数会初始化互斥量,检查输入输出合法性。调用LayerSetUp设置详细参数,Reshape调整Blob结构,这两个虚函数,不同的层实现不同。最后来设置top blobs的loss function的权重

  inline void SetLossWeights(const vector<Blob<Dtype>*>& top) {
const int num_loss_weights = layer_param_.loss_weight_size();//在protobuf中获取权重个数
if (num_loss_weights) {
CHECK_EQ(top.size(), num_loss_weights) << "loss_weight must be "//检查权重个数是否匹配
"unspecified or specified once per top blob.";
for (int top_id = 0; top_id < top.size(); ++top_id) {
const Dtype loss_weight = layer_param_.loss_weight(top_id);//从protobuf中获取对应权重
if (loss_weight == Dtype(0)) { continue; }//权重为零则不赋值
this->set_loss(top_id, loss_weight);//设置权重
const int count = top[top_id]->count();
Dtype* loss_multiplier = top[top_id]->mutable_cpu_diff();//得到diff指针
caffe_set(count, loss_weight, loss_multiplier);//给diff指针赋值
}
}
}

前向传播和反向传播

Layer最重要的功能就是前向传播和反向传播。前向传播,是数据沿着网络向前流,反向传播是梯度(误差)反方向往回流,用来更新权重和偏置。对应的函数为Forward何Backward,再详细一点,这两个函数还应该有对应的CPU版本和GPU版本。

不同类型的Layer,前向和反向传播具体实现不同,在Layer层,这是两个纯虚函数。

caffe源码阅读(2)-Layer的更多相关文章

  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. caffe源码阅读(1)-数据流Blob

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

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

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

  5. caffe源码阅读(1)_整体框架和简介(摘录)

    原文链接:https://www.zhihu.com/question/27982282 1.Caffe代码层次.回答里面有人说熟悉Blob,Layer,Net,Solver这样的几大类,我比较赞同. ...

  6. caffe 源码阅读

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

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

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

  8. caffe中batch norm源码阅读

    1. batch norm 输入batch norm层的数据为[N, C, H, W], 该层计算得到均值为C个,方差为C个,输出数据为[N, C, H, W]. <1> 形象点说,均值的 ...

  9. 源码阅读经验谈-slim,darknet,labelimg,caffe(1)

    本文首先谈自己的源码阅读体验,然后给几个案例解读,选的例子都是比较简单.重在说明我琢磨的点线面源码阅读方法.我不是专业架构师,是从一个深度学习算法工程师的角度来谈的,不专业的地方请大家轻拍. 经常看别 ...

随机推荐

  1. Floyd-Warshall算法的理解

    Floyd算法可以求图内任意两点之间的最短路径,三重循环搞定,虽然暴力,但是属于算法当中最难的动态规划的一种,很有必要理解. 花了一晚上和半个下午专门看这个,才看个一知半解,智商被碾压没办法. 我一直 ...

  2. setTimeout中0毫秒延时

    先来看段代码,思考一下执行的结果. alert(1); setTimeout(function(){alert(2);}, 0); alert(3); 估计很多人认为执行结果为1,2,3,原因就是认为 ...

  3. JBPM流程实例(PI)Process Instance

    /** * 流程实例 *    *  启动流程实例 *    *  完成任务 *    *  查询 *      *  查询流程实例 *      *  查询任务 *          *  查询正在 ...

  4. String的点点滴滴

    一.String 的 equals()到底比较的是什么?equals() 与 == 的区别? 当使用关系运算符==比较两个对象时,是比较两个对象使用的内存地址和内容是否相同,如果两个对象使用的是同一个 ...

  5. unity3d 获取相机视口四个角的坐标

    功能:如标题所示,主要考虑用来做3d Plane的自适应屏幕 /// <summary> /// 获取指定距离下相机视口四个角的坐标 /// </summary> /// &l ...

  6. Android虚拟机Dalvik介绍

     Dalvik和标准Java虚拟机(JVM)之间的首要差别之一,就是Dalvik基于寄存器,而JVM基于栈.一直以来都有人在猜测,选择基于寄存器的方式是因为它对提前优化(ahead-of-time o ...

  7. VOA学习-South Sudan Must Allow Aid

    South Sudan Must Allow Aid The United States is gravelyconcerned by the serious escalation of the hu ...

  8. 15 Linux Split and Join Command Examples to Manage Large Files--reference

    by HIMANSHU ARORA on OCTOBER 16, 2012 http://www.thegeekstuff.com/2012/10/15-linux-split-and-join-co ...

  9. linux启动的过程

    总结一下,linux的开机整个流程. · 1: 启动电源后,主机第一步先做的就是查询BIOS(全称:basic input/output system 基本输入输出系统)信息.了解整个系统的硬件状态, ...

  10. chrome浏览器频频崩溃,如何解决?

    之前chrome常崩溃,也没有找到原因,就将就着用吧,一直用到今天, 今天连续几次崩了,突然想到,难道是因为我访问的域名没有解析(能想到这个,是因为今天分配公司域名测试的时候常输错),于是就输入一个不 ...