由于caffe在一步一步的更新,因此半年前的教程可能不适用于当前版的caffe
因此把这次尝试caffe修改过程记录下来,以饷后人。
首先下载caffe
https://github.com/yjxiong/caffe
这个版本的caffe是multi-gpu支持比较好的,用的是MPI技术,用的显存又少,而且在第一时间段支持了cudnn4,follow起来还是很爽的
关于第一阶段最naive的想法是添加类似conv层功能的Layer,主要参考了
http://blog.csdn.net/kuaitoukid/article/details/41865803
同样的,我们将新的layer明明为wtf layer
修改步骤
1.在 include/caffe/vision_layers.hpp 中添加 wtflayer的定义,由于此处不实现GPU函数,因此注释掉了gpu函数
template <typename Dtype> class WtfLayer : public BaseConvolutionLayer<Dtype> { public: explicit WtfLayer(const LayerParameter& param) : BaseConvolutionLayer<Dtype>(param) {} virtual inline const char* type() const { return "Wtf"; } 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); virtual inline bool reverse_dimensions() { return false; } virtual void compute_output_shape(); };2.将Wtf_layer.cpp添加到src\caffe\layers文件夹中,代码内容复制convolutio_layer.cpp即可,注意在最后复制的时候添加 REGISTER_LAYER_CLASS(Wtf); 注册一下Wtf Layer
#include <vector> #include "caffe/filler.hpp" #include "caffe/layer.hpp" #include "caffe/util/im2col.hpp" #include "caffe/util/math_functions.hpp" #include "caffe/vision_layers.hpp" namespace caffe { template <typename Dtype> void WtfLayer<Dtype>::compute_output_shape() { this->height_out_ = (this->height_ + 2 * this->pad_h_ - this->kernel_h_) / this->stride_h_ + 1; this->width_out_ = (this->width_ + 2 * this->pad_w_ - this->kernel_w_) / this->stride_w_ + 1; } template <typename Dtype> void WtfLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { const Dtype* weight = this->blobs_[0]->cpu_data(); for (int i = 0; i < bottom.size(); ++i) { const Dtype* bottom_data = bottom[i]->cpu_data(); Dtype* top_data = top[i]->mutable_cpu_data(); for (int n = 0; n < this->num_; ++n) { this->forward_cpu_gemm(bottom_data + bottom[i]->offset(n), weight, top_data + top[i]->offset(n)); if (this->bias_term_) { const Dtype* bias = this->blobs_[1]->cpu_data(); this->forward_cpu_bias(top_data + top[i]->offset(n), bias); } } } } template <typename Dtype> void WtfLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) { const Dtype* weight = this->blobs_[0]->cpu_data(); Dtype* weight_diff = this->blobs_[0]->mutable_cpu_diff(); for (int i = 0; i < top.size(); ++i) { const Dtype* top_diff = top[i]->cpu_diff(); const Dtype* bottom_data = bottom[i]->cpu_data(); Dtype* bottom_diff = bottom[i]->mutable_cpu_diff(); // Bias gradient, if necessary. if (this->bias_term_ && this->param_propagate_down_[1]) { Dtype* bias_diff = this->blobs_[1]->mutable_cpu_diff(); for (int n = 0; n < this->num_; ++n) { this->backward_cpu_bias(bias_diff, top_diff + top[i]->offset(n)); } } if (this->param_propagate_down_[0] || propagate_down[i]) { for (int n = 0; n < this->num_; ++n) { // gradient w.r.t. weight. Note that we will accumulate diffs. if (this->param_propagate_down_[0]) { this->weight_cpu_gemm(bottom_data + bottom[i]->offset(n), top_diff + top[i]->offset(n), weight_diff); } // gradient w.r.t. bottom data, if necessary. if (propagate_down[i]) { this->backward_cpu_gemm(top_diff + top[i]->offset(n), weight, bottom_diff + bottom[i]->offset(n)); } } } } } #ifdef CPU_ONLY STUB_GPU(WtfLayer); #endif INSTANTIATE_CLASS(WtfLayer); REGISTER_LAYER_CLASS(Wtf); } // namespace caffe3. 修改proto/caffe.proto文件,找到LayerType,添加WTF,并更新ID。假如说Wtf_Layer有参数,比如Convolution肯定是有参数的,那么添加WtfParameter类
optional WtfParameter wtf_param = 141;以及
message WtfParameter { optional uint32 num_output = 1; // The number of outputs for the layer optional bool bias_term = 2 [default = true]; // whether to have bias terms // Pad, kernel size, and stride are all given as a single value for equal // dimensions in height and width or as Y, X pairs. optional uint32 pad = 3 [default = 0]; // The padding size (equal in Y, X) optional uint32 pad_h = 9 [default = 0]; // The padding height optional uint32 pad_w = 10 [default = 0]; // The padding width optional uint32 kernel_size = 4; // The kernel size (square) optional uint32 kernel_h = 11; // The kernel height optional uint32 kernel_w = 12; // The kernel width optional uint32 group = 5 [default = 1]; // The group size for group conv optional uint32 stride = 6 [default = 1]; // The stride (equal in Y, X) optional uint32 stride_h = 13; // The stride height optional uint32 stride_w = 14; // The stride width optional FillerParameter weight_filler = 7; // The filler for the weight optional FillerParameter bias_filler = 8; // The filler for the bias enum Engine { DEFAULT = 0; CAFFE = 1; CUDNN = 2; } optional Engine engine = 15 [default = DEFAULT]; }以及
WTF = 52;以及
optional WtfParameter wtf_param = 53;
如何测试我们写的layer的正确性呢?
1.将某些层的type: "Convolution" 转化为type: "Wtf" 测试Wtf的loss情况下降的和Convolution是否一样
2.有了训练好的model和prototxt,用matlab和python接口测试一下是否达到了卷积的效果。
暂时到这里~等待后来继续添加层