
简介本资源为面向YOLO系列目标检测算法的葡萄数据集适用于从事农业视觉检测、果实分拣与成熟度识别的开发者及学生可解决葡萄拣选点定位、斑点与腐烂识别、成熟与未成熟分类等实际任务。压缩包共496个文件包含165张jpg图像、165个txt标签、165个xml标签及1个data.yaml配置文件整体约13.85MB已划分好训练与验证集可直接用于yolov5、yolov8、yolov9、yolov7、yolov10、yolo11等模型训练。标签同时提供YOLO格式与VOC格式YOLO格式采用归一化中心点与宽高比例便于快速接入主流框架。目前已有101人学习下载读者可获取完整标注数据、配置文件与双格式标签省去自行采集与标注成本快速搭建葡萄检测基线并验证算法效果。1. 165 张葡萄图像够不够训一个能落地的 YOLO 拣选模型先给结论够但前提是你把它当成“分拣线概念验证”而不是“通用葡萄检测大模型”。我拿到手的场景很典型——一条小型葡萄分拣台摄像头固定在传送带正上方需要把三类目标框出来成熟葡萄、未成熟葡萄、腐烂/斑点葡萄并且给出一个“拣选点”坐标让下游气动推杆把不合格果粒吹走。165 张图像带标签听起来少得可怜但工业分拣里真正决定成败的不是图像总量而是类别边界是否清晰、标注是否一致、以及你打算用检测框还是分割掩码。标题里的“拣选点”是个容易被忽略的词。它意味着你最终要输出的不只是类别和置信度还要有一个可执行的坐标。常见做法是用 YOLO 检测出腐烂葡萄和未成熟葡萄的边界框取框中心作为拣选点如果果粒重叠严重就升级到实例分割取掩码质心。165 张图如果每张有 8 到 15 个果粒实际目标实例数能到 1500 以上对 YOLOv8n 或 YOLO11n 这种轻量模型做迁移学习是够的。但如果你直接从头训练或者把成熟/未成熟/腐烂当成三个互斥类却忽略了“斑点”和“腐烂”在视觉上的渐变模型会给你上一课验证集 mAP 看着还行一到产线就疯狂误检。这篇文章面向两类人一是手里已经有一批葡萄图像、想快速跑通 YOLO 训练和推理的工程师二是正在评估“小样本 工业分拣”这条路值不值得投入的团队。我会把数据检查、标签格式转换、训练参数、拣选点计算、以及 165 张图最容易翻车的几个地方拆开讲。你不需要有 GPU 集群一张 8GB 显存的卡就能跟完。2. 葡萄数据集拆包后的第一件事别急着训练先做标签审计2.1 165 张图里藏着哪些类别不平衡陷阱拿到葡萄数据集-165张图像带标签这个压缩包解压后你大概率会看到images/和labels/两个目录或者一个data.yaml加若干.txt。先别写训练脚本用下面这段脚本统计每个类别的实例数和图像分布。我见过太多人直接yolo train结果训练完才发现“腐烂葡萄”只有 40 个框模型根本学不动。import os from collections import Counter from pathlib import Path label_dir Path(labels/train) # 根据实际目录调整 class_names [mature, immature, rotten_spot] # 按 data.yaml 顺序 counter Counter() img_with_class Counter() for txt in label_dir.glob(*.txt): classes_in_img set() with open(txt, r) as f: for line in f: cls_id int(line.strip().split()[0]) counter[cls_id] 1 classes_in_img.add(cls_id) for c in classes_in_img: img_with_class[c] 1 for i, name in enumerate(class_names): print(f{name}: {counter[i]} 个实例, 出现在 {img_with_class[i]} 张图中)这段代码的逻辑很直白逐行读取 YOLO 格式的标签文件第一列是类别 ID统计总实例数和覆盖图像数。参数上你只需要改label_dir和class_names的顺序顺序必须和data.yaml里的names完全一致否则统计结果会张冠李戴。如果发现某个类别实例数低于 100或者覆盖图像数少于 30 张就要考虑过采样、复制粘贴增强或者干脆把它合并到相近类别。比如“斑点葡萄”和“腐烂葡萄”在 165 张图的尺度下如果标注边界模糊合并成一个“缺陷”类反而更稳。2.2 用 labelImg 或 CVAT 复查 20 张图比调参更值165 张图全查一遍不现实但随机抽 20 张用 labelImg 打开重点看三件事框是否把果粒完整包住、有没有漏标被遮挡的果粒、腐烂和斑点的框是否画在了同一个区域却给了不同标签。我一般会把这 20 张的复查结果记成一个简单表格检查项合格标准常见问题处理方式框贴合度框边缘距果粒轮廓不超过 5 像素框过大包含背景重新标注或裁剪遮挡处理遮挡超过 50% 的果粒不标强行标导致模型学偏删除该框类别一致性同一视觉特征只对应一个类斑点/腐烂混标合并类别或明确规则拣选点可用性框中心落在果粒内部框中心偏移到背景调整标注或改用掩码这一步的产出不是“干净数据”四个字而是一份明确的标注规则文档。比如规定“腐烂葡萄”必须满足颜色发褐且面积超过果粒 30%“斑点”只算表面小面积黑点。规则写清楚后后面无论谁补标都不会跑偏。165 张图的小数据集标注噪声的杀伤力比模型容量大得多。2.3 把 VOC 或 COCO 标签转成 YOLO 格式的脚本与边界坑如果你拿到的标签是 XML 或 JSON需要转成 YOLO 的class x_center y_center width height归一化格式。下面这个脚本处理 VOC XML转换时有两个坑一是图像尺寸要从 XML 里读不能硬编码二是归一化后的坐标必须裁剪到 0 到 1 之间否则训练时 YOLO 会直接报错或静默丢弃。import xml.etree.ElementTree as ET from pathlib import Path from PIL import Image def voc_to_yolo(xml_path, img_dir, out_dir, class_map): tree ET.parse(xml_path) root tree.getroot() img_name root.find(filename).text img_path Path(img_dir) / img_name w, h Image.open(img_path).size lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) x_center (xmin xmax) / 2.0 / w y_center (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 裁剪到 [0,1]防止标注越界 x_center min(max(x_center, 0), 1) y_center min(max(y_center, 0), 1) bw min(max(bw, 0), 1) bh min(max(bh, 0), 1) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) out_path Path(out_dir) / (Path(xml_path).stem .txt) with open(out_path, w) as f: f.write(\n.join(lines)) class_map {mature: 0, immature: 1, rotten_spot: 2} for xml_file in Path(annotations).glob(*.xml): voc_to_yolo(xml_file, images, labels, class_map)逻辑说明先解析 XML 拿到图像宽高再对每个目标框计算归一化中心点和宽高。class_map决定了类别 ID 的映射必须和data.yaml一致。裁剪操作是后悔药没有它一个越界框就能让整个 batch 的损失变成 NaN。转换完成后用yolo checks或手动抽查几个 txt 文件确认坐标都在 0 到 1 之间。3. 用 YOLOv8 在 165 张图上跑通训练参数怎么设才不玄学3.1 从预训练权重出发别从头训小数据集训练的第一原则必须用预训练权重。YOLOv8n 或 YOLO11n 在 COCO 上学到的边缘、纹理、颜色特征对葡萄果粒检测有直接迁移价值。常见做法是下载yolov8n.pt或yolo11n.pt然后model.train(datadata.yaml, pretrainedTrue)。如果你非要从yaml从头初始化165 张图连 50 个 epoch 都撑不到收敛验证集 loss 会像过山车一样。data.yaml的写法要特别注意路径和类别顺序path: ./grape_dataset train: images/train val: images/val test: images/test names: 0: mature 1: immature 2: rotten_spotpath是数据集根目录train/val/test是相对路径。165 张图建议按 7:2:1 划分即 115 张训练、33 张验证、17 张测试。如果某些类别在验证集里一个实例都没有那验证结果就没有意义需要重新分层抽样。我一般会写个脚本按类别分层划分确保每个子集里三类都有。3.2 训练命令与六个必调参数下面是一条我常用的训练命令基于 Ultralytics 的 YOLOv8yolo detect train \ modelyolov8n.pt \ data./grape_dataset/data.yaml \ epochs150 \ imgsz640 \ batch16 \ lr00.001 \ lrf0.01 \ patience30 \ augmentTrue \ mosaic0.5 \ mixup0.1 \ degrees15 \ translate0.1 \ scale0.3 \ fliplr0.5 \ namegrape_yolov8n逐个说参数epochs150是因为小数据集需要多轮但容易过拟合配合patience30早停。imgsz640是默认值如果葡萄果粒在图像里很小可以提到 1280但显存要够。batch16在 8GB 卡上跑 640 分辨率基本安全。lr00.001是初始学习率小数据集别用 0.01否则前几个 epoch 就把预训练权重冲垮了。lrf0.01是最终学习率因子让学习率余弦衰减到初始值的 1%。mosaic0.5和mixup0.1是增强强度葡萄图像背景单一mosaic 能显著提升泛化但别开到 1.0否则果粒被拼得七零八落。degrees15和fliplr0.5针对传送带场景允许小角度旋转和水平翻转。训练过程中重点看val/box_loss和metrics/mAP50。如果训练 loss 持续下降但验证 mAP 在 30 个 epoch 后不升反降就是过拟合需要降低模型容量或加强增强。如果训练 loss 一开始就爆炸检查标签坐标是否越界、类别 ID 是否从 0 开始。3.3 用混淆矩阵判断“腐烂”和“斑点”是不是该合并训练完成后Ultralytics 会在runs/detect/grape_yolov8n/下生成confusion_matrix.png。重点看rotten_spot这一行如果大量样本被误判为mature或immature说明类间差异不够。165 张图里腐烂和斑点的视觉边界往往只有颜色深浅的区别模型很难学。这时候有两个选择一是把两类合并成defect重新训练二是保持两类但增加难例挖掘把误判的图挑出来重新标注。我一般会先跑一版三类模型看混淆矩阵。如果rotten_spot和mature的混淆率超过 20%就果断合并。合并后类别变成mature、immature、defect模型收敛更快拣选逻辑也更简单defect和immature都触发推杆。4. 拣选点计算与推理部署从检测框到气动推杆坐标4.1 取框中心还是掩码质心取决于果粒重叠程度拣选点的最简做法是取检测框中心cx (x1 x2) / 2cy (y1 y2) / 2。但如果两个果粒重叠框中心可能落在另一个果粒上推杆就吹错了。这时候需要实例分割。YOLOv8-seg 可以输出每个实例的掩码用cv2.moments计算质心精度更高。165 张图如果标注的是多边形可以直接训分割模型如果只有框可以用 SAM 或手动补几十张掩码图做微调。下面这段推理代码同时输出检测框和拣选点from ultralytics import YOLO import cv2 model YOLO(runs/detect/grape_yolov8n/weights/best.pt) img cv2.imread(test_grape.jpg) results model(img, conf0.4, iou0.5) for r in results: boxes r.boxes for box in boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) x1, y1, x2, y2 box.xyxy[0].tolist() cx (x1 x2) / 2 cy (y1 y2) / 2 # 只对缺陷和未成熟果粒输出拣选点 if cls_id in [1, 2] and conf 0.5: cv2.circle(img, (int(cx), int(cy)), 5, (0, 0, 255), -1) print(f拣选点: ({cx:.1f}, {cy:.1f}), 类别: {cls_id}, 置信度: {conf:.2f}) cv2.imwrite(result.jpg, img)conf0.4是置信度阈值产线上宁可漏检也不要误检可以调到 0.5 以上。iou0.5控制 NMS 重叠阈值果粒密集时调到 0.3 到 0.4 能减少框重叠。拣选点只对immature和defect输出成熟葡萄不触发推杆。坐标是图像像素坐标实际部署时要根据相机标定转换成传送带物理坐标。4.2 把模型导出成 ONNX 或 TensorRT 再上产线PyTorch 模型在产线工控机上推理速度往往不够。常见做法是导出 ONNX再用 TensorRT 或 OpenVINO 加速yolo export modelruns/detect/grape_yolov8n/weights/best.pt formatonnx opset12 simplifyTrueopset12兼容性最好simplifyTrue会做图优化。导出后可以用onnxruntime验证输出是否和 PyTorch 一致。如果工控机是 NVIDIA 显卡继续导出 TensorRTyolo export modelbest.pt formatengine halfTrue device0halfTrue启用 FP16速度提升明显但要注意小目标精度可能下降。165 张图训练出的模型本身泛化能力有限量化后如果 mAP 掉超过 5 个点就保持 FP32。4.3 产线联调时看哪三个指标模型部署后别只看 mAP。产线上我盯三个指标单帧推理耗时、拣选点重复精度、误吹率。推理耗时用time.time()包住推理循环目标是在工控机上低于 30ms。拣选点重复精度是同一颗葡萄连续过线 10 次拣选点坐标的标准差超过 5 像素就要检查相机触发和传送带速度同步。误吹率是推杆实际吹掉的果粒中真正缺陷果粒的比例低于 90% 就要回头调置信度阈值或重新标注。5. 165 张葡萄数据集训练避坑五个血泪翻车现场5.1 现象训练 loss 正常但验证集 mAP 始终为 0原因data.yaml里的val路径指向了不存在的目录或者验证集标签文件和图像文件名不对应。YOLO 在找不到验证标签时会静默跳过导致 mAP 计算为空。解决用pathlib检查val目录下每个图像是否有同名 txt缺一个就补一个。另外确认names的键从 0 开始且连续。5.2 现象模型把成熟葡萄也框成腐烂置信度还很高原因训练集中腐烂葡萄的标注框包含了大量成熟区域模型学到了“大框腐烂”的错误关联。165 张图里如果腐烂样本少这种偏差会被放大。解决复查腐烂类的标注框确保只框住缺陷区域。如果缺陷区域太小改用分割标注或放大图像后再标。同时增加成熟葡萄的负样本让模型看到成熟葡萄不总是腐烂。5.3 现象推理时拣选点落在两个果粒中间原因检测框中心不等于果粒中心尤其当果粒被部分遮挡或框不对称时。165 张图训练出的框回归精度有限中心偏移更明显。解决改用实例分割取质心或者在检测框内用颜色阈值找最暗区域作为缺陷中心。产线上还可以加一个“拣选点有效性检查”如果中心点落在背景区域直接丢弃该检测。5.4 现象导出 ONNX 后推理结果和 PyTorch 不一致原因导出时opset版本不匹配或者预处理归一化、通道顺序没有对齐。YOLO 导出默认包含预处理但某些 ONNX 运行时需要手动做1/255归一化和 BGR 到 RGB 转换。解决用同一张图分别跑 PyTorch 和 ONNX逐层对比输出。如果差异在 1e-3 以内算正常超过 1e-2 就要检查opset和simplify设置。5.5 现象训练到 80 个 epoch 后验证 loss 突然飙升原因学习率没有正确衰减或者增强强度过大导致模型在后期无法拟合。小数据集上mosaic1.0和mixup0.5会让模型一直处于“混乱”状态。解决降低mosaic到 0.3 到 0.5mixup到 0.1 以下。如果已经飙升加载第 60 个 epoch 的权重继续训把lr0调低一个数量级。6. 小样本葡萄检测的进阶技巧用 165 张图撬动更高精度165 张图的天花板很明显但你可以用几个技巧把 mAP 再往上推 5 到 10 个点。第一个技巧是复制粘贴增强把训练集中的缺陷果粒抠出来随机粘贴到其他图像的成熟果粒上生成新的训练样本。这个做法在工业缺陷检测里很常见能有效增加缺陷类的实例数。实现时用掩码抠图注意粘贴后的边缘融合否则模型会学到“硬边缺陷”的捷径。第二个技巧是伪标签半监督用训练好的模型对未标注的葡萄图像推理把高置信度的预测框作为伪标签加入训练集。165 张图之外你手头可能还有几百张没标的产线图用conf0.7筛一轮人工复查后合并。迭代两到三轮模型对产线光照变化的鲁棒性会明显提升。第三个技巧是测试时增强TTA推理时对同一张图做水平翻转、多尺度缩放把预测结果融合。Ultralytics 支持augmentTrue推理但速度会慢 2 到 3 倍。产线上如果节拍允许TTA 能把漏检率降低一截。最后说一个我自己的习惯每次训练完我会把验证集里误检和漏检的图单独存一个hard_examples/目录下次训练前优先复查这些图的标注。165 张图的数据集迭代五轮之后真正决定精度的不是模型结构而是你有没有把每一张难例都吃透。希望帮到你。本文还有配套的精品资源点击获取