1. 原理介绍

目标检测typical architecture 通常可以分为两个阶段:
(1)region proposal:给定一张输入image找出objects可能存在的所有位置。这一阶段的输出应该是一系列object可能位置的bounding box。这些通常称之为region proposals或者 regions of interest(ROI)。
(2)final classification:确定上一阶段的每个region proposal是否属于目标一类或者背景。

这个architecture存在的一些问题是:
产生大量的region proposals 会导致performance problems,很难达到实时目标检测。在处理速度方面是suboptimal。无法做到end-to-end training。这就是ROI pooling提出的根本原因。
ROI pooling层能实现training和testing的显著加速,并提高检测accuracy。该层有两个输入:从具有多个卷积核池化的深度网络中获得的固定大小的feature maps;一个表示所有ROI(也可以叫GT)的N*5的矩阵,其中N表示ROI的数目。第一列表示图像index,其余四列表示其余的左上角和右下角坐标。

ROI pooling具体操作如下:
(1)根据输入image,将ROI映射到feature map对应位置,映射是根据image缩小的尺寸来的;
(2)按照ROI Pooling输出的数据的坐标,将其映射到上一步中映射的feature区域上,这样就将原来feature map上的ROI映射划分成了几个sections(sections数量与输出的维度(pooled_w*pooled_h)相同);
(3)对每个sections进行max pooling操作;
这样我们就可以从不同大小的方框得到固定大小的相应的feature maps。值得一提的是,输出的feature maps的大小不取决于ROI和卷积feature maps大小,而是取决于该层设置的pooled_h与pooled_w。ROI pooling 最大的好处就在于极大地提高了处理速度。这样不管给定feature map输入的大小,使得输出的数据维度统一,这与SPP-Net的思想类似。

2. ROI pooling的图文解释

考虑一个8∗88*88∗8大小的feature map,一个ROI,以及ROI Pooling之后的输出大小为2∗22*22∗2
(1)输入的固定大小的feature map

(2)region proposal 投影之后位置(左上角,右下角坐标):(0,3),(7,8)。

(3)将其划分为(2∗22*22∗2)个sections(因为输出大小为2∗22*22∗2),我们可以得到:

(4)对每个section做max pooling,可以得到:

ROI pooling总结:
(1)用于目标检测任务;
(2)允许我们对CNN中的feature map进行reuse;
(3)可以显著加速training和testing速度;
(4)允许end-to-end的形式训练目标检测系统。

3. Caffe中的使用与实现

对于ROI Pooling层在Caffe的prototxt中是这样定义的

layer {name: "roi_pool5"type: "ROIPooling"bottom: "conv5_3"bottom: "rois"top: "pool5"roi_pooling_param {pooled_w: 7pooled_h: 7spatial_scale: 0.0625 # 1/16}
}

对应的源代码,这里已经写了必要的注释

template <typename Dtype>
void ROIPoolingLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top) {ROIPoolingParameter roi_pool_param = this->layer_param_.roi_pooling_param();CHECK_GT(roi_pool_param.pooled_h(), 0)<< "pooled_h must be > 0";CHECK_GT(roi_pool_param.pooled_w(), 0)<< "pooled_w must be > 0";pooled_height_ = roi_pool_param.pooled_h();   //Pooling之后的heightpooled_width_ = roi_pool_param.pooled_w();   //Pooling之后的widthspatial_scale_ = roi_pool_param.spatial_scale();  //GT标注的缩放比例LOG(INFO) << "Spatial scale: " << spatial_scale_;
}template <typename Dtype>
void ROIPoolingLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top) {channels_ = bottom[0]->channels();height_ = bottom[0]->height();width_ = bottom[0]->width();top[0]->Reshape(bottom[1]->num(), channels_, pooled_height_,  //输出的维度是GT标注的n*channels*Pooling_w*Pooling_hpooled_width_);max_idx_.Reshape(bottom[1]->num(), channels_, pooled_height_,pooled_width_);
}template <typename Dtype>
void ROIPoolingLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top) {const Dtype* bottom_data = bottom[0]->cpu_data();   //卷积的feature map数据const Dtype* bottom_rois = bottom[1]->cpu_data(); //标注的GT数据// Number of ROIsint num_rois = bottom[1]->num();      //标注数据的个数int batch_size = bottom[0]->num();     //卷积数据int top_count = top[0]->count();      //输出数据的大小Dtype* top_data = top[0]->mutable_cpu_data();      //空间初始化caffe_set(top_count, Dtype(-FLT_MAX), top_data);int* argmax_data = max_idx_.mutable_cpu_data();caffe_set(top_count, -1, argmax_data);// For each ROI R = [batch_index x1 y1 x2 y2]: max pool over Rfor (int n = 0; n < num_rois; ++n) {  //遍历每个GT标注数据int roi_batch_ind = bottom_rois[0];    //取出GT坐标对应当前batch中的indexint roi_start_w = round(bottom_rois[1] * spatial_scale_);  //按照图像缩小的尺寸(scale),去计算对应坐标在特征图上的相对位置int roi_start_h = round(bottom_rois[2] * spatial_scale_);int roi_end_w = round(bottom_rois[3] * spatial_scale_);int roi_end_h = round(bottom_rois[4] * spatial_scale_);CHECK_GE(roi_batch_ind, 0);CHECK_LT(roi_batch_ind, batch_size);int roi_height = max(roi_end_h - roi_start_h + 1, 1); //计算特征图上roi的宽高int roi_width = max(roi_end_w - roi_start_w + 1, 1);const Dtype bin_size_h = static_cast<Dtype>(roi_height)    //计算roi在特征图上的宽高与Pooling之后的宽高的比例/ static_cast<Dtype>(pooled_height_);const Dtype bin_size_w = static_cast<Dtype>(roi_width)/ static_cast<Dtype>(pooled_width_);const Dtype* batch_data = bottom_data + bottom[0]->offset(roi_batch_ind); //取出正在运算的batch//使用当前GT对应的Pooling结果位置反向到feature map中去做求最大值操作for (int c = 0; c < channels_; ++c) {for (int ph = 0; ph < pooled_height_; ++ph) {for (int pw = 0; pw < pooled_width_; ++pw) {// Compute pooling region for this output unit://  start (included) = floor(ph * roi_height / pooled_height_)//  end (excluded) = ceil((ph + 1) * roi_height / pooled_height_)int hstart = static_cast<int>(floor(static_cast<Dtype>(ph) //计算Pooling之后的数据在* bin_size_h));int wstart = static_cast<int>(floor(static_cast<Dtype>(pw)* bin_size_w));int hend = static_cast<int>(ceil(static_cast<Dtype>(ph + 1)* bin_size_h));int wend = static_cast<int>(ceil(static_cast<Dtype>(pw + 1)* bin_size_w));hstart = min(max(hstart + roi_start_h, 0), height_);    //计算当前Pooling位置对应feature map的区域hend = min(max(hend + roi_start_h, 0), height_);wstart = min(max(wstart + roi_start_w, 0), width_);wend = min(max(wend + roi_start_w, 0), width_);bool is_empty = (hend <= hstart) || (wend <= wstart);const int pool_index = ph * pooled_width_ + pw;if (is_empty) {top_data[pool_index] = 0;argmax_data[pool_index] = -1;}for (int h = hstart; h < hend; ++h) {   //求出圈定区域的最大值for (int w = wstart; w < wend; ++w) {const int index = h * width_ + w;if (batch_data[index] > top_data[pool_index]) {top_data[pool_index] = batch_data[index];argmax_data[pool_index] = index;}}}}}// Increment all data pointers by one channelbatch_data += bottom[0]->offset(0, 1); //当前batch的下一个channeltop_data += top[0]->offset(0, 1);      //当前Pooling的下一个channelargmax_data += max_idx_.offset(0, 1);}// Increment ROI data pointerbottom_rois += bottom[1]->offset(1);   //下一个roi区域}
}

4. 参考

  1. ROI Pooling层详解

关于ROI Pooling Layer的解读相关推荐

  1. 到底什么是 ROI Pooling Layer ???

    到底什么是 ROI Pooling Layer ??? 只知道 faster rcnn 中有 ROI pooling, 而且其他很多算法也都有用这个layer 来做一些事情,如:SINT,检测的文章等 ...

  2. Faster R-CNN源码中ROI Pooling的解析

    如图可以看出来ROI Pooling使用RPN产生的Proposal和fearture map,ROIpooling其实使用的是feature map中的Proposal,如下图也可以看出来.Prop ...

  3. R-FCN 与 Position Sensitive ROI Pooling

    Faster R-CNN 通过与 RPN 共享特征图提高了整个检测过程的速度.然而,其第2阶段仍保留 Fast R-CNN 的处理手法,将数百区域逐一送入子网络.R-FCN 在 RoI 间亦共享特征, ...

  4. Caffe源码中Pooling Layer文件分析

    Caffe源码(caffe version commit: 09868ac , date: 2015.08.15)中有一些重要的头文件,这里介绍下include/caffe/vision_layers ...

  5. RoI Pooling 与 RoI Align 有什么区别?

    ↑ 点击蓝字 关注视学算法 作者丨AlexChung@知乎 来源丨https://zhuanlan.zhihu.com/p/161540817 编辑丨极市平台 基本概念 RoI RoI(Region ...

  6. NMS和roi pooling 实现以及加速

    https://github.com/fmscole/benchmark/tree/6335c5ba6d673e9a78c43e704ae93f77cbe1eca2 NMS和roi pooling的各 ...

  7. SPP pooling layer

    参考:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition SPP_net的提出 因为传统的CNN ...

  8. ROI Pooling层解析

    ROI Pooling的意义 ROIs Pooling顾名思义,是Pooling层的一种,而且是针对RoIs的Pooling,他的特点是输入特征图尺寸不固定,但是输出特征图尺寸固定: 什么是ROI呢? ...

  9. RoI Pooling 系列方法介绍(文末附源码)

    作者简介 CW,广东深圳人,毕业于中山大学(SYSU)数据科学与计算机学院,毕业后就业于腾讯计算机系统有限公司技术工程与事业群(TEG)从事Devops工作,期间在AI LAB实习过,实操过道路交通元 ...

最新文章

  1. flask运行环境搭建(nginx+gunicorn)
  2. linux内核关于io的变迁
  3. TF之NN:利用神经网络系统自动学习散点(二次函数+noise+优化修正)输出结果可视化(matplotlib动态演示)
  4. 高级php面试题及部分答案
  5. 在word中插入代码段的方法[转]
  6. Linux内核驱动调试,Linux内核设备驱动之内核的调试技术笔记整理
  7. 隐形Euler方法的java程序_常微分方程的解法 (二): 欧拉(Euler)方法
  8. 大数据高地,这样炼成!
  9. python程序设计与算法基础教程微课版课后答案_Python程序设计与算法基础教程
  10. 成都盛铭轩:商家怎么装修设计
  11. 网站seo运营中如何精确预测热门搜索关键词?
  12. 学java好还是学挖机好_现在开挖掘机还能月入上万吗,为何年轻人还是热衷于学挖掘机?...
  13. 68个Python内置函数详解,进阶必备
  14. 梦幻西游服务器维修,《梦幻西游》电脑版2017年12月12日定期维护公告
  15. Python 遍历List三种方式
  16. 鸡声茅店月,人迹板桥霜;莫道君行早,更有早行人
  17. Lust(Codeforces Round #446 Div.1-891E)(母函数\生成函数)
  18. MySQL:常用的MySQL优化工具
  19. python 包用法,Python包的使用
  20. Java实现 LeetCode 374 猜数字大小

热门文章

  1. easypoi动态设置列宽
  2. 亚马逊广告打造篇(第一期)
  3. excel剔除空格_如何快速去掉EXCEL中的大量空格?—文字讲解与视频操作版
  4. JAVA面试题——初级
  5. Siki_Unity_3-3_背包系统
  6. 如何把照片的底色修改为想要的颜色
  7. ffmpeg直播系统
  8. 1-19 HashMap、IO流递归遍历文件实战
  9. mysql添加约束_fk_MySQL中外键的创建、约束以及删除
  10. 人工智能风口已过?不,其实才刚刚开始...