本文分为两部分,先写一个入门的教程,然后再给出自己添加maxout与NIN的layer的方法

(一)

其实在Github上已经有答案了(https://github.com/BVLC/caffe/issues/684

Here's roughly the process I follow.

  1. Add a class declaration for your layer to the appropriate one of common_layers.hppdata_layers.hpp,loss_layers.hppneuron_layers.hpp, or vision_layers.hpp. Include an inline implementation oftype and the *Blobs() methods to specify blob number requirements. Omit the *_gpu declarations if you'll only be implementing CPU code.
  2. Implement your layer in layers/your_layer.cpp.

    • SetUp for initialization: reading parameters, allocating buffers, etc.
    • Forward_cpu for the function your layer computes
    • Backward_cpu for its gradient
  3. (Optional) Implement the GPU versions Forward_gpu and Backward_gpu in layers/your_layer.cu.
  4. Add your layer to proto/caffe.proto, updating the next available ID. Also declare parameters, if needed, in this file.
  5. Make your layer createable by adding it to layer_factory.cpp.
  6. Write tests in test/test_your_layer.cpp. Use test/test_gradient_check_util.hpp to check that your Forward and Backward implementations are in numerical agreement.

上面是一个大致的流程,我就直接翻译过来吧,因为我自己琢磨出来的步骤跟这个是一样的。在这里,我们就添加一个Wtf_Layer,然后作用跟Convolution_Layer一模一样。注意这里的命名方式,Wtf第一个字母大写,剩下的小写,算是一个命名规范吧,强迫症表示很舒服。

1. 首先确定要添加的layer的类型,是common_layer 还是 data_layer 还是loss_layer, neuron_layer, vision_layer ,这里的Wtf_Layer肯定是属vision_layer了,所以打开vision_layers.hpp 然后复制convolution_layer的相关代码,把类名还有构造函数的名字改为WtfLayer,如果没有用到GPU运算,那么把里面的带GPU的函数都删掉

2. 将Wtf_layer.cpp 添加到src\caffe\layers文件夹中,代码内容复制convolution_layer.cpp 把对应的类名修改(可以搜一下conv关键字,然后改为Wtf)

3. 假如有gpu的代码就添加响应的Wtf_layer.cu (这里不添加了)

4. 修改proto/caffe.proto文件,找到LayerType,添加WTF,并更新ID(新的ID应该是34)。假如说Wtf_Layer有参数,比如Convolution肯定是有参数的,那么添加WtfParameter类

5. 在layer_factory.cpp中添加响应的代码,就是一堆if ... else的那片代码

6. 这个可以不做,但是为了结果还是做一个,就是写一个测试文件,检查前向后向传播的数据是否正确。gradient_check的原理可以参考UFLDL教程的对应章节


之后我会更新我自己写的maxout_layer的demo,在这立一个flag以鞭策自己完成吧╮(╯▽╰)╭


(二) 如何添加maxout_layer

表示被bengio的maxout给搞郁闷了,自己摆出一个公式巴拉巴拉说了一堆,结果用到卷积层的maxout却给的另一种方案,吐槽无力,不过后来又想了下应该是bengio没表述清楚的问题。


我的maxout的算法思路是这样的,首先要确定一个group_size变量,表示最大值是在group_size这样一个规模的集合下挑选出来的,简而言之就是给定group_size个数,取最大。确定好group_size变量,然后让卷积层的output_num变为原来的group_size倍,这样输出的featuremap的个数就变为原来的group_size倍,然后以group_size为一组划分这些featuremap,每组里面挑出响应最大的点构成一个新的featuremap,这样就得到了maxout层的输出。


                                                       如何在caffe中添加新的Layer

要是还不明白我就拿上面的图来说一下,上面一共9张图,相当于卷积层输出9张featuremap,我们每3个为一组,那么maxout层输出9/3=3张featuremap,对于每组featuremaps,比如我们挑出绿色的三张featuremaps,每张大小为w*h,那么声明一个新的output_featuremap大小为w*h,遍历output_featuremap的每个点,要赋的数值为三张绿色featuremap对应点的最大的那个,也就是三个数里面选最大的,这样就输出了一张output_featuremap,剩下的组类似操作。


我觉得到这应该明白maxout的原理跟算法了吧= =,下面就直接贴代码了

新建一个maxout_layer.cpp放到src/caffe/layer文件夹下

[cpp] view plain copy

  1. #include <cstdio>  
  2.   
  3. #include <vector>  
  4.   
  5.   
  6.   
  7. #include "caffe/filler.hpp"  
  8.   
  9. #include "caffe/layer.hpp"  
  10.   
  11. #include "caffe/util/im2col.hpp"  
  12.   
  13. #include "caffe/util/math_functions.hpp"  
  14.   
  15. #include "caffe/vision_layers.hpp"  
  16.   
  17.   
  18.   
  19. namespace caffe {  
  20.   
  21.   
  22.   
  23. template <typename Dtype>  
  24.   
  25. void MaxoutLayer<Dtype>::SetUp(const vector<Blob<Dtype>*>& bottom,  
  26.   
  27.       vector<Blob<Dtype>*>* top) {  
  28.   
  29.   Layer<Dtype>::SetUp(bottom, top);  
  30.   
  31.   printf("===============================================================has go into setup !==============================================\n");  
  32.   
  33.   MaxoutParameter maxout_param = this->layer_param_.maxout_param();  
  34.   
  35.     
  36.   
  37.     
  38.   
  39.   // maxout_size  
  40.   
  41.   //CHECK(!maxout_param.has_num_output())  
  42.   
  43.   //    << "maxout size are required.";  
  44.   
  45.   //if (maxout_param.has_num_output()) {  
  46.   
  47.   //  num_output_ = maxout_param.num_output();  
  48.   
  49.   //}  
  50.   
  51.   num_output_ = this->layer_param_.maxout_param().num_output();  
  52.   
  53.   CHECK_GT(num_output_, 0) << "output number cannot be zero.";  
  54.   
  55.     
  56.   
  57.   // bottom ÊÇFEATURE_MAP  
  58.   
  59.   num_ = bottom[0]->num();  
  60.   
  61.   channels_ = bottom[0]->channels();  
  62.   
  63.   height_ = bottom[0]->height();  
  64.   
  65.   width_ = bottom[0]->width();  
  66.   
  67.     
  68.   
  69.   // Ã²ËÆÏÂÃæÕâžöif²»»áÅÜœøÈ¥  
  70.   
  71.   // TODO: generalize to handle inputs of different shapes.  
  72.   
  73.   for (int bottom_id = 1; bottom_id < bottom.size(); ++bottom_id) {  
  74.   
  75.     CHECK_EQ(num_, bottom[bottom_id]->num()) << "Inputs must have same num.";  
  76.   
  77.     CHECK_EQ(channels_, bottom[bottom_id]->channels())  
  78.   
  79.         << "Inputs must have same channels.";  
  80.   
  81.     CHECK_EQ(height_, bottom[bottom_id]->height())  
  82.   
  83.         << "Inputs must have same height.";  
  84.   
  85.     CHECK_EQ(width_, bottom[bottom_id]->width())  
  86.   
  87.         << "Inputs must have same width.";  
  88.   
  89.   }  
  90.   
  91.     
  92.   
  93.   // Set the parameters ž³Öµ²ÎÊý  
  94.   
  95.   CHECK_EQ(channels_ % num_output_, 0)  
  96.   
  97.       << "Number of channel should be multiples of output number.";  
  98.   
  99.         
  100.   
  101.   group_size_ = channels_ / num_output_;  
  102.   
  103.     
  104.   
  105.   // Figure out the dimensions for individual gemms. ŒÆËãŸØÕóµÄÐÐÁР 
  106.   
  107.     
  108.   
  109.   // ÆäʵBengioµÄÂÛÎÄÖжÔÓÚK_µÄŽóС¶šÒåºÜÄ£ºý£¬¶ÔÓÚÍŒÏñœöœöÊÇžøÁËe.g.  
  110.   
  111.   // Ò²Ã»ÓÐ˵µœµ×ʵŒÊÊDz»ÊÇÕâÃŽ²Ù×÷µÄ£¬ÒòΪÈç¹ûÕæµÄÊÇchannelÖ±œÓœøÐбȜϠ 
  112.   
  113.   // ÄÇÃŽŸÍžúÀíÂ۵Ĺ«ÊœÎǺϵIJ»ºÃ£¬µ«ÊÇÄܹ»œâÊÍÍŒÏñ£¬±ÈÈç˵Äóö×îºÃµÄÒ»²ã  
  114.   
  115.   // ¶øÇÒÍŒÏñžú·ÇÍŒÏñµÄmaxoutµÄ×ö·š²îÌ«¶àÁË°¡¡£ŒÙÈç×öµœŒæÈݵĻ°Ö»ÄÜÈÃÇ°Ò»²ã  
  116.   
  117.   // µÄoutput_numÅäºÏmaxout  
  118.   
  119.     
  120.   
  121.   //for (int top_id = 0; top_id < top->size(); ++top_id) {  
  122.   
  123.     (*top)[0]->Reshape(num_, num_output_, height_, width_); // œöœöÊǞıäµÄchannelžöÊý  
  124.     max_idx_.Reshape(num_, num_output_, height_, width_);  
  125.   
  126.   //}  
  127.   
  128. }  
  129.   
  130.   
  131.   
  132.   
  133.   
  134. template <typename Dtype>  
  135.   
  136. Dtype MaxoutLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,  
  137.   
  138.       vector<Blob<Dtype>*>* top) {  
  139.   
  140.        
  141.   
  142.     int featureSize = height_ * width_;  
  143.   
  144.     Dtype* mask = NULL;  
  145.   
  146.     mask = max_idx_.mutable_cpu_data();  
  147.   
  148.   
  149.   
  150. //printf("1.maxout_forward\n");  
  151.       
  152.     const int top_count = (*top)[0]->count();  
  153.   
  154.     caffe_set(top_count, Dtype(0), mask);  
  155.   
  156.       
  157.   
  158. //printf("2.maxout_forward\n");  
  159.       
  160.   
  161.   
  162.   
  163.     for (int i = 0; i < bottom.size(); ++i) {  
  164.   
  165.         const Dtype* bottom_data = bottom[i]->cpu_data();  
  166.   
  167.         Dtype* top_data = (*top)[i]->mutable_cpu_data();    
  168.   
  169.                   
  170.   
  171.         for (int n = 0; n < num_; n ++) {  
  172.   
  173.             // È¡µÚnÕÅÍŒÏñ  
  174.   
  175.             for (int o = 0; o < num_output_; o ++) {  
  176.   
  177.                 for (int g = 0; g < group_size_; g ++) {  
  178.   
  179.                     if (g == 0) {  
  180.   
  181.                         for (int h = 0; h < height_; h ++) { // Áœ²ãÑ­»·Óеã¶ù†ªà  
  182.   
  183.                             for (int w = 0; w < width_; w ++) {  
  184.   
  185.                                 int index = w + h * width_;  
  186.   
  187.                                 top_data[index] = bottom_data[index];  
  188.   
  189.                                 mask[index] = index;  
  190.   
  191.                             }  
  192.   
  193.                         }  
  194.   
  195.                     }  
  196.   
  197.                     else {  
  198.   
  199.                         for (int h = 0; h < height_; h ++) {  
  200.   
  201.                             for (int w = 0; w < width_; w ++) {  
  202.   
  203.                                 int index0 = w + h * width_;  
  204.   
  205.                                 int index1 = index0 + g * featureSize;  
  206.   
  207.                                 if (top_data[index0] < bottom_data[index1]) {  
  208.   
  209.                                     top_data[index0] = bottom_data[index1];  
  210.   
  211.                                     mask[index0] = index1;  
  212.   
  213.                                 }                                 
  214.   
  215.                             }  
  216.   
  217.                         }  
  218.   
  219.                     }  
  220.   
  221.                 }  
  222.   
  223.                 bottom_data += featureSize * group_size_;  
  224.   
  225.                 top_data += featureSize;  
  226.   
  227.                 mask += featureSize;  
  228.   
  229.             }  
  230.   
  231.         }  
  232.   
  233.     }  
  234.   
  235.   
  236.   
  237.     return Dtype(0.);  
  238.   
  239. }  
  240.   
  241.   
  242.   
  243. template <typename Dtype>  
  244.   
  245. void MaxoutLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,  
  246.   
  247.       const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom) {  
  248.   
  249.     if (!propagate_down[0]) {  
  250.   
  251.         return;  
  252.   
  253.     }  
  254.   
  255.     const Dtype* top_diff = top[0]->cpu_diff();  
  256.   
  257.     Dtype* bottom_diff = (*bottom)[0]->mutable_cpu_diff();  
  258.   
  259.     caffe_set((*bottom)[0]->count(), Dtype(0), bottom_diff);  
  260.   
  261.     const Dtype* mask = max_idx_.mutable_cpu_data();  
  262.   
  263.     int featureSize = height_ * width_;  
  264.   
  265.   
  266.     for (int i = 0; i < top.size(); i ++) {  
  267.   
  268.         const Dtype* top_diff = top[i]->cpu_diff();  
  269.   
  270.         Dtype* bottom_diff = (*bottom)[i]->mutable_cpu_diff();    
  271.   
  272.                   
  273.   
  274.         for (int n = 0; n < num_; n ++) {  
  275.   
  276.             // È¡µÚnÕÅÍŒÏñ  
  277.   
  278.             for (int o = 0; o < num_output_; o ++) {  
  279.   
  280.                 for (int h = 0; h < height_; h ++) { // Áœ²ãÑ­»·Óеã¶ù†ªà  
  281.   
  282.                     for (int w = 0; w < width_; w ++) {  
  283.   
  284.                         int index = w + h * width_;  
  285.   
  286.                         int bottom_index = mask[index];  
  287.   
  288.                         bottom_diff[bottom_index] += top_diff[index];  
  289.   
  290.                     }  
  291.   
  292.                 }  
  293.   
  294.                 bottom_diff += featureSize * group_size_;  
  295.   
  296.                 top_diff += featureSize;  
  297.   
  298.                 mask += featureSize;  
  299.   
  300.             }  
  301.   
  302.         }  
  303.   
  304.     }  
  305.   
  306. }  
  307.   
  308.   
  309.   
  310. //#ifdef CPU_ONLY  
  311.   
  312. //STUB_GPU(MaxoutLayer);  
  313.   
  314. //#endif  
  315.   
  316.   
  317.   
  318. INSTANTIATE_CLASS(MaxoutLayer);  
  319.   
  320.   
  321.   
  322. }  // namespace caffe  


里面的乱码是中文,到了linux里面就乱码了,不影响,还一个printf是测试用的(要被笑话用printf了= =)


vision_layers.hpp 里面添加下面的代码

[cpp] view plain copy

  1. /* MaxoutLayer 
  2. */  
  3. template <typename Dtype>  
  4. class MaxoutLayer : public Layer<Dtype> {  
  5.  public:  
  6.   explicit MaxoutLayer(const LayerParameter& param)  
  7.       : Layer<Dtype>(param) {}  
  8.   virtual void SetUp(const vector<Blob<Dtype>*>& bottom,  
  9.       vector<Blob<Dtype>*>* top); // 为什么需要bottom与top,肯定的啊,  
  10.       //要初始化bottom top的形状  
  11.   virtual inline LayerParameter_LayerType type() const {  
  12.     return LayerParameter_LayerType_MAXOUT;  
  13.   }  
  14.   
  15.  protected:  
  16.   virtual Dtype Forward_cpu(const vector<Blob<Dtype>*>& bottom,  
  17.       vector<Blob<Dtype>*>* top);  
  18.   //virtual Dtype Forward_gpu(const vector<Blob<Dtype>*>& bottom,  
  19.   //    vector<Blob<Dtype>*>* top);  
  20.   virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,  
  21.       const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);  
  22.   //virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,  
  23.   //    const vector<bool>& propagate_down, vector<Blob<Dtype>*>* bottom);  
  24.     
  25.   int num_output_;  
  26.   int num_;  
  27.   int channels_;  
  28.   int height_;  
  29.   int width_;  
  30.   int group_size_;  
  31.   Blob<Dtype> max_idx_;  
  32.     
  33. };  


剩下的是layer_factory.cpp 的改动,不说明了,然后是proto文件的改动

[cpp] view plain copy

  1. message MaxoutParameter {  
  2.   optional uint32 num_output = 1; // The number of outputs for the layer  
  3. }  

额,当然还有proto文件的其他改动也不说明了,还有test文件,我没写,因为我自己跑了下demo,没啥问题,所以代码可以说是正确的。

不过要说明的是,目前的代码不能接在全连接层后面,是我里面有几句代码写的有问题,之后我会改动一下,问题不大。

然后就是NIN的实现了,表示自己写的渣一样的代码啊,效率目测很低。哦对了,这些都是CPU算的,GPU不大会,还没打算写。


NIN_layer 的实现

我之前一直以为Github上的network in network 是有问题的,事实证明,我最后也写成了Github上面的样子= =所以大家自行搜索caffe+network in network吧……不过得翻墙下载,所以我就把网络格式的代码直接贴出来(cifar10数据库的网络结构)

[plain] view plain copy

  1. layers {  
  2.   name: "cifar"  
  3.   type: DATA  
  4.   top: "data"  
  5.   top: "label"  
  6.   data_param {  
  7.     source: "cifar-train-leveldb"  
  8.     batch_size: 128  
  9.   }  
  10.   include: { phase: TRAIN }  
  11. }  
  12. layers {  
  13.   name: "cifar"  
  14.   type: DATA  
  15.   top: "data"  
  16.   top: "label"  
  17.   data_param {  
  18.     source: "cifar-test-leveldb"  
  19.     batch_size: 100  
  20.   }  
  21.   include: { phase: TEST }  
  22. }  
  23. layers {  
  24.   name: "conv1"  
  25.   type: CONVOLUTION  
  26.   bottom: "data"  
  27.   top: "conv1"  
  28.   blobs_lr: 1  
  29.   blobs_lr: 2  
  30.   weight_decay: 1.  
  31.   weight_decay: 0.  
  32.   convolution_param {  
  33.     num_output: 192  
  34.     pad: 2  
  35.     kernel_size: 5  
  36.     weight_filler {  
  37.       type: "gaussian"  
  38.       std: 0.05  
  39.     }  
  40.     bias_filler {  
  41.       type: "constant"  
  42.     }  
  43.   }  
  44. }  
  45. layers {  
  46.   name: "relu1"  
  47.   type: RELU  
  48.   bottom: "conv1"  
  49.   top: "conv1"  
  50. }  
  51. layers {  
  52.   name: "cccp1"  
  53.   type: CONVOLUTION  
  54.   bottom: "conv1"  
  55.   top: "cccp1"  
  56.   blobs_lr: 1  
  57.   blobs_lr: 2  
  58.   weight_decay: 1  
  59.   weight_decay: 0  
  60.   convolution_param {  
  61.     num_output: 160  
  62.     group: 1  
  63.     kernel_size: 1  
  64.     weight_filler {  
  65.       type: "gaussian"  
  66.       std: 0.05  
  67.     }  
  68.     bias_filler {  
  69.       type: "constant"  
  70.       value: 0  
  71.     }  
  72.   }  
  73. }  
  74. layers {  
  75.   name: "relu_cccp1"  
  76.   type: RELU  
  77.   bottom: "cccp1"  
  78.   top: "cccp1"  
  79. }  
  80. layers {  
  81.   name: "cccp2"  
  82.   type: CONVOLUTION  
  83.   bottom: "cccp1"  
  84.   top: "cccp2"  
  85.   blobs_lr: 1  
  86.   blobs_lr: 2  
  87.   weight_decay: 1  
  88.   weight_decay: 0  
  89.   convolution_param {  
  90.     num_output: 96  
  91.     group: 1  
  92.     kernel_size: 1  
  93.     weight_filler {  
  94.       type: "gaussian"  
  95.       std: 0.05  
  96.     }  
  97.     bias_filler {  
  98.       type: "constant"  
  99.       value: 0  
  100.     }  
  101.   }  
  102. }  
  103. layers {  
  104.   name: "relu_cccp2"  
  105.   type: RELU  
  106.   bottom: "cccp2"  
  107.   top: "cccp2"  
  108. }  
  109. layers {  
  110.   name: "pool1"  
  111.   type: POOLING  
  112.   bottom: "cccp2"  
  113.   top: "pool1"  
  114.   pooling_param {  
  115.     pool: MAX  
  116.     kernel_size: 3  
  117.     stride: 2  
  118.   }  
  119. }  
  120. layers {  
  121.   name: "drop3"  
  122.   type: DROPOUT  
  123.   bottom: "pool1"  
  124.   top: "pool1"  
  125.   dropout_param {  
  126.     dropout_ratio: 0.5  
  127.   }  
  128. }  
  129. layers {  
  130.   name: "conv2"  
  131.   type: CONVOLUTION  
  132.   bottom: "pool1"  
  133.   top: "conv2"  
  134.   blobs_lr: 1  
  135.   blobs_lr: 2  
  136.   weight_decay: 1.  
  137.   weight_decay: 0.  
  138.   convolution_param {  
  139.     num_output: 192  
  140.     pad: 2  
  141.     kernel_size: 5  
  142.     weight_filler {  
  143.       type: "gaussian"  
  144.       std: 0.05  
  145.     }  
  146.     bias_filler {  
  147.       type: "constant"  
  148.     }  
  149.   }  
  150. }  
  151. layers {  
  152.   name: "relu2"  
  153.   type: RELU  
  154.   bottom: "conv2"  
  155.   top: "conv2"  
  156. }  
  157. layers {  
  158.   name: "cccp3"  
  159.   type: CONVOLUTION  
  160.   bottom: "conv2"  
  161.   top: "cccp3"  
  162.   blobs_lr: 1  
  163.   blobs_lr: 2  
  164.   weight_decay: 1  
  165.   weight_decay: 0  
  166.   convolution_param {  
  167.     num_output: 192  
  168.     group: 1  
  169.     kernel_size: 1  
  170.     weight_filler {  
  171.       type: "gaussian"  
  172.       std: 0.05  
  173.     }  
  174.     bias_filler {  
  175.       type: "constant"  
  176.       value: 0  
  177.     }  
  178.   }  
  179. }  
  180. layers {  
  181.   name: "relu_cccp3"  
  182.   type: RELU  
  183.   bottom: "cccp3"  
  184.   top: "cccp3"  
  185. }  
  186. layers {  
  187.   name: "cccp4"  
  188.   type: CONVOLUTION  
  189.   bottom: "cccp3"  
  190.   top: "cccp4"  
  191.   blobs_lr: 1  
  192.   blobs_lr: 2  
  193.   weight_decay: 1  
  194.   weight_decay: 0  
  195.   convolution_param {  
  196.     num_output: 192  
  197.     group: 1  
  198.     kernel_size: 1  
  199.     weight_filler {  
  200.       type: "gaussian"  
  201.       std: 0.05  
  202.     }  
  203.     bias_filler {  
  204.       type: "constant"  
  205.       value: 0  
  206.     }  
  207.   }  
  208. }  
  209. layers {  
  210.   name: "relu_cccp4"  
  211.   type: RELU  
  212.   bottom: "cccp4"  
  213.   top: "cccp4"  
  214. }  
  215. layers {  
  216.   name: "pool2"  
  217.   type: POOLING  
  218.   bottom: "cccp4"  
  219.   top: "pool2"  
  220.   pooling_param {  
  221.     pool: AVE  
  222.     kernel_size: 3  
  223.     stride: 2  
  224.   }  
  225. }  
  226. layers {  
  227.   name: "drop6"  
  228.   type: DROPOUT  
  229.   bottom: "pool2"  
  230.   top: "pool2"  
  231.   dropout_param {  
  232.     dropout_ratio: 0.5  
  233.   }  
  234. }  
  235. layers {  
  236.   name: "conv3"  
  237.   type: CONVOLUTION  
  238.   bottom: "pool2"  
  239.   top: "conv3"  
  240.   blobs_lr: 1.  
  241.   blobs_lr: 2.  
  242.   weight_decay: 1.  
  243.   weight_decay: 0.  
  244.   convolution_param {  
  245.     num_output: 192  
  246.     pad: 1  
  247.     kernel_size: 3  
  248.     weight_filler {  
  249.       type: "gaussian"  
  250.       std: 0.05  
  251.     }  
  252.     bias_filler {  
  253.       type: "constant"  
  254.     }  
  255.   }  
  256. }  
  257. layers {  
  258.   name: "relu3"  
  259.   type: RELU  
  260.   bottom: "conv3"  
  261.   top: "conv3"  
  262. }  
  263. layers {  
  264.   name: "cccp5"  
  265.   type: CONVOLUTION  
  266.   bottom: "conv3"  
  267.   top: "cccp5"  
  268.   blobs_lr: 1  
  269.   blobs_lr: 2  
  270.   weight_decay: 1  
  271.   weight_decay: 0  
  272.   convolution_param {  
  273.     num_output: 192  
  274.     group: 1  
  275.     kernel_size: 1  
  276.     weight_filler {  
  277.       type: "gaussian"  
  278.       std: 0.05  
  279.     }  
  280.     bias_filler {  
  281.       type: "constant"  
  282.       value: 0  
  283.     }  
  284.   }  
  285. }  
  286. layers {  
  287.   name: "relu_cccp5"  
  288.   type: RELU  
  289.   bottom: "cccp5"  
  290.   top: "cccp5"  
  291. }  
  292. layers {  
  293.   name: "cccp6"  
  294.   type: CONVOLUTION  
  295.   bottom: "cccp5"  
  296.   top: "cccp6"  
  297.   blobs_lr: 0.1  
  298.   blobs_lr: 0.1  
  299.   weight_decay: 1  
  300.   weight_decay: 0  
  301.   convolution_param {  
  302.     num_output: 10  
  303.     group: 1  
  304.     kernel_size: 1  
  305.     weight_filler {  
  306.       type: "gaussian"  
  307.       std: 0.05  
  308.     }  
  309.     bias_filler {  
  310.       type: "constant"  
  311.       value: 0  
  312.     }  
  313.   }  
  314. }  
  315. layers {  
  316.   name: "relu_cccp6"  
  317.   type: RELU  
  318.   bottom: "cccp6"  
  319.   top: "cccp6"  
  320. }  
  321. layers {  
  322.   name: "pool3"  
  323.   type: POOLING  
  324.   bottom: "cccp6"  
  325.   top: "pool3"  
  326.   pooling_param {  
  327.     pool: AVE  
  328.     kernel_size: 8  
  329.     stride: 1  
  330.   }  
  331. }  
  332. layers {  
  333.   name: "accuracy"  
  334.   type: ACCURACY  
  335.   bottom: "pool3"  
  336.   bottom: "label"  
  337.   top: "accuracy"  
  338.   include: { phase: TEST }  
  339. }  
  340. layers {  
  341.   name: "loss"  
  342.   type: SOFTMAX_LOSS  
  343.   bottom: "pool3"  
  344.   bottom: "label"  
  345.   top: "loss"  
  346. }  




训练参数

[plain] view plain copy

  1. test_iter: 100  
  2. test_interval: 500  
  3. base_lr: 0.1  
  4. momentum: 0.9  
  5. weight_decay: 0.0001  
  6. lr_policy: "step"  
  7. gamma: 0.1  
  8. stepsize: 100000  
  9. display: 100  
  10. max_iter: 120000  
  11. snapshot: 10000  
  12. snapshot_prefix: "cifar10_nin"  



该文章算是告一段落了,剩下的任务就是如何训练得到state-of-the-art了