Caffe源码理解(2)——超级完整版教程:如何自定义一个新的层结构并重新编译Caffe
2017-09-26 17:27
465 查看
假设我们要重新定义一个激活函数,这个层的名字是Reverse。
1. reverse.hpp
首先我们需要创建一个caffe/include/caffe/layers/reverse.hpp,仿照caffe-master中的代码编写:
注:如果不用gpu那么上述虚函数中Forward_gpu()/Backward_gpu()无需做定义,对应的也只需要编写.cpp文件,不用写.cu文件。
2.reverse.cpp/reverse.cu
然后创建caffe/src/caffe/layers/reverse.cpp和caffe/src/caffe/layers/reverse.cu,针对cpu和gpu模式的源代码:
reverse.cpp:
reverse.cu:
注:.cu文件会调用CUDA,需要环境配置成功,并且在成员函数中写:CUDA_POST_KERNEL_CHECK;
3.修改caffe.proto
在上面的两步中我们已经把需要修改的源代码核心部分编写完毕,如果你的层定义中有添加的新的参数,那么现在要为我们新定义的层的参数添加ID。
打开caffe/src/caffe/proto/caffe.proto文件:
- 在message V0LayerParameter{}中添加新参数的ID:
无论有没有添加新的参数都需要对层添加ID,并且添加message消息
- 在message LayerParameter {}中添加新参数信息,并且添加建一个唯一的ID:
在caffe.proto中添加messga消息函数:
在caffe.proto中找到message V1LayerParameter函数:
4.layer_factory.cpp
在caffe/src/caffe/layer_factory.cpp中写入新的层定义:
5.upgrade_proto.cpp
在caffe/src/caffe/util/upgrade_proto.cpp中找到:
V1LayerParameter_LayerType UpgradeV0LayerType(const string& type) {…}
bool UpgradeV1LayerParameter(const V1LayerParameter&v1_layer_param,LayerParameter* layer_param) {…}
const char* UpgradeV1LayerType(const V1LayerParameter_LayerType type) {switch (type) {…}}
根据其他的层定义仿写即可,具体代码略。
6.重新编译caffe
到这一步基本上该做修改的底层代码已经修改完毕,需要重新编译Caffe,检查自己的代码是否书写正确。
打开Terminal,进入caffe-master,依次输入以下语句:
如果无报错,恭喜你已经成功的定义一个新的层结构啦~~
写在后面:最近几天在开始研究Caffe底层代码,记录了一下自己的改层过程,但是自己的C++能力有限,有问题的地方还望不吝赐教,十分感谢。
1. reverse.hpp
首先我们需要创建一个caffe/include/caffe/layers/reverse.hpp,仿照caffe-master中的代码编写:
//首先声明: #ifndef CAFFE_REVERSE_HPP_ #define CAFFE_REVERSE_HPP_ #include <vector> #include "caffe/blob.hpp" #include "caffe/layer.hpp" #include "caffe/proto/caffe.pb.h" #include "caffe/layers/neuron_layer.hpp" namespace caffe { //定义不同类型的成员变量 template <typename Dtype> class ReverseLayer : public NeuronLayer<Dtype> { public: /** * @param param provides ReverseParameter reverse_param, * with ReverseLayer options: * - negative_slope (\b optional, default 0). * the value @f$ \nu @f$ by which negative values are multiplied. */ explicit ReverseLayer(const LayerParameter& param) : NeuronLayer<Dtype>(param) {} virtual inline const char* type() const { return "Reverse"; } protected: //定义4个纯虚函数,代表cpu/gpu下训练的前向反向过程 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); };//class reverselayer }//namespace caffe ...//根据自己的需求定义不同类型的成员变量或者成员函数 #endif // CAFFE_REVERSE_HPP_
注:如果不用gpu那么上述虚函数中Forward_gpu()/Backward_gpu()无需做定义,对应的也只需要编写.cpp文件,不用写.cu文件。
2.reverse.cpp/reverse.cu
然后创建caffe/src/caffe/layers/reverse.cpp和caffe/src/caffe/layers/reverse.cu,针对cpu和gpu模式的源代码:
reverse.cpp:
#include <algorithm> #include <vector> //调用上一步已经定义好的对应的头文件 #include "caffe/layers/reverse_layer.hpp" namespace caffe { //定义头文件中创建的虚函数,即具体的前向反向的过程 template <typename Dtype> void ReverseLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {...} template <typename Dtype> void ReLULayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {...} #ifdef CPU_ONLY STUB_GPU(ReLULayer); #endif INSTANTIATE_CLASS(ReverseLayer); }// namespace caffe
reverse.cu:
#include <algorithm> #include <vector> #include "caffe/layers/reverse.hpp" namespace caffe { template <typename Dtype> __global__ void ReverseForward(const int n, const Dtype* in, Dtype* out, Dtype negative_slope) { CUDA_KERNEL_LOOP(index, n) {...} template <typename Dtype> void ReverseLayer<Dtype>::Forward_gpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {...} template <typename Dtype> __global__ void ReverseBackward(const int n, const Dtype* in_diff, const Dtype* in_data, Dtype* out_diff, Dtype negative_slope) { CUDA_KERNEL_LOOP(index, n) {...} template <typename Dtype> void ReverseLayer<Dtype>::Backward_gpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {...} INSTANTIATE_LAYER_GPU_FUNCS(ReLULayer); }// namespace caffe
注:.cu文件会调用CUDA,需要环境配置成功,并且在成员函数中写:CUDA_POST_KERNEL_CHECK;
3.修改caffe.proto
在上面的两步中我们已经把需要修改的源代码核心部分编写完毕,如果你的层定义中有添加的新的参数,那么现在要为我们新定义的层的参数添加ID。
打开caffe/src/caffe/proto/caffe.proto文件:
- 在message V0LayerParameter{}中添加新参数的ID:
optional 类型 参数名 = ID [default = *];
无论有没有添加新的参数都需要对层添加ID,并且添加message消息
- 在message LayerParameter {}中添加新参数信息,并且添加建一个唯一的ID:
optional ReverseParameter reverse_param = ***;
在caffe.proto中添加messga消息函数:
//例如ReLU函数的: message ReLUParameter { optional float negative_slope = 1 [default = 0]; enum Engine { DEFAULT = 0; CAFFE = 1; CUDNN = 2; } optional Engine engine = 2 [default = DEFAULT]; }
在caffe.proto中找到message V1LayerParameter函数:
message V1LayerParameter{ ... enum LayerType { ... REVERSE = **;//为Reverse添加唯一的ID ... } ... optional ReverseParameter reverse_param = **;//继续添加一个唯一的ID,不与上面的相同 ... }
4.layer_factory.cpp
在caffe/src/caffe/layer_factory.cpp中写入新的层定义:
// Get reverse layer according to engine. template <typename Dtype> shared_ptr<Layer<Dtype> > GetReverseLayer(const LayerParameter& param) {...} REGISTER_LAYER_CREATOR(Reverse, GetReverseLayer);
5.upgrade_proto.cpp
在caffe/src/caffe/util/upgrade_proto.cpp中找到:
V1LayerParameter_LayerType UpgradeV0LayerType(const string& type) {…}
bool UpgradeV1LayerParameter(const V1LayerParameter&v1_layer_param,LayerParameter* layer_param) {…}
const char* UpgradeV1LayerType(const V1LayerParameter_LayerType type) {switch (type) {…}}
根据其他的层定义仿写即可,具体代码略。
6.重新编译caffe
到这一步基本上该做修改的底层代码已经修改完毕,需要重新编译Caffe,检查自己的代码是否书写正确。
打开Terminal,进入caffe-master,依次输入以下语句:
make clean make -j all make -j test make -j runtest make pycaffe
如果无报错,恭喜你已经成功的定义一个新的层结构啦~~
写在后面:最近几天在开始研究Caffe底层代码,记录了一下自己的改层过程,但是自己的C++能力有限,有问题的地方还望不吝赐教,十分感谢。
相关文章推荐
- 自定义一个compass可编译的目录结构
- Android4.2.2源码编译-如何把第三方的动态库重新编译到Android系统的/system/lib目录
- 如何编译tizen源码(图文教程)?
- 17.3.9 caffe自定义一个Layer会遇到的一些理解方面的问题
- 17.2.23 caffe如何自定义一个layer
- 将自定义函数 helloUDF2 注册到hive 源码中,并且重新编译hive
- 【Python笔记】源码编译安装Python时,如何支持自定义安装的高版本openssl库
- 如何分析一个Android程序(反编译+重新编译+签名)
- 如何在Android源码编译系统中添加一个C项目
- WindowsMobile如何自定义一个ToolBar?[币多理财助手部分源码]
- 已有Java/Android源码项目,如何快速理解代码结构
- Caffe源码解读(十一):自定义一个layer
- 如何在Android源码编译系统中添加一个Java项目
- [转]如何编译tizen源码(图文教程)?
- caffe部分配置修改后,重新编译caffe的教程
- Android4.2.2源码编译-如何把第三方的动态库重新编译到Android系统的/system/lib目录
- Android初级教程:如何自定义一个状态选择器
- 如何编译tizen源码(图文教程)?
- 通过源码包php-5.4.9.tar.gz编译安装PHP之后,如何加载动态模块,不需要重新配置PHP
- Android初级教程:如何自定义一个状态选择器