- ROI Pooling 的局限性分析
在常见的两级检测框架(比如Fast-RCNN,Faster-RCNN,RFCN)中,ROI Pooling 的作用是根据预选框的位置坐标在特征图中将相应区域池化为固定尺寸的特征图,以便进行后续的分类和包围框回归操作。由于预选框的位置通常是由模型回归得到的,一般来讲是浮点数,而池化后的特征图要求尺寸固定。故ROI Pooling这一操作存在两次量化的过程。
-
将候选框边界量化为整数点坐标值。
-
将量化后的边界区域平均分割成 k x k 个单元(bin),对每一个单元的边界进行量化。
事实上,经过上述两次量化,此时的候选框已经和最开始回归出来的位置有一定的偏差,这个偏差会影响检测或者分割的准确度。在论文里,作者把它总结为“不对齐问题(misalignment)”。
下面我们用直观的例子具体分析一下上述区域不对齐问题。如 图1 所示,这是一个Faster-RCNN检测框架。输入一张800×800的图片,图片上有一个665×665的包围框(框着一只狗)。图片经过主干网络提取特征后,特征图缩放步长(stride)为32。因此,图像和包围框的边长都是输入时的1/32。800正好可以被32整除变为25。但665除以32以后得到20.78,带有小数,于是ROI Pooling 直接将它量化成20。接下来需要把框内的特征池化7×7的大小,因此将上述包围框平均分割成7×7个矩形区域。显然,每个矩形区域的边长为2.86,又含有小数。于是ROI Pooling 再次把它量化到2。经过这两次量化,候选区域已经出现了较明显的偏差(如图中绿色部分所示)。更重要的是,该层特征图上0.1个像素的偏差,缩放到原图就是3.2个像素。那么0.8的偏差,在原图上就是接近30个像素点的差别,这一差别不容小觑。
引起这个定位不准确的核心原因,就是这个取整操作,所以,解决的办法也很简答
保持ROI在特征层上的小数部分,这样特征图尺寸反推原图尺寸的时候就是准确的。
比如,输入尺寸512×512,目标框200×145,经过VGG16的特征提取,特征图尺寸变成16×16,目标区域特征变成6.25×4.53,左上角坐标变成:(9.25,6),如果是roi pooling 操作,这里就直接取整,那么目标框的特征直接在特征图上粗暴的对齐了,但是就是反推的时候,会造成有一定像素的偏移(小目标比较明显)。
这张图,橘色部分就是粗暴的ROI Pooling 实现的结果。
2.如何实现浮点数的ROI
我们可以通过将原始RoI划分为9个相等大小的框并在其中每个框内应用双线性插值来跳过它。然后定义框:
每个盒子的大小取决于映射的RoI的大小和池化层的大小。我们使用的是3x3池化层,因此我们必须将映射的RoI(6.25x4.53)除以3。这使我们得到一个具有1.51高度和2.08宽度的框(我在这里舍入数值是为了使其更容易)。现在我们可以将盒子放入映射的RoI中:
如果查看第一个框(左上方),您会注意到它覆盖了六个不同的网格单元。为了提取池化层的值,我们必须从中抽取一些数据。要采样数据,我们必须在该框内创建四个采样点。
您可以通过将框的高度和宽度除以3来计算每个点的位置。
在我们的例子中,我们正在计算第一个点(左上角)坐标,如下所示:
- X = X_box +(width / 3)* 1 = 9.94
- Y = Y_box +(高度/ 3)* 1 = 6.50
要计算第二点(左下方),我们只需要更改Y:
- X = X_box +(width / 3)* 1 = 9.94
- Y = Y_box +(高度/ 3)* 2 = 7.01
现在,当我们拥有所有点时,可以将双线性插值应用于此框的采样数据。双线性插值通常用于图像处理中以对颜色进行采样,其等式如下所示:
当您从方框中选取第一个点时,就是将其与最近的相邻单元格连接(恰好位于中间),除非已被取下。在这种情况下,我们的点的坐标为(9.44,6.50)。单元格在左上方向上最靠近中间的位置是(9.50,6.50)(如果我们的点在网格上仅高出0.01,则将是(9.50,5.50)。然后我们必须选择一个左下角的点,最接近的是(9.50,7.50)。遵循相同的规则,我们选择(10.50,6.50)和(10.50,7.50)作为右上和右下点。在RoI上方,您可以看到整个计算以获得第一个点的值(0.14)。
这次我们从:
左上方:(10.50,6.50)
左下角:(10.50,7.50)
右上角:(11.50,6.50)
右下角:(11.50,7.50)
左上方:(9.50,6.50)
左下角:(9.50,7.50)
右上角:(10.50,6.50)
右下角:(10.50,7.50)
最后一个点:
左上方:(10.50,6.50)
左下角:(10.50,7.50)
右上角:(11.50,6.50)
右下角:(11.50,7.50)
现在我们已经计算了所有点,可以在它们上应用最大池化(如果需要,可以是平均池化):
我不会向您展示所有插值,因为这将花费很长时间,并且您可能已经知道如何进行插值。我将向您展示使用RoIAlign从该RoI池中收集数据的整个过程如何工作:
过程适用于每一层,因此最终结果包含512层(与要素地图输入相同)
如果比较RoIAlign和RoIPooling的数据丢失/数据增益,您应该看到RoIAlign使用整个区域来汇总来自以下方面的数据:
- 绿色表示用于合并的其他数据。
- 蓝色(两个阴影)表示合并时数据丢失。
3. RoIWarp
RoIWarp的思想与RoIAlign大致相同,唯一的区别是RoIWarp正在将RoI映射量化为特征图。
4. ROI Align 的反向传播
常规的ROI Pooling的反向传播公式如下:
这里,xi代表池化前特征图上的像素点;yrj代表池化后的第r个候选区域的第j个点;i*(r,j)代表点yrj像素值的来源(最大池化的时候选出的最大像素值所在点的坐标)。由上式可以看出,只有当池化后某一个点的像素值在池化过程中采用了当前点Xi的像素值(即满足i=i*(r,j)),才在xi处回传梯度。
类比于ROIPooling,ROIAlign的反向传播需要作出稍许修改:首先,在ROIAlign中,xi*(r,j)是一个浮点数的坐标位置(前向传播时计算出来的采样点),在池化前的特征图中,每一个与 xi*(r,j) 横纵坐标均小于1的点都应该接受与此对应的点yrj回传的梯度,故ROI Align 的反向传播公式如下:
上式中,d(.)表示两点之间的距离,Δh和Δw表示 xi 与 xi*(r,j) 横纵坐标的差值,这里作为双线性内插的系数乘在原始的梯度上。
5.结果对比
更新log:
2021年10月4日20:19:14 更新部分公式显示问题,翻译文字修正。
参考博客:
Understanding Region of Interest - Part 2 (RoI Align)
youtube:4 Mask RCNN Arc.(Part3) - How RoI Pooling, RoI Warping & RoI Align Work
youtube:hekaiming @ Mask R-CNN