Caffe 运行平台支持DenseNet模型


在计算机视觉领域,卷积神经网络(CNN)已经成为最主流的方法,比如GoogLenet、VGG-19、Incepetion等模型。CNN史上的一个里程碑事件是ResNet模型的出现,ResNet可以训练出更深的CNN模型,从而实现更高的准确度。ResNet模型的核心是通过建立前面层与后面层之间的“短路连接”(shortcuts,skip connection),这有助于训练过程中梯度的反向传播,从而能训练出更深的CNN网络。

DenseNet模型的基本思路与ResNet一致,但是它建立的是前面所有层与后面层的密集连接(dense connection),它的名称也是由此而来。DenseNet的另一大特色是通过特征在channel上的连接来实现特征重用(feature reuse)。这些特点让DenseNet在参数和计算成本更少的情形下实现比ResNet更优的性能,DenseNet也因此斩获CVPR 2017的最佳论文奖。

1 集成DenseNet的报错信息

最近要把DenseNet集成到现有的运行平台,结果发现加载模型时caffe报如下错误信息:

[TL] 2019/03/21 19:52:17.688357 [8 12 34642][libprotobuf ERROR google/protobuf/text_format.cc:245] Error parsing text-format caffe.NetParameter: 54:15: Message type "caffe.PoolingParameter" has no field named "round_mode".
[TL] 2019/03/21 19:52:17.688714 [8 12 34642]F0321 19:52:17.688385 34642 upgrade_proto.cpp:90] Check failed: ReadProtoFromTextFile(param_file, param) Failed to parse NetParameter file: /workspace/AI/expression_v2/expression.prototxt
[TL] 2019/03/21 19:52:17.688827 [8 12 34642]*** Check failure stack trace: ***
[TL] 2019/03/21 19:52:17.689052 [8 12 34642]    @     0x7fc916efc84d  google::LogMessage::Fail()
[TL] 2019/03/21 19:52:17.689222 [8 12 34642]    @     0x7fc916efe61c  google::LogMessage::SendToLog()
[TL] 2019/03/21 19:52:17.689387 [8 12 34642]    @     0x7fc916efc43c  google::LogMessage::Flush()
[TL] 2019/03/21 19:52:17.689550 [8 12 34642]    @     0x7fc916efef2e  google::LogMessageFatal::~LogMessageFatal()
[TL] 2019/03/21 19:52:17.690197 [8 12 34642]    @     0x7fc91639a17e  caffe::ReadNetParamsFromTextFileOrDie()
[TL] 2019/03/21 19:52:17.690515 [8 12 34642]    @     0x7fc91624f23c  caffe::Net<>::Net()
[TL] 2019/03/21 19:52:17.690695 [8 12 34642]    @     0x7fc91733088f  ai_init()
[TL] 2019/03/21 19:52:17.690865 [8 12 34642]    @     0x7fc917331ac9  general_classify_init
[TL] 2019/03/21 19:52:17.690893 [8 12 34642]    @           0x406c2b  process()
[TL] 2019/03/21 19:52:17.690949 [8 12 34642]    @           0x437564  aicalc_poll()
[TL] 2019/03/21 19:52:17.690983 [8 12 34642]    @           0x405689  main
[TL] 2019/03/21 19:52:17.691576 [8 12 34642]    @     0x7fc9207e6b35  __libc_start_main
[TL] 2019/03/21 19:52:17.691649 [8 12 34642]    @           0x405b79  (unknown)

最核心的报错信息是Message type "caffe.PoolingParameter" has no field named "round_mode",这是因为我们现有运行平台使用的caffe版本较低,pooling层不支持round_mode参数。(之所以选择一个较低的caffe版本,则是因为最初做工程化的时候,最新版caffe不支持SSD模型)

一开始编译caffe的时候还发现了编译出现乱码的情况,通过命令export LC_ALL="C",去除所有本地化的设置,即可让编译正确执行。

2 caffe源码分析及修改

2.1 pooling层源码分析

pooling_layer.hpp新旧版本代码对比:

   48   int stride_h_, stride_w_;                                                  |   48   int stride_h_, stride_w_;
   49   int pad_h_, pad_w_;                                                        |   49   int pad_h_, pad_w_;
   50   int channels_;                                                             |   50   int channels_;
   51   int height_, width_;                                                       |   51   int height_, width_;
   52   int pooled_height_, pooled_width_;                                         |   52   int pooled_height_, pooled_width_;
   53   bool global_pooling_;                                                      |   53   bool global_pooling_;
   54   PoolingParameter_RoundMode round_mode_;                                    |      ----------------------------------------------------------------------------
   55   Blob<Dtype> rand_idx_;                                                     |   54   Blob<Dtype> rand_idx_;
   56   Blob<int> max_idx_;                                                        |   55   Blob<int> max_idx_;
   57 };                                                                           |   56 };
   58                                                                              |   57 
   59 }  // namespace caffe                                                        |   58 }  // namespace caffe
   60                                                                              |   59 
-  61 #endif  // CAFFE_POOLING_LAYER_HPP_                                          |-  60 #endif  // CAFFE_POOLING_LAYER_HPP_

对比之后发现头文件的改动只是增加了一个字段:PoolingParameter_RoundMode round_mode_

pooling_layer.cpp新旧版本代码对比:

   91   switch (round_mode_) {                                                     |   90   pooled_height_ = static_cast<int>(ceil(static_cast<float>(                
   92   case PoolingParameter_RoundMode_CEIL:                                      |   91       height_ + 2 * pad_h_ - kernel_h_) / stride_h_)) + 1;                  
   93     pooled_height_ = static_cast<int>(ceil(static_cast<float>(               |   92   pooled_width_ = static_cast<int>(ceil(static_cast<float>(                 
   94         height_ + 2 * pad_h_ - kernel_h_) / stride_h_)) + 1;                 |   93       width_ + 2 * pad_w_ - kernel_w_) / stride_w_)) + 1;                   
   95     pooled_width_ = static_cast<int>(ceil(static_cast<float>(                |      ----------------------------------------------------------------------------
   96         width_ + 2 * pad_w_ - kernel_w_) / stride_w_)) + 1;                  |      ----------------------------------------------------------------------------
   97     break;                                                                   |      ----------------------------------------------------------------------------
   98   case PoolingParameter_RoundMode_FLOOR:                                     |      ----------------------------------------------------------------------------
   99     pooled_height_ = static_cast<int>(floor(static_cast<float>(              |      ----------------------------------------------------------------------------
  100         height_ + 2 * pad_h_ - kernel_h_) / stride_h_)) + 1;                 |      ----------------------------------------------------------------------------
  101     pooled_width_ = static_cast<int>(floor(static_cast<float>(               |      ----------------------------------------------------------------------------
  102         width_ + 2 * pad_w_ - kernel_w_) / stride_w_)) + 1;                  |      ----------------------------------------------------------------------------
  103     break;                                                                   |      ----------------------------------------------------------------------------
  104   default:                                                                   |      ----------------------------------------------------------------------------
  105     LOG(FATAL) << "Unknown rounding mode.";                                  |      ----------------------------------------------------------------------------
  106   }

对比之后发现cpp文件的改动也很小,只是根据round_mode参数决定对池化后的宽高取ceil还是floor。

2.2 caffe源码修改

改动1:用新版本caffe中的pooling_layer.hpppooling_layer.cpp文件替换旧版本caffe中的相应文件。

改动2:在caffe.proto文件的message PoolingParameter中追加如下代码:

// How to calculate the output size - using ceil (default) or floor rounding.
  enum RoundMode {
    CEIL = 0; 
    FLOOR = 1; 
  }
  optional RoundMode round_mode = 13 [default = CEIL];

使用make -j64重新编译caffe,编译完成后,得到新版的libcaffe.so.1.0.0,用最新so替代运行平台中的旧版本so,即可支持DenseNet了。

3 总结

修改流程:

  1. 改动pooling层的hpp和cpp文件
  2. 修改caffe.proto文件(因为涉及参数增加)
  3. 重新编译
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页