caffe添加层的步骤

来源:互联网 发布:qt access数据库 2003 编辑:程序博客网 时间:2024/05/14 21:08

转载地址:http://blog.csdn.net/happyflyy/article/details/54866037


针对2017年2月时caffe官网版本。

1. caffe官网中添加新层的流程

官方增加新层的流程可见如下链接: 
https://github.com/BVLC/caffe/wiki/Development

  • Add a class declaration for your layer to include/caffe/layers/your_layer.hpp
    • Include an inline implementation of type overriding the methodvirtual inline const char* type() const { return "YourLayerName"; } replacing YourLayerName with your layer’s name.
    • Implement the {*}Blobs() methods to specify blob number requirements; see /caffe/include/caffe/layers.hpp to enforce strict top and bottom Blob counts using the inline {*}Blobs() methods.
    • Omit the *_gpu declarations if you’ll only be implementing CPU code.
  • Implement your layer in src/caffe/layers/your_layer.cpp
    • (optional) LayerSetUp for one-time initialization: reading parameters, fixed-size allocations, etc.
    • Reshape for computing the sizes of top blobs, allocating buffers, and any other work that depends on the shapes of bottom blobs
    • Forward_cpu for the function your layer computes
    • Backward_cpu for its gradient (Optional – a layer can be forward-only)
  • (Optional) Implement the GPU versions Forward_gpu and Backward_gpu in layers/your_layer.cu.
  • If needed, declare parameters in proto/caffe.proto, using (and then incrementing) the “next available layer-specific ID” declared in a comment above message LayerParameter
  • Instantiate and register your layer in your cpp file with the macro provided in layer_factory.hpp. Assuming that you have a new layer MyAwesomeLayer, you can achieve it with the following command:
INSTANTIATE_CLASS(MyAwesomeLayer);REGISTER_LAYER_CLASS(MyAwesome);
  • 1
  • 2
  • 3
  • Note that you should put the registration code in your own cpp file, so your implementation of a layer is self-contained.
  • Optionally, you can also register a Creator if your layer has multiple engines. For an example on how to define a creator function and register it, see GetConvolutionLayer in caffe/layer_factory.cpp.
  • Write tests in test/test_your_layer.cpp. Use test/test_gradient_check_util.hpp to check that your Forward and Backward implementations are in numerical agreement.

2. 增加新层实践

因为官网的只给出了流程,并没给出具体例子,因此将结合添加maxout层对整个流程进行说明。 
旧版本添加maxout以及maxout原理可参考下面博客。 
http://blog.csdn.net/kuaitoukid/article/details/41865803

Step1: 确定要添加的层的基类

相比于上面博客中旧版caffe对层的分类,现在的caffe中层的分类有所改变,去掉了vision层,直接由layer层派生。除此之外还有loss层,neuron层,以及data层。 
- loss层和data层顾名思义,不加赘述 
- 输入blob和输出blob的大小一样,从neuron层派生。例如激活层ReLU,以及逐点操作的exp层和power层。需要实现虚函数SetUpForward_cpuBackward_cpu。 
- 输入blob和输出blob的大小不一样,直接从layer层派生。例如conv层,将要添加的maxout层。需要实现虚函数SetUpReshapeForward_cpuBackward_cpu

Step2: caffe.proto定义该层的参数 
- 添加Maxout LayerParameter的ID 
message LayerParameter最后一行添加MyMaxoutParameter,并将ID按顺序设置为没有用过的数字。

optional MyMaxoutParameter my_maxout_param = 147;
  • 1

message LayerParameter的注释中有最后添加的层名以及可用的ID号,为了便于以后使用,建议更改一下。

// NOTE// Update the next available ID when you add a new LayerParameter field.//// LayerParameter next available layer-specific ID: 147 (last added: recurrent_param)
  • 1
  • 2
  • 3
  • 4
  • 添加Maxout layer的参数消息 
    在caffe.proto任意位置添加Maxout layer的参数消息:
// message that stores paremeters used to maxout layersmessage MyMaxoutParameter {  // the number of output for this layer  optional uint32 num_output = 1;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 添加Maxout layer的层名 
    message V1LayerParameter中的enum LayerType添加Maxout层的层名:
MYMAXOUT = 40;
  • 1

同时添加:

optional MyMaxoutParameter my_maxout_param = 43;
  • 1

数字只要不重复就可以。

Step3: 增加maxout层的头文件到./include/caffe/layers/mymaxout.hpp

主要在MyMaxoutLayer类中定义构造函数和SetUpReshapeForward_cpuBackward_cpu函数以及一些变量。

#ifndef CAFFE_MY_MAXOUT_LAYER_HPP_#define CAFFE_MY_MAXOUT_LAYER_HPP_#include <vector>#include "caffe/blob.hpp"#include "caffe/layer.hpp"#include "caffe/proto/caffe.pb.h"namespace caffe {  template <typename Dtype>  class MyMaxoutLayer : public Layer<Dtype> {   public:    explicit MyMaxoutLayer(const LayerParameter& param)        : Layer<Dtype>(param) {}    // initialize the bottom and top blobs  virtual inline const char* type() const { return "MyMaxout"; }  virtual void SetUp(const vector<Blob<Dtype>*>& bottom, vector<Blob<Dtype>*>& top);  virtual void Reshape(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top); protected:    virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top);    //virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,    //    vector<Blob<Dtype>*>* top);    virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  //virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,    //    const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);    int num_output_;    int num_;    int channels_;    int height_;    int width_;    int group_size_;    Blob<Dtype> max_idx_;  };  }#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

Step4: 增加maxout层的源文件到./src/caffe/layers/mymaxout.cpp 
SetUp: 进行check 
Reshape: 更改top blob的大小 
Forward_cpu: 实现正向传播 
Backward_cpu: 实现反向传播 
REGISTER_LAYER_CLASS: 最后注册层。

#include <vector>  #include "caffe/util/im2col.hpp"   #include "caffe/util/math_functions.hpp"  #include "caffe/layers/my_maxout_layer.hpp"  namespace caffe {   template <typename Dtype>  void MyMaxoutLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,         vector<Blob<Dtype>*>& top) {  const MyMaxoutParameter& my_maxout_param = this->layer_param_.my_maxout_param();  CHECK(my_maxout_param.has_num_output())      << "num_output should be specified.";   }  template <typename Dtype>  void MyMaxoutLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top){  num_output_ = this->layer_param_.my_maxout_param().num_output();     CHECK_GT(num_output_, 0) << "output number cannot be zero.";    // bottom   num_ = bottom[0]->num();    channels_ = bottom[0]->channels();    height_ = bottom[0]->height();      width_ = bottom[0]->width();       // TODO: generalize to handle inputs of different shapes.      for (int bottom_id = 1; bottom_id < bottom.size(); ++bottom_id) {        CHECK_EQ(num_, bottom[bottom_id]->num()) << "Inputs must have same num.";        CHECK_EQ(channels_, bottom[bottom_id]->channels())            << "Inputs must have same channels.";        CHECK_EQ(height_, bottom[bottom_id]->height())            << "Inputs must have same height.";        CHECK_EQ(width_, bottom[bottom_id]->width())            << "Inputs must have same width.";      }    // Set the parameters, compute the group size  CHECK_EQ(channels_ % num_output_, 0)         << "Number of channel should be multiples of output number.";     group_size_ = channels_ / num_output_;      top[0]->Reshape(num_, num_output_, height_, width_);     max_idx_.Reshape(num_, num_output_, height_, width_);}template <typename Dtype>   void MyMaxoutLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,      const vector<Blob<Dtype>*>& top) {    int featureSize = height_ * width_;      Dtype* mask = NULL;      mask = max_idx_.mutable_cpu_data();  //printf("1.maxout_forward\n");      const int top_count = top[0]->count();      caffe_set(top_count, Dtype(0), mask);  //printf("2.maxout_forward\n");      for (int i = 0; i < bottom.size(); ++i) {          const Dtype* bottom_data = bottom[i]->cpu_data();          Dtype* top_data = top[i]->mutable_cpu_data();            for (int n = 0; n < num_; n ++) {              for (int o = 0; o < num_output_; o ++) {                  for (int g = 0; g < group_size_; g ++) {                       if (g == 0) {                          for (int h = 0; h < height_; h ++) { // á?2??-?·óDμ??ù?aà?                              for (int w = 0; w < width_; w ++) {                                  int index = w + h * width_;                                  top_data[index] = bottom_data[index];                                  mask[index] = index;                              }                          }                      }                      else {                          for (int h = 0; h < height_; h ++) {                              for (int w = 0; w < width_; w ++) {                                  int index0 = w + h * width_;                                  int index1 = index0 + g * featureSize;                                  if (top_data[index0] < bottom_data[index1]) {                                      top_data[index0] = bottom_data[index1];                                      mask[index0] = index1;                                  }                                                             }                          }                      }                  }                  bottom_data += featureSize * group_size_;                  top_data += featureSize;                  mask += featureSize;              }          }      }    }  template <typename Dtype>  void MyMaxoutLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,      const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {      if (!propagate_down[0]) {          return;      }      // const Dtype* top_diff = top[0]->cpu_diff();      Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();      caffe_set(bottom[0]->count(), Dtype(0), bottom_diff);      const Dtype* mask = max_idx_.mutable_cpu_data();      int featureSize = height_ * width_;      for (int i = 0; i < top.size(); i ++) {          const Dtype* top_diff = top[i]->cpu_diff();          Dtype* bottom_diff = bottom[i]->mutable_cpu_diff();            for (int n = 0; n < num_; n ++) {             for (int o = 0; o < num_output_; o ++) {                  for (int h = 0; h < height_; h ++) { // á?2??-?·óDμ??ù?aà?                      for (int w = 0; w < width_; w ++) {                          int index = w + h * width_;                          int bottom_index = mask[index];                          bottom_diff[bottom_index] += top_diff[index];                      }                  }                  bottom_diff += featureSize * group_size_;                  top_diff += featureSize;                  mask += featureSize;              }          }      }  }  #ifdef CPU_ONLYSTUB_GPU(MyMaxoutLayer);#endifINSTANTIATE_CLASS(MyMaxoutLayer);REGISTER_LAYER_CLASS(MyMaxout); }  // namespace caffe  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134

Step5: 重新编译

make cleanmake all -j16
  • 1
  • 2

3. 注意事项

  1. 从layer层派生一定得实现四个虚函数SetUpReshapeForward_cpuBackward_cpu;从neuron派生则不需要实现Reshape函数。

  2. 虚函数的函数名,函数返回值,函数参数以及参数类型必须得和基类中的定义一致,建议直接从基类中拷贝。否则可能在编译时报如下错误:

./include/caffe/layer_factory.hpp"135:67: error: cannot allocate an object of abstract type

原创粉丝点击