Caffe源码解析3:Layer

转载:http://home.cnblogs.com/louyihang-loves-baiyan/

layer这个类可以说是里面最终的一个基本类,深度网络就是一层一层的layer,相互之间通过blob传输数据连接起来。首先layer必须要实现一个forward function,前递函数功能可以自己定义,在forward中他会从input也就是layer的bottom中获取blob,caffe里面网络的前一层是叫bottom,并且计算输出的blob,当然他们也会实现一个反向传播,根据他们的input的blob以及output blob 的error gradient梯度误差计算得到该层的梯度误差。

首先来看layer类的构造部分,以及public部分的函数

template <typename Dtype>
class Layer {
 public:
  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));
        }
      }
    }
  virtual ~Layer() {}

首先获得当前网络的phase,是train还是test,在初始化列表初始化LayerParaneter,之后blibs_这里存放的是一个指向blob类的shared_ptr指针的一个vector,在这里是申请空间,然后将传入的layer_param中的blob拷贝过来。

void SetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) {
    InitMutex();
    CheckBlobCounts(bottom, top);
    LayerSetUp(bottom, top);
    Reshape(bottom, top);
    SetLossWeights(top);
  }

这里是Setup函数,首先check这个bottom和top的blob是否正确,在调用Layersetup对每一具体的层做进一步设置,之后在做reshape来设置top blobs和internal buffer。最后在设置loss weight multiplier的blob对每一个非零的loss和weight,一般这个方法被继承后是不会被重写的。

virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top)
virtual inline bool ShareInParallel()
inline bool IsShared() const
inline void SetShared(bool is_shared)

LayerSetup就是对具体某一个layer的setup,被上面的那个函数所调用,ShareInParallel和IsShared和SetShared分别是用来返回并行状态和获得这一layer是否被多个nets所共享,默认是除了data layer都是关闭的。在多个GPU下的Train阶段以及share是true的情况下,is_shared将会被置成true。

virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top) = 0;

这个reshape主要是layer用来根据输入的blob调节Internal buffer以及输出的Blob的

注意

接下来是几个最重要的函数,首先是Forward.这其实是一个装饰器,继承之后在调用的调用其相应的forward_cpu或者forward_gpu,根据输入的input data blob计算相应的output data blob,同时会反应这一层layer的total loss.

inline Dtype Forward(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);

这里是BackWard,实现的是反向传播,也就是给定top blob和计算得到bottom的error gradient.其输入是output blobs,在Output blobs里面的diff存储的就是其相应的error gradients。其中propagate_down这个参数跟Bottom的长度是一样的,每一个index用来指定是否需要反向传播error gradients到对应的bootom blob。而botton这里卖弄的diff 区域存放的就是BackWard计算出来相应的gradient error。

inline void Backward(const vector<Blob<Dtype>*>& top,
      const vector<bool>& propagate_down,
      const vector<Blob<Dtype>*>& bottom);

如果自己要实现一个Layer的话,那么Forward_cpu和Backward_cpu以及gpu(可选),应该要有自己的实现。

接下来几个函数比较简单,同意说明:

vector<shared_ptr<Blob<Dtype> > >& blobs()\\返回blobs
const LayerParameter& layer_param() \\返回layer 的参数parameter
virtual void ToProto(LayerParameter* param, bool write_diff = false)\\将层参数写到Protobuffer里
inline Dtype loss(const int top_index) const \\给定index返回相应的scalar loss
inline void set_loss(const int top_index, const Dtype value)\\给定Index设置loss
virtual inline const char* type()\\返回layer的type

以下几个函数主要获得bottom或者top blob的数量状态,比较简单,看名字即可:

virtual inline int ExactNumBottomBlobs()
virtual inline int MinBottomBlobs()
virtual inline int MaxBottomBlobs()
virtual inline int ExactNumTopBlobs()
virtual inline int MinTopBlobs()
virtual inline int MaxTopBlobs()
virtual inline bool EqualNumBottomTopBlobs()
virtual inline bool AutoTopBlobs()

AllowforceBackward用来设置是否前置梯度返回,因为有些层其实不需要梯度信息,后面两个函数分别查看以及设置是否需要计算梯度。

virtual inline bool AllowForceBackward(const int bottom_index)
inline bool param_propagate_down(const int param_id)
inline void set_param_propagate_down(const int param_id, const bool value)

往下看,几个变量和函数都是保护变量:

LayerParameter layer_param_; \\保存layer的参数 parameter
Phase phase_; \\标定阶段是train还是test
vector<shared_ptr<Blob<Dtype> > > blobs_; \\是Blob的一个集合,保存了learnbale参数
vector<bool> param_propagate_down_;\\标志位是否要计算param blob的梯度
vector<Dtype> loss_;\\用来表明那个top blob 有非零的权重

下面几个函数,分别是计算cpu和gpu模式下的正反传播:

virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top)
virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& 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)

这个函数被setup调用,主要是check bottom和top 的blob是否match,这里面用了上面提到的ExactBottomBlobs()等函数

virtual void CheckBlobCounts(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top)

SetLoss是非常重要的一个步骤,是被SetUp调用来初始化top bottom的weights,并且存储非零的loss weights 在diff blob里面

inline void SetLossWeights(const vector<Blob<Dtype>*>& top)

私有变量和函数如下,东西比较少,主要是对并行中的锁进行控制

bool is_shared_; //标记该layer是否被其他nets所共享
shared_ptr<boost::mutex> forward_mutex_;//若该layer被shared,则需要这个mutex序列保持forward过程的正常运行
void InitMutex();//初始化forward 的 mutex
void Lock();//locak mutex
void Unlock();//unlock mutex这一看就明白了

原文地址:https://www.cnblogs.com/xymmc/p/8586302.html

时间: 2024-11-08 23:40:06

Caffe源码解析3:Layer的相关文章

读caffe源码(未完待续)

caffe源码阅读杂记 准备 一些参考网页 Neural Networks and Deep Learning TUTORIAL ON DEEP LEARNING FOR VISION Deep Learning Tutorial 知乎-深度学习caffe的代码怎么读 Caffe源码解析 caffe源码结构 官方代码结构doxygen 官方Caffe Tutorial 以C++源码形式配置debug&CPU版的caffe,便于阅读源码与单步调试[参考] 参考官方的文档,先了解某个模块的作用 为了

神经网络caffe框架源码解析--softmax_layer.cpp类代码研究

// Copyright 2013 Yangqing Jia // #include <algorithm> #include <vector> #include "caffe/layer.hpp" #include "caffe/vision_layers.hpp" #include "caffe/util/math_functions.hpp" using std::max; namespace caffe { /**

神经网络caffe框架源码解析--data_layer.cpp类代码研究

dataLayer作为整个网络的输入层, 数据从leveldb中取.leveldb的数据是通过图片转换过来的. 网络建立的时候, datalayer主要是负责设置一些参数,比如batchsize,channels,height,width等. 这次会通过读leveldb一个数据块来获取这些信息. 然后启动一个线程来预先从leveldb拉取一批数据,这些数据是图像数据和图像标签. 正向传播的时候, datalayer就把预先拉取好数据拷贝到指定的cpu或者gpu的内存. 然后启动新线程再预先拉取数

分析caffe源码以及相应的Google c++ style

本人项目需分析caffe源码,并做一些相应的修改 1.caffe源码工程目录 src目录为整个工程的核心,它主要实现了神经网络的基本模型的组件:Blob.Layer.Net.Solver等核心类. include目录存放整个工程所有头文件. tools目录中存放了caffe的入口函数,用于参数解析,神经网络配置等. data目录和examples目录用于提供一些基本例子和相应数据. matlab和python目录存放用于两者的接口,只要不使用两者,目录下的内容没有实质作用. 其他一些目录和文件是

源码解析:dialog, popupwindow, 和activity 的第一个view是怎么来的?

问题 在慢慢熟悉android 的过程中,发现一个view 或者layout的初始化,或者构造的流程还是比较清楚的,也就是加到父控件中,然后就开始了对应的生命周期.但是整个界面的父控件,或者说系统的第一个view, 是怎么来的,如何初始化和绘制的呢? 概述 概述:带着困扰我的问题,在前文的基础上,继续分析应用界面和framework的关系,通过分析viewrootimpl 的来源,并结合dialog, popupwindow, 和activity 的 根view的创建流程,回答了问题界面的根vi

caffe源码分析--poolinger_layer.cpp

对于采样层,cafffe里实现了最大采样和平均采样的算法. 最大采样,给定一个扫描窗口,找最大值, 平均采样,扫描窗口内所有值的平均值. 其实对于caffe的实现一直有个疑问, 就是每一层貌似没有绑定一个激活函数? 看ufldl教程,感觉激活函数是必要存在的. 这怎么解释呢? 看到源码中,看到一些激活函数,比如sigmoid_layer.cpp和sigmoid_layer.cu. 也就是说,激活函数作为layer层面来实现了.当然,还有tanh_layer和relu_layer. 那,这个意思是

iOS即时通讯之CocoaAsyncSocket源码解析四

原文 前言: 本文为CocoaAsyncSocket源码系列中第二篇:Read篇,将重点涉及该框架是如何利用缓冲区对数据进行读取.以及各种情况下的数据包处理,其中还包括普通的.和基于TLS的不同读取操作等等.注:由于该框架源码篇幅过大,且有大部分相对抽象的数据操作逻辑,尽管楼主竭力想要简单的去陈述相关内容,但是阅读起来仍会有一定的难度.如果不是诚心想学习IM相关知识,在这里就可以离场了... 注:文中涉及代码比较多,建议大家结合源码一起阅读比较容易能加深理解.这里有楼主标注好注释的源码,有需要的

convnet源码解析(一):基础准备

Jeremy Lin ConvNet是一个基于GPU实现的卷积神经网络开源代码(C++11),是由多伦多大学的Geoffrey Hinton深度学习团队编写的,它的最初版本是Hinton的学生Alex Krizhevsky编写的cuda-convnet(其项目地址在google code上面),最近cuda-convnet也从1.0版本更新到2.0版本(地址). 这份开源代码的官方地址是:http://deeplearning.cs.toronto.edu/codes 在CNN的开源代码中最出名

caffe源码分析--softmax_layer.cpp

caffe源码分析--softmax_layer.cpp 文件位置为caffe-master/src/caffe/layers/softmax_layer.cpp 这个是一个以前版本的程序,现在的代码有些不同了,不过可以参考 [cpp] view plaincopy // Copyright 2013 Yangqing Jia // #include <algorithm> #include <vector> #include "caffe/layer.hpp"