您的位置:首页 > Web前端

Caffe源码理解(2)——超级完整版教程:如何自定义一个新的层结构并重新编译Caffe

2017-09-26 17:27 465 查看
假设我们要重新定义一个激活函数,这个层的名字是Reverse。

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++能力有限,有问题的地方还望不吝赐教,十分感谢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: