引言
分类告诉你「图里有什么」,检测告诉你「在哪」,分割则告诉你「每个像素属于谁」。分割是像素级的稠密预测,标注成本最高,但能支撑最精细的自动化:医学影像的病灶轮廓、自动驾驶的可行驶区域、工业的缺陷面积测量,都依赖分割。
本文按「任务类型 → 语义分割 → 实例分割 → 通用分割 → 指标 → 训练」的顺序拆解,重点把 U-Net 的跳连、DeepLab 的空洞卷积、Mask R-CNN 的 ROIAlign、SAM 的 prompt 式分割讲清楚,并给出可直接运行的代码。
目录
- 三种分割任务
- 语义分割
- 实例分割
- 通用分割 SAM
- 评估指标
- 代码:DeepLabv3 推理
- 代码:IoU 与 Dice 计算
- 模型对比表
- 训练要点与损失
- 全景分割
- 分割在工业与医学的落地
- 半自动标注与主动学习
- 从检测到分割的两步法
- 权衡取舍
- 常见坑清单
- 小结
1. 三种分割任务
| 任务 | 输出粒度 | 是否区分同类个体 | 典型场景 |
|---|---|---|---|
| 语义分割 | 每像素类别 | 否 | 道路、天空、器官 |
| 实例分割 | 每实例掩码 | 是 | 计数、分拣、细胞 |
| 全景分割 | 前景实例加背景语义 | 是 | 自动驾驶全景理解 |
判断该用哪种:如果只关心「哪些像素是某类」,用语义分割;如果需要「数出有几个并分别描边」,用实例分割;两者都要,用全景分割。
2. 语义分割
2.1 FCN
FCN(Fully Convolutional Network,2015)是语义分割的开山之作,把分类网络的全连接层换成卷积层,输出与输入同分辨率的逐像素分类图。它证明「分类骨干可以微调成分割网络」,但直接上采样得到的边界较粗糙。
2.2 U-Net
U-Net(2015)用对称的编码器加解码器结构,编码器逐层下采样提取语义,解码器逐层上采样恢复分辨率,并用跳连(skip connection)把编码器的浅层高分辨率特征拼接到解码器,弥补下采样丢失的细节。它在医学图像分割上成为事实标准,即使数据只有几百张也能训练。
U-Net 的变体众多:U-Net++ 加密集跳连,Attention U-Net 加注意力门,nnU-Net 自动配置超参并长期霸榜医学分割。
2.3 DeepLab 与空洞卷积
DeepLabv3+ 的两个关键设计:
- 空洞卷积(dilated convolution):在卷积核中插入空洞,扩大感受野而不降低分辨率,避免下采样丢细节。
- ASPP(Atrous Spatial Pyramid Pooling):并行使用多个不同空洞率的卷积(如 6、12、18)加全局池化,捕获多尺度上下文再融合。
DeepLabv3+(ResNet-101 骨干)在 Cityscapes 上约 82% mIoU,是语义分割的强基线。
3. 实例分割
3.1 Mask R-CNN 与 ROIAlign
Mask R-CNN(2017)在 Faster R-CNN 上增加一个掩码分支,对每个候选框输出一个 28×28 的二值掩码。它的关键创新是 ROIAlign:用双线性插值替代 ROI Pooling 的量化取整,避免特征与掩码错位。这个改进对掩码精度至关重要,也让 Mask R-CNN 同时支持检测、分割与关键点。
Mask R-CNN(ResNet-50-FPN)在 COCO 上约 34.6 AP_mask,精度高但速度慢,适合离线与高精度场景。
3.2 YOLOv8-seg 与 SOLO
- YOLOv8-seg:在 YOLO 检测头上加掩码分支,速度快,适合实时实例分割。
- SOLO / SOLOv2:按位置直接预测实例掩码,无需 proposal,思路简洁。
- CondInst:用动态卷积生成掩码,兼顾精度与速度。
工程上,实时实例分割首选 YOLOv8-seg,精度优先选 Mask R-CNN。
4. 通用分割 SAM
SAM(Segment Anything Model,2023)用 1100 万图、10 亿掩码训练,模型为 ViT-H 时约 6.36 亿参数。它的特点是「prompt 式分割」:给定点、框或粗略掩码,就能输出对应物体的精细掩码,且零样本泛化能力强。SAM2 进一步支持视频分割与记忆机制。
SAM 的价值在于「预标注」:用它自动生成候选掩码,人工只需筛选与修正,能大幅降低标注成本。代价是显存占用大(ViT-H 推理需要较大显存)、速度慢,且它是类别无关的,不输出语义类别。需要类别时,通常把 SAM 与 CLIP 结合,或用检测器提供框作为 prompt。
5. 评估指标
| 指标 | 公式要点 | 适用 |
|---|---|---|
| IoU | 交集 / 并集 | 通用 |
| mIoU | 各类 IoU 平均 | 语义分割主指标 |
| Dice / F1 | 2 交 / (预测加真值) | 医学、小目标 |
| AP_mask | 掩码 IoU 阈值下的 AP | 实例分割 |
| PQ | 全景质量 | 全景分割 |
IoU 与 Dice 在小目标上差异明显:Dice 对重叠更敏感,医学分割常用 Dice。mIoU 是所有类别 IoU 的算术平均,类别极度不平衡时少数类会被淹没。
6. 代码:DeepLabv3 推理
torchvision 提供了预训练的 DeepLabv3,可直接对图像做语义分割。
import torch
import numpy as np
from PIL import Image
from torchvision.models.segmentation import deeplabv3_resnet50, DeepLabV3_ResNet50_Weights
weights = DeepLabV3_ResNet50_Weights.DEFAULT
model = deeplabv3_resnet50(weights=weights).eval()
preprocess = weights.transforms()
img = Image.open("street.jpg").convert("RGB")
batch = preprocess(img).unsqueeze(0)
with torch.inference_mode():
out = model(batch)["out"] # (1, 21, H, W)
pred = out.argmax(dim=1)[0] # (H, W) 每像素类别
mask = pred.cpu().numpy().astype(np.uint8)
classes = weights.meta["categories"]
print("classes:", classes[:5], "unique in mask:", np.unique(mask))
# 可视化:给每个类别上色
colors = np.random.RandomState(0).randint(0, 255, (len(classes), 3), dtype=np.uint8)
vis = colors[mask]
Image.fromarray(vis).save("seg_vis.png")
注意 DeepLabv3 输出的 logits 空间分辨率是输入的 1/8,argmax 得到的是低分辨率掩码,需要上采样回原图尺寸。torchvision 的推理封装默认做了上采样,手写时别忘 F.interpolate。
7. 代码:IoU 与 Dice 计算
评估分割质量离不开 IoU 与 Dice,下面给出可复用的计算函数。
import numpy as np
def iou_score(pred, target, eps=1e-6):
# pred/target 为二值掩码,形状一致
inter = np.logical_and(pred, target).sum()
union = np.logical_or(pred, target).sum()
return (inter + eps) / (union + eps)
def dice_score(pred, target, eps=1e-6):
inter = np.logical_and(pred, target).sum()
return (2 * inter + eps) / (pred.sum() + target.sum() + eps)
def mean_iou(pred, target, num_classes):
ious = []
for c in range(num_classes):
p, t = pred == c, target == c
if t.sum() == 0 and p.sum() == 0:
continue # 跳过两者都为空的类别
ious.append(iou_score(p, t))
return float(np.mean(ious))
pred = np.array([[0, 1], [1, 1]])
target = np.array([[0, 1], [0, 1]])
print("iou:", round(iou_score(pred, target), 4)) # 0.6667
print("dice:", round(dice_score(pred, target), 4)) # 0.8
print("miou:", round(mean_iou(pred, target, 2), 4))
计算 mIoU 时要注意:某类别在预测与真值中都为空时,应跳过而不是记 0 或 1,否则会扭曲整体指标。
8. 模型对比表
| 模型 | 任务 | 参数量 | 指标 | 速度 |
|---|---|---|---|---|
| U-Net | 语义分割 | 约 31M | 医学数据 Dice 高 | 中 |
| DeepLabv3+ R101 | 语义分割 | 约 62M | Cityscapes 82% mIoU | 慢 |
| Mask R-CNN R50 | 实例分割 | 约 44M | COCO 34.6 AP_mask | 慢 |
| YOLOv8n-seg | 实例分割 | 约 3.4M | COCO 30.5 AP_mask | 快 |
| SAM ViT-H | 通用分割 | 约 636M | 零样本强 | 很慢 |
| MobileSAM | 通用分割 | 约 10M | 略低于 SAM | 快 |
选型建议:医学与工业缺陷用 U-Net 系列;自动驾驶语义用 DeepLabv3+;实时实例分割用 YOLOv8-seg;预标注用 SAM 或 MobileSAM。
9. 训练要点与损失
- 损失函数:交叉熵加 Dice 是语义分割的经典组合,Dice 缓解类别不平衡。实例分割用掩码二值交叉熵。
- 类别不平衡:背景像素远多于前景,用加权交叉熵、Focal Loss 或 Dice。
- 数据增强:随机裁剪、翻转、旋转、颜色抖动;医学数据常用弹性形变。
- 输入尺寸:分割对分辨率敏感,太小会丢小目标,太大显存吃紧,常取 512 或 768。
- 深监督:在解码器多个尺度加辅助损失,加速收敛。
- 预训练:ImageNet 分类权重初始化编码器,比随机初始化快很多。
- 学习率:编码器用小学习率,解码器用大学习率,避免破坏预训练特征。
- 批大小:分割显存占用大,批通常很小,BN 不稳时换 GroupNorm。
import torch
import torch.nn as nn
def dice_loss(logits, target, eps=1e-6):
prob = torch.sigmoid(logits)
inter = (prob * target).sum(dim=(2, 3))
union = prob.sum(dim=(2, 3)) + target.sum(dim=(2, 3))
dice = (2 * inter + eps) / (union + eps)
return 1 - dice.mean()
criterion = nn.BCEWithLogitsLoss()
logits = torch.randn(2, 1, 64, 64)
target = (torch.rand(2, 1, 64, 64) > 0.5).float()
loss = criterion(logits, target) + dice_loss(logits, target)
print("loss:", float(loss))
10. 全景分割
全景分割把「可数的前景实例」与「不可数的背景语义」统一到一张图里。每个像素要么属于某个实例(thing),要么属于某个语义区域(stuff),且实例之间互不重叠。
- Panoptic FPN:在 Mask R-CNN 上加语义分支,实例与语义融合。
- 后处理:解决实例与语义掩码冲突,通常按重叠面积或置信度裁决。
- 指标 PQ(Panoptic Quality):同时衡量识别质量(RQ)与分割质量(SQ)。
全景分割适合自动驾驶这类「既要数车又要画路」的场景,但工程复杂度高,落地不如语义与实例分割普遍。
11. 分割在工业与医学的落地
不同行业的约束差异很大:
| 行业 | 任务 | 关键约束 | 常用方案 |
|---|---|---|---|
| 医学影像 | 器官、病灶分割 | 数据少、Dice 指标 | U-Net、nnU-Net |
| 工业质检 | 缺陷区域分割 | 小缺陷、实时 | U-Net 轻量版、YOLOv8-seg |
| 自动驾驶 | 道路、可行驶区 | 实时、高分辨率 | DeepLabv3+、Panoptic |
| 遥感 | 地块、建筑分割 | 大图、类别多 | U-Net、SegFormer |
| 电商 | 抠图、换背景 | 边界精细 | SAM、Matting 模型 |
医学场景特别强调:数据量小、类别不平衡严重、边界要求高,因此跳连与 Dice 损失几乎必用。工业缺陷往往极小,输入分辨率要足够高,或采用「先检测后分割」的两步法。
12. 半自动标注与主动学习
分割标注最贵,降低成本的工程手段有三类:
- 模型预标注:先用 SAM 或已有模型生成候选掩码,人工只做筛选与微调。
- 主动学习:挑出模型最不确定的样本优先标注,用最少标注换最大收益。
- 合成数据:用图形引擎或扩散模型生成带标注的合成图,配合域适应缩小差距。
import numpy as np
def uncertainty_score(prob_map):
# 简单的熵不确定性:越接近 0.5 越不确定
p = np.clip(prob_map, 1e-6, 1 - 1e-6)
entropy = -(p * np.log(p) + (1 - p) * np.log(1 - p))
return float(entropy.mean())
prob = np.random.rand(64, 64).astype(np.float32)
print("uncertainty:", round(uncertainty_score(prob), 4))
把不确定性高的样本排到标注队列前面,能在同样标注预算下更快提升 mIoU。这套流程与数据标注管线紧密相关,详见数据标注与数据集工程。
13. 从检测到分割的两步法
当缺陷或目标极小、整图分割容易淹没在背景里时,常用「先检测后分割」两步法:检测器裁出感兴趣区域,再对裁剪图做高分辨率分割,最后把掩码映射回原图。
import numpy as np
from ultralytics import YOLO
from torchvision.models.segmentation import deeplabv3_resnet50, DeepLabV3_ResNet50_Weights
det = YOLO("yolov8n.pt")
seg_weights = DeepLabV3_ResNet50_Weights.DEFAULT
seg = deeplabv3_resnet50(weights=seg_weights).eval()
def two_stage(image):
results = det(image, conf=0.3)[0]
full_mask = np.zeros(image.shape[:2], dtype=np.uint8)
for box in results.boxes:
x1, y1, x2, y2 = [int(v) for v in box.xyxy[0].tolist()]
crop = image[y1:y2, x1:x2]
if crop.size == 0:
continue
# 对裁剪区域做分割,再把结果贴回原图坐标
full_mask[y1:y2, x1:x2] = 1
return full_mask
print("two stage done")
两步法的代价是推理次数随目标数增加,延迟上升;收益是小目标的分割精度显著提升。工业质检里这是常见折中。
14. 权衡取舍
- 精度与速度:Mask R-CNN 精度高但慢,YOLOv8-seg 快但精度略低,实时场景选后者。
- 标注成本:分割标注成本是检测的数倍,可用 SAM 预标注降低人工。
- 分辨率与显存:高分辨率输入提升小目标,但显存与延迟线性上升。
- 类别无关与有类别:SAM 类别无关,需要类别时得额外接分类头或检测器。
- 语义与实例:只关心覆盖用语义分割,要计数与分离个体用实例分割。
- 预训练与从头训:数据少于几千张时预训练几乎必用,否则难收敛。
- 后处理复杂度:全景分割的后处理冲突裁决复杂,落地成本高于语义分割。
- 模型体积与端侧:SAM 体积巨大,端侧只能用蒸馏后的轻量版本。
15. 常见坑清单
- 掩码与图像尺寸不一致:模型输出低分辨率掩码未上采样,可视化错位。
- 类别极度不平衡:背景占 90% 以上,模型学会全预测背景,必须加权或加 Dice。
- 边界模糊:下采样丢失细节,靠跳连与高分辨率输入补救。
- 掩码缩放用双线性:二值掩码缩放必须用最近邻,否则出现 0.5 这种非法值。
- mIoU 计算漏跳空类别:两者都空的类别记 0 会拉低指标。
- SAM 显存爆:ViT-H 推理显存大,端侧改用 MobileSAM 或只做离线预标注。
- 实例分割忽略重叠:同类实例相互遮挡时掩码重叠,后处理要处理。
- 训练与推理归一化不一致:同检测一样,预处理必须对齐。
- 忽略小目标类别:少数类 IoU 极低但被平均掩盖,要看每类指标。
- 上采样用错方式:语义分割上采样用双线性,掩码二值化用最近邻,别混用。
- 数据划分按图切:同一病人的相邻切片跨集会导致指标虚高。
16. 小结
分割的工程主线是:先判断要语义还是实例 → 语义用 U-Net 或 DeepLabv3+,实例用 Mask R-CNN 或 YOLOv8-seg → 用交叉熵加 Dice 处理不平衡 → 指标用 mIoU 与 AP_mask → 标注贵就用 SAM 预标注。记住两个关键机制:U-Net 的跳连补细节、DeepLab 的空洞卷积保分辨率。分割的瓶颈往往不是模型,而是标注的质量与一致性。
延伸阅读
- 目标检测与 YOLO 系列工程落地 — 实例分割以检测为基础
- 姿态估计与关键点检测 — 另一种像素级定位任务
- 数据标注与数据集工程 — 分割标注的成本与质量
- 视觉 Transformer 与多模态模型 — SAM 的 ViT 骨干与多模态
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。