使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数

时间:2021-04-10 03:59:47

在使用 Caffe 过程中经常会有这样的需求:已有 Layer 不符合我的应用场景;我需要这样这样的功能,原版代码没有实现;或者已经实现但效率太低,我有更好的实现。


方案一:简单粗暴的解法——偷天换日


如果你对 ConvolutionLayer 的实现不满意,那就直接改这两个文件:$CAFFE_ROOT/include/caffe/layers/conv_layer.hpp 和 $CAFFE_ROOT/src/caffe/layers/conv_layer.cpp 或 conv_layer.cu ,将 im2col + gemm 替换为你自己的实现(比如基于 winograd 算法的实现)。

优点:快速迭代,不需要对 Caffe 框架有过多了解,糙快狠准。

缺点:代码难维护,不能 merge 到 caffe master branch,容易给使用代码的人带来困惑(效果和 #define TRUE false 差不多)。


方案二:稍微温柔的解法——千人千面

和方案一类似,只是通过预编译宏来确定使用哪种实现。例如可以保留 ConvolutionLayer 默认实现,同时在代码中增加如下段:

[cpp] view plain copy print?使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数
  1. #ifdef SWITCH_MY_IMPLEMENTATION  
  2. // 你的实现代码  
  3. #else  
  4. // 默认代码  
  5. #endif  

这样可以在需要使用该 Layer 的代码中,增加宏定义:

[cpp] view plain copy print?使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数
  1. #define SWITCH_MY_IMPLEMENTATION  

就可以使用你的实现。而未定义该宏的代码,仍然使用原版实现。


优点:可以在新旧实现代码之间灵活切换;

缺点:每次切换需要重新编译;


方案三:优雅转身——山路十八弯

同一个功能的 Layer 有不同实现,希望能灵活切换又不需要重新编译代码,该如何实现?

这时不得不使用 ProtoBuffer 工具了。

首先,要把你的实现,要像正常的 Layer 类一样,分解为声明部分和实现部分,分别放在 .hpp 与 .cpp、.cu 中。Layer 名称要起一个能区别于原版实现的新名称。.hpp 文件置于 $CAFFE_ROOT/include/caffe/layers/,而 .cpp 和 .cu 置于 $CAFFE_ROOT/src/caffe/layers/,这样你在 $CAFFE_ROOT 下执行 make 编译时,会自动将这些文件加入构建过程,省去了手动设置编译选项的繁琐流程。

其次,在 $CAFFE_ROOT/src/caffe/proto/caffe.proto 中,增加新 LayerParameter 选项,这样你在编写 train.prototxt 或者 test.prototxt 或者 deploy.prototxt 时就能把新 Layer 的描述写进去,便于修改网络结构和替换其他相同功能的 Layer 了。

最后也是最容易忽视的一点,在 Layer 工厂注册新 Layer 加工函数,不然在你运行过程中可能会报如下错误:

[plain] view plain copy print?使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数
  1. F1002 01:51:22.656038 1954701312 layer_factory.hpp:81] Check failed: registry.count(type) == 1 (0 vs. 1) Unknown layer type: AllPass (known types: AbsVal, Accuracy, ArgMax, BNLL, BatchNorm, BatchReindex, Bias, Concat, ContrastiveLoss, Convolution, Crop, Data, Deconvolution, Dropout, DummyData, ELU, Eltwise, Embed, EuclideanLoss, Exp, Filter, Flatten, HDF5Data, HDF5Output, HingeLoss, Im2col, ImageData, InfogainLoss, InnerProduct, Input, LRN, Log, MVN, MemoryData, MultinomialLogisticLoss, PReLU, Pooling, Power, ReLU, Reduction, Reshape, SPP, Scale, Sigmoid, SigmoidCrossEntropyLoss, Silence, Slice, Softmax, SoftmaxWithLoss, Split, TanH, Threshold, Tile, WindowData)  
  2. *** Check failure stack trace: ***  
  3.     @        0x10243154e  google::LogMessage::Fail()  
  4.     @        0x102430c53  google::LogMessage::SendToLog()  
  5.     @        0x1024311a9  google::LogMessage::Flush()  
  6.     @        0x1024344d7  google::LogMessageFatal::~LogMessageFatal()  
  7.     @        0x10243183b  google::LogMessageFatal::~LogMessageFatal()  
  8.     @        0x102215356  caffe::LayerRegistry<>::CreateLayer()  
  9.     @        0x102233ccf  caffe::Net<>::Init()  
  10.     @        0x102235996  caffe::Net<>::Net()  
  11.     @        0x102118d8b  time()  
  12.     @        0x102119c9a  main  
  13.     @     0x7fff851285ad  start  
  14.     @                0x4  (unknown)  
  15. Abort trap: 6  



下面给出一个实际案例,走一遍方案三的流程。

这里我们实现一个新 Layer,名称为 AllPassLayer,顾名思义就是全通 Layer,“全通”借鉴于信号处理中的全通滤波器,将信号无失真地从输入转到输出。

虽然这个 Layer 并没有什么卵用,但是在这个基础上增加你的处理是非常简单的事情。另外也是出于实验考虑,全通层的 Forward/Backward 函数非常简单不需要读者有任何高等数学和求导的背景知识。读者使用该层时可以插入到任何已有网络中,而不会影响训练、预测的准确性。


首先看头文件:

[cpp] view plain copy print?使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数
  1. #ifndef CAFFE_ALL_PASS_LAYER_HPP_  
  2. #define CAFFE_ALL_PASS_LAYER_HPP_  
  3.   
  4. #include <vector>  
  5.   
  6. #include "caffe/blob.hpp"  
  7. #include "caffe/layer.hpp"  
  8. #include "caffe/proto/caffe.pb.h"  
  9.   
  10. #include "caffe/layers/neuron_layer.hpp"  
  11.   
  12. namespace caffe {  
  13. template <typename Dtype>  
  14. class AllPassLayer : public NeuronLayer<Dtype> {  
  15.  public:  
  16.   explicit AllPassLayer(const LayerParameter& param)  
  17.       : NeuronLayer<Dtype>(param) {}  
  18.   
  19.   virtual inline const char* type() const { return "AllPass"; }  
  20.   
  21.  protected:  
  22.   
  23.   virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,  
  24.       const vector<Blob<Dtype>*>& top);  
  25.   virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,  
  26.       const vector<Blob<Dtype>*>& top);  
  27.   virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,  
  28.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  
  29.   virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,  
  30.       const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom);  
  31. };  
  32.   
  33. }  // namespace caffe  
  34.   
  35. #endif  // CAFFE_ALL_PASS_LAYER_HPP_  


再看源文件:

[cpp] view plain copy print?使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数
  1. #include <algorithm>  
  2. #include <vector>  
  3.   
  4. #include "caffe/layers/all_pass_layer.hpp"  
  5.   
  6. #include <iostream>  
  7. using namespace std;  
  8. #define DEBUG_AP(str) cout<<str<<endl  
  9. namespace caffe {  
  10.   
  11. template <typename Dtype>  
  12. void AllPassLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,  
  13.     const vector<Blob<Dtype>*>& top) {  
  14.   const Dtype* bottom_data = bottom[0]->cpu_data();  
  15.   Dtype* top_data = top[0]->mutable_cpu_data();  
  16.   const int count = bottom[0]->count();  
  17.   for (int i = 0; i < count; ++i) {  
  18.     top_data[i] = bottom_data[i];  
  19.   }  
  20.   DEBUG_AP("Here is All Pass Layer, forwarding.");  
  21.   DEBUG_AP(this->layer_param_.all_pass_param().key());  
  22. }  
  23.   
  24. template <typename Dtype>  
  25. void AllPassLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,  
  26.     const vector<bool>& propagate_down,  
  27.     const vector<Blob<Dtype>*>& bottom) {  
  28.   if (propagate_down[0]) {  
  29.     const Dtype* bottom_data = bottom[0]->cpu_data();  
  30.     const Dtype* top_diff = top[0]->cpu_diff();  
  31.     Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();  
  32.     const int count = bottom[0]->count();  
  33.     for (int i = 0; i < count; ++i) {  
  34.       bottom_diff[i] = top_diff[i];  
  35.     }  
  36.   }  
  37.   DEBUG_AP("Here is All Pass Layer, backwarding.");  
  38.   DEBUG_AP(this->layer_param_.all_pass_param().key());  
  39. }  
  40.   
  41.   
  42. #ifdef CPU_ONLY  
  43. STUB_GPU(AllPassLayer);  
  44. #endif  
  45.   
  46. INSTANTIATE_CLASS(AllPassLayer);  
  47. REGISTER_LAYER_CLASS(AllPass);  
  48. }  // namespace caffe  


时间考虑,我没有实现 GPU 模式的 forward、backward,故本文例程仅支持 CPU_ONLY 模式。


编辑 caffe.proto,找到 LayerParameter 描述,增加一项:

[cpp] view plain copy print?使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数
  1. message LayerParameter {  
  2.   optional string name = 1; // the layer name  
  3.   optional string type = 2; // the layer type  
  4.   repeated string bottom = 3; // the name of each bottom blob  
  5.   repeated string top = 4; // the name of each top blob  
  6.   
  7.   // The train / test phase for computation.  
  8.   optional Phase phase = 10;  
  9.   
  10.   // The amount of weight to assign each top blob in the objective.  
  11.   // Each layer assigns a default value, usually of either 0 or 1,  
  12.   // to each top blob.  
  13.   repeated float loss_weight = 5;  
  14.   
  15.   // Specifies training parameters (multipliers on global learning constants,  
  16.   // and the name and other settings used for weight sharing).  
  17.   repeated ParamSpec param = 6;  
  18.   
  19.   // The blobs containing the numeric parameters of the layer.  
  20.   repeated BlobProto blobs = 7;  
  21.   
  22.   // Specifies on which bottoms the backpropagation should be skipped.  
  23.   // The size must be either 0 or equal to the number of bottoms.  
  24.   repeated bool propagate_down = 11;  
  25.   
  26.   // Rules controlling whether and when a layer is included in the network,  
  27.   // based on the current NetState.  You may specify a non-zero number of rules  
  28.   // to include OR exclude, but not both.  If no include or exclude rules are  
  29.   // specified, the layer is always included.  If the current NetState meets  
  30.   // ANY (i.e., one or more) of the specified rules, the layer is  
  31.   // included/excluded.  
  32.   repeated NetStateRule include = 8;  
  33.   repeated NetStateRule exclude = 9;  
  34.   
  35.   // Parameters for data pre-processing.  
  36.   optional TransformationParameter transform_param = 100;  
  37.   
  38.   // Parameters shared by loss layers.  
  39.   optional LossParameter loss_param = 101;  
  40.   
  41.   // Layer type-specific parameters.  
  42.   //  
  43.   // Note: certain layers may have more than one computational engine  
  44.   // for their implementation. These layers include an Engine type and  
  45.   // engine parameter for selecting the implementation.  
  46.   // The default for the engine is set by the ENGINE switch at compile-time.  
  47.   optional AccuracyParameter accuracy_param = 102;  
  48.   optional ArgMaxParameter argmax_param = 103;  
  49.   optional BatchNormParameter batch_norm_param = 139;  
  50.   optional BiasParameter bias_param = 141;  
  51.   optional ConcatParameter concat_param = 104;  
  52.   optional ContrastiveLossParameter contrastive_loss_param = 105;  
  53.   optional ConvolutionParameter convolution_param = 106;  
  54.   optional CropParameter crop_param = 144;  
  55.   optional DataParameter data_param = 107;  
  56.   optional DropoutParameter dropout_param = 108;  
  57.   optional DummyDataParameter dummy_data_param = 109;  
  58.   optional EltwiseParameter eltwise_param = 110;  
  59.   optional ELUParameter elu_param = 140;  
  60.   optional EmbedParameter embed_param = 137;  
  61.   optional ExpParameter exp_param = 111;  
  62.   optional FlattenParameter flatten_param = 135;  
  63.   optional HDF5DataParameter hdf5_data_param = 112;  
  64.   optional HDF5OutputParameter hdf5_output_param = 113;  
  65.   optional HingeLossParameter hinge_loss_param = 114;  
  66.   optional ImageDataParameter image_data_param = 115;  
  67.   optional InfogainLossParameter infogain_loss_param = 116;  
  68.   optional InnerProductParameter inner_product_param = 117;  
  69.   optional InputParameter input_param = 143;  
  70.   optional LogParameter log_param = 134;  
  71.   optional LRNParameter lrn_param = 118;  
  72.   optional MemoryDataParameter memory_data_param = 119;  
  73.   optional MVNParameter mvn_param = 120;  
  74.   optional PoolingParameter pooling_param = 121;  
  75.   optional PowerParameter power_param = 122;  
  76.   optional PReLUParameter prelu_param = 131;  
  77.   optional PythonParameter python_param = 130;  
  78.   optional ReductionParameter reduction_param = 136;  
  79.   optional ReLUParameter relu_param = 123;  
  80.   optional ReshapeParameter reshape_param = 133;  
  81.   optional ScaleParameter scale_param = 142;  
  82.   optional SigmoidParameter sigmoid_param = 124;  
  83.   optional SoftmaxParameter softmax_param = 125;  
  84.   optional SPPParameter spp_param = 132;  
  85.   optional SliceParameter slice_param = 126;  
  86.   optional TanHParameter tanh_param = 127;  
  87.   optional ThresholdParameter threshold_param = 128;  
  88.   optional TileParameter tile_param = 138;  
  89.   optional WindowDataParameter window_data_param = 129;  
  90.   optional AllPassParameter all_pass_param = 155;  
  91. }  

注意新增数字不要和以前的 Layer 数字重复。


仍然在 caffe.proto 中,增加 AllPassParameter 声明,位置任意。我设定了一个参数,可以用于从 prototxt 中读取预设值。


[cpp] view plain copy print?使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数
  1. message AllPassParameter {  
  2.   optional float key = 1 [default = 0];  
  3. }  

在 cpp 代码中,通过

[cpp] view plain copy print?使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数
  1. this->layer_param_.all_pass_param().key()  
这句来读取 prototxt 预设值。

在 $CAFFE_ROOT 下执行 make clean,然后重新 make all。要想一次编译成功,务必规范代码,对常见错误保持敏锐的嗅觉并加以避免。


万事具备,只欠 prototxt 了。


不难,我们写个最简单的 deploy.prototxt,不需要 data layer 和 softmax layer,just for fun。

[cpp] view plain copy print?使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数
  1. name: "AllPassTest"  
  2. layer {  
  3.   name: "data"  
  4.   type: "Input"  
  5.   top: "data"  
  6.   input_param { shape: { dim: 10 dim: 3 dim: 227 dim: 227 } }  
  7. }  
  8. layer {  
  9.   name: "ap"  
  10.   type: "AllPass"  
  11.   bottom: "data"  
  12.   top: "conv1"  
  13.   all_pass_param {  
  14.     key: 12.88  
  15.   }  
  16. }  


注意,这里的 type :后面写的内容,应该是你在 .hpp 中声明的新类 class name 去掉 Layer 后的名称。

上面设定了 key 这个参数的预设值为 12.88,嗯,你想到了刘翔对不对。


为了检验该 Layer 是否能正常创建和执行  forward, backward,我们运行 caffe time 命令并指定刚刚实现的 prototxt :

[plain] view plain copy print?使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数使用Caffe 增加自定义 Layer 及其 ProtoBuffer 参数
  1. $ ./build/tools/caffe.bin time -model deploy.prototxt  
  2. I1002 02:03:41.667682 1954701312 caffe.cpp:312] Use CPU.  
  3. I1002 02:03:41.671360 1954701312 net.cpp:49] Initializing net from parameters:  
  4. name: "AllPassTest"  
  5. state {  
  6.   phase: TRAIN  
  7. }  
  8. layer {  
  9.   name: "data"  
  10.   type: "Input"  
  11.   top: "data"  
  12.   input_param {  
  13.     shape {  
  14.       dim: 10  
  15.       dim: 3  
  16.       dim: 227  
  17.       dim: 227  
  18.     }  
  19.   }  
  20. }  
  21. layer {  
  22.   name: "ap"  
  23.   type: "AllPass"  
  24.   bottom: "data"  
  25.   top: "conv1"  
  26.   all_pass_param {  
  27.     key: 12.88  
  28.   }  
  29. }  
  30. I1002 02:03:41.671463 1954701312 layer_factory.hpp:77] Creating layer data  
  31. I1002 02:03:41.671484 1954701312 net.cpp:91] Creating Layer data  
  32. I1002 02:03:41.671499 1954701312 net.cpp:399] data -> data  
  33. I1002 02:03:41.671555 1954701312 net.cpp:141] Setting up data  
  34. I1002 02:03:41.671566 1954701312 net.cpp:148] Top shape: 10 3 227 227 (1545870)  
  35. I1002 02:03:41.671592 1954701312 net.cpp:156] Memory required for data: 6183480  
  36. I1002 02:03:41.671605 1954701312 layer_factory.hpp:77] Creating layer ap  
  37. I1002 02:03:41.671620 1954701312 net.cpp:91] Creating Layer ap  
  38. I1002 02:03:41.671630 1954701312 net.cpp:425] ap <- data  
  39. I1002 02:03:41.671644 1954701312 net.cpp:399] ap -> conv1  
  40. I1002 02:03:41.671663 1954701312 net.cpp:141] Setting up ap  
  41. I1002 02:03:41.671674 1954701312 net.cpp:148] Top shape: 10 3 227 227 (1545870)  
  42. I1002 02:03:41.671685 1954701312 net.cpp:156] Memory required for data: 12366960  
  43. I1002 02:03:41.671695 1954701312 net.cpp:219] ap does not need backward computation.  
  44. I1002 02:03:41.671705 1954701312 net.cpp:219] data does not need backward computation.  
  45. I1002 02:03:41.671710 1954701312 net.cpp:261] This network produces output conv1  
  46. I1002 02:03:41.671720 1954701312 net.cpp:274] Network initialization done.  
  47. I1002 02:03:41.671746 1954701312 caffe.cpp:320] Performing Forward  
  48. Here is All Pass Layer, forwarding.  
  49. 12.88  
  50. I1002 02:03:41.679689 1954701312 caffe.cpp:325] Initial loss: 0  
  51. I1002 02:03:41.679714 1954701312 caffe.cpp:326] Performing Backward  
  52. I1002 02:03:41.679738 1954701312 caffe.cpp:334] *** Benchmark begins ***  
  53. I1002 02:03:41.679746 1954701312 caffe.cpp:335] Testing for 50 iterations.  
  54. Here is All Pass Layer, forwarding.  
  55. 12.88  
  56. Here is All Pass Layer, backwarding.  
  57. 12.88  
  58. I1002 02:03:41.681139 1954701312 caffe.cpp:363] Iteration: 1 forward-backward time: 1 ms.  
  59. Here is All Pass Layer, forwarding.  
  60. 12.88  
  61. Here is All Pass Layer, backwarding.  
  62. 12.88  
  63. I1002 02:03:41.682394 1954701312 caffe.cpp:363] Iteration: 2 forward-backward time: 1 ms.  
  64. Here is All Pass Layer, forwarding.  
  65. 12.88  
  66. Here is All Pass Layer, backwarding.  
  67. 12.88  
  68. I1002 02:03:41.683653 1954701312 caffe.cpp:363] Iteration: 3 forward-backward time: 1 ms.  
  69. Here is All Pass Layer, forwarding.  
  70. 12.88  
  71. Here is All Pass Layer, backwarding.  
  72. 12.88  
  73. I1002 02:03:41.685096 1954701312 caffe.cpp:363] Iteration: 4 forward-backward time: 1 ms.  
  74. Here is All Pass Layer, forwarding.  
  75. 12.88  
  76. Here is All Pass Layer, backwarding.  
  77. 12.88  
  78. I1002 02:03:41.686326 1954701312 caffe.cpp:363] Iteration: 5 forward-backward time: 1 ms.  
  79. Here is All Pass Layer, forwarding.  
  80. 12.88  
  81. Here is All Pass Layer, backwarding.  
  82. 12.88  
  83. I1002 02:03:41.687713 1954701312 caffe.cpp:363] Iteration: 6 forward-backward time: 1 ms.  
  84. Here is All Pass Layer, forwarding.  
  85. 12.88  
  86. Here is All Pass Layer, backwarding.  
  87. 12.88  
  88. I1002 02:03:41.689038 1954701312 caffe.cpp:363] Iteration: 7 forward-backward time: 1 ms.  
  89. Here is All Pass Layer, forwarding.  
  90. 12.88  
  91. Here is All Pass Layer, backwarding.  
  92. 12.88  
  93. I1002 02:03:41.690251 1954701312 caffe.cpp:363] Iteration: 8 forward-backward time: 1 ms.  
  94. Here is All Pass Layer, forwarding.  
  95. 12.88  
  96. Here is All Pass Layer, backwarding.  
  97. 12.88  
  98. I1002 02:03:41.691548 1954701312 caffe.cpp:363] Iteration: 9 forward-backward time: 1 ms.  
  99. Here is All Pass Layer, forwarding.  
  100. 12.88  
  101. Here is All Pass Layer, backwarding.  
  102. 12.88  
  103. I1002 02:03:41.692805 1954701312 caffe.cpp:363] Iteration: 10 forward-backward time: 1 ms.  
  104. Here is All Pass Layer, forwarding.  
  105. 12.88  
  106. Here is All Pass Layer, backwarding.  
  107. 12.88  
  108. I1002 02:03:41.694056 1954701312 caffe.cpp:363] Iteration: 11 forward-backward time: 1 ms.  
  109. Here is All Pass Layer, forwarding.  
  110. 12.88  
  111. Here is All Pass Layer, backwarding.  
  112. 12.88  
  113. I1002 02:03:41.695264 1954701312 caffe.cpp:363] Iteration: 12 forward-backward time: 1 ms.  
  114. Here is All Pass Layer, forwarding.  
  115. 12.88  
  116. Here is All Pass Layer, backwarding.  
  117. 12.88  
  118. I1002 02:03:41.696761 1954701312 caffe.cpp:363] Iteration: 13 forward-backward time: 1 ms.  
  119. Here is All Pass Layer, forwarding.  
  120. 12.88  
  121. Here is All Pass Layer, backwarding.  
  122. 12.88  
  123. I1002 02:03:41.698225 1954701312 caffe.cpp:363] Iteration: 14 forward-backward time: 1 ms.  
  124. Here is All Pass Layer, forwarding.  
  125. 12.88  
  126. Here is All Pass Layer, backwarding.  
  127. 12.88  
  128. I1002 02:03:41.699653 1954701312 caffe.cpp:363] Iteration: 15 forward-backward time: 1 ms.  
  129. Here is All Pass Layer, forwarding.  
  130. 12.88  
  131. Here is All Pass Layer, backwarding.  
  132. 12.88  
  133. I1002 02:03:41.700945 1954701312 caffe.cpp:363] Iteration: 16 forward-backward time: 1 ms.  
  134. Here is All Pass Layer, forwarding.  
  135. 12.88  
  136. Here is All Pass Layer, backwarding.  
  137. 12.88  
  138. I1002 02:03:41.702761 1954701312 caffe.cpp:363] Iteration: 17 forward-backward time: 1 ms.  
  139. Here is All Pass Layer, forwarding.  
  140. 12.88  
  141. Here is All Pass Layer, backwarding.  
  142. 12.88  
  143. I1002 02:03:41.704056 1954701312 caffe.cpp:363] Iteration: 18 forward-backward time: 1 ms.  
  144. Here is All Pass Layer, forwarding.  
  145. 12.88  
  146. Here is All Pass Layer, backwarding.  
  147. 12.88  
  148. I1002 02:03:41.706471 1954701312 caffe.cpp:363] Iteration: 19 forward-backward time: 2 ms.  
  149. Here is All Pass Layer, forwarding.  
  150. 12.88  
  151. Here is All Pass Layer, backwarding.  
  152. 12.88  
  153. I1002 02:03:41.708784 1954701312 caffe.cpp:363] Iteration: 20 forward-backward time: 2 ms.  
  154. Here is All Pass Layer, forwarding.  
  155. 12.88  
  156. Here is All Pass Layer, backwarding.  
  157. 12.88  
  158. I1002 02:03:41.710043 1954701312 caffe.cpp:363] Iteration: 21 forward-backward time: 1 ms.  
  159. Here is All Pass Layer, forwarding.  
  160. 12.88  
  161. Here is All Pass Layer, backwarding.  
  162. 12.88  
  163. I1002 02:03:41.711272 1954701312 caffe.cpp:363] Iteration: 22 forward-backward time: 1 ms.  
  164. Here is All Pass Layer, forwarding.  
  165. 12.88  
  166. Here is All Pass Layer, backwarding.  
  167. 12.88  
  168. I1002 02:03:41.712528 1954701312 caffe.cpp:363] Iteration: 23 forward-backward time: 1 ms.  
  169. Here is All Pass Layer, forwarding.  
  170. 12.88  
  171. Here is All Pass Layer, backwarding.  
  172. 12.88  
  173. I1002 02:03:41.713964 1954701312 caffe.cpp:363] Iteration: 24 forward-backward time: 1 ms.  
  174. Here is All Pass Layer, forwarding.  
  175. 12.88  
  176. Here is All Pass Layer, backwarding.  
  177. 12.88  
  178. I1002 02:03:41.715248 1954701312 caffe.cpp:363] Iteration: 25 forward-backward time: 1 ms.  
  179. Here is All Pass Layer, forwarding.  
  180. 12.88  
  181. Here is All Pass Layer, backwarding.  
  182. 12.88  
  183. I1002 02:03:41.716487 1954701312 caffe.cpp:363] Iteration: 26 forward-backward time: 1 ms.  
  184. Here is All Pass Layer, forwarding.  
  185. 12.88  
  186. Here is All Pass Layer, backwarding.  
  187. 12.88  
  188. I1002 02:03:41.717725 1954701312 caffe.cpp:363] Iteration: 27 forward-backward time: 1 ms.  
  189. Here is All Pass Layer, forwarding.  
  190. 12.88  
  191. Here is All Pass Layer, backwarding.  
  192. 12.88  
  193. I1002 02:03:41.718962 1954701312 caffe.cpp:363] Iteration: 28 forward-backward time: 1 ms.  
  194. Here is All Pass Layer, forwarding.  
  195. 12.88  
  196. Here is All Pass Layer, backwarding.  
  197. 12.88  
  198. I1002 02:03:41.720289 1954701312 caffe.cpp:363] Iteration: 29 forward-backward time: 1 ms.  
  199. Here is All Pass Layer, forwarding.  
  200. 12.88  
  201. Here is All Pass Layer, backwarding.  
  202. 12.88  
  203. I1002 02:03:41.721837 1954701312 caffe.cpp:363] Iteration: 30 forward-backward time: 1 ms.  
  204. Here is All Pass Layer, forwarding.  
  205. 12.88  
  206. Here is All Pass Layer, backwarding.  
  207. 12.88  
  208. I1002 02:03:41.723042 1954701312 caffe.cpp:363] Iteration: 31 forward-backward time: 1 ms.  
  209. Here is All Pass Layer, forwarding.  
  210. 12.88  
  211. Here is All Pass Layer, backwarding.  
  212. 12.88  
  213. I1002 02:03:41.724261 1954701312 caffe.cpp:363] Iteration: 32 forward-backward time: 1 ms.  
  214. Here is All Pass Layer, forwarding.  
  215. 12.88  
  216. Here is All Pass Layer, backwarding.  
  217. 12.88  
  218. I1002 02:03:41.725587 1954701312 caffe.cpp:363] Iteration: 33 forward-backward time: 1 ms.  
  219. Here is All Pass Layer, forwarding.  
  220. 12.88  
  221. Here is All Pass Layer, backwarding.  
  222. 12.88  
  223. I1002 02:03:41.726771 1954701312 caffe.cpp:363] Iteration: 34 forward-backward time: 1 ms.  
  224. Here is All Pass Layer, forwarding.  
  225. 12.88  
  226. Here is All Pass Layer, backwarding.  
  227. 12.88  
  228. I1002 02:03:41.728013 1954701312 caffe.cpp:363] Iteration: 35 forward-backward time: 1 ms.  
  229. Here is All Pass Layer, forwarding.  
  230. 12.88  
  231. Here is All Pass Layer, backwarding.  
  232. 12.88  
  233. I1002 02:03:41.729249 1954701312 caffe.cpp:363] Iteration: 36 forward-backward time: 1 ms.  
  234. Here is All Pass Layer, forwarding.  
  235. 12.88  
  236. Here is All Pass Layer, backwarding.  
  237. 12.88  
  238. I1002 02:03:41.730716 1954701312 caffe.cpp:363] Iteration: 37 forward-backward time: 1 ms.  
  239. Here is All Pass Layer, forwarding.  
  240. 12.88  
  241. Here is All Pass Layer, backwarding.  
  242. 12.88  
  243. I1002 02:03:41.732275 1954701312 caffe.cpp:363] Iteration: 38 forward-backward time: 1 ms.  
  244. Here is All Pass Layer, forwarding.  
  245. 12.88  
  246. Here is All Pass Layer, backwarding.  
  247. 12.88  
  248. I1002 02:03:41.733809 1954701312 caffe.cpp:363] Iteration: 39 forward-backward time: 1 ms.  
  249. Here is All Pass Layer, forwarding.  
  250. 12.88  
  251. Here is All Pass Layer, backwarding.  
  252. 12.88  
  253. I1002 02:03:41.735049 1954701312 caffe.cpp:363] Iteration: 40 forward-backward time: 1 ms.  
  254. Here is All Pass Layer, forwarding.  
  255. 12.88  
  256. Here is All Pass Layer, backwarding.  
  257. 12.88  
  258. I1002 02:03:41.737144 1954701312 caffe.cpp:363] Iteration: 41 forward-backward time: 2 ms.  
  259. Here is All Pass Layer, forwarding.  
  260. 12.88  
  261. Here is All Pass Layer, backwarding.  
  262. 12.88  
  263. I1002 02:03:41.739090 1954701312 caffe.cpp:363] Iteration: 42 forward-backward time: 1 ms.  
  264. Here is All Pass Layer, forwarding.  
  265. 12.88  
  266. Here is All Pass Layer, backwarding.  
  267. 12.88  
  268. I1002 02:03:41.741575 1954701312 caffe.cpp:363] Iteration: 43 forward-backward time: 2 ms.  
  269. Here is All Pass Layer, forwarding.  
  270. 12.88  
  271. Here is All Pass Layer, backwarding.  
  272. 12.88  
  273. I1002 02:03:41.743450 1954701312 caffe.cpp:363] Iteration: 44 forward-backward time: 1 ms.  
  274. Here is All Pass Layer, forwarding.  
  275. 12.88  
  276. Here is All Pass Layer, backwarding.  
  277. 12.88  
  278. I1002 02:03:41.744732 1954701312 caffe.cpp:363] Iteration: 45 forward-backward time: 1 ms.  
  279. Here is All Pass Layer, forwarding.  
  280. 12.88  
  281. Here is All Pass Layer, backwarding.  
  282. 12.88  
  283. I1002 02:03:41.745970 1954701312 caffe.cpp:363] Iteration: 46 forward-backward time: 1 ms.  
  284. Here is All Pass Layer, forwarding.  
  285. 12.88  
  286. Here is All Pass Layer, backwarding.  
  287. 12.88  
  288. I1002 02:03:41.747185 1954701312 caffe.cpp:363] Iteration: 47 forward-backward time: 1 ms.  
  289. Here is All Pass Layer, forwarding.  
  290. 12.88  
  291. Here is All Pass Layer, backwarding.  
  292. 12.88  
  293. I1002 02:03:41.748430 1954701312 caffe.cpp:363] Iteration: 48 forward-backward time: 1 ms.  
  294. Here is All Pass Layer, forwarding.  
  295. 12.88  
  296. Here is All Pass Layer, backwarding.  
  297. 12.88  
  298. I1002 02:03:41.749826 1954701312 caffe.cpp:363] Iteration: 49 forward-backward time: 1 ms.  
  299. Here is All Pass Layer, forwarding.  
  300. 12.88  
  301. Here is All Pass Layer, backwarding.  
  302. 12.88  
  303. I1002 02:03:41.751124 1954701312 caffe.cpp:363] Iteration: 50 forward-backward time: 1 ms.  
  304. I1002 02:03:41.751147 1954701312 caffe.cpp:366] Average time per layer:  
  305. I1002 02:03:41.751157 1954701312 caffe.cpp:369]       data  forward: 0.00108 ms.  
  306. I1002 02:03:41.751183 1954701312 caffe.cpp:372]       data  backward: 0.001 ms.  
  307. I1002 02:03:41.751194 1954701312 caffe.cpp:369]         ap  forward: 1.37884 ms.  
  308. I1002 02:03:41.751205 1954701312 caffe.cpp:372]         ap  backward: 0.01156 ms.  
  309. I1002 02:03:41.751220 1954701312 caffe.cpp:377] Average Forward pass: 1.38646 ms.  
  310. I1002 02:03:41.751231 1954701312 caffe.cpp:379] Average Backward pass: 0.0144 ms.  
  311. I1002 02:03:41.751240 1954701312 caffe.cpp:381] Average Forward-Backward: 1.42 ms.  
  312. I1002 02:03:41.751250 1954701312 caffe.cpp:383] Total Time: 71 ms.  
  313. I1002 02:03:41.751260 1954701312 caffe.cpp:384] *** Benchmark ends ***  

可见该 Layer 可以正常创建、加载预设参数、执行 forward、backward 函数。

实际上对于算法 Layer,还要写 Test Case 保证功能正确。由于我们选择了极为简单的全通 Layer,故这一步可以省去。