SPPNet论文笔记和caffe实现说明

SPPNet:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition
pdf:https://arxiv.org/pdf/1406.4729v2.pdf

论文主要贡献

之前的CNN网络的输入的size都是固定,为什么要这样呢,是因为最后fc层的输入需要是一个固定的尺寸,例如AlexNet的fc6的输入就是需要固定,但是如果各种图片都通过crop或者warp来resize成一样,就会有下面的情况发生:

crop导致看不全,warp导致变形

SPPNet

而该论文通过在conv和fc层之间引入Spatial Pyramid Pooling,可以接受不同的size输入,在SPP层后面产生固定size的输出送入fc层,而且SPP相较于之前的Pooling来说,通过设置不同level的spatial bins来达到Mutil-level,而且由于输入的size是多变的,所以它可以从各个不同的scales来pool feature,有更强的鲁棒性。


随手画了下大致的网络示意图 以AlexNet为例(有点难看 轻喷)

这里写图片描述

实验效果

  1. 直接把原来的Pooling换掉,其他不变输入还是fixed的,这样做为了控制变量,直接看SPP的效果,发现也有1个点的提升
  2. 输入不同size的图片进行训练,比起第一个实验,又有了0.5点的提升吧(注意此处训练是用了不同size,但是测试还是同一size)
  3. 做了组对比实验,每张图片令min(w,h)= 256,然后保持比例放缩到这个大小,送入网络。另一个是取刚刚放缩好的图片中间部位的224x224送入网络,实验结果发现full image比crop image高0.5个点,这也说明了输入全图更好。
  4. 测试时取很多view,比如中心、四个角、四个边的中间以及他们的翻转这18个view,然后全图计算一次conv5的feature map就行,通过映射看这18个view在feature map都是哪块,然后把这18块送入SPP后进入fc,发现也是有提升的

caffe实现

#caffe.proto中的关于SPP层参数的定义
message SPPParameter {
  enum PoolMethod {
    MAX = 0;
    AVE = 1;
    STOCHASTIC = 2;
  }
  optional uint32 pyramid_height = 1;
  optional PoolMethod pool = 2 [default = MAX]; // The pooling method
  enum Engine {
    DEFAULT = 0;
    CAFFE = 1;
    CUDNN = 2;
  }
  optional Engine engine = 6 [default = DEFAULT];
}
# AlexNet trainval.prototxt
....
layer {
  name: "relu5"
  type: "ReLU"
  bottom: "conv5"
  top: "conv5"
}
#之前的Pooling层
#layer {
#  name: "pool5"
#  type: "Pooling"
#  bottom: "conv5"
#  top: "pool5"
#  pooling_param {
#    pool: MAX
#    kernel_size: 3
#    stride: 2
# }
#}
layer {
  name: "spatial_pyramid_pooling"
  type: "SPP"
  bottom: "conv5"
  top: "pool5"
  spp_param {
    pool: MAX
    pyramid_height: 2 # SPP的level的数量
  }
}
layer {
  name: "fc6"
  type: "InnerProduct"
  bottom: "pool5"
  top: "fc6"
  ...
}
...
void SPPLayer<Dtype>::LayerSetUp(......){

    for (int i = 0; i < pyramid_height_; i++) {
        ......
        // pooling layer setup
        LayerParameter pooling_param = GetPoolingParam(
        i, bottom_h_, bottom_w_, spp_param);
    }
}
// 关于pyramid_height
// pyramid_level是0到pyramid_height-1
// 暂时是这样理解这段代码的,但是没有找到stride在哪???
// pool 1x1 2x2 4x4 8x8 ... pow(2, pyramid_height-1)xpow(2, pyramid_height-1)
LayerParameter SPPLayer<Dtype>::GetPoolingParam(const int pyramid_level,......){
    ......
      LayerParameter pooling_param;
      int num_bins = pow(2, pyramid_level);
      // find padding and kernel size so that the pooling is
      // performed across the entire image
      int kernel_h = ceil(bottom_h / static_cast<double>(num_bins));
      // remainder_h is the min number of pixels that need to be padded before
      // entire image height is pooled over with the chosen kernel dimension
      int remainder_h = kernel_h * num_bins - bottom_h;
      // pooling layer pads (2 * pad_h) pixels on the top and bottom of the
      // image.
      int pad_h = (remainder_h + 1) / 2;

      // similar logic for width
      int kernel_w = ceil(bottom_w / static_cast<double>(num_bins));
      int remainder_w = kernel_w * num_bins - bottom_w;
      int pad_w = (remainder_w + 1) / 2;

      pooling_param.mutable_pooling_param()->set_pad_h(pad_h);
      pooling_param.mutable_pooling_param()->set_pad_w(pad_w);
      pooling_param.mutable_pooling_param()->set_kernel_h(kernel_h);
      pooling_param.mutable_pooling_param()->set_kernel_w(kernel_w);
      pooling_param.mutable_pooling_param()->set_stride_h(kernel_h);
      pooling_param.mutable_pooling_param()->set_stride_w(kernel_w);
      ...
}

这里写图片描述这里写图片描述


注意事项

  1. 直接复现实验1是很容易,就是输入还是固定的,只是Pooling换掉,只有一点注意,pyramid_height的设置如果过大(图片的size很小)会报的错误:Check failed: pad_h_ < kernel_h_,因为size太小了,到conv5时feature map太小了,而caffe这里限制pad_h_ < kernel_h_

  2. 复现实验2就有些许问题,如果你的batch不是1的话,因为load_batch是多线程同步的,caffe会默认用这个batch里的第一个数据的chanel height width作为输出的格式,所以会报类似的错误:Check failed: height <= datum_height (80(第一个数据的height) vs. 64(后续数据的height)) ,暂时如果不修改部分源码的话,只有先把trainval.prototxt和test.prototxt的batchsize都设为1吧,实验2仍需要注意实验1的问题

  3. 实验3,4自行根据前两条注意事项进行操作
阅读更多

扫码向博主提问

爆米花好美啊

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • deep learn
  • detection
  • segmentati
去开通我的Chat快问
版权声明:本文为博主原创文章,如若转载,请注明出处! https://blog.csdn.net/u013010889/article/details/53928363
上一篇scipy csr_matrix和csc_matrix函数详解
下一篇OpenCV、Skimage、PIL图像处理的细节差异
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭