Mask R-CNN

Mask R-CNN

论文链接:https://arxiv.org/pdf/1703.06870v3.pdf  ICCV2017的一篇文章

主要贡献: 在faster rcnn的基础上扩展出mask 分支用于实例分割,提出roi align弥补roi pool的misalignment,在计算mask分支的loss的时候predict a binary mask for each class independently, without competition among classes,而不是采用FCN那种的多分类的交叉熵损失。

整体的结构图如下图,简单来说就是对rpn选出的proposal经过ROIAlign,接着经过mask分支进行类别的预测。

 mask rcnn根据是否采用FPN采用了两种结构

 左边是不加rpn的时候的ResNet C4,即在resnet的第四个block进行roialign的操作,接着经过resnet的第五个block,具体实现的时候结构有点不一样(https://github.com/open-mmlab/mmdetection/blob/master/configs/mask_rcnn_r50_caffe_c4_1x.py) 对于resnet C5输出的feature一个是用于faster rcnn的分类与回归,mask分支首先是上采样到14*14接着在conv变成[nums_pos,80,14,14],这里的nums_pos是rcnn对rpn选出的proposal进行target_proposal之后的所有正样本的数目,右边是加了FPN之后的,其实也是类似的,在将roi根据area分配到FPN的不同level进行roialign之后得到的feature分为两个分支,需要注意的是上面的分支用的roialign是RoIAlign(out_size=(7, 7), sample_num=2, use_torchvision=False),所以得到的feature的size是7*7的,而下面的分支用到的roialign是RoIAlign(out_size=(14, 14), sample_num=2, use_torchvision=False),所以得到的feature的size是14*14的,至于为什么会不同还不知道。。。上面的分支同样也是用于faster rcnn的分类与回归,下面的为mask 分支,首先是经过四个14*14*256的conv,至于这里为什么是四个也还不知道。。。,之后也是进行上采样然后在conv成最后的[nums_pos,80,28,28]

 对于faster rcnn中原来的roi pool, 其存在两次整数化,此时的候选框已经和最开始回归出来的位置有一定的偏差,这个偏差会影响检测或者分割的准确度。在论文里,作者把它总结为“不匹配问题”(misalignment)。(来自https://zhuanlan.zhihu.com/p/37998710,讲的比较清楚,可以看看)

 于是有了roi align

 假设roi被分成2*2的bin,每个bin中有四个采样点,每个采样点的值通过线性插值获得,从文中的实验来时四个采样点效果最好,而且就算是一个采样点的效果也和四个的差不多。

以下是来自https://zhuanlan.zhihu.com/p/65321082的一张图可以更好地理解roi align的必要性,红色框和黄色框都框住了目标,但是经过roi pool之后得到的feature map是同一个,所以这个时候网络要对同一个feature去拟合两个框,这就给训练造成了麻烦。

mask rcnn的损失由三部分组成

前两部分就是faster rcnn里面的回归月分类损失,重点在于最后的Lmask.首先是对就是rcnn对rpn选出的proposal进行target_proposal之后的所有正样本进行mask_target(代码来自:https://github.com/open-mmlab/mmdetection

def mask_target_single(pos_proposals, pos_assigned_gt_inds, gt_masks, cfg):
"""
gt_masks[nums_pos, h,w] #这里的nums_pos是rcnn对rpn选出的proposal进行target_proposal之后的所有正样本的数目,h,w对应着原图整幅图的大小标注
pos_proposals[nums_pos,4] #,pos_proposals就是rcnn对rpn选出的proposal进行target_proposal之后的所有正样本的box坐标
pos_assigned_gt_inds[nums_pos] #表示pos_proposals中的每个box对应gt_masks中的那个gt
"""
    mask_size = _pair(cfg.mask_size) #对应到油FPN的mask rcnn中值就是[28,28]
    num_pos = pos_proposals.size(0)
    mask_targets = []
    if num_pos > 0:
        proposals_np = pos_proposals.cpu().numpy() #在cpu上面计算???
        _, maxh, maxw = gt_masks.shape
        #pos_proposas不能超过图像边界
        proposals_np[:, [0, 2]] = np.clip(proposals_np[:, [0, 2]], 0, maxw - 1)
        proposals_np[:, [1, 3]] = np.clip(proposals_np[:, [1, 3]], 0, maxh - 1)
        pos_assigned_gt_inds = pos_assigned_gt_inds.cpu().numpy()
        for i in range(num_pos):
            gt_mask = gt_masks[pos_assigned_gt_inds[i]]
            bbox = proposals_np[i, :].astype(np.int32)
            x1, y1, x2, y2 = bbox
            w = np.maximum(x2 - x1 + 1, 1)
            h = np.maximum(y2 - y1 + 1, 1)
            # mask is uint8 both before and after resizing
            # mask_size (h, w) to (w, h)
            target = mmcv.imresize(gt_mask[y1:y1 + h, x1:x1 + w], #用proposals_np在原图中截取相应区域,最后直接进行resize其实就是调用cv2.resize,这样简单粗暴的方式不会影响精度吗
                                   mask_size[::-1])
            mask_targets.append(target)
        mask_targets = torch.from_numpy(np.stack(mask_targets)).float().to(
            pos_proposals.device)
    else:
        mask_targets = pos_proposals.new_zeros((0, ) + mask_size)
    return mask_targets #[nums_pos,28,28]

接着与gt计算Lmask

def mask_cross_entropy(pred, target, label, reduction='mean', avg_factor=None):
"""
pred[nums_pos,81,28,28] #对应着mask分支的输出
target[nums_pos,28,28] #对应着mask_target之后的结果
label[nums_pos] #表示target中每个pos_proposal对应的真实label
"""
    # TODO: handle these two reserved arguments
    assert reduction == 'mean' and avg_factor is None
    num_rois = pred.size()[0]
    inds = torch.arange(0, num_rois, dtype=torch.long, device=pred.device)
    pred_slice = pred[inds, label].squeeze(1) #在pred中取得label对应的那个mask得到[nums_pos,28,28],本来对于pred每个pos_proposal都有[1,81,28,28]的预测,但是在计算损失的时候只取该pos_proposal真实对应的那个类的mask[1,1,28,28],这样就避免了类间竞争
    return F.binary_cross_entropy_with_logits( #其实就是sigmoid+二分类的交叉熵
        pred_slice, target, reduction='mean')[None]

 最后作者的实验证明FPN,roialign,sigmoid+二分类的交叉熵对于精度都是有很大的提升的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值