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
- Caffe源码解读(十一):自定义一个layer
- Caffe源码解读(三):Layer类的源码解读
- Caffe源码解读(十三):caffe.proto中Layer参数与源代码中Layer的相互关系
- Caffe源码解读3--layer.hpp
- 17.2.23 caffe如何自定义一个layer
- Caffe源码解读(十二):自定义数据输入层
- caffe自定义layer
- Caffe源码(三):layer 分析
- caffe源码学习(四) layer
- caffe源码学习(五) data layer
- Caffe源码(三):layer 分析
- caffe源码 layer分析
- caffe源码学习:layer
- caffe源码:Layer
- caffe源码追踪--layer
- Caffe源码解读(二):Blob类的源码解读
- Caffe源码(十一):io.cpp 分析
- Caffe源码(十一):io.cpp 分析
- 18.[个人]C++线程入门到进阶(18)----线程函数:SuspendThread
- mnist deep convolutional cetwork源码说明
- opencv中houghlines函数返回的rho和theta
- 你好,再见;你好,幸会!
- 【C语言】C语言中3种作用域举例
- Caffe源码解读(十一):自定义一个layer
- linux shell脚本对未定义变量的判断以及if的用法
- 网狐6603、客户端创建房间、会陪分配到其他客户端已创建好的房间去
- Java static修饰初始块{}
- 19.[个人]C++线程入门到进阶(19)----线程函数:ResumeThread
- Spring入门学习——第二阶段总结图
- 图片管理器
- cannot open include file 'afxres.h'错误的一种解决方法
- 20.[个人]C++线程入门到进阶(20)----线程函数:OpenThread