多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

YOLOv8-seg芒果实例分割训练实战:数据、调参与部署

YOLOv8-seg芒果实例分割训练实战:数据、调参与部署 简介这份YOLOv8格式芒果实例分割数据集面向目标检测与深度学习学习者内含453条训练数据和91条验证数据可直接用于YOLOv8分割模型训练。包体共1088个文件以542张PNG原图与对应TXT标注文件为主同时包含2个JSON配置文件和2个cache缓存文件整体压缩包约187MB结构清晰便于快速加载。目前已有761人学习下载。数据集覆盖果园环境下的芒果个体可用于精准农业、自动化采摘、质量评估与病虫害检测等场景帮助读者从数据准备到模型训练完整掌握YOLOv8实例分割流程也可作为算法效果对比与调参实验的基准数据。1. 芒果实例分割数据集453张训练图为什么够用芒果实例分割数据集训练453张、验证91张全部按yolov8-seg的标准格式组织。第一次拿到这组图我下意识按目标检测的流程跑了一遍yolov8框是出来了可mask边缘像锯齿一样乱。换成yolov8-seg之后才意识到实例分割和检测在数据标注、损失计算、调参重心上完全是两套逻辑。这套数据集解决的是果园场景下“既要位置又要轮廓”的问题——自动化采摘要避开果柄、质量分级要看芒果形状和表面瑕疵一个矩形框远不够。适合三类人做农业视觉落地的工程师、拿公开数据练yolov8手感的算法新人、想对比detect与seg差异的老手。下面从数据本身拆起再把训练链路和坑位逐一讲透。2. 数据解剖train.json里的mask坐标、bbox字段与图片命名规律2.1 文件和命名azure_rgb前缀意味着什么拿到压缩包先看文件清单。里面除了图片还有train.cache、test.cache、train.json、test.json。cache文件是ultralytics首次加载数据集时生成的缓存记录每张图片是否有对应标注、标注是否合法下次启动训练直接读缓存跳过校验启动速度快不少。json是COCO格式的标注文件train.json对应训练集test.json对应验证集。图片命名值得细看azure_rgb_5fps_2500expo_539.png。azure指Azure Kinect相机rgb是彩色通道5fps是采集帧率2500expo是快门时间最后的539是帧号。这意味着采集源是Azure Kinect深度相机同一场景大概率还采集了深度图。对采摘机器人来说这个命名规律很关键——如果深度图和RGB图同名对齐完全可以把预测mask投影到点云上估算芒果体积甚至算果柄朝向。数据集本身只给了RGB图但采集设备的线索已经写在名字里复现别人实验时能少走很多弯路。2.2 train.json里都有什么字段train.json是COCO格式标签文件。yolov8对COCO格式天然友好ultralytics内部只用images、annotations、categories三段训练前自动转成yolov8需要的txt格式。抽一条标注看结构{ images: [ { id: 1, file_name: azure_rgb_5fps_2500expo_539.png, width: 1280, height: 720 } ], annotations: [ { id: 1, image_id: 1, category_id: 1, bbox: [512, 180, 240, 190], area: 28900, segmentation: [[502, 186, 560, 178, 601, 190, 640, 210, 638, 260, 580, 300, 510, 280, 490, 230]], iscrowd: 0 } ], categories: [ { id: 1, name: mango, supercategory: fruit } ] }逐字段解释。bbox是[x, y, w, h]整数坐标左上角起点。area是分割区域的像素面积训练时ultralytics用它来过滤小目标一般不会直接动这个值但如果你发现训练日志里丢掉了很多小目标回头查area阈值要往这个字段想。segmentation是多边形顶点坐标按(x1,y1,x2,y2,...)顺序排列yolov8-seg训练时会把多边形转成mask参与损失计算。iscrowd0表示这是普通独立实例不是一群目标1的话会走RLE编码后者通常在人群数据集里出现。2.3 两种标注形态多边形与RLECOCO的segmentation字段有两种形态显式多边形和RLE压缩编码。带iscrowd1的群体验证码才用RLE普通实例用多边形。yolov8-seg转换时多边形直接使用RLE要先解码成mask再从mask反提轮廓。这套芒果数据集标注都是纯多边形理论上转换很快但我建议你拿到手后还是跑一遍随机校验抽几张图把segmentation坐标画出来看是否贴合芒果轮廓。因为自动标注工具生成的polygon有时会串点一个点坐标错位mask就扭成麻花。2.4 校验数据与图片是否对齐最容易忽略的是json里file_name与图片是否匹配、宽高是否与真实分辨率一致。常见翻车是json写1280x720图片实际是1920x1080ultralytics做letterbox时不报错但训练出的mask和坐标全部偏差一个缩放系数。我一般用一段脚本批量核对import json from PIL import Image import os with open(train.json, r) as f: data json.load(f) for img_info in data[images]: path os.path.join(train, img_info[file_name]) if not os.path.exists(path): print(缺失文件:, img_info[file_name]) continue w, h Image.open(path).size if w ! img_info[width] or h ! img_info[height]: print(尺寸不符:, img_info[file_name], 标注, img_info[width], img_info[height], 实际, w, h)这段逻辑很直白先检查文件是否存在再比对标注宽高和实际宽高。脚本跑了没问题说明数据链路的第一关过了。这类校验花不了两分钟但能省掉训练跑一半才发现标签错位的血泪时间。2.5 关于train.cache与test.cache的生成时机train.cache和test.cache是ultralytics的产物不是你解压zip就自带的。第一次运行训练或验证命令时ultralytics会把图片和标注的校验结果写进cache文件之后加载数据集直接读缓存不再逐张解析。如果你的数据集目录被手动改过或者json内容被替换过旧cache会缓存错误信息导致训练行为诡异。遇到这种情况直接删掉cache文件让ultralytics重新生成是最稳妥的做法后面避坑章节再展开。3. 环境与训练把train/val目录变成yolov8能直接吃的yaml配置3.1 安装ultralytics并确认GPU可用训练实例分割模型环境就三件事Python版本、torch版本、ultralytics版本。我一般在3.10以上的虚拟环境里装最新稳定版ultralyticstorch用2.x配套的CUDA版本pip install ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118装完后先确认GPU是否真的能用。很多人装了CUDA版torch跑起来却在CPU上训练速度差一个数量级还浑然不觉。用Python快速验证import torch print(CUDA available:, torch.cuda.is_available()) print(GPU name:, torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU only)参数说明--index-url指定PyTorch官方CUDA 11.8的wheel源避免pip默认装成CPU版。如果你的显卡驱动较新也可以把cu118换成cu121但建议先看驱动支持的CUDA版本再选装高了会报版本不匹配。nvidia-smi看一下驱动信息再决定装哪套这一步别省。3.2 构造mango_seg.yaml数据集配置ultralytics训练实例分割模型数据集配置用yaml文件。新建mango_seg.yaml# 芒果实例分割数据集配置 path: /data/mango_dataset # 数据集根目录改成你的实际路径 train: train # 训练图片目录相对path val: test # 验证图片目录相对path names: 0: mango # 类别id和名称顺序必须与train.json的categories一致yaml字段不多但别小看names这段。类别顺序错一个训练出来的模型预测结果全乱。比如train.json里category_id1对应类别0你这里写成0: appleloss照样收敛但输出的类别语义全错。这也是实例分割训练里最常被忽视的“静默错误”。3.3 先用验证命令自检数据链路不要急着训练先用验证命令让ultralytics完整走一遍数据加载流程yolo segment val modelyolov8n-seg.pt datamango_seg.yaml这条命令会做几件事加载yolov8n-seg预训练权重、按mango_seg.yaml指定的路径扫描数据和标签、生成cache文件、跑一次前向传播输出指标。如果配置有问题这里就会暴露。第一次运行会慢一些因为要逐张解析json扫描完会提示cache文件已生成。如果报标签缺失或图片打不开趁这个阶段修复成本最低。3.4 启动首次训练数据链路通了再启动训练yolo segment train \ datamango_seg.yaml \ modelyolov8n-seg.pt \ epochs200 \ imgsz640 \ batch8 \ device0 \ projectruns_mango \ nameseg_base参数选择逻辑模型先用yolov8n-seg而不是s或m。453张训练数据对实例分割来说不算充裕n模型参数量最小过拟合风险低先跑通流程拿到可用的baseline。等验证集mAP稳定之后再用yolov8s-seg在n模型的基础上微调通常能再涨两三个点。epochs设200是因为小数据集收敛较慢配合早停机制实际跑不到那么久。imgsz640是折中设备显存不够就降到480后面调参章节细说。device0指定第一块GPU只有CPU的环境去掉这个参数但训练很慢不推荐。4. 调参实战imgsz、epochs与batch在芒果小目标上的取舍4.1 imgsz640起步先看目标在画面里的占比剪裁后的芒果图片里芒果占画面比例差别很大。近景特写一张图就一两个大芒果远景整枝挂果一张图可能有十几个小芒果。imgsz直接决定小目标的分辨率上限。用640时一个仅占画面5%的小芒果在缩放后可能只剩30像素左右segmentation头几乎分不清轮廓。我一般先用640跑一版看验证集结果再针对性看漏检的图片是哪类——如果漏的全是远景小芒果就把imgsz提到1024。imgsz1024对显存的需求接近翻倍1660Ti的6GB显存跑不动2080Ti以上的卡才值得试。另一个变通办法是imgsz保持640训练时开启增强里的scale参数往小目标方向倾斜让模型见过更多“小芒果”样本。4.2 epochs与patience早停不是玄学小数据集训练的典型问题是后段震荡损失已经降到平台期每过几个epoch又突然跳上去然后又降回来。这是小样本训练的常态不代表模型坏了。ultralytics的早停参数patience控制“连续多少个epoch没有改善就停止训练”yolo segment train datamango_seg.yaml modelyolov8n-seg.pt \ epochs300 patience60 imgsz640 batch8patience60意味着连续60个epoch验证集mAP没有刷新最佳值训练才停。这种配置下即使中间震荡只要最终能突破平台期就不会被早停误杀。如果你用默认的patience100配epochs300数据集小的场景里训练时间反而拉长因为模型进入平台期后迟迟不触发早停。我习惯把epochs设大一些、patience设成epochs的五分之一到三分之一让早停说了算。4.3 batch与显存的账实例分割比目标检测吃显存因为要多存一个mask分支的中间特征。GTX 1660Ti这类6GB入门卡跑yolov8n-segbatch8在imgsz640下勉强能过如果开一堆数据增强的缓存变量也可能爆显存。显存不够时的处理顺序是有讲究的# 方案一降低batch yolo segment train datamango_seg.yaml modelyolov8n-seg.pt \ imgsz640 batch4 # 方案二保持batch开混合精度 yolo segment train datamango_seg.yaml modelyolov8n-seg.pt \ imgsz640 batch8 ampTrue # 方案三梯度累积等效增大batch yolo segment train datamango_seg.yaml modelyolov8n-seg.pt \ imgsz640 batch4 accumulate2batch8降到4显存压力直接减半但BN层的统计量会受影响收敛会略微不稳。ampTrue在16位精度下做前向和梯度计算显存省一大截大部分情况下精度损失在一个点以内。accumulate2是折中方案实际batch4每两步累积梯度后再更新一次等效于batch8的优化步长显存占用却是batch4的量级。我先切amp再考虑accumulate最后才降batch。4.4 数据增强别把芒果的颜色特征破坏掉芒果的成熟度判断高度依赖颜色——青色到橙红色的渐变就是品质信号。ultralytics默认的hsv增强会随机改变色调饱和度增强过度会让模型学不到真实的成熟度特征。对这套数据我建议把hsv增强幅度调小# 在训练命令里覆盖数据增强参数 hsv_h: 0.01 hsv_s: 0.3 hsv_v: 0.3 scale: 0.5 fliplr: 0.5参数说明hsv_h控制色调偏移0.01基本等于不偏移hsv_s和hsv_v降低后颜色抖动幅度变小模型更依赖真实的颜色分布。scale0.5控制图像缩放范围如果漏检小目标可以调到0.7甚至0.9让模型在训练时见到更多被缩小的目标。fliplr水平翻转对芒果这种非对称物体要谨慎翻转后芒果的果柄朝向会变反对采摘机器人来说可能引入偏差如果下游只做长势分析fliplr0.5问题不大。4.5 单类别场景下的置信度与NMS参数数据集只有一个mango类分类分支几乎没有区分压力模型的主要注意力应该在mask回归上。验证和推理时conf阈值不要设太高。默认conf0.25对单类别实例分割偏保守很多边缘遮挡的芒果会被滤掉。我验证时会设conf0.1先看模型的真实召回能力再结合precision挑部署阈值。NMS的iou参数也影响实例分割结果。芒果互相遮挡的场景不少两个芒果挨在一起时iou0.7的NMS可能会把其中一个吞掉降到0.5能保留更多实例但也会带来少量重复框。这个参数没有绝对正确值建议在验证集上扫一遍0.3到0.7看mAP50和mAP50-95的变化趋势再定。5. 避坑记录yolov8实例分割训练中的5个翻车现场5.1 缓存文件损坏导致loss不降现象训练能启动但loss在前20个epoch几乎不动验证集mAP一直是0。原因之前中断过一次训练train.cache文件里记录的图片路径或标注信息已经过期。ultralytics读cache时会直接跳过解析但你改过json或移动过目录cache里的索引和实际文件对不上数据链路里混进了大量无效样本。解决删掉训练数据目录下的train.cache和test.cache重新运行训练或验证命令让ultralytics重新生成缓存。从那以后我每次改过数据集都会顺手把cache文件删干净两秒钟的事情能避免一上午的无效训练。5.2 验证集类别错乱mask画到别的类上现象训练正常loss下降也正常但用验证集图片做预测时明明图片上是青芒果模型输出的类别名却是另一个类。原因mango_seg.yaml里的names顺序与train.json里categories的顺序不一致。比如train.json里category_id1是mango但yaml里0: mango1: something_else模型学到的类别编号和语义对应关系对不上。解决构建设置类别的脚本固定一套清单yaml和json都从同一份清单生成不手写。或者更简单——检查yaml的names是否从0开始连续编号以及category_id是否从1开始且顺序一致。5.3 mask预测成一坨边缘锯齿严重现象框的位置基本正确但mask完全不成形状要么糊成一片要么锯齿锐利得像纸片。原因模型过拟合或训练不充分。453张训练数据对实例分割来说偏少mask分支很容易死记训练集的形状模式遇到新姿态的芒果就崩。另外训练时数据增强里的scale开得过大mask被反复拉伸变形模型学到的是扭曲后的形状分布。解决降低scale到0.3-0.5提高epochs让mask分支充分收敛或者换更大的模型yolov8s-seg。还有一种情况是验证时conf设太低0.05以下会输出大量低质量mask把conf拉回0.25再看效果。5.4 小目标漏检远端的芒果完全没有mask现象近景大芒果检测和分割都正常远景小芒果要么没框要么有框但mask是空的。原因imgsz640时小芒果的像素太少mask分支的特征图上目标区域不到几个像素分割头根本分不出轮廓。本质是输入分辨率限制了小目标的信息量。解决先确认漏检图片里目标占画面比例如果普遍小于10%把imgsz提高到1024。显存不够就采用双尺度训练思路——用640训练推理时用1024提升小目标召回。ultralytics推理时可以单独指定imgsz训练和推理解耦实测这套数据用640训练1024推理mAP50能提升3个点左右。5.5 显存溢出不只是batch的锅现象训练到一半报RuntimeError: CUDA out of memory但batch已经降到4了还是爆。原因显存被其他进程占用或者数据加载时缓存了太多图像。很多人只看batch大小忽略了nvidia-smi里显示的已占用显存。另外ultralytics默认预加载数据和缓存小数据集的图片会全部进显存占用很可观。解决先nvidia-smi看谁在占用显存杀掉残留的python进程。再排查数据加载参数训练命令加cacheFalse或改为缓存到磁盘。还有一种情况是workers开太多数据加载线程本身也吃显存降成workers2或4试试。6. 推理验证单图预测、mask结果解析与onnx导出6.1 用best.pt做单图预测训练完的模型都在runs_mango/seg_base/weights/下best.pt是验证集上表现最好的权重。单图预测这么写from ultralytics import YOLO model YOLO(runs_mango/seg_base/weights/best.pt) results model.predict( azure_rgb_5fps_2500expo_539.png, conf0.25, iou0.5, saveTrue, save_txtTrue )conf0.25标注最低置信度iou0.5控制NMS的IoU阈值。saveTrue会在runs/segment/predict目录下生成带mask的标注图片save_txtTrue会额外输出每个实例的坐标和类别文本。预测结果出来后别只看图片效果还要看txt里输出的坐标是否落在合理范围内——验证一下推理阶段的坐标空间是否和训练时一致这决定你后续做面积换算靠不靠谱。6.2 masks对象解析与坐标还原results里的masks是预测的实例mask数据结构值得细看for result in results: print(boxes:, result.boxes.xyxy) # 检测框坐标 nx4 print(masks data shape:, result.masks.data.shape) print(masks orig shape:, result.masks.orig_shape)参数说明masks.data是归一化到输入尺寸的mask张量形状是(num_dets, 640, 640)表示每个检测框对应一个二值mask尺寸和模型输入分辨率一致比如640x640。orig_shape是原始图片尺寸如果你要拿mask去原始图上做面积统计或三维投影必须做一个letterbox的反变换把640x640的mask映射回原始分辨率。不还原直接去算像素面积结果会被letterbox的缩放和填充污染全部偏大。推荐的做法是用result.plot()把mask直接画在原始图上然后基于原始图坐标做后处理而不是手动处理坐标空间。6.3 导出onnx交给嵌入式侧接续部署阶段通常要导出onnx特别是有边缘设备部署需求的场景比如rk3588这类开发板上跑yolov8-seg导出onnx是必经之路yolo export modelruns_mango/seg_base/weights/best.pt formatonnx opset12 dynamicTrueopset12是RK3588的NPU工具链常见的兼容版本opset太高可能不被NPU编译器支持。dynamicTrue保留动态输入维度让模型接受任意长宽输入如果部署时固定输入分辨率可以关掉dynamic减少转换时的麻烦。导出后务必检查onnx的输入输出节点是否正确mask输出分支的维度是否符合预期。实操收尾的习惯导出onnx后我会在电脑上先用onnxruntime跑一遍推理确认输出数据和ultralytics的results一致再交到嵌入式侧。这一步能提前暴露算子和精度问题省得到板子上调试到怀疑人生。从那以后我每次拿新数据集训练完都会强制走一遍导出验证再说部署的事。这套流程走下来剩下的就是根据实际场景迭代数据了希望帮到你。本文还有配套的精品资源点击获取
返回列表