Caffe源码解读(十一):自定义一个layer

来源:互联网 发布:百度云盘加载数据失败 编辑:程序博客网 时间:2024/06/05 02:18

自定义神经层的步骤:

1、创建新定义的头文件include/caffe/layers/my_neuron_layer.hpp
- 重新Layer名的方法:virtual inline const char* type() const { return “MyNeuron”; }
- 如果只是需要cpu方法的话,可以注释掉forward/backward_gpu()这两个方法

2、 创建对应src/caffe/src/my_neuron_layer.cpp的源文件

  • 重写方法LayerSetUp,实现能从prototxt读取参数

  • 重写方法Reshape,如果对继承类没有修改的话,就不需要重写

  • 重写方法Forward_cpu

  • 重写方法Backward_cpu(非必须)

  • 如果要GPU支持,则还需要创建src/caffe/src/my_neuron_layer.cu,同理重写方法Forward_gpu/Backward_gpu(非必须)

3、proto/caffe.proto注册新的Layer

message LayerParameter{...++ optional MyNeuronParameter my_neuron_param = 150;...}...++ message MyNeuronParameter {++  optional float power = 1 [default = 2]; //自定义层的新增参数++ }...message V1LayerParameter{...++ MYNEURON = 40;...}

4、my_neuron_layer.cpp添加注册的宏定义

INSTANTIATE_CLASS(MyNeuronLayer);REGISTER_LAYER_CLASS(MyNeuron);

如果有my_neuron_layer.cu,则添加

INSTANTIATE_LAYER_GPU_FUNCS(MyNeuronLayer);

5、重新编译和install

cmake -DCMAKE_BUILD_TYPE=Release -DCPU_ONLY=ON CMAKE_PREFIX_INSTALL=/usr/local ..make allmake intall

测试自定义的Layer

定义deploy.prototxt

name: "CaffeNet"input: "data"input_shape {  dim: 1 # batchsize  dim: 1 # number of colour channels - rgb  dim: 28 # width  dim: 28 # height}layer {  name: "myneuron"  type: "MyNeuron"  bottom: "data"  top: "data_out"  my_neuron_param {    power : 2  }}

实例

自定义my_neuron_layer.hpp,放在include/caffe/Layers目录下,这个神经层的作用是对每个元素值做指数运算。

#ifndef CAFFE_MY_NEURON_LAYER_HPP_#define CAFFE_MY_NEURON_LAYER_HPP_#include <vector>#include "caffe/blob.hpp"#include "caffe/layer.hpp"#include "caffe/proto/caffe.pb.h"//继承自neuron_layer#include "caffe/layers/neuron_layer.hpp"namespace caffe {template <typename Dtype>//该自定义层继承自NeuronLayer层。class MyNeuronLayer : public NeuronLayer<Dtype> { public:  explicit MyNeuronLayer(const LayerParameter& param)      : NeuronLayer<Dtype>(param) {}  //声明LayerSetUp层  virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,      const vector<Blob<Dtype>*>& top);  //重新设置Layer名  virtual inline const char* type() const { return "MyNeuron"; } protected:  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);  virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  Dtype power_;//需要定义一个成员变量power_作为指数运算的幂。};}  // namespace caffe#endif  // CAFFE_MY_NEURON_LAYER_HPP_

自定义my_neuron_layer的实现my_neuron_layer.cpp,放在src/caffe/Layers目录下。

#include <vector>#include "caffe/layers/my_neuron_layer.hpp"#include "caffe/util/math_functions.hpp"namespace caffe {template <typename Dtype>void MyNeuronLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top){  //调用父类的LayerSetUp函数,实现从prototxt读参数。  NeuronLayer<Dtype>::LayerSetUp(bottom,top);  //1、layer_param_是基类Layer层的成员变量,在caffe.proto可以看到,类型为LayerParameter。  //2、在步骤3中,我们在LayerParameter中增加了参数my_neuron_param,类型为MyNeuronParameter。  //3、MyNeuronParameter类型也是为该层添加的,里面定义了参数power。  power_ = this->layer_param_.my_neuron_param().power();}// Compute y = x^powertemplate <typename Dtype>void MyNeuronLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top){  //bottom和top都是一组向量,向量的元素是Blob类型的指针。  //Forward操作要更新top值,所以这里用top的mutable_cpu_data数据指针。因为我们定义的网络结构只有一个top,所以只使用top[0]。  Dtype* top_data = top[0]->mutable_cpu_data();  const int count = bottom[0]->count();  //caffe_powx在math_functions.hpp中定义  /*    void caffe_powx<float>(const int n, const float* a, const float b, float* y)    作用:y[i] = a[i] ^ b,n表示元素个数  */  caffe_powx(count, bottom[0]->cpu_data(), Dtype(power_), top_data);}template <typename Dtype>void MyNeuronLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,const vector<bool>& propagate_down,const vector<Blob<Dtype>*>& bottom){  //反向传播:由top计算出bottom,更进一步是由top的cpu_diff对bottom的cpu_data求导。cpu_diff是实际误差,bo  const int count = top[0]->count();  const Dtype* top_diff = top[0]->cpu_diff();  if(propagate_down[0]){    const Dtype* bottom_data = bottom[0]->cpu_data();    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();    //y = power * x ^ (power-1)    //bottom_diff表示梯度下降算法的权值更新的量    caffe_powx(count, bottom_data, Dtype(power_ - 1), bottom_diff);    caffe_scal(count, Dtype(power_), bottom_diff);    //    caffe_mul(count, bottom_diff, top_diff, bottom_diff);  }}#ifdef CPU_ONLYSTUB_GPU(MyNeuronLayer);#endif//实例化模板类MyNeuronLayerINSTANTIATE_CLASS(MyNeuronLayer);REGISTER_LAYER_CLASS(MyNeuron);}// namespace caffe
0 0
原创粉丝点击