ARTICLE DETAIL

资讯详情

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

YOLO葡萄叶片病害检测数据集:从格式解析到训练避坑指南

YOLO葡萄叶片病害检测数据集:从格式解析到训练避坑指南 简介这是一份面向目标检测学习者与农业AI研究者的YOLO葡萄叶片病害检测数据集包含5000张真实场景高质量图片场景覆盖多样针对葡萄叶片病害识别任务可直接用于YOLO系列目标检测模型的训练与验证免去自行采集和标注流程。资源共2000个文件压缩包约176.9MB结构清晰1985个XML文件为VOC格式标注同时提供COCO(JSON)与YOLO(TXT)格式标签适配不同训练框架6个HTML教程覆盖Linux与Windows环境搭建及训练案例6个TXT列表配合3个Python脚本可灵活划分训练集、验证集与测试集。目前已有1400人学习下载。数据集采用LabelImg软件标注标注框质量高三种格式标签分类存放可无缝接入YOLO系列模型附赠教程从环境搭建到按案例修改训练自有数据集均有详细说明配合划分脚本能快速生成自定义数据集结构既适合初学者系统实践也便于中高级研究者迁移实验。1. 这份葡萄叶片病害数据集 rar 怎么用先搞清楚它能省你哪些事如果你是第一次看到“YOLO葡萄叶片病害检测数据集(含5000张图片)对应voc、coco和yolo三种格式标签划分脚本训练教程.rar”这个名字它更像是一个压缩包的说明书而不是模型论文。我的第一反应是终于有人把数据准备阶段最烦的三件事打包了。做目标检测的都知道真正花时间的不是跑通 YOLO而是把标注数据整理成模型能吃的格式并且让训练集、验证集、测试集在类别分布上不打架。这个 rar 要解决的就是这三件事5000 张葡萄叶片病害图片VOC、COCO、YOLO 三种标签格式外加划分脚本和训练教程。适合想用 YOLO 做农业检测项目、做毕业设计或快速验证算法的人。2. 看懂 5000 张图与三格式标签先对齐数据再谈训练2.1 葡萄叶片病害数据集的常见类别与目录结构打开 rar 后别急着跑训练命令。目标检测数据集的核心不是图片数量而是“每张图里有什么病害、每个框写在哪个文件里”。葡萄叶片病害检测通常不是二分类而是多类别目标检测。这个数据集里最常见的四个类别是葡萄黑腐病Black rot、黑麻疹/轮斑病Black measles/Esca、叶枯病Leaf blight和健康叶片Healthy。前三个是叶片上的病斑第四类别是负样本。叶片图像多来自田间拍摄背景复杂光照不均匀同一叶片上可能同时有多处病斑所以每张图的标注框数量并不固定可能从 0 个到十几个不等。从解压后的目录看通常会分成 images 和 labels 两个大块。我见过的最通用布局是images 下放一整包 JPGannotations/voc 放 XMLannotations/coco 放 JSONannotations/yolo 放 txt根目录放 classes.txt、划分脚本和 README。如果你拿到的是已经按 train/val/test 切好的三套目录那“划分脚本”就变成检查脚本如果拿到的是全量未划分数据就得先看 classes.txt再决定怎么切。我拿到任何数据后的第一步不是统计类别而是跑一条命令看三个文件数能不能对上。# 统计图片、VOC XML、YOLO txt 三类文件数量是否一致 find images -name *.jpg | wc -l find annotations/voc -name *.xml | wc -l find annotations/yolo -name *.txt | wc -l # 查看每个 YOLO 标签的非空行数判断是否存在无标注图片 wc -l annotations/yolo/*.txt | tail -20图片数等于 XML 数等于 txt 数这是最低级要求。注意 COCO 不能按文件数量校验因为所有标注都挤在一个 JSON 里真正要对齐的是 JSON 里的 image_id 和 image 文件名。另一个细节是YOLO 标签如果是 0 字节wc -l会显示 0说明这张图被标注为没有目标如果这张图本身是健康叶片这是正常现象但在训练时它的作用容易被忽视后面划分脚本部分我会专门说。2.2 VOC、COCO、YOLO 三种标签的本质同一种框三种写法很多人在格式转换时翻车是因为没有认清一个事实这三种格式标注的其实是同一批矩形框只是坐标参照系和文件组织方式不同。我习惯把它们看成“同一种框的三种序列化方式”。格式文件组织框坐标类别表达VOC每张图一个 XMLxmin, ymin, xmax, ymax 绝对像素字符串类别名COCO所有图一个或多个 JSONx, y, width, height 绝对像素category_id 整数 categories 数组YOLO每张图一个 txtx_center, y_center, width, height 归一化class_id 整数从 0 开始VOC 和 COCO 是给人看的“绝对坐标”YOLO 是给模型吃的“归一化坐标”。VOC 转 YOLO 时需要读图片宽高把左上角右下角转成中心点和宽高的归一化值COCO 转 YOLO 时要把 [x, y, width, height] 里的 x, y 当左上角而不是中心点这是最容易错的地方。另一个很容易被忽略的点是编号YOLO 的 class_id 约定从 0 开始而很多 COCO 风格 JSON 里的 category_id 从 1 开始。如果直接沿用原始编号而不减一训练出来的模型会把黑腐病和叶枯病永远错一位。所以拿到 classes.txt 后先确认它的顺序是否与 txt 里的第一列数字一一对应。2.3 拿到包后的一小时先做一次全量校验不要直接跳过校验进入训练。下面这个脚本我几乎每次拿到数据集都会跑一遍它能把最常见的三类问题一次性暴露出来XML 里坐标超过图片边界、JSON 里 category_id 和类别列表不对应、YOLO txt 里出现负数或大于 1 的归一化框。# check_dataset.py: 最小数据集校验脚本 import os import glob from PIL import Image from tqdm import tqdm IMG_DIR images YOLO_DIR annotations/yolo img_files glob.glob(os.path.join(IMG_DIR, *.jpg)) empty_labels [] bad_boxes [] for img_path in tqdm(img_files): stem os.path.splitext(os.path.basename(img_path))[0] txt_path os.path.join(YOLO_DIR, stem .txt) if not os.path.exists(txt_path): print(missing label:, txt_path) continue with open(txt_path) as f: lines [line.strip() for line in f.readlines() if line.strip()] if not lines: empty_labels.append(stem) continue with Image.open(img_path) as im: w, h im.size for line in lines: parts line.split() xc, yc, bw, bh map(float, parts[1:5]) if not (0 xc 1 and 0 yc 1 and 0 bw 1 and 0 bh 1): bad_boxes.append((stem, line)) if bw * w 0 or bh * h 0: bad_boxes.append((stem, zero-area box)) print(empty labels:, len(empty_labels)) print(bad boxes:, len(bad_boxes))这段逻辑很简单先保证每张图都有同名 txt再解析每行的四个归一化坐标并用原图宽高检查它是否落在有效范围内。为什么用 YOLO 格式做校验而不是 XML因为 YOLO 格式是最后送到模型里训练的它错了前面所有流程都白做。如果 empty_labels 过多说明数据集里混入了大量背景图你要在划分脚本里决定是把它们保留为背景样本还是直接过滤掉。我的习惯是如果病害类别已经很多就保留因为真实果园里确实有大量健康叶片模型应该学会“什么都不框”。3. 划分脚本这样用按图片分不让标签掉队也不让类别失衡3.1 划分的本质是按图分不是按标注行分看到“划分脚本”四个字新手最容易把它理解成“把 txt 里的一行行标注按比例抽出来”。这是大忌。目标检测数据集的划分单位永远是“图片”一张图里的所有目标、所有格式标签必须完整地进入同一个子集。否则就是数据泄漏同一条病害框的语义信息被同时送进训练集和验证集验证指标会虚高部署到新果园里立刻现原形。常见的划分比例有两种训练/验证/测试 8:1:1或者训练/验证 9:1 再单独留测试集。如果验证集还要用来做早停和超参选择我建议验证集至少保留 100 到 200 张不要因为图片总量看着多就切到 2% 以下。5000 张图切 10% 出来是 500 张对于葡萄叶片病害这种类内差异小的任务已经够稳。另外要留意划分脚本是否支持“同名拷贝”。图片叫 img_0001.jpg对应的格式标签应该叫 img_0001.xml、img_0001.txt以及在大 JSON 里有对应的 image 记录。只有按 basename 做关联才能保证三种格式不会互相错位。如果脚本里用了随机数而不是图片名那就是在给以后挖坑。3.2 一个按比例划分并同步三格式标签的脚本下面这个脚本是我比较习惯的版本核心思路是先把图片文件名打乱再按比例切成三段随后把图片、VOC XML、YOLO txt 复制到对应目录最后再从原始的 COCO 大 JSON 里按 image_id 过滤出属于各个子集的标注重新导出三个 JSON。# split_dataset.py: 按 train/val/test 划分并同步三种格式标签 import json import os import random from shutil import copy2 SRC_IMAGES images SRC_VOC annotations/voc SRC_YOLO annotations/yolo SRC_COCO annotations/coco/instances_all.json OUT split TRAIN_RATIO, VAL_RATIO, TEST_RATIO 0.8, 0.1, 0.1 SEED 42 # 1. 按图片名划分 img_stems [os.path.splitext(f)[0] for f in os.listdir(SRC_IMAGES) if f.endswith(.jpg)] random.seed(SEED) random.shuffle(img_stems) n_train int(len(img_stems) * TRAIN_RATIO) n_val int(len(img_stems) * VAL_RATIO) split { train: img_stems[:n_train], val: img_stems[n_train:n_train n_val], test: img_stems[n_train n_val:], } # 2. 复制图片、VOC XML、YOLO txt for subset, stems in split.items(): for stem in stems: copy2(os.path.join(SRC_IMAGES, stem .jpg), os.path.join(OUT, subset, images, stem .jpg)) copy2(os.path.join(SRC_VOC, stem .xml), os.path.join(OUT, subset, voc, stem .xml)) copy2(os.path.join(SRC_YOLO, stem .txt), os.path.join(OUT, subset, yolo, stem .txt)) # 3. 拆分 COCO JSON with open(SRC_COCO) as f: coco json.load(f) filename_to_id {img[file_name]: img[id] for img in coco[images]} id_to_subset {} for subset, stems in split.items(): for stem in stems: jpg stem .jpg if jpg in filename_to_id: id_to_subset[filename_to_id[jpg]] subset for subset in split: imgs [img for img in coco[images] if img[id] in id_to_subset and id_to_subset[img[id]] subset] img_ids {img[id] for img in imgs} anns [ann for ann in coco[annotations] if ann[image_id] in img_ids] out_path os.path.join(OUT, subset, coco, instances.json) os.makedirs(os.path.dirname(out_path), exist_okTrue) json.dump({images: imgs, annotations: anns, categories: coco[categories]}, open(out_path, w)) print(train/val/test:, len(split[train]), len(split[val]), len(split[test]))脚本里有两个值得解释的参数。SEED42是随机种子固定下来后每次运行划分结果一致这对后面复现实验非常关键不固定种子的话同一个人跑两次划分实验结果都无法互相比较。TRAIN_RATIO/VAL_RATIO/TEST_RATIO三个值相加必须等于 1脚本里没有防御性检查改的时候记得自己算。COCO 拆分部分我刻意用了id_to_subset这个字典而不是对每个 annotation 遍历所有 subset这样做能避免一张图的标注被重复写进多个 JSON比很多网上的简化脚本可靠。3.3 划分比例怎么定按类别样本量而不是按图片张数葡萄叶片病害数据看起来类多实际上常常是黑腐病占了一半叶枯病只有少量。如果只是按图片名随机 shuffle测试集可能 500 张里只有一两个叶枯病目标PR 曲线直接没法看。这时候要做分层划分统计每张图包含哪些类别再按“图片至少包含某个稀有类别”做分组尽量保证稀有类别的框按比例出现在每个子集里。因为一张图可能同时有多个类别分层不能简单用 sklearn 的 train_test_split(stratifylabels) 直接套。一种稳妥做法是先把数据集按“主类别”打标比如按该图里出现次数最少的类别作为层标签然后再做分层采样。下面这个片段可以代替 3.2 里的随机 shuffle 部分。from sklearn.model_selection import train_test_split # 统计每张图的类别出现情况 img_classes {} for stem in img_stems: txt_path os.path.join(SRC_YOLO, stem .txt) with open(txt_path) as f: classes [int(line.split()[0]) for line in f if line.strip()] # 用“最少出现类别”作为分层字段 if classes: rarest min(set(classes), keylambda c: classes.count(c)) img_classes[stem] rarest else: img_classes[stem] -1 # 背景图单独一层 stems list(img_classes.keys()) labels [img_classes[s] for s in stems] train_stems, test_stems train_test_split( stems, test_size0.2, stratifylabels, random_state42 )stratifylabels会让训练/测试集合里的各类别比例尽量接近原始比例背景图单独标记为 -1是为了让没有病害的图片也被均匀切分而不是全部堆到测试集。划分完成后建议用一条命令看每个子集的类别框数量分布# 统计 train 里各类别框数量用第 1 列 class_id 做聚合 for f in split/train/yolo/*.txt; do cat $f; done | awk {print $1} | sort | uniq -c如果某个类别在 train 里有 800 个框在 val 里只有 3 个那你后面验证结果会非常不稳定。此时就该回头把该类别的图片在三个子集之间手动匀一匀而不是指望模型自己适应。4. 用 YOLOv8 跑通训练教程从 data.yaml 到 best.pt4.1 准备数据 YAML让 YOLOv8 认识你的葡萄叶片rar 里的训练教程大概率是围绕 YOLOv5 或 YOLOv8 写的。以现在的生态“yolov8训练自己的数据集”是最常见的长尾需求我直接按 YOLOv8 讲。下载并安装 ultralytics 包后第一步不是跑命令而是写一个 grape.yaml告诉训练脚本三件事你的图片放在哪、你的标签是哪种格式、一共有几个类别。# grape.yaml path: /absolute/path/to/split # 数据集根目录 train: train/images val: val/images test: test/images nc: 4 names: [black_rot, black_measles, leaf_blight, healthy]这里最重要的不是names的写法而是names的顺序必须和 YOLO txt 里的class_id完全一致。假设你的 classes.txt 顺序是 black_rot, black_measles, leaf_blight, healthy那么 txt 里第一列数字 0 一定代表黑腐病换成任何其他顺序都会让训练指标看起来正常但预测结果完全离谱。我习惯把 grape.yaml 放在 split 目录的上一级而不是 images 附近这样相对路径不容易出错。path 建议写绝对路径尤其是第一次跑的时候写相对路径在 Jupyter 和命令行之间来回切换时很容易翻车。然后跑训练最小命令是yolo detect train datagrape.yaml modelyolov8n.pt epochs100 imgsz640 batch16注意modelyolov8n.pt表示从 COCO 预训练权重继续训练而不是从随机权重开始。5000 张图规模不大用 yolov8n 或 yolov8s 是性价比最高的组合用 yolov8l 反而容易过拟合训练速度也会慢到让你怀疑人生。YOLOv8 默认只认 YOLO txt 格式标签VOC 和 COCO 在这个阶段只是备份不需要让训练脚本去读它们。4.2 训练参数怎么设imgsz、batch、optimizer 和损失函数的关系训练过程不是玄学但很多人喜欢把参数调乱。我给出一个在 5000 张葡萄叶片数据上比较稳的起点参数建议值说明imgsz640YOLOv8 默认输入尺寸病斑细节能保留batch1624G 显存可用 3216G 显存用 8epochs100配合早停实际 40 到 60 轮就收敛optimizerAdamW 或 SGD小数据集首选 AdamW想稳定收敛用 SGDlr00.01AdamW 可降到 0.001SGD 保持 0.01patience30验证集 30 轮不涨就停省时间为什么 imgsz 很关键YOLOv8 训练时的分辨率会影响病斑这种小尺寸目标的检测能力。如果原图是 4000x3000 的果园相机照片直接缩到 640 会让小黑斑只剩十几个像素有条件的话可以试 960 或 1280但显存和速度会明显上涨。我个人的习惯是先用 640 跑通全流程确认 loss 正常后再单独试 960。训练时会输出三行主要损失box_loss、cls_loss、dfl_loss。box 是回归框位置的损失cls 是分类损失dfl 是分布焦点损失负责让预测框的边界更准。YOLOv8 的损失函数默认带了数据增强mosaic 会把四张图拼接成一张如果你的葡萄叶片图像里有很多孤立的小病斑mosaic 可能把目标切碎导致早期 loss 震荡此时可以在训练命令后加mosaic0.5来降低增强强度。如果看到 box_loss 一直在降但 cls_loss 震荡大概率是类别不均回去看看叶枯病样本有没有被划分脚本漏掉不要急着改学习率。4.3 训练完选哪个权重best.pt、last.pt 和一次验证训练结束后会在 runs/detect/train/weights/ 下看到至少两个文件。best.pt 是在整个训练过程中验证集 mAP 最高的那一轮last.pt 是最后一轮。我的习惯是直接用 best.pt 做后续测试last.pt 只在你怀疑验证集有严重数据泄漏时才拿出来对比。跑验证和跑测试用的命令不同不要混# 在验证集上评估 yolo detect val modelpath/to/best.pt datagrape.yaml # 在测试集上评估 yolo detect val modelpath/to/best.pt datagrape.yaml splittestsplittest只有当你 data.yaml 里定义了 test 字段才生效如果没有定义会用 val 代替。验证结果会打印 mAP50 和 mAP50-95。mAP50 是 IoU 阈值 0.5 的平均精度mAP50-95 是 0.5 到 0.95 每隔 0.05 的平均后者对框的定位精度要求苛刻得多。葡萄叶片病害只要 mAP50 能到 0.85 以上实际用起来就不会太差mAP50-95 受小病斑影响大不必强求 0.6 以上。5. 避坑清单从标签格式到训练崩坏的 5 个常见问题训练跑不出来八成不是模型的错是数据在某个环节被做坏了。下面这五条是我在数据集类项目里反复踩过的坑按“现象、原因、解决”写清楚。5.1 坐标越界导致 loss 变成 nan现象VOC 转 YOLO 后训练到一半某个 epoch 的 loss 突然变成 nan或者预测时框画到了图片外面。原因XML 里的 xmax 偶尔比图像宽度还大 2 到 3 个像素。这是标注工具和人工修正共同造成的公开数据集里非常常见。另一个来源是 COCO 的 bbox 用 x,y,w,h 表示x,y 是左上角w,h 是宽高如果直接混用成中心点写法就会出现负坐标或超大框。解决格式转换时不要只做字符串替换要对坐标做一次 clamp把越界值截断为图片边界同时过滤掉 w 或 h 小于等于 0 的框。把 2.3 的校验脚本作为训练前置步骤任何一个 YOLO txt 里出现大于 1 或小于 0 的小数都直接报警。这是成本最低的后悔药。5.2 类别编号偏移让模型学错病害现象训练时 loss 正常mAP 也很高但把模型拿去做预测黑腐病图片被输出成叶枯病而且是稳定地错位。原因原始 COCO JSON 的 category_id 从 1 开始而 YOLO 的 class_id 从 0 开始。如果转换脚本没有把 category_id 全部减一那么 4 个类别会变成 0 到 3 的错位映射。还有一种情况是 classes.txt 的顺序与标注者当时用的顺序不同但 rar 里没有更新 classes.txt。解决先打印一份类别映射表人工核对每个数字对应的病害名。把 COCO 转 YOLO 时明确执行class_id category_id - 1不要在几个脚本里各写各的偏移量。最稳妥的做法是先用 YOLO txt 里的 class_id 画一遍框并附上类别名输出几张图人工看错了就说明映射有问题。5.3 验证集的稀有类别样本数为 0现象训练日志显示验证集 mAP 很高但部署到另一批葡萄园图片时某个病害类别完全框不出来。打开混淆矩阵一看那一类全部被预测成了背景。原因随机划分时稀有病害类别几乎全部分到了训练集验证集里那个类别的样本数为 0。模型虽然在训练时见过该类但验证时没有任何真值框参与评测早停和选 best 权重都对这个类别“失明”最终选出的权重可能在该类上极差。解决使用 3.3 的分层划分把稀有类别按比例塞进每个子集如果某个类别框数量太少比如只有 10 个框建议把它固定放进验证集而不是测试集至少保证训练时能看住它。训练前在命令行里打印各子集类别分布只要某类数量为 0 就中止不要心存侥幸。5.4 背景图被划分脚本误删现象数据集中有几百张健康叶片的图片YOLO txt 是 0 字节划分脚本把它们全部过滤掉了。训练出来的模型在背景上疯狂误检把土壤、石子都框成病斑。原因很多划分脚本只复制“有标签”的图片因为目标检测通常假设每张图都有框。但葡萄叶片场景中健康叶片本身就是重要负样本没有框的图片不是垃圾而是告诉模型“这里什么都没有”的样本。解决划分脚本不要用“txt 文件是否为空”来判断图片是否有效。所有图片都应该进入某个子集空标签图片同样复制到 train 和 val。训练时 YOLO 支持空标签图它会输出“无目标”的预测这对降低误检很有帮助。如果 rar 里这些健康叶片图已经被整理到单独文件夹也要在划分时把它们均匀插到三个子集里。5.5 训练中 BN 崩溃与图片损坏现象训练跑到第 20 个 epoch 左右box_loss 突然变成 nan命令行报出 nan 或 CUDA error重启训练后在同一位置再次崩溃。原因这种情况在中文技术社区里常被叫“yolo训练中bn崩溃”底层原因通常是某张图片读出来是全黑或全白或者标签坐标与图片尺寸严重不匹配导致 BN 层的统计量产生极端值。另一类原因是 data.yaml 的 train 路径指向了一个只有一个文件的目录数据加载器几乎每次迭代都抽到同一张异常图。解决先用 OpenCV 把所有图片读一遍统计读不出的文件再跑一遍 2.3 的校验脚本把异常输入过滤掉。如果偶尔才出现把 batch 调小一档试试。更持久的方法是在训练命令里加 cacheTrueYOLOv8 第一次会把图片缓存进内存并暴露无法解码的文件。如果还在崩检查是不是图片 EXIF 旋转信息导致 OpenCV 读到的宽高和标注时不一致这种问题会在第 6 章的可视化验证里暴露得更明显。6. 验证不只是看 mAP用混淆矩阵和 PR 曲线找到模型短板6.1 从混淆矩阵看哪些叶片被漏检训练完成后runs/detect/train/ 下会生成混淆矩阵图。很多人只看对角线数字忽略了一个细节YOLO 的混淆矩阵总合不唯一因为它对每个 GT 框只匹配一次但预测框可能被重复计入背景行。所以不要拿矩阵里的百分比去和别人的论文对比而是看“真实黑腐病那一行里被判成背景的比例是多少”。如果背景占比超过 10%说明你的病斑太小模型在特征提取时把信息丢了。这时可以考虑提升训练分辨率或从 yolov8n 换到 yolov8s而不是继续压着 nano 硬调。6.2 用 PR 曲线挑选置信度阈值验证阶段除了 mAP还会输出 PR 曲线。横轴是召回率纵轴是精确率曲线往右上角弯代表模型既准又全。部署时YOLO 默认的 conf0.25 对很多农业场景太宽松。病害检测宁可漏掉也不能乱报所以我会把 conf 提到 0.35 或 0.4。方法是先看 PR 曲线的拐点如果某个类别在召回率 0.8 时精确率掉到 0.6说明要继续提高 conf 到精确率较高的区间否则果园里的石头也会被误报成病斑。如果调高 conf 后某类召回率骤降则说明该类别的特征学习不足回到数据层面补样本而不是继续调阈值。6.3 一个小技巧用 TTA 对单张难例做兜底如果测试集里总有几张叶片被强光或阴影干扰conf 调不下去我一般会给 predict 加 --augment 开启测试时增强将多尺度推理结果合并。速度会慢一些但对单张图片的召回率提升非常明显。这是农业检测项目里比较实用的兜底手段能有效缓解因光照导致的小病斑漏检。做这类项目久了我的习惯是“先别管模型用什么先检查标签和划分对不对”。数据划分、格式对齐一旦出错后面所有实验都是在错误地基上盖楼。这次整理的流程希望能帮你在拿到数据集后少走弯路把时间真正花在训练和验证上而不是和格式与路径作斗争。希望帮到你。本文还有配套的精品资源点击获取
返回列表