由于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函数
<span class="hljs-keyword">template</span> <<span class="hljs-keyword">typename</span> Dtype> <span class="hljs-keyword">class</span> WtfLayer : <span class="hljs-keyword">public</span> BaseConvolutionLayer<Dtype> { <span class="hljs-keyword">public</span>: <span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">WtfLayer</span><span class="hljs-params">(<span class="hljs-keyword">const</span> LayerParameter& param)</span> : BaseConvolutionLayer<Dtype><span class="hljs-params">(param)</span> </span>{} <span class="hljs-keyword">virtual</span> <span class="hljs-keyword">inline</span> <span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>* type() <span class="hljs-keyword">const</span> { <span class="hljs-keyword">return</span> <span class="hljs-string">"Wtf"</span>; } <span class="hljs-keyword">protected</span>: <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Forward_cpu</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-built_in">vector</span><Blob<Dtype>*>& bottom, <span class="hljs-keyword">const</span> <span class="hljs-built_in">vector</span><Blob<Dtype>*>& top)</span></span>; <span class="hljs-comment">//virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,</span> <span class="hljs-comment">// const vector<Blob<Dtype>*>& top);</span> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Backward_cpu</span><span class="hljs-params">(<span class="hljs-keyword">const</span> <span class="hljs-built_in">vector</span><Blob<Dtype>*>& top, <span class="hljs-keyword">const</span> <span class="hljs-built_in">vector</span><<span class="hljs-keyword">bool</span>>& propagate_down, <span class="hljs-keyword">const</span> <span class="hljs-built_in">vector</span><Blob<Dtype>*>& bottom)</span></span>; <span class="hljs-comment">//virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,</span> <span class="hljs-comment">// const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);</span> <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">inline</span> <span class="hljs-keyword">bool</span> <span class="hljs-title">reverse_dimensions</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>; } <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-keyword">void</span> <span class="hljs-title">compute_output_shape</span><span class="hljs-params">()</span></span>; };2.将Wtf_layer.cpp添加到src\caffe\layers文件夹中,代码内容复制convolutio_layer.cpp即可,注意在最后复制的时候添加 REGISTER_LAYER_CLASS(Wtf); 注册一下Wtf Layer
<span class="hljs-preprocessor">#<span class="hljs-keyword">include</span> <vector></span> <span class="hljs-preprocessor">#<span class="hljs-keyword">include</span> "caffe/filler.hpp"</span> <span class="hljs-preprocessor">#<span class="hljs-keyword">include</span> "caffe/layer.hpp"</span> <span class="hljs-preprocessor">#<span class="hljs-keyword">include</span> "caffe/util/im2col.hpp"</span> <span class="hljs-preprocessor">#<span class="hljs-keyword">include</span> "caffe/util/math_functions.hpp"</span> <span class="hljs-preprocessor">#<span class="hljs-keyword">include</span> "caffe/vision_layers.hpp"</span> <span class="hljs-keyword">namespace</span> caffe { <span class="hljs-keyword">template</span> <<span class="hljs-keyword">typename</span> Dtype> <span class="hljs-keyword">void</span> WtfLayer<Dtype>::compute_output_shape() { <span class="hljs-keyword">this</span>->height_out_ = (<span class="hljs-keyword">this</span>->height_ + <span class="hljs-number">2</span> * <span class="hljs-keyword">this</span>->pad_h_ - <span class="hljs-keyword">this</span>->kernel_h_) / <span class="hljs-keyword">this</span>->stride_h_ + <span class="hljs-number">1</span>; <span class="hljs-keyword">this</span>->width_out_ = (<span class="hljs-keyword">this</span>->width_ + <span class="hljs-number">2</span> * <span class="hljs-keyword">this</span>->pad_w_ - <span class="hljs-keyword">this</span>->kernel_w_) / <span class="hljs-keyword">this</span>->stride_w_ + <span class="hljs-number">1</span>; } <span class="hljs-keyword">template</span> <<span class="hljs-keyword">typename</span> Dtype> <span class="hljs-keyword">void</span> WtfLayer<Dtype>::Forward_cpu(<span class="hljs-keyword">const</span> <span class="hljs-stl_container"><span class="hljs-built_in">vector</span><Blob<Dtype></span>*>& bottom, <span class="hljs-keyword">const</span> <span class="hljs-stl_container"><span class="hljs-built_in">vector</span><Blob<Dtype></span>*>& top) { <span class="hljs-keyword">const</span> Dtype* weight = <span class="hljs-keyword">this</span>->blobs_[<span class="hljs-number">0</span>]->cpu_data(); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < bottom.size(); ++i) { <span class="hljs-keyword">const</span> Dtype* bottom_data = bottom[i]->cpu_data(); Dtype* top_data = top[i]->mutable_cpu_data(); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> n = <span class="hljs-number">0</span>; n < <span class="hljs-keyword">this</span>->num_; ++n) { <span class="hljs-keyword">this</span>->forward_cpu_gemm(bottom_data + bottom[i]->offset(n), weight, top_data + top[i]->offset(n)); <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>->bias_term_) { <span class="hljs-keyword">const</span> Dtype* bias = <span class="hljs-keyword">this</span>->blobs_[<span class="hljs-number">1</span>]->cpu_data(); <span class="hljs-keyword">this</span>->forward_cpu_bias(top_data + top[i]->offset(n), bias); } } } } <span class="hljs-keyword">template</span> <<span class="hljs-keyword">typename</span> Dtype> <span class="hljs-keyword">void</span> WtfLayer<Dtype>::Backward_cpu(<span class="hljs-keyword">const</span> <span class="hljs-stl_container"><span class="hljs-built_in">vector</span><Blob<Dtype></span>*>& top, <span class="hljs-keyword">const</span> <span class="hljs-stl_container"><span class="hljs-built_in">vector</span><<span class="hljs-keyword">bool</span>></span>& propagate_down, <span class="hljs-keyword">const</span> <span class="hljs-stl_container"><span class="hljs-built_in">vector</span><Blob<Dtype></span>*>& bottom) { <span class="hljs-keyword">const</span> Dtype* weight = <span class="hljs-keyword">this</span>->blobs_[<span class="hljs-number">0</span>]->cpu_data(); Dtype* weight_diff = <span class="hljs-keyword">this</span>->blobs_[<span class="hljs-number">0</span>]->mutable_cpu_diff(); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < top.size(); ++i) { <span class="hljs-keyword">const</span> Dtype* top_diff = top[i]->cpu_diff(); <span class="hljs-keyword">const</span> Dtype* bottom_data = bottom[i]->cpu_data(); Dtype* bottom_diff = bottom[i]->mutable_cpu_diff(); <span class="hljs-comment">// Bias gradient, if necessary.</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>->bias_term_ && <span class="hljs-keyword">this</span>->param_propagate_down_[<span class="hljs-number">1</span>]) { Dtype* bias_diff = <span class="hljs-keyword">this</span>->blobs_[<span class="hljs-number">1</span>]->mutable_cpu_diff(); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> n = <span class="hljs-number">0</span>; n < <span class="hljs-keyword">this</span>->num_; ++n) { <span class="hljs-keyword">this</span>->backward_cpu_bias(bias_diff, top_diff + top[i]->offset(n)); } } <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>->param_propagate_down_[<span class="hljs-number">0</span>] || propagate_down[i]) { <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> n = <span class="hljs-number">0</span>; n < <span class="hljs-keyword">this</span>->num_; ++n) { <span class="hljs-comment">// gradient w.r.t. weight. Note that we will accumulate diffs.</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>->param_propagate_down_[<span class="hljs-number">0</span>]) { <span class="hljs-keyword">this</span>->weight_cpu_gemm(bottom_data + bottom[i]->offset(n), top_diff + top[i]->offset(n), weight_diff); } <span class="hljs-comment">// gradient w.r.t. bottom data, if necessary.</span> <span class="hljs-keyword">if</span> (propagate_down[i]) { <span class="hljs-keyword">this</span>->backward_cpu_gemm(top_diff + top[i]->offset(n), weight, bottom_diff + bottom[i]->offset(n)); } } } } } <span class="hljs-preprocessor">#ifdef CPU_ONLY</span> STUB_GPU(WtfLayer); <span class="hljs-preprocessor">#<span class="hljs-keyword">endif</span></span> INSTANTIATE_CLASS(WtfLayer); REGISTER_LAYER_CLASS(Wtf); } <span class="hljs-comment">// namespace caffe</span>3. 修改proto/caffe.proto文件,找到LayerType,添加WTF,并更新ID。假如说Wtf_Layer有参数,比如Convolution肯定是有参数的,那么添加WtfParameter类
optional WtfParameter wtf_param = <span class="hljs-number">141</span>;以及
message WtfParameter { optional uint32 num_output = <span class="hljs-number">1</span>; <span class="hljs-comment">// The number of outputs for the layer</span> optional <span class="hljs-keyword">bool</span> bias_term = <span class="hljs-number">2</span> [<span class="hljs-keyword">default</span> = <span class="hljs-keyword">true</span>]; <span class="hljs-comment">// whether to have bias terms</span> <span class="hljs-comment">// Pad, kernel size, and stride are all given as a single value for equal</span> <span class="hljs-comment">// dimensions in height and width or as Y, X pairs.</span> optional uint32 pad = <span class="hljs-number">3</span> [<span class="hljs-keyword">default</span> = <span class="hljs-number">0</span>]; <span class="hljs-comment">// The padding size (equal in Y, X)</span> optional uint32 pad_h = <span class="hljs-number">9</span> [<span class="hljs-keyword">default</span> = <span class="hljs-number">0</span>]; <span class="hljs-comment">// The padding height</span> optional uint32 pad_w = <span class="hljs-number">10</span> [<span class="hljs-keyword">default</span> = <span class="hljs-number">0</span>]; <span class="hljs-comment">// The padding width</span> optional uint32 kernel_size = <span class="hljs-number">4</span>; <span class="hljs-comment">// The kernel size (square)</span> optional uint32 kernel_h = <span class="hljs-number">11</span>; <span class="hljs-comment">// The kernel height</span> optional uint32 kernel_w = <span class="hljs-number">12</span>; <span class="hljs-comment">// The kernel width</span> optional uint32 group = <span class="hljs-number">5</span> [<span class="hljs-keyword">default</span> = <span class="hljs-number">1</span>]; <span class="hljs-comment">// The group size for group conv</span> optional uint32 stride = <span class="hljs-number">6</span> [<span class="hljs-keyword">default</span> = <span class="hljs-number">1</span>]; <span class="hljs-comment">// The stride (equal in Y, X)</span> optional uint32 stride_h = <span class="hljs-number">13</span>; <span class="hljs-comment">// The stride height</span> optional uint32 stride_w = <span class="hljs-number">14</span>; <span class="hljs-comment">// The stride width</span> optional FillerParameter weight_filler = <span class="hljs-number">7</span>; <span class="hljs-comment">// The filler for the weight</span> optional FillerParameter bias_filler = <span class="hljs-number">8</span>; <span class="hljs-comment">// The filler for the bias</span> <span class="hljs-keyword">enum</span> Engine { DEFAULT = <span class="hljs-number">0</span>; CAFFE = <span class="hljs-number">1</span>; CUDNN = <span class="hljs-number">2</span>; } optional Engine engine = <span class="hljs-number">15</span> [<span class="hljs-keyword">default</span> = DEFAULT]; }以及
WTF = 52;以及
optional WtfParameter wtf_param = 53;
如何测试我们写的layer的正确性呢?
1.将某些层的type: "Convolution" 转化为type: "Wtf" 测试Wtf的loss情况下降的和Convolution是否一样
2.有了训练好的model和prototxt,用matlab和python接口测试一下是否达到了卷积的效果。
暂时到这里~等待后来继续添加层