ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv8 三任务统一骨干:检测、分割与姿态估计解析

YOLOv8 三任务统一骨干:检测、分割与姿态估计解析 1. YOLOv8 三种任务共用一个骨干的真实逻辑第一次把 YOLOv8 的检测、分割、姿态三个权重文件同时跑在一张图上的时候我盯着输出结果看了很久。同一张图detect 模型给出框seg 模型给出框加像素掩码pose 模型给出框加 17 个骨架点三种输出结构完全不同但它们共享的却是同一套骨干网络和颈部结构。这件事本身就值得拆开讲清楚——为什么一个检测框架能同时扛下三种任务又为什么它在每种任务上的表现都没有明显拖后腿。先说清楚这三个任务到底在干什么。目标检测解决的是图里有什么、在哪里输出的是类别加矩形框实例分割在检测的基础上再往前一步要求给每个目标画出像素级的轮廓同一个类别的两只猫要能分得开关节点估计则是把人或动物的关键部位定位出来比如人的鼻子、肩膀、手腕、脚踝输出的是带置信度的点坐标。这三件事的难度是递进的检测只要知道范围分割要知道边界关节点要知道结构。传统做法是三个任务三套网络各训各的。YOLOv8 走的路线是统一骨干 任务专属头。骨干负责提取通用特征颈部负责多尺度融合最后接一个检测头要做分割就在检测头旁边挂一个掩码分支要做姿态就在检测头旁边挂一个关键点分支。这种设计不是 YOLOv8 发明的但它在工程上把这条路线打磨得足够顺滑使得你换任务时只需要换权重、换数据配置代码层面几乎不用动。我见过不少刚入门的朋友一上来就纠结为什么分割模型也能出检测框其实原因很简单分割分支是搭在检测分支之上的没有检测框就没有实例归属所以分割模型必然自带检测能力。理解这一点后面很多配置项和输出字段就顺理成章了。提示如果你想快速验证三种任务的差异拿同一张带人的街景图分别用 yolov8n.pt、yolov8n-seg.pt、yolov8n-pose.pt 推理一遍对比输出张量的形状比看十篇原理文章都直观。三种任务共享骨干带来的直接好处是部署成本低。在边缘设备上你不需要为每种任务准备一套完全独立的推理管线骨干部分的算子可以复用量化策略也可以统一制定。当然代价也存在分割和姿态头会增加计算量尤其是分割的原型掩码分支在高分辨率输入下显存占用并不小这一点后面会细说。从热词里能看到一个很典型的诉求——yolov8 网络结构图。很多人想要一张图把所有模块标清楚但只看图容易陷入每个模块都认识、连起来就懵的状态。所以接下来我按数据流动的顺序来讲先讲骨干和颈部这两个三种任务共用的部分再分别讲三个头各自的原理。2. 骨干与颈部C2f、SPPF 和多尺度融合到底在做什么2.1 C2f 模块相比 C3 改了什么YOLOv8 的骨干里最显眼的变化是把 YOLOv5 的 C3 模块换成了C2f。C3 的结构是一路卷积 若干 Bottleneck 堆叠 拼接C2f 则把 Bottleneck 的输出全部保留并拼接到最终输出里而不是只拼最后一路。这个改动的动机来自 ELAN 的设计思路让梯度在反向传播时有更多条路径可以走缓解深层网络的梯度消失。你可以把它类比成多个支流汇入主干每条支流都带着自己提取到的特征主干拿到的是更丰富的组合。代价是通道数变多但 YOLOv8 通过控制 Bottleneck 的数量和通道扩张比例把参数量压在了可接受范围内。实际做轻量化改进的时候C2f 是第一个被动手的地方。常见的做法是把标准卷积换成深度可分离卷积或者把 Bottleneck 里的卷积替换成 Ghost 模块。我自己试过在 C2f 里插入 Ghost 卷积YOLOv8n 的参数量能再降一截但在小目标上掉点比较明显所以要看你的数据集里小目标占比有多高。2.2 SPPF 与 PAN-FPN 的多尺度融合骨干末端接的是SPPF作用是增大感受野。它把特征图依次做三次最大池化池化核大小相同但堆叠起来等效于更大范围的池化然后拼接。这样做的计算量比直接用大核池化小得多效果接近。感受野变大的直接好处是模型能看到更大范围的上下文对判断一个大物体的类别很有帮助。颈部用的是PAN-FPN结构自顶向下传语义、自底向上传位置两条路径反复融合。为什么需要这个因为浅层特征分辨率高、位置信息准但语义弱深层特征语义强但位置信息在多次下采样后已经损失了。检测需要同时知道这是什么和在哪所以必须把两条信息合起来。YOLOv8 在 PAN-FPN 里也做了简化去掉了 YOLOv5 里的一些上采样后的卷积组合把融合路径做得更短。这个取舍换来的推理速度提升比较可观尤其是在高分辨率输入下。2.3 Anchor-Free 和解耦头的设计动机YOLOv8 是anchor-free的不再预设一堆锚框。YOLOv5 时代你需要根据数据集跑聚类得到 anchor 尺寸数据集一换就得重新聚很麻烦。anchor-free 直接预测中心点到四条边的距离省掉了这一步。对新手来说最直观的感受是训练自己的数据集时不用再纠结 anchor 匹配不上了。检测头是解耦的分类分支和回归分支各走各的卷积。分类关心的是像不像某个类回归关心的是边界在哪两者关注的特征其实不完全一样。共享一套卷积会让两者互相牵制拆开之后各自能学到更针对性的特征。这个思路最早在 YOLOX 上被验证有效YOLOv8 沿用了下来。注意解耦头会带来额外的参数量和计算量在极轻量场景下可以考虑重新耦合回去但精度通常会掉一点需要自己权衡。3. 目标检测头的原理解析与实操要点3.1 正负样本怎么分配Task-Aligned Assigner训练检测模型的核心问题之一是预测出来的几千个位置里哪些算正样本、哪些算负样本分错了模型就学歪了。YOLOv8 用的是Task-Aligned Assigner思路是同时考虑分类得分和回归质量给每个真实框挑出综合得分最高的若干个预测位置作为正样本。这个综合很关键——如果只看 IoU可能会选到分类很差的预测只看分类可能会选到框位置很偏的预测。两者加权对齐之后选出来的正样本在两方面都过得去。这个机制带来的实际好处是不需要像早期 YOLO 那样精心调 anchor 匹配阈值模型对超参不那么敏感了。我在一些小数据集上试过即使不改任何默认分配参数收敛也比 YOLOv5 稳。3.2 损失函数的三块拼图YOLOv8 的检测损失由三部分组成损失项作用对象主要作用BCE Loss分类分支判断每个位置属于哪个类别CIoU Loss边框回归让预测框和真实框重叠得更好DFL Loss边框分布把边框回归建模成离散概率分布CIoU 在 IoU 的基础上额外考虑了中心点距离和长宽比比单纯的 IoU 收敛更快。DFL 是 YOLOv8 比较有特色的地方它不再直接回归一个连续的距离值而是让网络在每个方向上输出一组离散概率最后取期望作为预测值。这样做的好处是回归目标被约束在一个有界区间内训练更稳定尤其是对边界模糊的目标。实际调参时这三个损失的权重是可以单独调的。如果你的场景里分类混淆严重比如外观相近的多个类别可以适当提高分类损失权重如果框位置总是偏就关注回归部分。但默认权重在多数场景下都是能用的不建议一上来就大改。3.3 训练参数里那几个真正影响结果的配置文件里参数一大堆但真正影响收敛和最终精度的其实就那么几个。imgsz输入分辨率。默认 640小目标多的话可以提到 960 甚至 1280但显存占用会显著上升而且推理速度会掉。我用 1660Ti 这种 6G 显存卡的时候640 配 batch 8 是比较稳的组合。batch批大小。太小会导致 BatchNorm 统计不准太大显存不够。有个实用技巧是用batch-1让框架自动按显存选一个合适的值。freeze冻结层数。迁移学习时常用冻结骨干前几层能加快收敛、防止小数据集过拟合。通常冻结前 10 层左右具体看你的数据集规模和目标域差异。lr0和lrf初始学习率和最终学习率比例。YOLOv8 默认用余弦退火从 lr0 衰减到 lr0*lrf。小数据集建议把 lr0 调到 0.001 左右大数据集可以保持 0.01。patience早停轮数。默认 50意思是在 50 轮内验证指标没提升就停。这个参数在数据集小的时候要调小否则容易白跑很多轮。实操心得训练自己的数据集前先拿官方权重在少量图上过一遍确认标注格式、类别名、路径配置都对再开正式训练。我见过太多人跑了半天才发现类别名写成了中文或者标签文件没对上白白浪费时间。4. 实例分割分支从检测框到像素掩码4.1 原型掩码加系数的组合思路YOLOv8 的分割分支没有直接为每个实例生成一张掩码图那样计算量太大了。它用的是原型掩码 系数的思路网络先输出一组共享的原型掩码形状大概是 32 通道、160×160 分辨率然后每个检测实例输出一组系数用这组系数对原型掩码做加权组合就得到该实例的掩码。这个思路和 Mask R-CNN 的 mask head 不一样好处是原型只算一次所有实例共享实例数量增加时额外计算量很小。坏处是原型数量有限如果一张图里目标种类特别多、形状差异特别大原型可能不够用掩码精度会受影响。4.2 掩码是怎么算出来的流程拆开是这样几步检测头照常输出框和类别掩码分支输出原型张量和每个框对应的系数向量两者做矩阵乘法得到每个实例的原始掩码最后按检测框的位置把掩码裁剪并缩放到原图尺寸。这里面有个容易踩的坑掩码是在特征图分辨率上生成的上采样回原图时会损失细节。如果你的目标边缘要求特别精细比如医学图像里的器官轮廓默认配置可能不够。这时候可以考虑提高输入分辨率或者在后处理阶段加边缘细化。另外掩码的阈值也需要调。默认二值化阈值是 0.5边缘区域会偏保守实际可视化时可以试 0.3 到 0.6 之间看哪个更贴合你的目标。4.3 分割数据标注的成本和替代方案实例分割的标注成本比检测高一个量级。检测只要画框分割要沿着轮廓描点一张复杂图可能要点几十个点。我做过一个项目几百张图标注花了整整一周。如果预算有限有几个思路可以考虑。一是用检测标注加弱监督的方式只用框信息训练推理时靠模型自己学到的形状先验去分割效果会打折但成本低很多。二是先用检测模型辅助标注把预测框转成初始掩码人工只做修正能省一半以上时间。三是找现成的公开数据集做预训练再在自己的少量标注上微调。标注工具方面labelme 和 roboflow 都能导出 YOLO 分割格式格式是每行一个多边形点序列归一化到 0 到 1。要注意多边形点的顺序和闭合性点太密会影响训练效率一般保留 20 到 50 个点就够描述轮廓了。5. 关节点估计分支把关键点当成回归问题5.1 热力图还是直接回归姿态估计有两条主流路线。一条是热力图方式为每个关键点生成一张概率图峰值位置就是关键点位置精度高但计算量大因为要逐像素处理。另一条是直接回归网络直接输出关键点的坐标值速度快但精度对坐标回归的稳定性要求高。YOLOv8 选的是直接回归路线和它的实时定位一致。每个关键点输出三个值x、y 和可见性置信度。COCO 数据集是 17 个关键点所以每个人实例输出 17×351 个值。这个选择的直接后果是速度快但遮挡情况下的表现会弱一些。热力图方式因为有空间上下文对遮挡更鲁棒。如果你做的是体育动作分析遮挡频繁可能要额外做时序平滑或者其他后处理。5.2 关键点的损失设计关键点分支的损失主要有两块位置损失和可见性损失。位置损失衡量预测点和真实点的距离可见性损失是一个二分类判断这个点在当前实例中是否可见被遮挡或者超出画面的点标为不可见。训练时要特别注意不可见点的处理。如果把不可见点也当成正常点去回归位置模型会学到错误的坐标。正确做法是让这些点不参与位置损失只参与可见性损失。YOLOv8 的默认实现已经处理了这一点但你自己写数据加载的时候要注意。注意关键点数据集的标注质量非常关键。同一个人的同一个关节不同标注员点的位置可能差好几个像素数据一致性别差的话模型很难学到稳定的位置。5.3 数据格式和常见坑YOLOv8 的关节点数据格式是每个实例一行包含类别、框中心坐标和宽高、以及每个关键点的 x、y、可见性。可见性取值是 0、1、2分别代表未标注、标注但不可见、标注且可见。最常见的问题是框和关键点不匹配。比如从 COCO 转格式时框的坐标和关键点坐标用了不同的归一化基准导致训练时框和点完全错位。我的做法是转完格式后随机抽几张图把框和点画在原图上目视检查这一步不能省。另一个坑是左右关键点标反。鼻子、眼睛这些无所谓但左右肩、左右肘标反会让模型学混。可以在可视化时用不同颜色区分左右一眼就能看出来。6. 训练、部署与常见问题排查实录6.1 环境配置和显存适配环境这块PyTorch 版本和 CUDA 版本的匹配是新手最容易卡住的地方。经验做法是先去 PyTorch 官网查版本对应表选一个稳定组合。比如较新的 PyTorch 配 CUDA 11.8 或 12.1都是经过验证的。显卡驱动版本要满足 CUDA 的最低要求这个用nvidia-smi一看就知道。显存不够是另一个高频问题。以 6G 显存的 1660Ti 为例跑 yolov8n 的检测任务640 分辨率、batch 8 是比较合适的跑分割任务就要降到 batch 4 左右跑姿态任务介于两者之间。如果实在不够可以开启 AMP 混合精度训练能省不少显存速度也快。Windows 下用 PyCharm 部署的话重点是把工作目录设对因为 ultralytics 默认会在当前目录下找数据集配置。建议在项目根目录建一个 datasets 文件夹配置文件里的路径用相对路径避免换机器后路径失效。6.2 常见问题速查表现象可能原因排查方向训练 loss 不下降学习率过大或数据标签错先降 lr再抽查标签可视化验证集指标远低于训练集过拟合加数据增强、冻结骨干、减小模型小目标漏检严重下采样丢失细节提高输入分辨率、改颈部融合分割掩码边缘毛糙原型分辨率不足提高 imgsz、调掩码阈值关节点左右错乱标注左右反了可视化检查左右颜色标记推理速度远低于预期未用半精度或 TensorRT导出 ONNX 后转 TensorRT显存溢出batch 或分辨率过大降 batch、开 AMP、降 imgsz6.3 部署侧的几个关键点训练完只是第一步真正落地要考虑推理效率。ONNX 导出是最通用的中间格式导出时记得指定 opset 版本太老的版本可能不支持某些算子。导出后可以用 onnxruntime 先验证一下输出是否和 PyTorch 一致不一致通常是某层算子被替换了。如果目标是边缘设备TensorRT 是提速最明显的路线。转 TensorRT 时要注意动态尺寸和静态尺寸的选择固定尺寸能获得更好的优化效果但灵活性差。INT8 量化能进一步提速但需要准备校准数据集量化不当会掉点建议先用 FP16 跑通再考虑 INT8。嵌入式平台部署的时候算子支持是最大的坑。某些算子在这些平台上没有高效实现会被回退到 CPU 执行速度断崖式下跌。解决办法通常是换用平台官方提供的模型转换工具把不支持的算子替换掉或者在训练阶段就避免使用这些算子。我在实际项目里踩过最深的一个坑是模型在 PC 上跑得好好的换到边缘设备后精度突然掉了十几个点。查了很久才发现是输入图像的预处理不一致——PC 上用的是 BGR设备上用了 RGB颜色通道反了模型自然认不准。所以部署前一定要用同一张图在两端跑一遍逐层对比中间输出把差异定位到具体环节。另一个值得养成的习惯是把损失曲线画出来看。YOLOv8 训练完会保存 results.csv用 pandas 读出来画 loss、mAP、precision、recall 的曲线能直观看出有没有过拟合、有没有震荡。震荡通常是学习率太大或者 batch 太小过拟合则是数据量不够或者增强太弱。这些信号比最终一个 mAP 数字有用得多。关于模型改进我的建议是先跑通基线再动手。很多人一上来就改 C2f、加注意力、换损失结果基线都没跑明白改完不知道是哪里起了作用。正确顺序是用默认配置跑出一个基线指标记录清楚硬件、参数、数据版本然后每次只改一个地方单独评估最后把有效的改动组合起来看是否有叠加增益。这套流程听起来笨但能帮你省下大量重复试错的时间。最后说一个关于数据集的实在话模型结构的改进带来的提升往往不如把标注质量提上去。我遇到过的精度瓶颈八成以上最后是靠清洗数据、补充难例、统一标注标准解决的真正靠改网络结构解决的不到两成。与其花时间在结构上反复折腾不如先把数据集里的错标、漏标、类别不平衡处理干净。
返回列表