1. 从需求出发检测和分割为什么值得塞进同一个网络1.1 分开跑两个模型的真实痛点刚接触这个需求的时候我第一反应也是检测归检测分割归分割各跑各的不就行了。真上手做项目才发现这套思路在稍复杂的场景里就撑不住了。比如做工业表面缺陷检测你既要知道哪里有一块缺陷目标检测给框又要知道这块缺陷的形状和面积有多大分割给像素级掩码如果拆成两个独立模型问题立刻冒出来。最直接的是算力翻倍。检测模型跑一遍骨干网络提取特征分割模型又要跑一遍自己的骨干同一张图被两套卷积网络反复咀嚼GPU 显存和推理时间几乎线性叠加。我在一块消费级显卡上试过 YOLOv5 检测加一个轻量分割网络串行跑单帧耗时直接从 20 毫秒飙到 60 毫秒以上产线传送带的速度根本跟不上。其次是流程割裂带来的误差累积。两阶段方案里分割通常要先等检测框出来再把框内的区域裁剪出来喂给分割头。一旦检测框没框准、漏检或者框偏了后面分割再准也是白搭这叫级联误差。而且两套模型往往用两套预处理参数、两套归一化方式部署时要维护两份代码、两份权重、两套版本管理工程上非常难受。所以把目标检测和实例分割合并到一个网络里最核心的动机就是共享计算、端到端输出、减少级联误差。这不是为了炫技是被延迟、显存和部署复杂度逼出来的工程选择。1.2 多任务合并的三种常见路线在实际落地中把检测和分割合到一起大致有下面三种组合方式各有取舍双骨干各自独立检测一个网络分割一个网络只是打包在一个推理进程里。优点是每个任务都能单独调优到极致缺点是算力和显存几乎不共享合并的意义不大。共享骨干加双头一条骨干加一个特征融合层neck挂两个头一个头输出边界框和类别另一个头输出掩码。这是当前最主流、性价比最高的方案也是 YOLOv5 系列做实例分割的典型做法。检测框驱动轻量分割头先出检测框再在特征图上对每个框做 ROI 对齐送进一个小分割头。本质上还是两阶段速度一般但精度在某些细粒度任务上更稳。我这篇主要聊第二种也就是共享骨干加双头这条路线因为它是工程上最平衡的选择改动量小、速度快、精度够用特别适合已经用 YOLOv5 做检测、现在想顺手把分割一起做掉的朋友。2. 结构拆解骨干共享与双头并行到底怎么搭2.1 骨干和特征融合层为什么可以直接复用YOLOv5 的骨干网络是 CSPDarknet配合 PANet 做多尺度特征融合输出三个尺度的特征图通常记作 P3、P4、P5分别对应输入尺寸的 1/8、1/16、1/32。这三个尺度的特征本身就富含语义和位置信息检测头正是在它们上面预测的。关键点在于分割同样需要多尺度特征。小目标的掩码依赖高分辨率的 P3大目标依赖语义更强的 P5。既然检测头已经把这三个尺度的特征用起来了分割头完全可以复用同一批特征图不用再训练一套骨干。这就省掉了绝大部分参数量和计算量也是共享骨干加双头能提速的根本原因。我当时对比过如果分割单独训一个骨干整个模型参数量大概翻 1.6 倍而共享骨干再加一个分割头参数量只增加约 8% 到 12%推理速度下降不到 15%。这个账一算共享骨干的优势就非常明显了。2.2 分割头的原型掩码设计分割头怎么输出一张掩码是这套方案里最需要理解的部分。直接让网络对每个目标回归一整张 H×W 的掩码是行不通的参数太多、训练不稳定、还无法适应任意数量的目标。成熟做法借鉴了原型掩码的思路先让网络生成一批全局原型掩码prototype masks比如 32 张尺寸为输入 1/4 分辨率的特征图然后每个检测框再额外预测一组掩码系数mask coefficients维度同样是 32。推理时用某个框的 32 个系数去线性组合那 32 张原型掩码得到一个该框专属的掩码再按框的位置裁剪到边界框内最后做一次 sigmoid 归一化得到二值掩码。打个比方原型掩码像是调色盘上的 32 种基础色掩码系数像是每个目标需要的配色比例乘一乘加一加就调出这个目标独有的颜色。这种设计的好处是参数量可控而且原型掩码在所有目标间共享天然适合一张图里有多个目标的实例分割。我实测下来原型数量取 32 是个经验值取 16 时细节会明显丢失尤其小目标边缘发糊取 64 时精度提升有限但显存涨得较快。所以 32 基本是精度和开销的甜点区。2.3 检测头和分割头的输出对齐既然两个头共享特征就要保证它们输出的东西能对得上。检测头的每个预测位置输出了边界框偏移、目标置信度和类别分割头在这里额外多输出一个 32 维的掩码系数向量。也就是说检测头原本的输出通道数要相应扩展。这里有个容易踩的坑掩码系数必须和检测结果一一对应。经过非极大值抑制之后保留下来的那些框它们的系数向量也要同步筛选出来不能错位。我一开始图省事两个头分别做筛选结果掩码和框完全对不上号出来的效果就是框在这儿、掩码在那儿的诡异画面。正确做法是让掩码系数跟着检测输出一起走在同一个张量里做筛选保证索引一致。3. 数据集准备标注格式与目录结构那些事3.1 检测标注和分割标注必须严格一致要做联合训练检测用的边界框标注和分割用的掩码标注必须是同一批图片、同一个目标。检测标注用 YOLO 的经典格式每张图对应一个 txt 文件每行是类别 id 加归一化的中心点 x、中心点 y、宽、高。分割标注则是每张图一张同名的二值或索引掩码图通常用 png 保存像素值代表类别。最容易出问题的地方是框和掩码对不齐。有些标注工具导出的框是紧贴掩码外接矩形的有些则留了余量如果两者偏差太大训练时网络会学得别扭推理出来的掩码要么被框切掉一块要么框里空荡荡。我的做法是掩码生成后统一用脚本重算一遍外接矩形覆盖原来的检测框确保框和掩码严格绑定。这一步看似多余实际能省掉后面一大堆调参时间。3.2 目录结构与数据集配置目录结构建议保持 YOLOv5 的习惯方便直接复用现成的训练脚本dataset/ images/ train/ val/ labels/ train/ val/ masks/ train/ val/图片和标注 txt 分别放在 images 和 labels 下掩码单独放 masks 下文件名和图片保持一致只是扩展名不同。数据集配置文件里除了常规的路径、类别数、类别名还要额外指定掩码目录的位置。这里提醒一句路径尽量用绝对路径或相对项目根目录的路径我在不同机器上迁移项目时因为用了相对当前工作目录的路径结果训练脚本在别的目录启动就找不到掩码排查了半天才反应过来。3.3 数据增强必须同步作用于掩码数据增强是这套方案里我最想强调的坑。YOLOv5 默认开启 mosaic、随机翻转、缩放、色域扰动等增强。对检测来说只要把框跟着变换就行但对分割来说掩码图必须和图片做完全相同的几何变换少一步都会错位。具体来说随机水平翻转时图片翻了掩码也要翻mosaic 把四张图拼成一张时四张掩码要按同样的位置和裁剪拼起来随机缩放和填充时掩码要跟着做相同的缩放和填充边缘补零。色域类的增强亮度、饱和度、HSV 抖动只作用于图片不用动掩码因为掩码是类别索引不是颜色改了反而有害。我见过有人直接拿默认增强跑分割结果模型学出来的掩码整体偏移怎么调学习率都没用最后发现是增强阶段掩码没同步。所以这一块要么用现成的支持分割的增强库要么自己写增强时严格保证几何变换同步没有第三条捷径。4. 训练损失构成、超参数与显存调优4.1 损失函数的组成与配比联合训练的损失可以理解为几部分的加权和边界框回归损失、目标置信度损失、类别损失再加上分割损失。前三项和纯检测时基本一样分割损失通常用逐像素的二值交叉熵把预测掩码和真实掩码在框内逐像素比对。配比很关键。如果分割损失权重给得太大网络会过度关注掩码细节反而拖累检测框的精度给得太小分割又学不起来。我从实践中总结的经验是分割损失权重从 1.0 起步比较稳然后根据验证集上框的 mAP 和掩码的 mIoU 一起看哪个掉得厉害就往哪个方向微调。另外分割损失只应该在正样本框内计算背景区域不用管否则海量背景像素会把损失淹没。4.2 超参数配置的实操建议我把一套实际跑通、效果比较稳的配置列出来供参考。这里要说明具体数值要结合你的数据集规模调整下面是常见实践下的合理起点超参数建议值说明初始学习率0.01批量较大时可适当上调配合预热学习率调度余弦退火后期收敛更平滑权重衰减0.0005抑制过拟合动量0.937默认值即可别乱动批量大小8 到 16受显存限制小批量用梯度累积补训练轮数100 到 300小数据集少些防过拟合图像尺寸640分割任务可提到 960 提升小目标掩码质量原型掩码数量32精度与显存的平衡点图像尺寸这个参数我想多说一句。分割对分辨率比检测敏感得多检测把 640 拉到 960 可能只是小目标涨一两个点但分割的掩码边缘质量提升会非常明显代价是显存和耗时上升。如果你显卡够用、且目标本身偏小值得往上试试。4.3 显存与批量的调优加了分割头之后显存占用会比纯检测明显增加主要吃在原型掩码和高分辨率特征图上。我常用的几个省显存手段一是梯度累积用小的物理批量但累积几步再更新等效大批量二是混合精度训练我实测能省下大约三成显存速度也更快收敛基本不受影响三是冻结骨干前几层先用检测预训练权重初始化骨干这样不仅省显存收敛也快得多。这里分享一个经验从官方检测预训练权重初始化骨干比从头训整个网络能省下大半的训练时间而且最终精度更高。原因很简单骨干学到的通用特征边缘、纹理、形状对检测和分割都有用没必要推倒重学。5. 推理与部署后处理与加速的落地细节5.1 后处理流程要理清楚顺序推理时的后处理顺序非常讲究顺序错了结果就废。我的标准流程是先对检测输出做置信度过滤再用非极大值抑制筛掉重叠框同时把保留下来的框对应的 32 维掩码系数一起筛出来然后用这些系数和原型掩码做矩阵乘法得到每个框的初步掩码接着按框在输入图中的实际位置把初步掩码裁剪并缩放到框的大小最后做阈值化得到干净的二值掩码。有个细节容易被忽略原型掩码是输入分辨率的四分之一裁剪和缩放时要注意坐标映射。如果直接把四分之一的掩码按框坐标裁剪尺度就错了掩码会整体缩小到框的角落。我起初就栽在这输出的掩码只有框的左上角一小块后来统一把框坐标除以四再做裁剪才对上。5.2 导出与加速的注意点训练完的模型要上线通常会导出成通用推理格式。导出时建议开启动态批量方便线上按吞吐调整如果目标平台支持半精度导出时一并指定速度提升明显。这里要提醒的是导出后一定要拿几张图重新验证一遍结果因为有些算子在导出过程中会被融合或替换偶尔会导致掩码精度轻微下降特别是 sigmoid 和矩阵乘法那一段务必确认输出和原始模型对得上。如果部署到算力受限的边缘设备可以考虑把输入尺寸适当降低或者减少原型掩码数量来换速度但要重新评估掩码的 mIoU别为了速度把质量牺牲太多。我的一般原则是mIoU 下降不超过两个点速度提升超过三成这笔交易才划算。6. 常见问题与排查技巧实录6.1 高频问题速查表实际做这个项目来来回回就那几个问题反复出现我整理成表方便对照现象可能原因排查方向掩码和框错位后处理筛选索引不一致检查框和系数是否同张量同步筛选掩码整体偏移增强阶段掩码未同步几何变换逐项核对面翻转、mosaic、缩放掩码只有框一角原型掩码尺度未换算框坐标除以原型下采样倍数小目标掩码糊成一团图像分辨率偏低提高输入尺寸或加强 P3 分支检测掉点严重分割损失权重过大下调分割损失权重平衡两任务显存爆掉原型数量或分辨率过高降原型数、开混合精度、梯度累积推理速度慢后处理在 CPU 上串行掩码组合移到 GPU批量处理6.2 几个不容易想到的避坑心得第一个心得不要一上来就联合训练整个网络。更稳的做法是先加载检测预训练权重冻结骨干训几轮让分割头找到感觉再解冻一起微调。这样能避免分割头一开始乱输出大梯度把好端端的检测能力带崩。第二个心得验证时一定要分任务看指标。检测看 mAP分割看 mIoU两个指标要一起盯。我遇到过一种情况模型整体损失降得很好看但拆开一看检测涨分割跌实际是因为任务间互相干扰光看总损失根本发现不了。第三个心得掩码的阈值化别用固定值死磕。不同数据集、不同目标最优阈值不一样边缘目标用 0.5 卡出来的掩码常常缺一块。我通常会在验证集上扫一遍阈值挑整体 mIoU 最高的那个而不是想当然用 0.5。第四个心得这个框架后续还能顺手扩展。比如加入关键点分支做姿态估计或者再挂一个小分类头做属性识别共享骨干的思路完全可以复制边际成本很低。我在实际项目中就是把检测、分割、属性分类三合一整体显存比三个独立模型加起来省了将近一半部署也只用维护一套权重省心不少。最后分享一个我觉得最实用的经验先跑通再调优。别一开始就纠结参数配比、原型数量这些细节先用小数据集和默认配置把一个能出结果的版本跑起来看着框和掩码大致对得上再去逐项抠精度。这套流程能让你把结构对不对和参数好不好两件事分开验证排查问题的效率会高很多。我踩过的最大坑就是新需求上来同时改结构和参数结果出问题时根本不知道该动哪里白白浪费了好几天。