ARTICLE DETAIL

资讯详情

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

葡萄叶片病害检测数据集:10000张图与VOC/COCO/YOLO标签实战

葡萄叶片病害检测数据集:10000张图与VOC/COCO/YOLO标签实战 简介这份资源面向从事农业图像识别、目标检测学习与科研的学生和开发者提供一套真实场景下的葡萄叶片病害检测数据集可直接用于YOLO系列模型训练与验证。压缩包共约2000个文件整体349.64MB以1985个xml标注文件为主另含少量txt、html与py脚本分别承担标签数据、说明文档和数据集划分功能。数据经labelimg精细标注同时提供voc、coco和yolo三种格式标签分目录存放便于不同框架直接读取。资源还附赠YOLO环境搭建、Windows与Linux训练案例教程以及训练集、验证集、测试集划分脚本可按需重新划分数据。目前已有355人学习下载适合希望快速搭建葡萄病害检测实验、复现训练流程并积累农业视觉项目经验的中高级读者参考使用。1. 葡萄叶片病害检测数据集从10000张图到三种标签格式的落地路径葡萄叶片病害检测这件事真正卡住大多数人的从来不是模型结构而是数据。你手上可能有一堆田间拍的照片但要让 YOLO 跑起来得先有标注、有格式转换、有划分脚本还得保证训练时不崩。这个标题指向的正是一套完整的数据集方案10000 张葡萄叶片图片配套 VOC、COCO、YOLO 三种格式标签外加划分脚本和训练教程。它解决的是从「有图」到「能训」之间的全部脏活累活。适合谁适合刚接手农业视觉项目、想快速验证 YOLO 检测效果、又不想在数据预处理上耗掉两周的一线开发者。下面我按自己实际跑这类数据集的顺序把选型理由、转换细节、训练参数和踩过的坑一次讲清。2. 三种标签格式怎么选VOC、COCO、YOLO 的适用边界2.1 先搞清楚每种格式到底存了什么VOC 格式的核心是 XML 文件每张图对应一个 XML里面用object标签记录类别名和边界框的xmin/ymin/xmax/ymax。它的优点是结构直观、工具链老牌LabelImg 默认就存这个。缺点是文件数量翻倍10000 张图就是 10000 个 XML小文件一多磁盘 IO 和传输都变慢。COCO 格式把整份数据集的标注塞进一个 JSON 文件结构是images、annotations、categories三个大数组。它的优势是单文件、适合分布式加载pycocotools 生态成熟。但 JSON 一旦损坏整份标注全废而且大 JSON 解析吃内存10000 张图的 COCO 文件动辄几十 MB。YOLO 格式最轻每张图对应一个.txt每行是class_id x_center y_center width height全部归一化到 0~1。训练时直接读没有解析开销。缺点是类别用数字索引换数据集时容易对错类别。提示如果你只跑 YOLO 训练最终用的就是 YOLO 格式VOC 和 COCO 是中间产物和兼容层别在训练时绕远路。2.2 转换链路VOC 是枢纽COCO 和 YOLO 从它派生常见做法是先把标注统一成 VOC因为标注工具最常输出 VOC然后写脚本从 VOC 转 COCO 和 YOLO。这样只需要维护一份转换逻辑减少不一致。下面是我常用的 VOC 转 YOLO 脚本核心部分import xml.etree.ElementTree as ET import os # 类别映射必须和训练时的 data.yaml 顺序一致 CLASS_MAP {black_rot: 0, esca: 1, leaf_blight: 2, healthy: 3} def voc_to_yolo(xml_path, img_w, img_h, out_txt): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): cls_name obj.find(name).text.strip() 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 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt, w) as f: f.write(\n.join(lines))逻辑说明CLASS_MAP是全局类别索引必须和后续data.yaml里的names列表顺序完全一致否则模型学到的类别会错位。归一化用图像真实宽高所以调用前要先读图拿到img_w和img_h不能硬编码。:.6f保留六位小数YOLO 官方推荐精度太少会丢框太多没必要。参数说明xmin/ymin/xmax/ymax是 VOC 的绝对像素坐标注意有些标注工具会写出界坐标转换前最好 clamp 到[0, img_w]和[0, img_h]否则 YOLO 训练时会出现负宽度导致 loss 变 NaN。2.3 划分脚本别用随机划分按病害分布分层10000 张图如果直接random.shuffle切 8:1:1遇到某类病害样本少的时候验证集可能一张都没有训练曲线看着好实际泛化崩。我一般用分层抽样保证每个类别在 train/val/test 里的比例接近。import os import random from collections import defaultdict def split_dataset(label_dir, img_dir, out_dir, ratios(0.8, 0.1, 0.1)): # 按类别归档每个类别单独打乱再切 cls_to_files defaultdict(list) for txt in os.listdir(label_dir): if not txt.endswith(.txt): continue with open(os.path.join(label_dir, txt)) as f: first_line f.readline().strip() if not first_line: continue cls_id first_line.split()[0] cls_to_files[cls_id].append(txt.replace(.txt, )) splits {train: [], val: [], test: []} for cls_id, files in cls_to_files.items(): random.shuffle(files) n len(files) n_train int(n * ratios[0]) n_val int(n * ratios[1]) splits[train] files[:n_train] splits[val] files[n_train:n_train n_val] splits[test] files[n_train n_val:] for split, names in splits.items(): os.makedirs(os.path.join(out_dir, split), exist_okTrue) with open(os.path.join(out_dir, f{split}.txt), w) as f: for name in names: f.write(os.path.join(img_dir, name .jpg) \n)逻辑说明先按class_id分组每组独立打乱后按比例切这样稀有类别也能进验证集。输出的是三个 txt 文件每行是图片绝对路径YOLO 训练时用train: train.txt直接读。参数说明ratios默认 8:1:1如果数据量小于 2000建议改成 7:2:1给验证集多留点。img_dir和label_dir要对应同一批文件名转换时别把扩展名搞混。3. 用这套数据集跑通 YOLO 训练环境、配置与首轮验证3.1 环境配置别追最新锁版本YOLO 训练环境翻车最多的就是版本冲突。我一般用 Python 3.8 PyTorch 1.12 CUDA 11.3这个组合在 V100 和 3090 上都稳。安装命令conda create -n grape_yolo python3.8 -y conda activate grape_yolo pip install torch1.12.1cu113 torchvision0.13.1cu113 -f https://download.pytorch.org/whl/torch_stable.html pip install ultralytics8.0.0 opencv-python pillow tqdm逻辑说明ultralytics是 YOLOv8 的官方包8.0.0 版本 API 稳定后面版本改过配置字段。torch和torchvision必须版本匹配cu113 对应 CUDA 11.3装错会报undefined symbol。参数说明如果你只有 CPU把cu113去掉装 CPU 版但 10000 张图训练会慢到怀疑人生建议至少一张 8G 显存的卡。3.2 data.yaml 的五个必填字段YOLO 训练靠data.yaml找数据和类别字段写错直接报Dataset not found。path: /data/grape_leaf train: train.txt val: val.txt test: test.txt nc: 4 names: [black_rot, esca, leaf_blight, healthy]逻辑说明path是数据集根目录train/val/test是相对路径的 txt 文件。nc是类别数必须等于names长度。names顺序必须和转换脚本里的CLASS_MAP完全一致差一个顺序模型就把黑腐病认成健康叶。参数说明如果 txt 里写的是绝对路径path可以留空但建议统一用相对路径换机器时只改path一处。3.3 首轮训练命令与关键参数yolo detect train \ data/data/grape_leaf/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/grape \ nameexp1逻辑说明modelyolov8n.pt是官方预训练权重小模型先跑通再换大模型。imgsz640是 YOLO 默认输入尺寸葡萄叶片病害的斑点通常不大640 够用想提小目标可以上 1024但显存翻倍。patience20是早停验证集 20 轮不涨就停省时间。参数说明batch16在 8G 显存上跑 640 尺寸刚好爆显存就降到 8。lr00.01是初始学习率YOLOv8 默认 0.01如果 loss 震荡厉害降到 0.001 再试。epochs100对 10000 张图通常够看results.csv里 mAP 曲线平了就停。3.4 训练中要看的三条曲线跑起来后别干等打开runs/grape/exp1/results.csv盯三个指标train/box_loss应该稳定下降如果上下跳多半是学习率太大或标注框有异常值metrics/mAP50是主指标葡萄病害检测一般能到 0.85 以上val/box_loss如果先降后升说明过拟合加数据增强或减模型复杂度。注意YOLO 混淆矩阵总合不唯一是常见现象因为多标签框可能被重复统计别慌看对角线占比就行。4. 避坑与排查葡萄叶片数据集训练中最容易翻车的五件事4.1 现象训练 loss 直接 NaN第一轮就崩原因VOC 转 YOLO 时没做坐标 clamp某些标注框的xmax小于xmin算出负宽度归一化后变成负数YOLO 计算 IoU 时开根号出 NaN。解决转换脚本里加一行xmin, xmax min(xmin, xmax), max(xmin, xmax)并对宽高做max(0, w)保护。转换完抽查几个 txt确认所有数值在 0~1 之间。4.2 现象训练正常但验证集 mAP 一直是 0原因data.yaml里的names顺序和转换时的CLASS_MAP不一致模型学到的类别索引和验证集标注对不上等于全错。解决把CLASS_MAP和names并排打印出来逐行核对。更稳的做法是转换脚本直接从data.yaml读names生成映射不手写两份。4.3 现象BN 层崩溃报Expected more than 1 value per channel原因batch16时最后一批只剩 1 张图BatchNorm 在单样本上算不出方差。10000 张图除以 16 除不尽时必现。解决训练命令加drop_lastTrue或者把batch改成能整除数据集大小的值。YOLOv8 默认已经处理但自己改 dataloader 时容易漏。4.4 现象训练到一半显存爆了进程被 kill原因imgsz640配batch16在 8G 卡上刚好但验证阶段会额外占显存加上 COCO 格式的 JSON 如果还在内存里没释放峰值就超了。解决训练前把 COCO JSON 转完就删掉别留在内存。显存紧就把batch降到 8或者用yolov8n而不是yolov8m。V100 32G 可以忽略这条。4.5 现象模型把健康叶也框出来误检率高原因健康叶样本在数据集里占比过大且标注时把健康叶也标了框模型学到「有叶就框」。葡萄病害检测应该只标病斑区域。解决检查标注健康叶要么不标要么单独一类但降低采样权重。训练时加cls0.5提高分类损失权重或者用focal_loss替换默认分类损失。5. 进阶技巧用混淆矩阵和单张推理反查数据质量训练完别只看 mAP 数字混淆矩阵能告诉你模型到底把什么认成了什么。YOLO 训练结束会在runs/grape/exp1/下生成confusion_matrix.png打开看对角线如果black_rot和esca之间有大块非对角值说明这两类病斑在图像上太像标注时可能混了。我一般会挑出混淆最多的那对类别各抽 20 张图肉眼过一遍十有八九能找到标错的。单张推理验证更直接from ultralytics import YOLO model YOLO(runs/grape/exp1/weights/best.pt) results model.predict( sourcetest_images/leaf_001.jpg, conf0.25, # 置信度阈值低于此值不输出 iou0.45, # NMS IoU 阈值重叠框合并 saveTrue, # 保存带框图片 show_labelsTrue ) for r in results: for box in r.boxes: cls_id int(box.cls) conf float(box.conf) print(f类别: {model.names[cls_id]}, 置信度: {conf:.3f})逻辑说明conf0.25是常用起点误检多就提到 0.4漏检多就降到 0.15。iou0.45控制重叠框合并病斑密集时调到 0.5 避免漏框。model.names直接读data.yaml的names不用再手写映射。参数说明saveTrue会把结果存到runs/detect/predict/方便和原图对比。如果发现某类病斑总是漏先别改模型回去看这类样本的标注框是不是太小或太模糊10000 张图里总有一些拍虚的挑出来重标比调参管用。我自己的习惯是每训完一版先跑 50 张测试集推理把置信度低于 0.3 的框全部人工过一遍标错的回炉重标标对的加进下一轮训练。这样迭代三轮mAP 通常能再涨 3 到 5 个点。数据质量这件事没有后悔药但混淆矩阵和单张推理就是最好的黑匣子。希望帮到你。本文还有配套的精品资源点击获取
返回列表