欢迎访问个人网络日志🌹🌹知行空间🌹🌹
1 ROI
首先,何为ROI ? ROI 是Region of Interest 的缩写,即感兴趣区域。在不同的情况下用户关心的图像区域是不同的,因此ROI 所指含义也不同。对于物体检测的目标ROI ,ROI 就是要找到对象在图像中Bounding Box 区域。如
对于物体检测的目标,我们关心的是对象是人,则上图中红色的框中人的框选区域就是ROI 。
而在Fast RCNN 中,ROI Pooling 作用在backbone 和检测头之间,其关心的是物体检测框的候选框proposal boxes ,而非真正的target boxes ,对proposal boxes 经过置信度评分过滤和极大值抑制后才能生成target boxes 。因此,此时的ROI 指的是候选框proposal boxes 所指的区域。如下图,目标框是准确框出图中的两只狗狗,但通过selective search 或RPN 网络生成的proposal boxes 如图中花花绿绿的框所时,ROI Pooling 和ROI Align 正是作用在这些proposal boxes 所指的ROI 上。
图片来源于https://d2l.ai/chapter_computer-vision/anchor.html
2.ROI Pooling
将深度学习用于目标检测,网络架构一般是分成Backbone 基干网络用于提取图像特征,和检测头用来实现分类和检测框位置回归。2015年4月份微软的Ross Girshick 发表的Fast RCNN 论文中提出了ROI Pooling , 解决了模型固定大小输入的问题,提升了检测的性能,一起来看ROI Pooling 到底是怎么回事。
ROI Pooling 顾名思意,就是池化操作的一种,只不过这个池化操作是作用在ROI 上面,而非整个图像区域。先看fast RCNN 的整体架构,
图片来自fast RCNN 论文
图中Deep ConvNet 是深度卷积网络,也就是backbone 是用来提取特征得到feature map 的,feature map 就是对输入的图像经过层层卷积后得到的shape为NCHW 的张量,其中feature map 的宽高大小通常等于输入图像宽高除以stride ,stride 是输入图像经过卷积池化得到的feature map 的缩放倍数,ROI Pooling 正是紧跟在feature map 后面,作用在feature map 的池化操作。输入图像中红色的框是一个proposal box ,这个proposal box 是selective search 或region proposal network 算法自动生成的ROI 区域,还不是物体检测框bounding box ,proposal boxes 的尺度是相对于输入图像的,因此可根据stride 参数,将其映射到feature map 尺度上,也就是图中的ROI Projection 。得到feature map 和经过stride 缩放投射到feature map 上的proposal box 后,就可以开始进行池化操作了。
从上图中可以看到ROI Pooling 的全过程,绿色虚线框以外的部分是得到proposals 并变换到feature map 上的过程,绿色虚线框内是在1个通道上进行ROI Pooling 的过程。ROI Pooling 与空间金字塔池化Spatial Pyramid Pooling 一样,都是无论输出的WH 大小,指定池化后输入结果的WH ,据此自适应计算池化核的大小,然后在划分后的池化核范围内进行最大值池化或均值池化,如图中绿色框中所示。空间金字塔池化Spatial Pyramid Pooling是何凯明于2014年06月份在微软亚洲研究院时发表的论文Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition 中提出的。ROI Pooling 是作用在每一个proposal 上的,假如是batch size=B , proposals 的数量为N , 则ROI Pooling 后的张量大小为,
B
×
N
×
C
×
H
r
o
i
p
o
o
l
×
W
r
o
i
p
o
o
l
B\times N \times C \times H_{roi pool} \times W_{roi pool}
B×N×C×Hroipool?×Wroipool?在将proposals 投射到feature map 上时,计算结果很有可能是不能整除的,如图中21/32=0.625 ,这时选择近似取整的方法选定proposal 对应的feature map 对应的区域,如上图中将红色的框近似到蓝色框上,这里做了第一次量化取整,引入了误差。在计算自适应池化核大小时,遇到非整除的情况,这里对计算结果进行了向上取整和向下取整的近似,如8/3 通过近似得到池化核区域的大小为3,3,2 ,这里做了第二次量化,引入了误差。
通过以上的说明,有可能依然没有说清除,说明白,最能描述一个算法本身的应该是代码实现,ROI Pooling 的具体代码实现可以参考 github ROI Pooling。
3.ROI Align
从上面介绍中可知ROI Pooling 中有两处对计算结果取了近似,一次是在将proposal 投射到feature map 上时,对浮点数进行了近似取整,另外一次是在进行池化操作计算池化核的大小时也进行了近似取整。这对于分类问题影响不大,但对于检测问题因对检测框进行了近似,会影响检测的定位精度。ROI Align 也是一种池化操作,只不过其不对proposals 映射和池化核大小做近似,而是使用浮点数计算,然后使用双线性插值再近似浮点数位置的值来做池化,比直接近似取整更加准确。ROI Align 是He KaiMing 和Fast RCNN 的原作者Ross Girshick 一起在2017 年03 月份发表的论文Mask RCNN 中的提出的,用于目标检测和实例分割。有个小插曲,2015年Ross Girshick 发表Fast RCNN 时,其署名单位是微软,2017 年署名单位已经是Facebook 的FAIR 了。
还以上图中狗的检测为例,这次直接使用feature map 红色的框进行计算,而不再将其取整近似到蓝色框上。且在绿色框中的池化操作,池化核的大小也采用均分,而非近似的方法。其实现过程如下图:
ROI Align 主要涉及到的是如何求浮点位置的feature map 上的值,其确定是通过双线性插值来实现的,比ROI Pooling 中的取整近似要更准确。关于双线性插值的介绍可参考(五)线性插值,ROI Align 的代码实现可参考:
roi_align_cpu.cpp
其中计算线性插值的函数使用的方式是按邻近4个像素点对当前点贡献多少来决定的,也就是面积加权平均,可参考上面的线性插值介绍的文章。在计算坐标时
const T yy = start_y + ph * b_size_h + static_cast<T>(iy + 0.5f) * b_size_h / static_cast<T>(b_grid_h);
for (int ix = 0; ix < b_grid_w; ++ix) {
const T xx = start_x + pw * b_size_w + static_cast<T>(ix + 0.5f) * b_size_w / static_cast<T>(b_grid_w);
T x = xx, y = yy;
if (y < -1.0 || y > h || x < -1.0 || x > w) {
PreCalc<T> pc{0, 0, 0, 0, 0, 0, 0, 0};
pre_calc[idx] = pc;
idx += 1;
continue;
}
}
通过ROI Pooling 或ROI Align 后得到的张量的宽高同SPPNet ,是固定的,因此其后可以跟全连接层用来实现,检测框类别的判断和更好的位置回归。
欢迎访问个人网络日志🌹🌹知行空间🌹🌹
参考资料
|