
简介本资源为面向目标检测学习者的YOLO葡萄叶片病害检测数据集适合农业图像识别方向的课程设计、毕业设计及算法入门实践帮助解决真实场景下病害样本不足、标注格式不统一的问题。压缩包共2000个文件约34.79MB包含1000张真实场景图片及对应标注其中xml、txt为主要标签格式另有少量py划分脚本、yaml配置与html说明文档覆盖voc、coco、yolo三种主流格式可直接接入YOLO系列训练流程。资源附带数据集划分脚本与训练案例教程支持按需生成训练集、验证集、测试集并配有环境搭建与训练流程说明便于快速复现与二次调整。目前已有457人学习下载适合希望低成本获取高质量标注数据、快速跑通检测流程的读者参考使用。1. 葡萄叶片病害检测数据集从拿到压缩包到跑通第一条训练命令葡萄叶片病害检测这个方向真正卡住大多数人的从来不是模型结构而是数据。你手上如果有一个「1000 张图片 VOC/COCO/YOLO 三种格式标签 划分脚本 训练教程」的压缩包那它解决的正是最脏最累的那一段标注格式转换、训练集验证集划分、以及把数据喂进 YOLO 训练器的最后一公里。这篇笔记就围绕这个数据集包把「它是什么、三种标签格式怎么选、划分脚本怎么改、YOLO 训练命令怎么配、哪里最容易翻车」一条线讲透。适合两类人刚接触 YOLO 目标检测、想拿一个真实农业场景数据集练手的新手以及手上有类似数据、需要一套可复现流程的从业者。读完你应该能独立完成从解压到跑出第一轮 mAP 的全过程并且知道每个参数动了会发生什么。2. 三种标签格式到底差在哪VOC、COCO、YOLO 的选型逻辑拿到数据集先别急着训练先搞清楚压缩包里为什么同时给了三种格式。这不是作者凑数而是因为不同训练框架、不同评估工具吃的格式不一样。选错格式轻则多写一堆转换脚本重则坐标对不上、训练 loss 不降你还以为是模型问题。2.1 VOC 格式XML 的坐标是左上右下别和 YOLO 搞混VOC 格式每张图对应一个同名 XML 文件核心结构是annotation下面挂filename、size和若干个object。每个object里有name类别名和bndboxbndbox里是xmin/ymin/xmax/ymax注意这是绝对像素坐标而且是左上角到右下角。annotation filenameleaf_0001.jpg/filename size width640/width height480/height depth3/depth /size object nameblack_rot/name !-- 类别名黑腐病 -- bndbox xmin112/xmin !-- 左上角 x绝对像素 -- ymin88/ymin !-- 左上角 y -- xmax305/xmax !-- 右下角 x -- ymax260/ymax !-- 右下角 y -- /bndbox /object /annotationVOC 的好处是可读性强用文本编辑器就能改适合人工复核标注质量。坏处是文件数量翻倍1000 张图就是 1000 个 XML读取慢。常见做法是用 VOC 做标注复核和可视化确认框没问题后再转成 YOLO 格式去训练。2.2 COCO 格式一个 JSON 管全部但索引容易对错COCO 把所有标注塞进一个 JSON 文件顶层是images、annotations、categories三个数组。images里每张图有唯一idannotations里每条标注用image_id关联到图用category_id关联到类别bbox是[x, y, width, height]注意这里是左上角坐标加宽高不是右下角。{ images: [ {id: 1, file_name: leaf_0001.jpg, width: 640, height: 480} ], annotations: [ {id: 1, image_id: 1, category_id: 1, bbox: [112, 88, 193, 172], // x, y, w, h area: 33196, iscrowd: 0} ], categories: [ {id: 1, name: black_rot} ] }COCO 格式适合用 pycocotools 做评估也适合 MMDetection 这类框架。坑在于image_id和category_id必须从 1 开始且连续如果你自己拼 JSON很容易出现 id 跳号导致评估时类别对不上。我一般会写个校验脚本先确认categories数量和实际类别数一致再开始训练。2.3 YOLO 格式归一化中心点坐标训练前必须核对YOLO 格式最简单每张图一个同名.txt每行一条标注类别索引 中心x 中心y 宽 高后四个值都是相对图像宽高的归一化值范围 0 到 1。类别索引从 0 开始对应一个classes.txt或data.yaml里的names列表。0 0.336 0.362 0.302 0.358 1 0.712 0.540 0.180 0.220第一行意思是类别 0框中心在图像宽度 33.6%、高度 36.2% 的位置框宽占图宽 30.2%高占图高 35.8%。这个格式是 YOLOv5/v8 系列直接吃的训练时不用再转。判断转换对不对有个土办法用脚本把 YOLO 框画回原图肉眼看框有没有偏。偏了基本就是归一化时除了错的宽高或者 VOC 的右下角坐标没转成宽高。三种格式的对照关系可以记成这张表维度VOCCOCOYOLO存储方式每图一个 XML单个 JSON每图一个 txt坐标形式绝对左上右下绝对左上宽高归一化中心宽高类别表示字符串 namecategory_id整数索引典型用途标注复核pycocotools 评估YOLO 训练选型结论很直接训练用 YOLO 格式复核用 VOC评估要 COCO 再转。压缩包里三种都给就是让你不用自己写转换但转换逻辑你得懂否则出了问题无从排查。3. 划分脚本怎么改训练集验证集比例与随机种子的实操数据划分看着简单其实是复现性问题的重灾区。同一个数据集别人跑出 0.85 mAP你跑出 0.72很多时候不是模型问题是划分不同导致验证集难度不一样。这一章把划分脚本的关键参数讲清楚。3.1 划分比例不是拍脑袋8:2 还是 7:3 要看样本量1000 张图属于小数据集验证集太小会导致 mAP 抖动大太大又浪费训练样本。常见做法是训练集 800、验证集 200也就是 8:2。如果类别极不均衡比如黑腐病只有 80 张那验证集里可能只剩十几张评估结果参考价值有限这时候可以考虑 7:3 或者做分层抽样。分层抽样的意思是按类别分别划分保证每个类别在训练集和验证集里的比例一致。下面是一个可抄的划分脚本按类别分层固定随机种子。import os import random import shutil from collections import defaultdict # 参数区按需修改 IMG_DIR images # 原图目录 LBL_DIR labels # YOLO 标签目录 OUT_DIR dataset_split # 输出目录 VAL_RATIO 0.2 # 验证集比例 SEED 42 # 随机种子固定后划分可复现 random.seed(SEED) # 1. 收集所有图片按主类别分组取标签第一行的类别作为主类别 img_files [f for f in os.listdir(IMG_DIR) if f.endswith((.jpg, .png))] groups defaultdict(list) for img in img_files: lbl os.path.join(LBL_DIR, os.path.splitext(img)[0] .txt) if not os.path.exists(lbl): continue with open(lbl) as f: first_line f.readline().strip() if not first_line: continue main_cls first_line.split()[0] # 主类别索引 groups[main_cls].append(img) # 2. 每个类别内部按比例划分保证类别分布一致 train_list, val_list [], [] for cls, files in groups.items(): random.shuffle(files) n_val max(1, int(len(files) * VAL_RATIO)) # 至少留 1 张 val_list.extend(files[:n_val]) train_list.extend(files[n_val:]) # 3. 拷贝到输出目录保持 images/labels 结构 for split, files in [(train, train_list), (val, val_list)]: for sub in [images, labels]: os.makedirs(os.path.join(OUT_DIR, split, sub), exist_okTrue) for img in files: shutil.copy(os.path.join(IMG_DIR, img), os.path.join(OUT_DIR, split, images, img)) lbl os.path.splitext(img)[0] .txt shutil.copy(os.path.join(LBL_DIR, lbl), os.path.join(OUT_DIR, split, labels, lbl)) print(ftrain: {len(train_list)}, val: {len(val_list)})逻辑说明先按主类别分组再在组内打乱划分这样每个类别在验证集里都有代表。SEED42是关键固定后任何人跑这个脚本得到的划分完全一致方便对比实验。n_val max(1, ...)是防止小类别被全部划进训练集验证时该类直接消失。参数说明VAL_RATIO一般 0.15 到 0.25 之间1000 张图建议 0.2SEED换成别的值会得到不同划分做对比实验时不要中途改如果类别极度不均衡可以把main_cls换成多标签分组但脚本会复杂不少小数据集一般没必要。3.2 划分后必须做的两项校验划分完不要直接开训先做两个检查。第一确认训练集和验证集没有重复图片重复会导致验证指标虚高。第二确认每张图都有对应标签文件缺标签的图在训练时会被跳过等于白占位置。# 校验1检查图片和标签是否一一对应 for img in dataset_split/train/images/*.jpg; do lbl${img/images/labels} lbl${lbl%.jpg}.txt [ -f $lbl ] || echo 缺标签: $img done # 校验2检查训练集和验证集是否有同名图片重复 comm -12 (ls dataset_split/train/images | sort) \ (ls dataset_split/val/images | sort)第一条命令遍历训练集图片把路径里的images替换成labels、后缀换成.txt不存在就打印。第二条用comm找两个目录的交集有输出就说明有重复需要手动处理。这两步花不了一分钟但能省掉后面几小时的无效训练。4. 用 YOLOv8 跑通训练data.yaml 配置与关键参数数据准备好了接下来是训练。这里以 YOLOv8 为例因为它的配置文件最直观社区资料也最多。如果你用的是 YOLOv5命令结构类似参数名略有差异核心逻辑一样。4.1 data.yaml 怎么写路径、类别数、类别名三件套YOLOv8 训练靠一个data.yaml告诉它数据在哪、有几个类、类叫什么。这个文件写错训练直接报错或者类别全乱。# data.yaml path: /home/user/dataset_split # 数据集根目录绝对路径最稳 train: train/images # 相对 path 的训练图目录 val: val/images # 相对 path 的验证图目录 nc: 4 # 类别数必须和实际一致 names: # 类别名顺序对应标签里的索引 0: black_rot 1: esca 2: leaf_blight 3: healthypath建议写绝对路径相对路径在不同工作目录下跑容易找不到文件。nc是类别数写错会直接报维度不匹配。names的顺序必须和标签文件里的类别索引严格对应索引 0 就是black_rot不能乱。如果你不确定类别数去标签目录里统计一下所有 txt 第一列的最大值加一。# 统计标签里出现过的类别索引 cat dataset_split/train/labels/*.txt | awk {print $1} | sort -u输出几个数字就说明有几个类最大值加一就是nc。这个命令比人眼数靠谱尤其是类别多的时候。4.2 训练命令与必调参数epochs、imgsz、batch 怎么定配置写好一条命令就能开训。下面这条是我在单卡 8G 显存上跑 1000 张图常用的配置。yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/grape \ nameexp1逐参数说明modelyolov8n.pt是最小的预训练权重1000 张图用 n 或 s 就够别一上来上 x容易过拟合还慢。epochs100对小数据集通常够配合patience20早停验证指标 20 轮不涨就停省时间。imgsz640是输入尺寸如果你的原图分辨率远大于 640可以调到 960 或 1280但显存占用会明显上升。batch16在 8G 显存上比较稳显存不够就降到 8 或 4别硬撑OOM 报错会中断训练。lr00.01是初始学习率YOLOv8 默认会自动调手动设的话 0.01 是常用起点。训练开始后重点看两个东西一是box_loss和cls_loss是否稳定下降二是每轮结束打印的mAP50。如果 loss 震荡剧烈先把lr0降到 0.001 试试如果 mAP 一直不涨检查标签格式和类别对应八成是数据问题不是模型问题。4.3 训练完怎么验证混淆矩阵和预测可视化训练结束权重存在runs/grape/exp1/weights/best.pt。别只看最后的 mAP 数字用混淆矩阵看每个类别的误判情况再用预测脚本抽几张图肉眼看。# 在验证集上评估输出混淆矩阵和各类指标 yolo detect val \ modelruns/grape/exp1/weights/best.pt \ datadata.yaml \ imgsz640 \ plotsTrueplotsTrue会在输出目录生成混淆矩阵、PR 曲线等图。重点看混淆矩阵对角线如果某个类别大量被误判成另一个类别说明这两类视觉特征太像可能需要更多样本或者调整标注边界。然后再跑一次预测把结果图存下来看。# 对验证集图片做预测保存可视化结果 yolo detect predict \ modelruns/grape/exp1/weights/best.pt \ sourcedataset_split/val/images \ conf0.25 \ saveTrueconf0.25是置信度阈值低于这个值的框不显示。看预测图时注意漏检和误检漏检多说明模型没学好或者标注有遗漏误检多说明背景干扰大或者阈值太低。这一步是训练流程里最容易被跳过、但最能发现问题的一步。5. 避坑与排查葡萄叶片病害检测训练中最容易翻车的 5 个点这一章是我自己踩过和帮别人排查过的真实问题每条按「现象 → 原因 → 解决」写。如果你训练不顺利先对照这里过一遍大概率能定位到。5.1 训练 loss 不降mAP 一直是 0现象训练跑起来box_loss在几个数值之间来回跳mAP50始终是 0 或者极低。原因最常见的是标签格式不对。比如把 VOC 的绝对坐标直接当 YOLO 归一化坐标用坐标值大于 1模型根本学不到有效位置。其次是data.yaml里nc和实际类别数不一致或者names顺序和标签索引对不上。解决先跑一遍格式校验确认所有 YOLO 标签的坐标值都在 0 到 1 之间。命令很简单awk {if($21||$31||$41||$51) print FILENAME} labels/*.txt有输出就说明坐标没归一化。再核对nc和names用前面统计类别索引的命令确认。5.2 验证集 mAP 很高但实际预测一塌糊涂现象训练日志里mAP50到 0.9 了拿新图片去预测框得乱七八糟或者什么都检测不到。原因训练集和验证集划分时没有打乱或者验证集图片和训练集高度相似比如同一片叶子的连拍导致验证指标虚高。另一个可能是过拟合1000 张图跑了几百轮模型把训练集背下来了。解决检查划分脚本有没有random.shuffle确认训练集和验证集没有重复图片。如果已经过拟合减少epochs加数据增强YOLOv8 默认有可以调mosaic、flipud等参数或者换更小的模型。判断过拟合看训练 loss 和验证 loss 的差距验证 loss 开始上升就是信号。5.3 显存溢出训练中途崩掉现象训练跑了几轮突然报 CUDA out of memory进程被杀。原因batch或imgsz设太大或者没有及时释放上一轮缓存。8G 显存跑imgsz640、batch16一般没问题但如果调到imgsz1280batch还保持 16基本必崩。解决先把batch减半还崩就再减。或者用yolo detect train ... batch-1让框架自动选 batch size。另外训练前确认没有其他进程占着显存nvidia-smi看一眼有残留进程就清掉。5.4 类别不均衡导致小类别检测效果极差现象黑腐病检测很准但 healthy 或者某个少见类别几乎检测不到混淆矩阵里该类全是漏检。原因小类别样本太少模型在训练时被大类别主导学不到小类别的特征。解决三个方向。一是数据层面对小类别做增强比如随机裁剪、旋转、加噪声扩充样本。二是损失层面YOLOv8 支持类别权重可以在data.yaml同级配置里调整但小数据集效果有限。三是评估层面别只看总体 mAP分开看每个类别的 AP小类别 AP 低是正常的关键是别为 0。5.5 训练速度异常慢GPU 利用率上不去现象一轮训练要十几分钟nvidia-smi看 GPU 利用率只有 20% 到 30%。原因数据加载是瓶颈。图片放在机械硬盘、或者workers设太少、或者图片尺寸太大导致解码慢。解决把数据集放到 SSD 上训练命令加workers8根据 CPU 核数调整imgsz不要盲目调大。如果还慢检查是不是开了太多后台进程抢 IO。GPU 利用率低基本都是数据供给跟不上不是模型问题。6. 进阶技巧用冻结训练和断点续训把 1000 张图榨干小数据集训练最怕两件事一是过拟合二是训练中断重来。这一章讲两个我常用的技巧能把 1000 张图的效果和效率都往上提一档。6.1 冻结主干先训头再解冻微调YOLOv8 的预训练权重是在大数据集上学的通用特征直接全量微调容易把好特征带偏。常见做法是前若干轮冻结主干网络只训检测头让头先适应你的类别再解冻全网络微调。YOLOv8 命令行支持freeze参数。# 第一阶段冻结主干只训检测头20 轮 yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs20 \ imgsz640 \ batch16 \ freeze10 \ projectruns/grape \ namestage1_freeze # 第二阶段解冻全部用第一阶段权重继续微调 yolo detect train \ datadata.yaml \ modelruns/grape/stage1_freeze/weights/best.pt \ epochs80 \ imgsz640 \ batch16 \ lr00.001 \ projectruns/grape \ namestage2_finetunefreeze10表示冻结前 10 层具体层数可以按模型结构调整n 模型冻结 10 层基本覆盖主干。第二阶段学习率降到 0.001因为此时模型已经接近好的解大学习率会破坏已学特征。这个两阶段流程在小数据集上通常比直接训 100 轮稳定mAP 也能高几个点。6.2 断点续训训练中断不用从头来训练到一半断电或者被抢占不用从头跑。YOLOv8 会在输出目录保存last.pt用它加resume参数就能接着训。yolo detect train \ resumeruns/grape/exp1/weights/last.ptresume会自动读取之前的优化器状态、学习率调度和 epoch 数从断点继续。注意last.pt和best.pt的区别last.pt是最后一轮的权重best.pt是验证指标最好的权重。续训用last.pt推理用best.pt别搞混。如果last.pt损坏那就只能从best.pt重新开始但优化器状态丢了效果可能略差。6.3 一个验证训练是否值得继续的土办法训练过程中不用一直盯着我一般跑起来后隔一段时间看一次results.csv里面每轮的 loss 和 mAP 都有记录。判断要不要停如果最近 20 轮mAP50波动不超过 0.005且验证 loss 不再下降基本可以停了再训就是浪费时间。如果mAP50还在缓慢上升哪怕每轮只涨 0.001也可以再等等。这个判断比死等patience更主动。最后说个我自己的习惯每次训练前把data.yaml、划分脚本、训练命令记在一个README里连同results.csv一起存档。葡萄叶片病害这个方向数据集不大实验迭代快不记录的话两周后就忘了哪组参数对应哪个结果。这个习惯帮我省了无数次重复试错。希望帮到你。本文还有配套的精品资源点击获取