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

自定义神经层的步骤:

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 all
make 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^power
template <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_ONLY
STUB_GPU(MyNeuronLayer);
#endif
//实例化模板类MyNeuronLayer
INSTANTIATE_CLASS(MyNeuronLayer);
REGISTER_LAYER_CLASS(MyNeuron);

}// namespace caffe
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值