ARTICLE DETAIL

资讯详情

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

改进YOLOv8实现枣子图像分割:RepHGNetV2与AFPN-P345实战

改进YOLOv8实现枣子图像分割:RepHGNetV2与AFPN-P345实战 简介这套面向计算机视觉研究与工程开发者的枣子图像分割系统以改进YOLOv8为核心整合了yolov8-seg-RepHGNetV2与yolov8-seg-AFPN-P345两种创新模型涵盖超过五十种网络优化点能解决复杂背景下枣子目标检测与像素级分割难题也便于迁移到类似农产品识别场景。包内共27个文件约4.66MB文件类型以Python脚本、PNG图像及Word/Markdown文档为主脚本对应训练、验证、预测与界面操作图像展示分割效果文档记录环境配置和使用说明。该资源已有279人学习适合具备一定深度学习基础的读者借助一键训练脚本和整理好的数据集可快速开启模型训练与调参免去从零搭建的繁琐。附赠资源文档进一步提供了网络结构、参数设置或论文线索等深入信息配合清晰的文件目录既能支撑毕业设计、科研实验也可为其他农产品分割任务提供参考。1. 枣子分割为什么不是“套个YOLOv8就完事”先看清三个硬约束把改进YOLOv8做枣子图像分割最直接的原因是默认YOLOv8-Seg在果园场景里不够用果实小、密度高、相邻果面互相遮挡加上树叶枝条和果皮颜色接近单靠COCO预训练权重很难输出干净的掩码。这份源码与数据集打包的项目里同时有yolov8-seg-RepHGNetV2、yolov8-seg-AFPN-P345以及50多种改进点并支持一键训练。它想解决的是从标注到训练、评估的整条链路数据集现成网络结构的改造成本降低训练入口封在一个脚本里。适合刚把检测调到能上线、想往分割迁移的从业者也适合想快速验证一批改进点在垂直数据上是否有效的实验者。读完你会知道哪些改进值得复现、哪些参数需要按自己的GPU重调以及在哪儿最容易翻车。2. 拆解改进点RepHGNetV2 主干和 AFPN-P345 颈部各自改变了什么2.1 RepHGNetV2 的重参数化设计训练多分支、推理单分支分割任务吃到什么红利RepHGNetV2 这个名字里最关键的词是 Rep也就是重参数化。它沿用了 RepVGG 那一套训练阶段用 3×3 和 1×1 并联的多分支结构推理阶段再把多分支等价折叠成一个 3×3 卷积。训练时梯度路径更多优化更容易收敛推理时只剩一个卷积核计算量不增加。放到枣子分割上这个特性比通用目标检测更值钱因为分割任务往往要处理 1280 甚至更高分辨率的输入特征图占用的显存和算力都集中在主干上主干多一条分支训练显存就涨一截推理时又不能直接复用训练结构。重参数化正好把这两件事拆开训练吃点显存推理只保留折叠后的单分支。但它的收益是有边界的。重参数化结构在中等规模网络上收益最明显把小模型硬撑到很深增幅会被梯度饱和吃掉。项目里给出的 yolov8-seg-RepHGNetV2通常是把 HGNetV2 的 stem 和 stage 按 Ultralytics 的 yaml 配置习惯重新写成一张结构图和官方 yolov8-seg 的 Neck、Head 拼在一起。换主干时如果只看 Backbone 字段不看 P3、P4、P5 的输出通道和 Neck 输入是否对齐模型能加载、第一次 forward 就会报维度错误。所以拿到这类 yaml 后我建议先跑一行代码确认结构# 用 ultralytics 内置接口打印模型各层输出尺寸确认改名后的主干能跑通 from ultralytics import YOLO model YOLO(yolov8-seg-rephgnetv2.yaml) yaml_info model.model.yaml print(fbackbone 层数: {len(yaml_info[backbone])}) # 这里用一张 640 的虚拟图做一次前向报错多半出在通道数对齐 import torch dummy torch.zeros(1, 3, 640, 640) out model.model(dummy) print(前向通过输出特征图数量:, len(out))这段代码的逻辑是先用 YAML 建模型再用假图跑一次完整前向。如果 backbone 某一层输出的通道数和 Neck 期望的不一致报错信息里会直接给出是哪一层的张量尺寸不对比训练到一半再暴露要快得多。跑通之后建议把 batch 设成 1、关掉一切增强再试一次排除是显存不足导致的假报错。2.2 AFPN-P345 的渐进跨尺度融合它补的是 PANet 在哪一层掉的精度AFPN-P345 解决的是特征金字塔内部的“特征不对齐”问题。PANet 的做法是自顶向下和自底向上各走一遍靠拼接把语义和空间信息汇合问题在于相邻尺度之间往往要经过多次上采样或下采样语义最丰富的高层特征传到低层时空间位置已经被拉偏了。对枣子这种直径可能只有几十个像素的小目标位置偏移几个像素掩码边缘就会错位一大圈。AFPN 的改法是渐进融合每次只让相邻两层特征做融合融合前先通过注意力权重计算各自该占多少比例而不是无差别拼接。P345 表示参与的是 P3、P4、P5 这三层正好覆盖了枣子分割里最常用的三个尺度P3 分辨率最高保住了果实轮廓的细节P5 语义最强在果实被树叶遮挡一半时还能给出正确的类别判断。相比原来的 PANet它少了一条跨越多层的信息搬运路径也少了很多重复上下采样带来的伪影。在复现这个改进时最值得较真的是融合权重怎么初始化。有些实现把注意力权重直接初始化为 0这会导致训练初期 Neck 输出的特征几乎全靠其中一条分支另一条分支等同被冻结常见做法是初始化为 0.5 附近让两条分支在早期都能拿到梯度。如果你下载的代码里不是这样训练曲线会在前二三十个 epoch 出现一段明显的平台期那不是网络不收敛是权重还没被激活。2.3 其余 50 改进点怎么归类注意力、损失函数、NMS、数据增强四大类50 多个改进点看着吓人拆开其实就四大类。第一类是注意力模块包括 SE、CBAM、ECA、CA、EMA、SimAM 这类按通道或空间做加权的东西作用是让主干更关注果实区域、忽略枝条和背景第二类是损失函数常见的有 CIoU、SIoU、WIoU、Alpha-IoU、Focal-EIoU它们改的是 bbox 回归的梯度形态我遇到的很多项目里对分割任务的提升不如检测任务明显因为掩码本身还依赖一份 BCE mask loss第三类是 NMS 策略Soft-NMS、DIoU-NMS 在果实密集粘连的时候能减少相邻果实被误删第四类是把结构模块换掉比如 C2f 换成 C2f-Faster、C2f-DCNSPPF 换成 SimSPPF、ASPP这类改动直接体现在参数量和感受野上。这四个类别在同一个数据集上的表现并不线性叠加。注意力模块叠加多了通道维度被反复加权梯度会互相掩盖损失函数换了一堆最后对 mAP50 的影响可能只有 0.5 个点。所以不要被“50 多种”带偏真正适合枣子这个具体场景的通常只有其中几组组合。2.4 改进点选型原则先消融再叠加别把改进清单当自助餐我的做法是先定一个对照组官方 yolov8n-seg 或者 yolov8m-seg用固定随机种子、固定 imgsz、固定 epoch 先跑一轮记录 mAP50、mAP50-95 和 mask 的 IoU。然后只换一个改进点其他参数完全不动再跑一轮。一个改进点跑完看两个东西指标有没有涨、参数量涨了多少。如果涨点在 0.5 个点以内但参数量涨了 20%我一般不会留下它。50 多个改进点全部单独消融不现实但对那条主线上最核心的 RepHGNetV2、AFPN 以及两三个注意力模块做消融两三天时间够用。另一个原则是区分“结构带来提升”和“玄学调参带来提升”。很多改进点换了之后效果变化其实是学习率、增强策略、预热 epoch 这些外在因素造成的。为了看清这一点我每次训练都固定住 optimizer、lr0、mosaic 这些变量只把结构差异作为变量。这样最后得到的对比表才可信也能复现。把 50 多个改进点一次性堆进去一旦效果变差你连是哪一层出了问题都找不到这是我最不推荐的用法。3. 环境与数据集准备从 LabelMe 多边形到 YOLOv8-Seg 能直接读取的标签3.1 搭建可复现环境CUDA、PyTorch 与 ultralytics 版本怎么配才不互相打架先说你最常遇到的坑网上搜到的环境教程很多但版本组合不对装完 ultralytics 能导入、一训练就报错。我的建议是用干净虚拟环境Python 3.10PyTorch 2.x 配对应 CUDA再装 ultralytics。CPU 版本也能跑适合验证代码能不能走通但你要有这个预期用 CPU 训练分割模型epoch 之间等的时间会让人怀疑人生最多用它做推理验证。# Ubuntu 20.04 下从零搭环境PyTorch 版本与 CUDA 要一致 python3.10 -m venv venv source venv/bin/activate pip install --upgrade pip pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics这里先装 PyTorch 再装 ultralytics 是有原因的。ultralytics 不会替你选 torch 版本而是直接依赖已存在的 torch如果你先 pip install ultralytics 再装 torch可能把 torch 装成 CPU 版后续训练奇慢无比。装完之后用python -c import torch;print(torch.cuda.is_available())验证一下输出 True 再继续。如果你拿到的是源码包里的一键训练脚本脚本里通常会有 requirements.txtpip install -r requirements.txt即可但要注意脚本里锁定的 ultralytics 版本和你的 PyTorch 是否匹配版本差太多时轻则报一堆警告重则训练到一半崩掉。3.2 数据集目录结构与第一次标签检查YOLOv8-Seg 的标准数据格式图片和标签分开放标签文件名与图片文件名一一对应扩展名不同图片是 .jpg 或 .png标签是同名 .txt。每个 txt 里每行一个目标格式是类别ID x1 y1 x2 y2 ...坐标全部归一化到 01 之间。不需要单独写 bbox 坐标YOLOv8 在读取分割标签时会自动从多边形坐标算出边界框。项目自带的数据集目录结构在细节上可能和你自己标注的不完全一样但大方向是固定的。我第一次拿到果实场景的分割数据时直接跑训练验证集 mAP 很高可视化一看掩码全画在树叶上。原因就是标签里存在大量“多边形超出图片边界”的脏数据。训练前一定要加一次标签检查不然问题会潜伏到训练之后。# 批量检查标签多边形是否全部落在图片范围内防止脏标签污染训练 import glob for label_path in glob.glob(dataset/labels/train/*.txt): with open(label_path) as f: lines f.readlines() for line in lines: pts [float(v) for v in line.split()[1:]] # 坐标归一化后必须在 [0, 1] 区间 for v in pts: if v 0 or v 1: print(f非法坐标: {label_path} - {v}) break这段脚本的核心就是遍历标签文件检查归一化坐标是否越界。越界的来源通常是 LabelMe 导出时没裁剪或者缩放图片后没同步缩放多边形。发现非法坐标直接删掉对应目标行或重新标注不要留到训练里。分割任务对这种标签错误比检测更敏感因为一个错位顶点就可能让掩码区域扩大一倍。3.3 LabelMe JSON 转 YOLO-Seg 多边形转换脚本与关键参数如果你从 LabelMe 标注起步或者项目里给的是 JSON 格式标注要先转成 YOLO 格式。LabelMe 的 JSON 里包含 imageWidth、imageHeight 和 shapes 数组每个 shape 是一个多边形。转换脚本不难写但有三个点必须注意一是类别名要和 data.yaml 里完全一致大小写不同就会被跳过二是多边形顶点要不要做抽稀LabelMe 里手勾的轮廓可能有三四百个点全部保留会让标签文件膨胀、训练时 IO 变慢三是坐标归一化时用图片实际宽高而不是训练时的 imgsz。# LabelMe JSON 转 YOLO-Seg 文本标签的最小实现 import json, os def labelme_to_yolo(json_path, out_path, class_names, max_points150): with open(json_path, encodingutf-8) as f: data json.load(f) h, w data[imageHeight], data[imageWidth] yolo_lines [] for shape in data[shapes]: if shape[label] not in class_names: continue cls_id class_names.index(shape[label]) pts shape[points] if len(pts) max_points: # 顶点过多时按等间隔抽稀 step len(pts) / max_points pts [pts[int(i * step)] for i in range(max_points)] coords [] for x, y in pts: coords.append(f{x / w:.6f}) coords.append(f{y / h:.6f}) yolo_lines.append(f{cls_id} .join(coords)) os.makedirs(os.path.dirname(out_path), exist_okTrue) with open(out_path, w) as f: f.write(\n.join(yolo_lines))这个脚本里有三个参数要解释。max_points 是抽稀阈值我一般设 150超过就等间隔采样对枣子这种轮廓相对圆滑的目标足够class_names 是类别列表顺序必须和 data.yaml 里的 names 顺序一致类别顺序错位是最隐蔽的错因为训练不报错只是所有标签类别整体偏移坐标拼接顺序是 x0 y0 x1 y1很多人会写成先全部 x 再全部 y导致多边形变成锯齿状。转完之后把 txt 放回与图片同名的 labels 目录再用上一节的检查脚本扫一遍确认坐标没有越界。3.4 写对 data.yaml路径、类别与验证集划分data.yaml 是训练入口路径写错会直接卡在加载数据阶段。YOLOv8 的 data.yaml 里 path 是相对于当前工作目录的路径train 和 val 指向图片目录names 是类别字典。枣子项目里通常只有一个类别比如 jujube但如果你自己额外标注了烂果、枯枝这类负样本类别类别数要同步改到 nc否则训练会一直报类别索引越界。# 一份枣子分割的 data.yaml 最小可跑版本 path: /home/user/jujube_dataset train: images/train val: images/val names: 0: jujubepath 建议写绝对路径因为在不同机器上相对路径的基准目录不一样。train 和 val 对应 images 目录程序会自动去同级的 labels 目录找标签。还有一个常见坑val 集不能是空的。有些一键训练脚本默认用 train 集切一小块做 val如果你把 val 路径删了训练会直接报错“validation dataset not found”。验证集划分上我一般随机抽 10%15% 做 val并且保证每个类别在 val 里都有样本。分割任务一旦 val 里缺某个类别best.pt 会在训练结束时选出一个对缺类倾向性不明的权重后续部署很难察觉。4. 把一键训练跑明白训练命令、参数含义与 loss 曲线怎么盯4.1 从预训练权重起步还是从零训练两种做法的一键训练入口一键训练脚本通常做的事就是把你选定的 model yaml、数据集 yaml 和超参打包成一条 yolo segment train 命令。区别在于 model 参数给的是 yaml 还是 pt。给的 yaml 表示从结构初始化预训练权重需要单独指定给的 pt 表示从已有权重续训权重里自带网络结构。对枣子分割我从 COCO 预训练权重起步带来的提升比从零训练快得多尤其当图片里还有树叶干扰时。# 用官方 COCO 预训练权重作为起点训练改进版 yolov8-seg yolo segment train \ modelyolov8n-seg.yaml \ pretrainedyolov8n-seg.pt \ datadataset.yaml \ epochs150 \ imgsz640 \ batch16 \ cacheTrue这里一个关键参数是 pretrained。如果你换的改进版主干在结构上和官方 yolov8 差距很大比如通道数完全不同加载预训练权重时会有很多层匹配不上ultralytics 会自动跳过不匹配的层只在日志里打印一行。这时候不要慌也不要把 pretrained 直接关掉保留能匹配的层对训练仍有帮助。如果项目里给的是“从零训练”入口可以加上pretrainedFalse但我不建议这样做除非你已经验证过改进结构太偏、预训练权重几乎全被跳过。4.2 训练阶段常改的参数imgsz、batch、lr0、mosaic、cache 的调法imgsz 决定输入分辨率也决定分割掩码的细腻程度。默认 640 在枣子这种小目标场景不一定够用我建议先试 1024显存撑不住再退回 640。imgsz 从 640 提到 1024显存占用接近翻倍batch 就要相应减半。batch 的基本原则是在不爆显存的前提下尽量大。ultralytics 支持把 batch 设成 -1 让程序自动探测也可以手工设成 16、32。batch 越小BN 的统计量越不稳定分割掩码的边界抖动越明显。lr0 是初始学习率默认 0.01 在检测任务上没问题但换过主干或加了注意力模块后把 lr0 降到 0.005、0.002 更稳尤其是从 COCO 预训练权重起步时学习率太大容易把预训练学到的好特征冲刷掉。mosaic 是数据增强里影响最大的一项。默认开启且权重为 1.0也就是每张图都做拼接。但枣子数据集里果实密集且互相粘连mosaic 拼接容易在拼接缝附近生成大量伪目标标签跟着错位。我一般把 mosaic 从 1.0 降到 0.5或者在最后 20 个 epoch 关闭。cache 建议设 True数据集不大时能把图片提前缓存进内存省去每个 epoch 的磁盘读取时间。如果你用的是机械硬盘这个参数区别特别明显能省下三分之一训练时间。还有一个容易被忽略的掩码专用参数 mask_ratio它控制训练时掩码下采样的倍数默认 4如果导出后的掩码边缘颗粒感重可以调成 2代价是显存和训练时间同步上涨。4.3 训练中要看哪些曲线train 与 val 指标怎么对得上训练跑起来后Ultralytics 会在 runs/segment 目录下生成 train 子目录里面包含 loss 曲线图和指标曲线图。常见文件有 train/box_loss.png、train/seg_loss.png、val/box_loss.png、val/seg_loss.png 等横向对比同名曲线就能看出是不是过拟合。loss 曲线我只看两个拐点前 20 个 epoch 是否快速下降后 50 个 epoch 是否还在缓慢下降。如果前 20 个 epoch 几乎不动多半是学习率太低或标签有问题如果后 50 个 epoch 训练 loss 还在降、val loss 已经反弹就说明过拟合开始需要加正则化或提前结束。val/seg_loss 是分割任务特有的一条曲线对应掩码预测的损失。它比 box_loss 更能反映掩码质量因为检测框收敛不代表掩码边缘收敛。我习惯用 val/seg_loss 稳定程度来定 best 权重而不是只看 mAP50。mAP50 对掩码边缘的容忍度很高一个稍微膨胀的掩码只要 IoU 过了 0.5 就会被记为正确所以 mAP50 高而 mask 不干净并不矛盾。想看到掩码质量的真实水平要看 mask_mAP_50-95这个是按 IoU 阈值从 0.5 到 0.95 取平均的掩码边缘差一点分数掉得很快。4.4 训练结束后第一时间做的事权重筛选与混淆矩阵解读训练结束后runs/segment 目录里会保留 last.pt 和 best.pt。last.pt 是最后一个 epoch 的权重best.pt 是在验证集上指标最优时的权重。不要因为 last.pt 训练到最后就直接部署它在验证集上大概率不如 best.pt因为最后一个 epoch 可能正处在学习率调度导致的震荡中。先看 results.png 或 results.csv确认 best.pt 对应的 epoch 号。混淆矩阵图也要看。detect 任务看的是类别混淆分割任务除了类别混淆还要看掩码 IoU 在不同类别下的分布。如果混淆矩阵里出现大量“树叶误判成果实”说明注意力模块没有真正把背景区分出来优先选择加了背景或负样本类别的改进点。如果混淆矩阵良好但 mask_mAP_50-95 仍然偏低问题就可能出在标签粗糙度上回到把标注边界重新修一遍这条路。5. 枣子分割训练与评估的五个坑现象、原因、解决5.1 验证集 mAP 很高但视频里掩码轮廓一直在抖现象best.pt 在验证集上 mAP50 能到 0.9 以上但拿到实拍视频里一帧一帧跑同一颗果实的掩码轮廓在相邻帧之间明显抖动边缘忽大忽小。原因有两个。一是训练时 imgsz 设了 640推理时为了速度把 imgsz 降到 320 或直接用原始分辨率输入尺寸不一致网络输出掩码的尺度也不一致二是 NMS 阈值设得太松同一目标被分裂出多个预测掩码在多个候选间跳变。分割任务对这两个因素比检测更敏感因为掩码是在特征图上直接回归像素位置。解决先统一训练和推理的 imgsz推理时固定成同一个值不要给预测接口传 None 让它猜。然后把推理端的 conf_thres 从默认 0.25 提到 0.35 到 0.5NMS iou 用 0.5把低置信度的分裂掩码过滤掉。改完再看如果还抖就回到标签检查脚本看看是不是训练集里存在同一目标标注不一致的情况。5.2 训练中途 loss 变 NaN 或显存 OOM 掉进程现象训练到二三十个 epoch控制台突然打印 NaN loss或者 CUDA out of memory 直接中断last.pt 可能都没来得及保存。原因NaN 最常见于学习率过大加 BN 的 batch 太小梯度爆炸OOM 最常见于 imgsz 或 batch 设置超出显存有时是在某个 epoch 刚好碰到特别大的图片特征图峰值内存超限。解决NaN 时先把 lr0 降到 0.002同时把 batch 提到至少 8 以上让 BN 统计量稳定如果还 NaN逐个检查数据集里是否有空标签文件空标签会让损失函数里某些项没有正样本出现除零。OOM 时先用 batch1 把训练跑通确认不是某个特殊样本导致再逐渐增大 batch或者用batch-1的自动探测配合ampTrue混合精度能省下一大截显存。不要在 OOM 后直接改小图片尺寸那样掩码分辨率跟着下降治标不治本。5.3 把 RepHGNetV2 换上去之后反而掉点现象同一个数据集上官方 yolov8n-seg 做基线能到 mAP50 0.88换到 yolov8-seg-RepHGNetV2 之后掉到 0.84比不改还差。原因第一是骨干通道数变化导致 Neck 输入特征的语义层次和原来不一致AFPN 或 PANet 的融合权重需要重新收敛第二是学习率没有跟随结构调整RepHGNetV2 的优化曲率和 CSPDarknet 不一样沿用默认 0.01 很容易震荡第三是预训练权重的大部分层被跳过等于几乎从零开始训骨干。解决换主干后先做一次短训练比如 30 个 epoch观察 loss 下降速度如果比基线慢把 lr0 降到 0.002 再试。同时确认 Neck 三个输入通道和主干输出通道对齐用第 2 章里那段打印前向结构的代码验证。如果这些都没问题就把新主干和官方主干在同一组增强参数下做消融记录参数量和推理速度掉点不冤有多大改进空间数据说了算。5.4 一键训练脚本报 no module named 或版本冲突现象跑一键训练脚本先报ModuleNotFoundError: No module named ultralytics或者报torch.cuda.is_available() is False脚本秒退。原因虚拟环境没激活或者在两个不同的 Python 环境里装了不同版本的依赖which python指向的和 pip 安装的并不是同一个环境。torch 报了 CPU 版基本可以断定是装完 PyTorch 后又用 pip 重装了一遍把 CUDA 版覆盖了。解决先source venv/bin/activate再python -c import torch; print(torch.__version__, torch.cuda.is_available())确认环境。如果 torch 是 CPU 版pip uninstall torch torchvision之后再按 CUDA 版重装。源码包里如果有 requirements.txt安装前先人工检查其中锁定的 torch 版本不要盲目一键安装。这类问题八成是环境问题不是代码问题代码报错拉到最后一行看真正原因。5.5 中断后续训结果变差甚至没有生成 val 指标现象训练跑了 80 个 epoch 被中断用 last.pt 续训结果最后的验证指标比第一次完整训练还差或者续训结束后 runs 目录里没有 val 指标曲线。原因续训时如果换了 data.yaml 或 model yaml网络结构对不上加载权重时大量层被跳过优化器状态没有正确恢复学习率重新从头算震荡幅度变大。val 指标缺失一般是保存后的 best.pt 在验证集上没有再算一次评估只是沿用了训练过程中的最优记录。解决续训时保持 model、data、imgsz 完全不变直接用resumeTrue让脚本自动找 last.pt 和对应训练配置。如果一定要手动续就从训练目录里复制原来的 args.yaml 和 last.pt 到同一级目录再指定resume。续训完后单独跑一次 valyolo segment val modelruns/segment/exp/weights/best.pt datadataset.yaml手动生成验证报告不要依赖训练过程中的中间指标。6. 从枣子走向生产线评估协议、阈值调节与导出部署6.1 用 IoU 和 Dice 建评估协议mAP50 之外还要看什么mAP50 只统计 IoU 超过 0.5 的预测对掩码边缘质量几乎不敏感。我在把分割模型交付出去之前会额外跑一遍逐目标 IoU 和 Dice 的分布。IoU 反映重叠程度Dice 对掩码面积误差更敏感。对一颗枣子Dice 低于 0.75 的预测基本不能用于后续的测径或分级因为它要么少切一块要么多圈了一圈叶子。可以写个小脚本把每个样本的 Dice 统计出来按区间画分布如果大量样本落在 0.70.8 之间说明掩码整体偏小或偏大这时候先别调网络回到标注流程检查有没有系统性偏差。6.2 conf 与 NMS IoU 阈值怎么调分割场景和检测场景不一样分割场景对漏检的容忍度通常更低。检测任务里框偏一点没关系分割掩码偏一点就影响面积统计。我一般先用 val 集做一次阈值扫描把 conf_thres 从 0.1 扫到 0.6NMS iou 固定在 0.5画精度-召回曲线然后按业务需求找平衡点。如果目标是精确计数宁可漏一点也不能错检conf 调到 0.5 以上如果目标是估产测径多检一两个不影响整体conf 可以放到 0.3 左右。换数据集时不要沿用上次的阈值阈值和类别分布强相关果实密度大时 NMS iou 还要再收紧。6.3 导出 ONNX/TensorRT从 .pt 到边缘设备推理的最短路径部署前把 best.pt 导出成 ONNX中间格式跨框架都能用。常用命令是 yolo export modelbest.pt formatonnx imgsz640导出时 opset 建议设 12 或 13 以兼容更多推理引擎后续要接 RK3588、Jetson 这类边缘设备时也更省事。# 导出 ONNX 并检查输出维度确认掩码输出通道数 yolo export modelbest.pt formatonnx imgsz640 opset12 python -c import onnx; monnx.load(best.onnx); print([o.name for o in m.graph.output])导出后分割头会输出两组数据一组检测框一组掩码预测系数。在板端推理时最常见的错误是只取检测框丢掉了掩码系数结果输出全黑。这种问题和你跑通训练完全是两条线务必在接入边缘设备前用一段旧视频样例走一遍全流程从 ONNX 输入到掩码解码确认每一帧都能出图。我自己踩过的还有一个坑是导出后的 opset 版本太高板端引擎不支持回退到 opset 12 就好。希望这些经验能帮你在枣子分割这条路上少走几趟弯路。本文还有配套的精品资源点击获取
返回列表