为什么MaskRcnn在fastRcnn的基础上加上FCN能实现实例分割?
在学习maskRcnn的时候找的资料大多讲述了这个算法是在FastRcnn的基础上添加FCN全卷积网络实现的实例分割,但是FCN是做语义分割的,所查找的资料并没有说明为什么加上FCN能够实现实例分割。接下来开始简述我对这个问题的理解。
1. 在数据标签上的不同
在maskRcnn算法的标签标准上,标签是对每一个实例都给一个掩膜,不管这些实例是否为同一类。
在FCN中,标签只需要给出相同类别的掩膜。
这两种标签在每个实例完全分开的情况下没有区别,但是在相同类别的实例相粘黏的时候区别就相对较大,如下图一所示:
2. 在数据加载处理时候不同
2.1 maskrcnn掩膜加载
Maskrcnn在加载标签掩膜的时候会先生成一个tensor.shape(图片宽度,图片高度,实例个数),将每一个实例以bool类型的形式写入到这个tensor中,true代表这个像素点输入这个实例,false代表这个像素点不属于这个实例。
例如:假设标签图片大小为1024×1024,标签图片中有28个实例标签,则生成tensor.shape(1024,1024,28),图二为该步骤实现的部分代码:
2.2 FCN数据加载
FCN的标签数据是一张csv的掩膜图片,首先对这张CSV图片进行编码,将图片的每一个像素点的RGB三通道的值经过编码映射成一个整数,最后生成一个tensor.shape(图片的宽,图片的高)。
例如:图三为FCN的标签,假设紫蓝色的RGB值为(64,0,128)类别为人行车道,紫红色的RGB值为(128,64,128)类别为机动车道。
经过哈希编码将紫蓝色的RGB(64,0,128)这三个值映射成数值4194432,这个数值代表行人车道类,记为1;将紫红色的RGB(128,64,128)映射成数值8405120,这个数字记为机动车道,记为2;
将上述的值放到一个哈希表中,也就是python中的字典,例如hash={1:4194432;2:8405120}。
最终形成一个二维度的一个tensor,tensor的shape就是图片的长宽,然后用映射的数填充,得到一个只有4194432,8405120这两个数的二维tensor。然后通过hash查找对应的类别最终得到的标签如图四。
3. 损失函数的计算不同
3.1 maskrcnn
Maskrcnn用的是二值交叉熵损失,在计算损失函数的时候,输入数据为预测的感兴趣区域(ROI),得到每个感兴趣区域的预测类别,计算这些感兴趣区域与标签样本同类别实例的IOU,与IOU最大的那个实例的mask做交叉熵损失。
例如:加入预测出的一个感兴趣区域的类别为1,则选取标签的时候只计算这个感兴趣区域与标签样本所有类别为1的实例的IOU,然后选择最大的那个做损失计算。
Maskrcnn的整体流程如下图五:
有一个问题就是可能预测出的感兴趣区域和标签样本的mask得到的box的大小不一样,在代码中了解到的是当选择了iou最大的那个标签后将标签这个box区域做一个resize得到和感兴趣区域的shape相同,不够的用0填充,然后在进行损失计算。这部分代码如下图六,函数路径:mrcnn/model.py:
3.2 FCN
FCN因为是做语义分割,所以不需要分开去对每一个实例做损失计算,由2.2所述,FCN的标签样本是一个与图片宽高相同shape的一个二维tensor,所以它的损失计算直接将预测出的结果与标签做二值交叉熵损失。
总结
总的来说,maskrcnn上述的所有操作的目的实际上就是为了对每个实例进行二值交叉熵损失,在FCN的基础上将各个类的实例分开进行像素级的分割。
以上就是我对这个问题的理解,如有错误,欢迎指出。