转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/

layer这个类可以说是里面最终的一个基本类了,深度网络呢就是一层一层的layer,相互之间通过blob传输数据连接起来。首先layer必须要实现一个forward function,前递函数当然功能可以自己定义啦,在forward中呢他会从input也就是Layer的bottom,对了caffe里面网络的前一层是叫bottom的,从bottom中获取blob,并且计算输出的Blob,当然他们也会实现一个反向传播,根据他们的input的blob以及output blob的error gradient 梯度误差计算得到该层的梯度误差。从公式中也可以看到:
\[\delta^l=((w^{l+1})^T\delta^{l+1}) \sigma'(z^l)\]

首先来看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,在初始化列表初始化LayerParameter,之后blobs_这里存放的是一个指向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额error gradient 计算得到bottom的error gradient。其输入时 output blobs ,在Ouput blobs里面的diff存储的就是其相应的error gradients。其中propagate_down这个参数跟Bottom的长度是一样的,每一个Index用来指定是否需要反向传播error gradients 到对应的bottom blob。而bottom 这里面的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这一看就明白了

最后其实proto里面有个layer_parameter是挺重要的一个结构,存储了layer的大量信息,这个具体可以到proto文件夹下查看,这里就暂时不列出了。

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

  1. Caffe源码解析7:Pooling_Layer

    转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/ Pooling 层一般在网络中是跟在Conv卷积层之后,做采样 ...

  2. Caffe源码解析6:Neuron_Layer

    转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/ NeuronLayer,顾名思义这里就是神经元,激活函数的相应 ...

  3. Caffe源码解析5:Conv_Layer

    转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/ Vision_layer里面主要是包括了一些关于一些视觉上的操 ...

  4. Caffe源码解析4: Data_layer

    转载请注明出处,楼燚(yì)航的blog,http://home.cnblogs.com/louyihang-loves-baiyan/ data_layer应该是网络的最底层,主要是将数据送给blo ...

  5. Caffe源码解析1:Blob

    转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang-loves-baiyan/ 首先看到的是Blob这个类,Blob是作为Caffe中数据流通的 ...

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

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

  7. Caffe源码解析2:SycedMem

    转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang loves baiyan/ 看到SyncedMem就知道,这是在做内存同步的操作.这类个类的 ...

  8. caffe源码解析

    http://blog.csdn.net/lanxuecc/article/details/53186613

  9. caffe源码阅读

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

随机推荐

  1. sql优化之not in

    sql : select ID from awhere XX <> 0 and ID not in (select ID from b) 4万多条记录,执行了316秒,无法接受.   优化 ...

  2. Java高级之线程同步

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 关于实现多线程的意义,"从业四年看并发"一文已经讲述,而本篇主要讲一下常用的设计 ...

  3. Karaf 依赖equinox and felix,karaf 本Apache的很多项目作为基础框架

    6月17日是Apache Karaf作为Apache顶级项目.Karaf是个运行时包,包含了一个OSGi框架(Equinox或Felix).一个命令shell(Felix Gogo)及默认情况下内置的 ...

  4. 常见的Unix指令

    ls -1 列出当前目录下的所有内容(文件/文件夹) pwd 显示当前操作的目录 cd   改变当前操作的目录 who 显示当前用户 clear 清屏 mkdir 新建一个目录 touch 新建一个文 ...

  5. 基于内嵌Tomcat的应用开发

    为什么使用内嵌Tomcat开发? 开发人员无需搭建Tomcat的环境就可以使用内嵌式Tomcat进行开发,减少搭建J2EE容器环境的时间和开发时容器频繁启动所花时间,提高开发的效率. 怎么搭建内嵌To ...

  6. SharePoint Client Add Folder,file to Library

    public void UploadDocument(string siteURL, string documentListName, string documentListURL, string d ...

  7. Objective-C语法快速参考(C# 和 Objective-C 语法的比较)

    大部分有一点其他平台开发基础的初学者看到XCode ,第一感想是磨拳擦掌,看到 Interface  Builder 之后,第一感想是跃跃欲试,而看到Objective-C 的语法,第一感想就变成就望 ...

  8. Spring的MethodInvokingFactoryBean

    通过MethodInvokingFactoryBean 可以向某静态方法注入参数. 如: <bean class="org.springframework.beans.factory. ...

  9. 表单元素的外观改变(webkit and IE10)

    1.禁止表单默认外观: input,select{ -webkit-appearance:none; appearance:none; }2.伪元素改变ie10表单元素默认外观 select::-ms ...

  10. RabbitMQ的使用场景

    RabbitMQ的使用场景   1 大数据日志收集消息中间件应用场景     2 消息中间件在搜索系统DIH(伪实时)中的应用       伪实时的搜索系统:   后台系统:(作为生产者发送消息)   ...