signed

QiShunwang

“诚信为本、客户至上”

[Extensive Reading]目标检测(object detection)系列(十五) Mask R-CNN:检测与分割结合

2021/6/9 1:26:07   来源:

简介

Mask R-CNN 是在2017年提出,是FAIR团队的Kaiming大神和RBG大神的强强联手之作。paper的名字非常简洁,就叫Mask R-CNN,R-CNN系列确实可以独树一帜。
Mask R-CNN无论是在方法创新上还是工程实现上,都非常具有影响力,首先是ICCV2017的best paper,其次FAIR团队的maskrcnn-benchmark项目也被很多人使用和改进,并作为其它工作的codebase model,现在,一方面由于maskrcnn-benchmark不再更新,以及detectron2和mm-detection的出现,maskrcnn-benchmark的被使用程度才逐渐下滑。

Mask R-CNN原理

在这里插入图片描述

Mask R-CNN是以Faster R-CNN为基础的工作,它的目标检测部分的结构与Faster R-CNN完全相同,细节上在于ROI Heads中的特征图resize操作,Mask R-CNN换成了RoIAlign,而不是使用Faster R-CNN的RoI Pooling 。
根据Faster R-CNN的结构,RPN进行区域建议输出后,会在最后一层的feature map上crop出不同shape的子特征图,如果想要接入下一层参数(det分支与mask分支),并输出为统一的维度的话,就必须将其reshape到一个固定的size(fixed size feature map)。
根据上图所示,这个改变后的reshape方法,也同样作用到了目标检测的class和box上。

Mask分支

此外,就是最重要的Mask分支,掩码分支是一个卷积网络,取 ROI 分类器选择的正区域为输入,并生成它们的掩码。其生成的掩码是低分辨率的:28x28 像素。但它们是由浮点数表示的软掩码,相对于二进制掩码有更多的细节。掩码的小尺寸属性有助于保持掩码分支网络的轻量性。在训练过程中,Mask R-CNN将真实的掩码缩小为 28x28 来计算损失函数,在推断过程中,我们将预测的掩码放大为 ROI 边框的尺寸以给出最终的掩码结果,每个目标有一个掩码。
Mask R-CNN主要以Faster R-CNN为基础,paper给出的结构图也非常简单,下图可以比较详细的看到Mask R-CNN的每部分构成
在这里插入图片描述

RoIAlign

Mask R-CNN之所以需要RoIAlign,本质上是由于RoI Pooling的不匹配问题(misalignment),在RoI Pooling中,RPN在roi head前的feature map上映射了一块区域,RoI Pooling首先需要把这个值取证,以扣取出与像素对齐的feature map,但是一般检测网络的backbone都会下采样最大到32倍,经过32倍步长的放大,这个不对称对应回原图时误差也会变大。
其次,RoI Pooling会根据fixed size对扣取的feature map进行切块,每个block内进行max pooling,这个时候,就会又一次面临取证问题,这造成了第二次不匹配。
RoI Pooling之所以这么做,主要是由SPP演化而来,RoI Pooling保证了fixed size的同时解决了梯度回传问题,同时对于目标检测没有很大的影响,所以在Faster R-CNN使用。
但是Mask R-CNN的分割需要达到像素级,RoI Pooling的两次不匹配导致候选框已经和最开始RPN选择出来的位置有一定的偏差,在这个有偏差的特征图进行分割,势必会影响准确度。
为了解决这个问题,Mask R-CNN引入了RoIAlign。RoIAlign虽然也使用了max pooling操作,但是是应用双线性内插值法解决取证后的不匹配问题,具体为,不再量化取整的选择一个特征图,而是在RPN的输出结果上(浮点数)直接进行分块操作,并在分块后的每一个块内进行max pooling操作。
在每个块内,Mask R-CNN选择再次划分为bin,这个操作很像hog,bin的数量为4时,实验效果是最好的,再一次浮点计算后,就能得到每个bin的浮点数坐标,这个浮点数最终会应用双线性内插值进行计算得到。
在这里插入图片描述

损失函数

需要注意的是,Mask R-CNN是一个实例分割级别的方法,而不是语义分割,但是由于检测部分的类别输出,Mask R-CNN的分割分支其实不需要关注实例问题,而且可以不关注类别问题,而是直接将instance的问题交RPN和目标检测的reg分支,将类别问题交给目标检测class分支。
具体为,Mask R-CNN将不同类别的mask映射到channel维度上,对于每一个RoIAlign后的特征都输出channel为80的特征图,并在每个通道上的每个像素点用sigmod函数进行求相对熵,得到平均相对熵误差Lmask。对于每一个ROI,如果检测得到ROI属于哪一个分类,就只使用哪一个分支的相对熵误差作为误差值进行计算。(举例说明:分类有3类(猫,狗,人),检测得到当前ROI属于“人”这一类,那么所使用的Lmask为“人”这一分支的mask。)这样的定义使得我们的网络不需要去区分每一个像素属于哪一类,只需要去区别在这个类当中的不同分别小类。最后可以通过与阈值0.5作比较输出二值mask。