☰
26类蔬菜VOC+YOLO数据集实战:YOLOv8训练与避坑指南
2026/9/28 2:59:56 网站建设 项目流程

简介:这份资源是面向计算机视觉学习者与目标检测项目开发者的蔬菜图像数据集,覆盖 avocado、beans、beet、bell pepper、broccoli、cabbage、carrot、corn、cucumber、eggplant、garlic、onion、peas、potato、pumpkin、tomato 等 26 个常见蔬菜类别,适合用于分类与检测模型的训练、微调及课程实验。压缩包共约 2000 个文件,以 1999 个 Pascal VOC 格式 xml 标注文件和 1 个说明 txt 为主,并配套同名的 YOLO 格式 txt 标注,图片为 jpg,整体约 544.19MB,可直接接入主流检测框架。数据集共 7155 张图片,每张均含对应 xml 与 txt 标注,类别框数分布较细,如 avocado 1163 框、beet 1004 框等,便于按类别统计与均衡采样。目前已有 402 人学习下载,适合需要多类别蔬菜检测数据、快速验证模型效果或开展数据增强实验的读者参考使用。

1. 7100 张、26 类蔬菜的 VOC+YOLO 数据集,到底能拿来干什么

如果你正在做农业视觉相关的目标检测,大概率会遇到一个很现实的问题:公开数据集里蔬菜类目少、标注格式不统一、拍出来的图跟自己的场景差太远。这个标题里的「26 种蔬菜、7100 张、VOC+YOLO 双格式」,恰好卡在了一个很实用的位置上——类目够多、量级够跑通一个 baseline、格式够省事。它解决的不是「发论文刷 SOTA」的问题,而是「我手头有个蔬菜分拣/识别/计数需求,怎么快速把模型跑起来并验证可行性」的问题。

适合谁?一是做智慧农业、分拣线、采摘机器人视觉的工程师,需要快速搭一个能识别多类蔬菜的检测原型;二是学生或转行者,想拿一个真实的多类数据集练手 YOLO 训练全流程,而不是在 COCO 上跑别人跑烂的 demo。VOC 和 YOLO 两种格式同时给,意味着你既能用 XML 做数据清洗和可视化,也能直接喂给 YOLOv5/v8 训练,省掉格式转换那一步的玄学。接下来我会按「数据集怎么读 → 怎么转 → 怎么训 → 坑在哪」的顺序,把这条链路讲透。

2. 先搞懂 VOC 与 YOLO 两种标注格式的差异

拿到一个「VOC+YOLO」双格式数据集,第一件事不是急着训练,而是搞清楚这两种格式各自长什么样、坐标怎么算。很多人训练时框全歪了,根子就在这一步没对齐。

2.1 VOC 格式:XML 里的绝对坐标

VOC 格式每张图对应一个同名 XML 文件,核心信息在<object>节点里,<bndbox>存的是像素绝对坐标xmin/ymin/xmax/ymax。它的好处是可读性强、工具支持广(LabelImg 默认就是它),缺点是坐标跟图像尺寸绑定,换分辨率就得重算。

<annotation> <filename>carrot_001.jpg</filename> <size> <width>640</width> <height>480</height> <depth>3</depth> </size> <object> <name>carrot</name> <!-- 类别名,26 类之一 --> <bndbox> <xmin>112</xmin> <!-- 左上角 x,绝对像素 --> <ymin>88</ymin> <xmax>305</xmax> <!-- 右下角 x --> <ymax>402</ymax> </bndbox> </object> </annotation>

这里要盯住两个点:一是<name>必须和你的类别列表严格一致,大小写、空格都算;二是xmax > xmin、ymax > ymin,如果标注时手抖画反了,训练时这个框会被算成负面积,直接污染损失。

2.2 YOLO 格式:归一化的中心点坐标

YOLO 格式每张图对应一个同名.txt,每行一个目标,格式是class_id cx cy w h,全部归一化到 0~1。它不存图像尺寸,所以换分辨率不影响,但你必须保证归一化时用的宽高和实际图像一致。

0 0.325000 0.510417 0.301563 0.654167 3 0.712500 0.333333 0.150000 0.208333

第一列class_id是从 0 开始的整数,对应你的names列表顺序。cx cy是框中心点,w h是框宽高,都是相对整图的比例。常见翻车点是:有人把 VOC 的xmin直接当cx填进去,结果框整体偏移半个身位。

2.3 两种格式的换算关系

换算公式不复杂,但必须记牢,因为后面写转换脚本全靠它:

目标公式
cx(xmin + xmax) / 2 / width
cy(ymin + ymax) / 2 / height
w(xmax - xmin) / width
h(ymax - ymin) / height

反推回 VOC 就是xmin = (cx - w/2) * width,以此类推。理解了这个,你就能判断数据集里两种格式是否自洽——我一般会抽 5 张图,用脚本把 YOLO 反算回 VOC,跟原始 XML 比对,误差超过 1 像素就说明有一边是错的。

提示:双格式数据集不一定两种都准。优先信任你打算用的那一种,另一种只当参考,别混着用。

3. 把 7100 张数据整理成可训练的目录结构

数据集能不能训起来,一半看目录结构对不对。YOLO 训练对路径和文件名有硬性要求,图.jpg和标签.txt必须同名同目录层级,差一个字符就报「找不到标签」。

3.1 标准目录长什么样

我一般会整理成下面这样,images和labels平行,各自再分train/val:

vegetables/ ├── images/ │ ├── train/ # 约 80% 图片 │ └── val/ # 约 20% 图片 ├── labels/ │ ├── train/ # 与 train 图片同名的 .txt │ └── val/ └── vegetables.yaml # 数据集配置文件

划分比例上,7100 张按 8:2 大约是 5680 训练、1420 验证。如果某些蔬菜类别样本特别少(比如只有几十张),建议改成 9:1,把更多样本留给训练,否则验证集里那几张小类根本学不到。

3.2 用脚本做划分和校验

手动分文件容易漏,直接上脚本。下面这段做三件事:按比例划分、复制图片和标签、顺手校验有没有孤儿标签。

import os, random, shutil random.seed(42) # 固定种子,保证可复现 src_img = "raw/images" src_lbl = "raw/labels" dst = "vegetables" ratio = 0.8 imgs = [f for f in os.listdir(src_img) if f.lower().endswith((".jpg", ".png"))] random.shuffle(imgs) split = int(len(imgs) * ratio) for phase, files in [("train", imgs[:split]), ("val", imgs[split:])]: for f in files: stem = os.path.splitext(f)[0] lbl = stem + ".txt" # 图片和标签必须成对存在,缺一个就跳过并打印 if not os.path.exists(os.path.join(src_lbl, lbl)): print("缺标签:", f) continue shutil.copy(os.path.join(src_img, f), os.path.join(dst, "images", phase, f)) shutil.copy(os.path.join(src_lbl, lbl), os.path.join(dst, "labels", phase, lbl)) print("划分完成,训练集", split, "验证集", len(imgs) - split)

参数说明:seed=42是为了每次划分结果一致,方便复现;ratio按你的小类分布调;continue那行是关键,遇到缺标签的图直接跳过而不是报错中断,能让你一次性看到所有问题文件。

3.3 写对 vegetables.yaml

YOLO 训练靠这个 yaml 找数据和类别名,写错一个字段就白跑。

path: /data/vegetables # 数据集根目录,绝对路径最稳 train: images/train val: images/val nc: 26 # 类别数,必须和 names 长度一致 names: 0: carrot 1: tomato 2: cucumber # ... 依次列到 25

nc和names数量对不上是最常见的启动报错来源。另外names的顺序必须和 YOLO 标签里class_id的编号严格对应,错一位,模型就把番茄认成黄瓜,而且训练 loss 还正常下降,属于典型的「静默翻车」。

注意:path用绝对路径。相对路径在不同工作目录下启动训练时行为不一致,是排查半天找不到原因的经典坑。

4. 用 YOLOv8 跑通第一个蔬菜检测 baseline

数据整理好,接下来就是训练。这里以 YOLOv8 为例,因为它的命令行和 Python API 都比较顺,新手能快速看到结果,熟手也方便改参数。

4.1 环境准备与最小训练命令

先装依赖,再一条命令启动训练:

pip install ultralytics yolo detect train \ data=vegetables.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ device=0

model=yolov8n.pt用的是官方预训练权重,小模型n版本在 7100 张量级上足够跑出可用效果,而且训练快。imgsz=640是通用起点,如果你的蔬菜在图中占比很小(比如远景拍摄),可以提到 960 或 1280,但显存占用会明显上升。batch=16在 8G 显存上基本安全,爆显存就降到 8。

4.2 关键参数怎么调

训练参数不是越多越好,先盯住这几个:

参数作用建议值
epochs训练轮数100~300,看验证 mAP 是否还在涨
imgsz输入分辨率640 起步,小目标提到 960
batch批大小显存允许下尽量大,8~32
lr0初始学习率默认 0.01,小数据集可降到 0.001
patience早停耐心值50,避免过拟合空跑

lr0这个参数值得单独说:7100 张属于中小数据集,默认 0.01 有时候前期 loss 震荡厉害,降到 0.001 收敛更稳,代价是训练慢一点。我一般先跑 20 个 epoch 看 loss 曲线,震荡就降学习率。

4.3 训练过程看什么指标

启动后别干等,盯住控制台输出的几个量:

  • box_loss:框回归损失,应该整体下降,如果一直高位不动,多半是标签坐标有问题。
  • cls_loss:分类损失,下降慢说明类别难分或标注不一致。
  • mAP50:IoU 0.5 下的平均精度,这是判断模型好坏的直接指标。
  • mAP50-95:更严格,反映框的精细程度。

如果mAP50卡在很低的值不动,先别怀疑模型,回头查标签格式。我见过太多次「训练不收敛」,最后发现是 YOLO 标签里混进了 VOC 的绝对坐标。

4.4 推理验证:拿几张图看真实效果

训练完用最好的权重跑推理,眼见为实:

from ultralytics import YOLO model = YOLO("runs/detect/train/weights/best.pt") results = model.predict( source="test_images", # 放几张没参与训练的图 conf=0.25, # 置信度阈值,低了误检多,高了漏检多 iou=0.45, # NMS 的 IoU 阈值 save=True )

conf=0.25是默认起点,蔬菜类目之间颜色形状差异大,通常可以调到 0.3~0.4 减少误检。iou=0.45控制重叠框合并,如果同一颗菜被框了好几次,就把它调小。跑完去runs/detect/predict看可视化结果,重点看小类蔬菜有没有被漏掉。

5. 训练蔬菜检测模型最容易踩的 5 个坑

这一章是我自己踩过、也看别人踩过的真实问题,每条按「现象 → 原因 → 解决」写,照着排查能省不少时间。

5.1 现象:训练 loss 正常下降,但 mAP 一直是 0

原因:YOLO 标签的class_id从 1 开始编号,而 YOLO 要求从 0 开始。数据集里如果混了从 1 开始的标签,模型学到的类别全错位,但 loss 计算本身不报错。

解决:写个脚本扫一遍所有.txt,找出class_id最大值,如果等于nc而不是nc-1,说明编号整体偏移了 1,全部减 1 即可。

5.2 现象:报错「No labels found in ...」

原因:图片和标签没放在对应的images/labels平行目录,或者文件名大小写不一致(Carrot_01.jpg对carrot_01.txt)。

解决:用第 3 章的校验脚本先跑一遍,把所有不成对的文件列出来。Linux 下文件名区分大小写,Windows 下不区分,跨系统搬数据时特别容易出这个问题。

5.3 现象:某些蔬菜类别几乎检测不到

原因:类别样本严重不均衡,26 类里可能有的类上千张、有的类只有几十张,模型偏向多数类。

解决:先统计每类样本数,对极少样本的类做数据增强(旋转、亮度、裁剪),或者用 YOLO 的copy_paste增强。实在补不齐的类,考虑合并到相近类目,别硬训。

5.4 现象:验证集 mAP 很高,实际用新图测试一塌糊涂

原因:训练集和验证集来自同一批拍摄条件(同背景、同光照),模型过拟合了背景而不是蔬菜本身。

解决:划分验证集时按拍摄批次或背景分组,别纯随机分。如果数据集本身场景单一,实际部署前一定要补拍目标场景的图做微调。

5.5 现象:训练中途显存爆掉(CUDA out of memory)

原因:batch或imgsz设太大,或者 dataloader 的workers开太多。

解决:先把batch减半,还不行就降imgsz。workers在 Windows 上建议设 0,Linux 上设 4~8,开太多反而抢内存。

提示:显存爆掉不一定是参数问题,也可能是某张图分辨率异常大。训练前统一 resize 到接近imgsz的尺寸,能避免这种偶发崩溃。

6. 让 26 类蔬菜检测更稳的两个进阶技巧

baseline 跑通只是起点,真正上线前还有优化空间。这里说两个我实际用过、性价比高的技巧。

6.1 用类别权重缓解长尾分布

26 类蔬菜天然存在长尾,与其硬补数据,不如在损失里给稀有类加权。YOLOv8 本身不直接暴露类别权重参数,但可以通过自定义数据集采样来实现——让稀有类在每轮中被采样的概率更高。简单做法是复制稀有类样本到训练集,配合增强,效果立竿见影。更讲究的做法是改 dataloader 的 sampler,按类别频率的倒数设权重,代码量不大但需要你熟悉训练流程。

6.2 用混淆矩阵定位「互相认错」的类别

训练完 YOLO 会自动生成混淆矩阵,别忽略它。蔬菜里像青椒和黄瓜、生菜和白菜,颜色形状接近,很容易互相误判。看混淆矩阵能直接定位是哪几类在打架,然后针对性处理:要么补这几类的区分性样本,要么在推理时对这几类调高conf阈值。我一般会把混淆矩阵和实际误检图对照看,比单纯盯 mAP 有用得多。

6.3 一个验证数据集质量的小习惯

最后分享一个我养成的习惯:正式训练前,先随机抽 20 张图,把标注框画出来肉眼过一遍。这一步花不了十分钟,但能提前发现框歪了、类别标错、漏标这些致命问题。数据集质量决定模型上限,7100 张里如果有 5% 的脏标注,训出来的模型就会带着这些错误去部署。宁可前期多花时间清洗,也别等上线后对着误检结果抓瞎。

希望这些步骤和踩坑记录,能帮你把这个蔬菜数据集真正用起来,而不是停在「下载完就吃灰」的状态。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询