第293篇 实例分割Mask R-CNN——不仅要分类,还要抠出来
语义分割聊完了,这篇讲实例分割。语义分割给每个像素一个类别,但不区分同类别的不同个体——两个人都是"人"这个类别。实例分割不仅区分个体,还要把每个个体的轮廓精确地分割出来。
机器人抓取场景里,实例分割非常关键。你要抓桌上的苹果,不仅要检测苹果在哪里,还要知道苹果的精确轮廓,才能规划合适的抓取姿态。语义分割做不到区分个体,实例分割可以。
Mask R-CNN是实例分割的里程碑工作,2017年由何恺明等人提出,发表在ICCV 2017上并获得最佳论文奖。面试中实例分割几乎必问Mask R-CNN——架构怎么设计的、mask分支怎么加的、RoI Align解决了什么问题。
一、从语义分割到实例分割
语义分割和实例分割的区别:语义分割把所有"人"的像素标为同一类。实例分割要把第一个人和第二个人分开——每个人有独立的mask。
实现实例分割的思路有几种:先检测后分割(Mask R-CNN)、先分组后分割(基于embedding的方法)、端到端预测(SOLOv2)。Mask R-CNN是目前最成熟、用得最多的方案。
二、Mask R-CNN架构
Mask R-CNN在Faster R-CNN的基础上加了一个mask预测分支。整体架构分三步。
Backbone + FPN:用ResNet+FPN提取多尺度特征。FPN生成5个尺度的特征图(P2-P6),不同大小的目标在不同尺度的特征图上检测。
RPN(区域提议网络):在FPN特征图上生成候选区域(proposals)。RPN在每个位置预测多个anchor的前景/背景分数和框偏移。筛选出高分的proposals作为后续处理的输入。
# Mask R-CNN架构概要
class MaskRCNN(nn.Module):
def __init__(self):
self.backbone = ResNet50_FPN()
self.rpn = RegionProposalNetwork()
self.roi_head = RoIHead(
cls_head=nn.Linear(256, num_classes),
bbox_head=nn.Linear(256, 4),
mask_head=MaskBranch(num_classes) # 新增的mask分支
)
RoI Head:对每个proposal做分类、框回归和mask预测。分类和框回归跟Faster R-CNN一样。新增的mask分支是一个小型的FCN——对每个RoI预测一个K通道(K=类别数)的mask,每个通道对应一个类别的二值mask。
mask分支的结构:4个3x3卷积(256通道)+ 1个2x2转置卷积(上采样2倍)+ 1个1x1卷积(输出K通道)。输入是RoI Align后的14x14特征图,输出是28x28xK的mask。28x28的分辨率看起来不高,但对于大多数物体已经够用了。如果需要更精细的mask,可以用Mask Scoring R-CNN等改进方案。
每个RoI只预测对应类别的mask,其他类别的mask不关心。训练时mask loss只对正确的类别计算——这样不同类别的mask预测不会互相干扰。
三、RoI Align:关键创新
Mask R-CNN最核心的技术贡献是RoI Align。
Faster R-CNN用的是RoI Pooling——把每个proposal映射到特征图上,然后划分成固定大小的网格,每个网格取最大值。问题是映射过程中有量化(取整),导致mask的位置偏差几个像素。对分类影响不大,但对像素级的mask预测影响很大。
RoI Align去掉了量化——用双线性插值代替取整。映射后的浮点坐标不取整,而是用周围4个像素的加权平均值。这样mask的位置精度大幅提升。
# RoI Align的核心思想
# 不用int(floor(x))取整,而是用双线性插值
def bilinear_interpolate(feature_map, x, y):
x0, y0 = floor(x), floor(y)
x1, y1 = x0 + 1, y0 + 1
# 四个角的加权平均
val = (feature_map[y0,x0] * (x1-x) * (y1-y) +
feature_map[y0,x1] * (x-x0) * (y1-y) +
feature_map[y1,x0] * (x1-x) * (y-y0) +
feature_map[y1,x1] * (x-x0) * (y-y0))
return val
RoI Align看起来是个小改动,但对mask精度的提升非常大。论文里的消融实验显示,RoI Pooling换RoI Align,mask AP提升了2.5个点。
四、训练与推理
训练时,每个RoI和GT的匹配用IoU阈值。IoU>0.5的是正样本。正样本同时训练分类、框回归和mask三个损失。mask损失用sigmoid+BCE(每个像素独立做二分类),不像分类用softmax(因为一个mask里可能有多个类别的像素)。
三个损失的权重:分类loss权重1,框回归loss权重1,mask loss权重1。mask loss是对28x28的mask做平均,所以实际梯度比另外两个小。有人发现把mask loss权重提高到2效果更好。
数据增强方面,除了常规的水平翻转和颜色抖动,实例分割还需要对mask做相应的变换。翻转图像的同时也要翻转mask。缩放图像的同时也要缩放mask。Mosaic增强也适用于实例分割训练。
推理流程:RPN生成proposals → RoI Head对每个proposal做分类和框回归 → 用NMS筛选最终检测结果 → 对每个检测框生成mask → mask阈值化(通常0.5)得到最终分割结果。
Mask R-CNN的推理速度不快——每张图大约200-400ms(取决于backbone和proposal数量)。实时场景需要用更轻量的backbone或者用YOLO+分割的方案。
五、后续发展与替代方案
Mask R-CNN之后,实例分割领域还有不少重要工作。
SOLOv2:不用proposal,直接预测。把图像分成网格,每个网格负责预测中心点落在其中的物体的mask。速度比Mask R-CNN快很多,接近实时。
YOLACT:实时实例分割。把mask预测分解为两步——先预测一组原型mask(prototype masks),再预测每个实例的mask系数(mask coefficients),两者线性组合得到最终mask。在Titan Xp上达到30fps以上。
YOLOv8-Seg:YOLOv8的分割版本。在YOLOv8检测头的基础上加了mask分支。继承了YOLO的速度优势,同时支持实例分割。工业界用得越来越多。
六、面试高频追问
Q:Mask R-CNN的mask分支为什么用K个通道而不是1个? A:K个通道每个对应一个类别。预测时先知道类别(分类头输出),再用对应类别的通道作为mask。这样每个类别有独立的mask预测器,不同类别的mask不会互相干扰。如果用1个通道,不同类别的mask会混在一起。
Q:实例分割和全景分割有什么区别? A:全景分割=实例分割+语义分割。"东西"类(stuff,如天空、地面)用语义分割,"个体"类(thing,如人、车)用实例分割。两者合在一起就是全景分割。Panoptic FPN是代表性工作。
Q:Mask R-CNN在机器人抓取中怎么应用? A:用Mask R-CNN分割出每个物体的精确轮廓,然后结合深度信息得到物体的3D形状。有了物体的分割mask和3D信息,就可以计算抓取点、规划抓取姿态。这是机器人抓取pipeline中的感知环节。
Mask R-CNN是实例分割的经典方案。架构设计、RoI Align创新、训练推理流程、后续发展方案、机器人应用,这五个方面理解了,实例分割的核心知识就掌握了。实例分割在机器人抓取中应用广泛,值得深入学习。下一篇我们聊6D位姿估计。
实例分割Mask R-CNN是机器人视觉感知的重要技术。从语义分割到实例分割、Mask R-CNN架构设计、RoI Align核心创新、训练推理与后续发展,这四个维度全面覆盖了实例分割的核心内容。
下一篇聊6D位姿估计。
如果这篇文章对你有帮助,欢迎点赞支持一下,你的鼓励是我持续更新的动力!
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)