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
定义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
#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 {
public:
explicit MyNeuronLayer(const LayerParameter& param)
: NeuronLayer(param) {}
//声明LayerSetUp层
virtual void LayerSetUp(const vector *>& bottom,
const vector *>& top);
//重新设置Layer名
virtual inline const char* type() const { return "MyNeuron"; }
protected:
virtual void Forward_cpu(const vector *>& bottom,
const vector *>& top);
virtual void Forward_gpu(const vector *>& bottom,const vector *>& top);
virtual void Backward_cpu(const vector *>& top,
const vector<bool>& propagate_down, const vector *>& bottom);
virtual void Backward_gpu(const vector *>& top,const vector<bool>& propagate_down, const vector *>& bottom);
Dtype power_;//需要定义一个成员变量power_作为指数运算的幂。
};
} // namespace caffe
#endif // CAFFE_MY_NEURON_LAYER_HPP_
自定义my_neuron_layer的实现my_neuron_layer.cpp,放在src/caffe/Layers目录下。
#include
#include "caffe/layers/my_neuron_layer.hpp"
#include "caffe/util/math_functions.hpp"
namespace caffe {
template <typename Dtype>
void MyNeuronLayer::LayerSetUp(const vector *>& bottom,const vector *>& top){
//调用父类的LayerSetUp函数,实现从prototxt读参数。
NeuronLayer::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::Forward_cpu(const vector *>& bottom,const vector *>& 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(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::Backward_cpu(const vector *>& top,const vector<bool>& propagate_down,const vector *>& 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