Object Detection - Mask R-CNN
在Objective Detection上比较有名的model是R-CNN以它相关的变种。下面简略介绍一下其实现的思路
R-CNN
R-CNN是Region-based Convolutional Neural Networks的缩写。其主要的思路是
- 找一个Pre-trained的CNN network
- 通过selective search为一张图片生成约2000个RoI,每个RoI大小不同
- 由于生成RoI尺寸大小不同,我们需要将它们warp成一个固定大小的矩形,作为后面CNN网络的输入。注意warp相当于对原矩形区域的图片进行缩放,而不是截取。
- 将每一个warp后的RoI输入Pre-trained CNN model得到feature map (fc7)
- 将feature map通过binary SVM classifier进行分类
- 将类型判断正确的RoI进行通过一个bbox regression model进行校正。
整个过程如下图所示
R-CNN虽然能完成目标检测的任务,但是速度却非常的慢
- 有2000个region proposal, 训练需要84小时
- 如果用vGG16,一次inference需要47s
- 整个过程需要三个Model,一个feature extraction的CNN model,一个SVM的classifier和一个bounding box的regression model
Fast R-CNN
为了让R-CNN更快,Fast R-CNN将上面三个model整合成了一个。其流程为
- 找一个Pre-trained的CNN network
- 通过selective search为一张图片生成约2000个RoI,每个RoI大小不同
- 调整Pre-trained的CNN model
- 将model最后一个max pooling layer替换为RoI pooling layer。RoI Pooling会输出一个组fixed-length的feature vectors
- 将model最后一个FC+softmax(K classes)替换为 FC+softmax(K+1 classes)
- model最后有两个输出,分别为
- 每个RoI的class概率
- 一个bbox的regression model用来对RoI进行校正(按照class分类)
总的来说,Fast R-CNN最大的提升在于它对feature map的提取是一次完成的,而不像R-CNN需要将每一个RoI单独计算,这大大节省了计算资源,提高了计算速度
这里我们需要重点了解一下RoI Pooling
RoI Pooling
和R-CNN一样,我们需要为每张图片生成大概2000个RoI。然后用一个Pre-trained CNN model(论文中使用的VGG16)提取图片中的feature。例如,一张(1, 3, 512, 512)
的图片经过CNN网络后得到一组(512, 3, 16, 16)
的feature map。
接下来我们要对从feature maps中提取RoI,由于我们的feature map的大小已经从(512, 512)
变成了(16, 16)
, 我们的RoI区域也要等比例缩小,例如一个(x:296, y:192, h:145, w:200)
的bounding box在feature map中将变成(x:9.25, y:6, h:4.53, w:6.25 )
如下图所示
此时我们发现bbox出现了小数,我们需要其quantize成整数,但是这会损失一部分数据,如下图三所示



接下来我们要对RoI中的像素进行RoI Pooling,其目的是将各种大小不一的bbox映射成长度统一的vector以便进行后面的FC。具体做法是使用max pooling,还是上面的例子,经过quantization后,我们的bbox变成了4x6
的,接下来我们用max pooling把它映射成3x3
的,如下图所示
上图中我们发现最下面一行数据也被丢弃掉了。通过RoI Pooling我们可以得到一组($roi,512,3,3
的feature map,这也是后面FC层的输入,最终通过两层FC我们得到了两个输出结果,一个是RoI的class,另一个是RoI的bbox。
虽然Fast R-CNN可以在training和inference的速度上比R-CNN快,但生成region proposal仍然占据了大部分的时间
Faster R-CNN
显然下一步的优化目标就是将region proposal也整合进网络,这也是Faster R-CNN的设计思路,其流程为
- 找一个Pre-trained的CNN network
Mask R-CNN
Mask R-CNN是基于Faster R-CNN的架构,引入了Instant Segmentation。它除了输出目标物体的类型和bbox意外,还输出一个segmentation mask,其结构如下图所示
由于Mask R-CNN需要生成像素级别的mask,前面提到的RoI Pooling由于损失太多data因此精度大大降低。为了解决这个问题Mask R-CNN对上面RoI pooling的改进,提出了RoI Align。我们下面来重点介绍这个算法
RoI Align
前面已经知道RoI Pooling的两次quantization损失了很多data,RoI Align通过使用双线性二次插值弥补了这一点。还是以前面例子来说明,下图是我们前面的bbox,我们的目标还是对其进行3x3的RoI Pooling操作
和之前不同的是,我们此时不对x,y,w,h进行取整,而是应用双线性插值,具体做法是将RoI区域划分成3x3的格子,然后计算4个点的位置如下图所示
接下来我们便可以使用下面公式对上面的4个点进行双线性插值计算,其中Q值为每个点对应的像素值
下面我们以左上角(9.44, 6.50)
为例,看一下双线性插值是如何计算的。公式里的x,y
分别对应(9.44, 6.50)
。其中(x1, x2, y1, y2)
分别对应四个点邻接cell的中心值,以(9.44, 6.50)
为例,和它最近的cell的中心点为(9.50, 6.50)
,因此x1
为9.5
,y1
为6.50
; 左下角点邻接cell的中心值为(9.50, 7.50)
,由于x1
没有发生变化还是9.5
,而y2
变成了7.5
; 以此类推,我们可以得到右上和右下两个cell的中心点分别为 (10.50, 6.50)
和(10.50, 7.50)
,此时x1,x2,y1,y2
的值均已确定,我们可以套用上面公式计算出(x,y)
点处的值为0.14
。
按照上述方式我们可以为剩余三个点计算其双线性插值结果,如下图所示



当我们结算完这个4个点的双线性插值结果,我们便可以用max pooling得到该区域的RoI Align的结果。
重复上述步骤我们可以得到这RoI Region的结果,如下图所示
理解了RoI Align之后,我们便可以和Fast R-CNN一样对所有的feature map进行RoI Align的操作,得到一组($roi,512,3,3)
的feature map,作为后续layer的输入


和RoI Pooling相比,RoI Align利用了更多RoI Region周围的像素信息(上图中左边绿色部分),因此可以得到更准确的结果