在没有出现sppnet之前,RCNN使用corp和warp来对图片进行大小调整,这种操作会造成图片信息失真和信息丢失。sppnet这个模型推出来之后(关于这个网络的描述,可以看看之前写的一篇理解:http://www.cnblogs.com/gongxijun/p/7172134.html),rg大神沿用了sppnet的思路到他的下一个模型中fast-rcnn中,但是roi_pooling和sppnet的思路虽然相同,但是实现方式还是不同的.我们看一下网络参数:

  1. layer {
  2. name: "roi_pool5"
  3. type: "ROIPooling"
  4. bottom: "conv5_3"
  5. bottom: "rois"
  6. top: "pool5"
  7. roi_pooling_param {
  8. pooled_w:
  9. pooled_h:
  10. spatial_scale: 0.0625 # /
  11. }

结合源代码,作者借助了sppnet的空域金字塔pool方式,但是和sppnet并不同的是,作者在这里只使用了(pooled_w,pooled_h)这个尺度,来将得到的每一个特征图分成(pooled_w,pooled_h),然后对每一块进行max_pooling取值,最后得到一个n*7*7固定大小的特征图。

  1. // ------------------------------------------------------------------
  2. // Fast R-CNN
  3. // Copyright (c) 2015 Microsoft
  4. // Licensed under The MIT License [see fast-rcnn/LICENSE for details]
  5. // Written by Ross Girshick
  6. // ------------------------------------------------------------------
  7.  
  8. #include <cfloat>
  9.  
  10. #include "caffe/fast_rcnn_layers.hpp"
  11.  
  12. using std::max;
  13. using std::min;
  14. using std::floor;
  15. using std::ceil;
  16.  
  17. namespace caffe {
  18.  
  19. template <typename Dtype>
  20. void ROIPoolingLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,
  21. const vector<Blob<Dtype>*>& top) {
  22. ROIPoolingParameter roi_pool_param = this->layer_param_.roi_pooling_param();
  23. CHECK_GT(roi_pool_param.pooled_h(), )
  24. << "pooled_h must be > 0";
  25. CHECK_GT(roi_pool_param.pooled_w(), )
  26. << "pooled_w must be > 0";
  27. pooled_height_ = roi_pool_param.pooled_h(); //定义网络的大小
  28. pooled_width_ = roi_pool_param.pooled_w();
  29. spatial_scale_ = roi_pool_param.spatial_scale();
  30. LOG(INFO) << "Spatial scale: " << spatial_scale_;
  31. }
  32.  
  33. template <typename Dtype>
  34. void ROIPoolingLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
  35. const vector<Blob<Dtype>*>& top) {
  36. channels_ = bottom[]->channels();
  37. height_ = bottom[]->height();
  38. width_ = bottom[]->width();
  39. top[]->Reshape(bottom[]->num(), channels_, pooled_height_,
  40. pooled_width_);
  41. max_idx_.Reshape(bottom[]->num(), channels_, pooled_height_,
  42. pooled_width_);
  43. }
  44.  
  45. template <typename Dtype>
  46. void ROIPoolingLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
  47. const vector<Blob<Dtype>*>& top) {
  48. const Dtype* bottom_data = bottom[]->cpu_data();
  49. const Dtype* bottom_rois = bottom[]->cpu_data();//获取roidb信息(n,x1,y1,x2,y2)
  50. // Number of ROIs
  51. int num_rois = bottom[]->num();//候选目标的个数
  52. int batch_size = bottom[]->num();//特征图的维度,vgg16的conv5之后为512
  53. int top_count = top[]->count();//需要输出的值个数
  54. Dtype* top_data = top[]->mutable_cpu_data();
  55. caffe_set(top_count, Dtype(-FLT_MAX), top_data);
  56. int* argmax_data = max_idx_.mutable_cpu_data();
  57. caffe_set(top_count, -, argmax_data);
  58.  
  59. // For each ROI R = [batch_index x1 y1 x2 y2]: max pool over R
  60. for (int n = ; n < num_rois; ++n) {
  61. int roi_batch_ind = bottom_rois[];
  62. int roi_start_w = round(bottom_rois[] * spatial_scale_);//缩小16倍,将候选区域在原始坐标中的位置,映射到conv_5特征图上
  63. int roi_start_h = round(bottom_rois[] * spatial_scale_);
  64. int roi_end_w = round(bottom_rois[] * spatial_scale_);
  65. int roi_end_h = round(bottom_rois[] * spatial_scale_);
  66. CHECK_GE(roi_batch_ind, );
  67. CHECK_LT(roi_batch_ind, batch_size);
  68.  
  69. int roi_height = max(roi_end_h - roi_start_h + , );//得到候选区域在特征图上的大小
  70. int roi_width = max(roi_end_w - roi_start_w + , );
  71. const Dtype bin_size_h = static_cast<Dtype>(roi_height)
  72. / static_cast<Dtype>(pooled_height_);//计算如果需要划分成(pooled_height_,pooled_weight_)这么多块,那么每一个块的大小(bin_size_w,bin_size_h);
  73. const Dtype bin_size_w = static_cast<Dtype>(roi_width)
  74. / static_cast<Dtype>(pooled_width_);
  75.  
  76. const Dtype* batch_data = bottom_data + bottom[]->offset(roi_batch_ind);//获取当前维度的特征图数据,比如一共有(n,x1,x2,x3,x4)的数据,拿到第一块特征图的数据
  77.  
  78. for (int c = ; c < channels_; ++c) {
  79. for (int ph = ; ph < pooled_height_; ++ph) {
  80. for (int pw = ; pw < pooled_width_; ++pw) {
  81. // Compute pooling region for this output unit:
  82. // start (included) = floor(ph * roi_height / pooled_height_)
  83. // end (excluded) = ceil((ph + 1) * roi_height / pooled_height_)
  84. int hstart = static_cast<int>(floor(static_cast<Dtype>(ph)
  85. * bin_size_h)); //计算每一块的位置
  86. int wstart = static_cast<int>(floor(static_cast<Dtype>(pw)
  87. * bin_size_w));
  88. int hend = static_cast<int>(ceil(static_cast<Dtype>(ph + )
  89. * bin_size_h));
  90. int wend = static_cast<int>(ceil(static_cast<Dtype>(pw + )
  91. * bin_size_w));
  92.  
  93. hstart = min(max(hstart + roi_start_h, ), height_);
  94. hend = min(max(hend + roi_start_h, ), height_);
  95. wstart = min(max(wstart + roi_start_w, ), width_);
  96. wend = min(max(wend + roi_start_w, ), width_);
  97.  
  98. bool is_empty = (hend <= hstart) || (wend <= wstart);
  99.  
  100. const int pool_index = ph * pooled_width_ + pw;
  101. if (is_empty) {
  102. top_data[pool_index] = ;
  103. argmax_data[pool_index] = -;
  104. }
  105.  
  106. for (int h = hstart; h < hend; ++h) {
  107. for (int w = wstart; w < wend; ++w) {
  108. const int index = h * width_ + w;
  109. if (batch_data[index] > top_data[pool_index]) {
  110. top_data[pool_index] = batch_data[index]; //在取每一块中的最大值,就是max_pooling操作.
  111. argmax_data[pool_index] = index;
  112. }
  113. }
  114. }
  115. }
  116. }
  117. // Increment all data pointers by one channel
  118. batch_data += bottom[]->offset(, );
  119. top_data += top[]->offset(, );
  120. argmax_data += max_idx_.offset(, );
  121. }
  122. // Increment ROI data pointer
  123. bottom_rois += bottom[]->offset();
  124. }
  125. }
  126.  
  127. template <typename Dtype>
  128. void ROIPoolingLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
  129. const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
  130. NOT_IMPLEMENTED;
  131. }
  132.  
  133. #ifdef CPU_ONLY
  134. STUB_GPU(ROIPoolingLayer);
  135. #endif
  136.  
  137. INSTANTIATE_CLASS(ROIPoolingLayer);
  138. REGISTER_LAYER_CLASS(ROIPooling);
  139.  
  140. } // namespace caffe

进过以上的操作过后,就得到了固定大小的特征图啦,然后就可以进行全连接操作了. 但愿我说明白了.

---完.

faster-rcnn中ROI_POOIING层的解读的更多相关文章

  1. 对faster rcnn 中rpn层的理解

    1.介绍 图为faster rcnn的rpn层,接自conv5-3 图为faster rcnn 论文中关于RPN层的结构示意图 2 关于anchor: 一般是在最末层的 feature map 上再用 ...

  2. BiLSTM-CRF模型中CRF层的解读

    转自: https://createmomo.github.io/ BiLSTM-CRF模型中CRF层的解读: 文章链接: 标题:CRF Layer on the Top of BiLSTM - 1  ...

  3. tensorflow object detection faster r-cnn 中keep_aspect_ratio_resizer是什么意思

    如果小伙伴的英语能力强可以直接阅读这里:https://stackoverflow.com/questions/45137835/what-the-impact-of-different-dimens ...

  4. AI佳作解读系列(二)——目标检测AI算法集杂谈:R-CNN,faster R-CNN,yolo,SSD,yoloV2,yoloV3

    1 引言 深度学习目前已经应用到了各个领域,应用场景大体分为三类:物体识别,目标检测,自然语言处理.本文着重与分析目标检测领域的深度学习方法,对其中的经典模型框架进行深入分析. 目标检测可以理解为是物 ...

  5. Domain Adaptive Faster R-CNN:经典域自适应目标检测算法,解决现实中痛点,代码开源 | CVPR2018

    论文从理论的角度出发,对目标检测的域自适应问题进行了深入的研究,基于H-divergence的对抗训练提出了DA Faster R-CNN,从图片级和实例级两种角度进行域对齐,并且加入一致性正则化来学 ...

  6. 【深度学习】目标检测算法总结(R-CNN、Fast R-CNN、Faster R-CNN、FPN、YOLO、SSD、RetinaNet)

    目标检测是很多计算机视觉任务的基础,不论我们需要实现图像与文字的交互还是需要识别精细类别,它都提供了可靠的信息.本文对目标检测进行了整体回顾,第一部分从RCNN开始介绍基于候选区域的目标检测器,包括F ...

  7. 利用FPN构建Faster R-CNN检测

    FPN就是所谓的金字塔结构的检测器,(Feature Pyramid Network) 把FPN融合到Faster rcnn中能够很大程度增加检测器对全图信息的认知, 步骤如图所示: 1.先将图像送入 ...

  8. 第三十一节,目标检测算法之 Faster R-CNN算法详解

    Ren, Shaoqing, et al. “Faster R-CNN: Towards real-time object detection with region proposal network ...

  9. faster rcnn 做识别

    faster rcnn 主要分为四个部分: 1. convolutional part: 特征提取 可以使用vgg,resnet 等等 2.region proposal network: 生成 re ...

随机推荐

  1. 201521123060 《Java程序设计》第5周学习总结

    1.本周学习总结 2.书面作业 Q1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过?哪句会出现错误?试改正该错误.并分析输出结果. 答:不能 ...

  2. 201521123063 《Java程序设计》第三周学习总结

    1.本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2.书面作业 ...

  3. informix服务端口和oralce服务端口

    查找informix的服务端口1>>more .profile 找到: INFORMIXDIR=/home/informix INFORMIXSERVER=aaaa2>>cd ...

  4. virtualbox修改主机名

    virtualbox修改主机名 /etc/hostname /etc/hosts

  5. geotrellis使用(三十三)关于Geotrellis读取Geotiff的两个细节

    前言 在上两篇文章中我介绍了如何直接将Geotiff(一个或者多个)发布为TMS服务.这中间其实我遇到了一个问题,并且这个问题伴随Geotrellis的几乎所有使用案例,下面我进行详细讲述. 一.问题 ...

  6. String类的一些常见的比较方法(4)

    1:boolean equals(Object obj); //比较字符穿的内容是否相同 区分大小写的 2:boolean equalsIgnoreCase(String str); //比较字符穿的 ...

  7. pycharm 2017新建文件添加编码方式等

    file->setting->Editor->File and Code Templates->Python Script 添加 #!/usr/bin/python3# -*- ...

  8. Quartz源码——QuartzSchedulerThread.run() 源码分析(三)

    QuartzSchedulerThread.run()是主要处理任务的方法!下面进行分析,方便自己查看! 我都是分析的jobStore 方式为jdbc的SimpleTrigger!RAM的方式类似分析 ...

  9. java集合系列——List集合之Stack介绍(五)

    1.Stack的简介 Stack 类表示后进先出(LIFO)的对象堆栈.它通过五个操作对类 Vector 进行了扩展 ,允许将向量视为堆栈.它提供了通常的 push 和 pop 操作,以及取堆栈顶点的 ...

  10. APUE 4 - 线程

    对传统的UNIX进程来讲,一个进程中只有一个线程,这就意味着一个进程在同一时刻只能做一件事(即使是多核CPU).使用多线程技术, 我们可以设计程序使得一个进程在同一时刻做多件事.使用多线程编程具有以下 ...