苹果叶病害数据集与YOLOv8训练全流程解析

苹果叶病害数据集与YOLOv8训练全流程解析 简介本资源是面向农业AI、植物病害识别研究者与计算机视觉初学者的高质量苹果叶病害检测数据集聚焦于果园真实场景下的细粒度分类与目标检测任务。数据涵盖5类常见病害Alternaria斑点病、褐斑病、花叶病、灰斑病与锈病全部图像源自实地果园采集与专业标注并经系统性数据增强确保类别均衡性与场景多样性适用于YOLOv5/v8、Faster R-CNN等模型训练与算法验证。压缩包共2000个文件含21119张JPG原图、21119份PASCAL VOC格式XML标注及21120份YOLO格式TXT标签完整支持双标准训练流程整体大小713.92MB结构规范、开箱即用。目前已有469人学习下载所附标签精准、样本丰富、项目实测可用配套博主实际科研与Demo验证经验可直接用于课程设计、毕业课题或轻量级部署实验。 拿到这个压缩包的时候我第一反应是终于有人把农业场景的数据集整理得这么规整了。21119张苹果叶病害图片、5个类别、VOC和YOLO两种标注格式都给你备齐这意味着你不需要再耗费几周时间去爬图、清洗、标注直接解压就能开始训练。对于正在做目标检测、农业AI、植物病害识别相关项目的开发者来说这个数据集省下的时间成本相当可观。这篇文章我会从数据格式解析、训练前数据体检、YOLOv8完整训练流程、常见坑排查到落地部署建议把整个链路拆开讲透尽量让你拿到手就能跑通。1. 这个数据集到底能做什么5类苹果叶病害的识别与检测逻辑1.1 5类病害分别是哪些为什么要识别它们苹果种植过程中叶部病害是影响产量和果品质量的核心因素之一。早期发现、精准定位病灶是果园管理里最耗时也最关键的一环。这个数据集覆盖的5类病害对应苹果叶部最常见的几种真菌性和病毒性病害我在实际项目里遇到过的大致是这几类苹果黑星病叶片上出现橄榄色到黑色绒状斑点、苹果锈病叶片正面有橙黄色圆形病斑后期背面凸起、苹果褐斑病病斑呈褐色边缘不明显严重时叶片枯焦、苹果花叶病叶片上出现黄绿色不规则斑驳属于病毒病、苹果炭疽病病斑圆形褐色到深褐色有轮纹状排列的小黑点。这5类病害的形态差异其实挺明显的有的靠颜色、有的靠纹理、有的靠边缘形状普通目标检测模型只要数据量够、标注质量过关识别难度不算太高。但要注意的是苹果叶片在自然光照下的颜色变化很大同一类病害在不同品种、不同生长阶段、不同光照条件下表现差异也很大。这个数据集有21119张图平均下来每个类别约4223张足够撑起一个小型专用检测模型的训练尤其适合做迁移学习微调。1.2 数据集的规模与标注格式决定了它能适配哪些任务21119张图这个规模在农业病害检测领域算是比较充裕的。对比一下很多公开的植物病害数据集只有几百到两三千张做深度学习训练很容易过拟合而超过两万张图的数据集配上预训练权重做微调在YOLOv8这种模型上基本能收敛到比较理想的效果。数据集的标注格式是VOC和YOLO双格式。VOC格式是XML文件存储记录了目标类别和边界框坐标是很多传统检测框架如Faster R-CNN、SSD的标准输入格式YOLO格式是TXT文件存储每行一个目标记录类别索引和归一化坐标是YOLO系列模型的直接输入格式。双格式的好处很直接你不用再拿标注工具导出互转想用哪个框架都能直接开工。从任务定位来说这个数据集适合两个方向检测任务在叶片图像中框出病害区域输出位置和类别。分类的预处理如果你只想判断“有没有病”可以把检测结果裁剪出来再做细粒度分类。如果你做的是语义分割这个数据集不适用需要自己去补充分割标注。但用检测结果生成伪分割标签也不是不行只是精度看运气不建议。2. 深入理解VOC与YOLO两种标注格式目录结构与坐标系差异2.1 解压后第一眼要看的目录结构拿到压缩包解压后正常的目录结构大概是这样的苹果叶病害数据集/ ├── annotations/ # VOC格式的XML标注 │ ├── train/ │ │ ├── 000001.xml │ │ ├── 000002.xml │ │ └── ... │ ├── val/ │ └── test/ ├── images/ # 原始图片 │ ├── train/ │ │ ├── 000001.jpg │ │ ├── 000002.jpg │ │ └── ... │ ├── val/ │ └── test/ ├── labels/ # YOLO格式的TXT标注 │ ├── train/ │ │ ├── 000001.txt │ │ ├── 000002.txt │ │ └── ... │ ├── val/ │ └── test/ ├── classes.txt # 类别列表按索引排列 ├── train.txt # 训练集图片路径列表 ├── val.txt # 验证集图片路径列表 └── test.txt # 测试集图片路径列表有的打包者会把train/val/test直接合并放在images根目录下再用txt文件划分这种也没问题只要你的训练脚本能正确读取列表就行。先确认一点classes.txt里的类别顺序一定要和labels目录下TXT文件里的数字索引对应上。这个顺序错一位模型训练的损失曲线看着正常实际预测结果就全乱了。2.2 VOCXML标注格式详解VOC格式的XML文件长这样annotation folderimages/folder filename000001.jpg/filename path/your/path/images/000001.jpg/path source databaseUnknown/database /source size width640/width height480/height depth3/depth /size segmented0/segmented object nameblack_rot/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin100/xmin ymin120/ymin xmax280/xmax ymax310/ymax /bndbox /object /annotation几个关键点size节点里的宽高是原始图片的像素尺寸转换坐标时必须用到。object节点里每个目标对应一个name类别名和bndbox左上角xmin/ymin、右下角xmax/ymax都是整数像素坐标。difficult为1表示该目标难以辨认训练时通常会被忽略。如果标注者把难例标得很多可能会影响模型收敛训练前可以统计一下。VOC的坐标是绝对的像素坐标对于模型来说直接输入时通常需要换算成归一化或者相对坐标。如果你用的是Faster R-CNN这类框架它们有内置的VOC数据加载器可以直接用但如果你用YOLO系列必须转成YOLO格式。2.3 YOLOTXT标注格式详解YOLO格式的TXT文件是每行一个目标2 0.468750 0.520833 0.156250 0.245833 0 0.625000 0.458333 0.093750 0.187500从左到右分别是类别索引整数从0开始对应classes.txt里的行号。归一化中心点x坐标(xmin xmax) / 2 / image_width。归一化中心点y坐标(ymin ymax) / 2 / image_height。归一化宽度(xmax - xmin) / image_width。归一化高度(ymax - ymin) / image_height。所有坐标值都是0到1之间的小数。很多人在这一步栽跟头YOLO的TXT里存的是绝对像素坐标而不是归一化坐标导致训练时loss直接爆炸、指标全是0因为模型输入的标签范围是0到1结果却收到了几千像素的框。判断一份TXT是否归一化很简单打开看看数值是否都在0到1之间就行。2.4 两种格式如何互相转换VOC转YOLO的Python脚本核心代码大概是这样的import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_file, output_dir, class_names): tree ET.parse(xml_file) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) base_name os.path.splitext(os.path.basename(xml_file))[0] txt_file os.path.join(output_dir, base_name .txt) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in class_names: continue cls_id class_names.index(cls_name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.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(txt_file, w) as f: f.write(\n.join(lines)) class_names [apple_scab, apple_rust, brown_spot, mosaic, anthracnose] xml_dir annotations/train out_dir labels/train os.makedirs(out_dir, exist_okTrue) for xml_name in os.listdir(xml_dir): if xml_name.endswith(.xml): voc_to_yolo(os.path.join(xml_dir, xml_name), out_dir, class_names)注意两个细节类别列表的顺序必须和classes.txt完全一致否则索引错位。转换前要检查图片尺寸是否和size节点一致。有些爬虫下来的图片被重采样过但XML里的尺寸没更新转换出来的坐标就会整体偏移。反向转换YOLO转VOC麻烦一点因为TXT里没有图片尺寸信息必须去读对应图片的宽高。这就是为什么数据集的目录结构里图片和标签要成对放光有TXT没有图片转换的时候会直接卡住。3. 训练前的数据体检统计、清洗与目录整理实操3.1 先统计类别数量与分布别急着训练我自己拿到一个数据集的第一件事不是直接丢进训练脚本而是先做统计。用下面的代码可以快速看每个类别的目标数量import os label_dirs [labels/train, labels/val, labels/test] class_counts {} total_boxes 0 for label_dir in label_dirs: for txt_name in os.listdir(label_dir): with open(os.path.join(label_dir, txt_name), r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cls_id int(parts[0]) class_counts[cls_id] class_counts.get(cls_id, 0) 1 total_boxes 1 print(f总标注框数: {total_boxes}) for cls_id in sorted(class_counts.keys()): print(f类别 {cls_id}: {class_counts[cls_id]} 个框)统计结果出来后重点关注两方面类别间是否严重不均衡、训练集和验证集的类别分布是否一致。如果某一类的样本量只有另一类的十分之一模型很容易偏向多数的类别小类别的召回率会很低。这个数据集平均下来每个类别有4000多张图算是比较均衡的但个别类别因为天然难以表现比如花叶病典型斑驳需要特定光照数量偏少也是可能的。3.2 检查标注异常越界、空标签、文件名对不上标注文件里的坑最常见的几种边界框越界坐标值超出图片宽高范围比如xmax大于图片宽度。这种框训练时会损失一部分梯度信息甚至导致某些增强操作如Mosaic报错。空标签图片有文件名但TXT或XML里没有目标或者TXT文件内容为空。这种情况在训练时会被当成背景图片如果混入了验证集指标计算会出偏差。文件名对不上图片存在但没有标签文件或反过来。数据集搬运、重命名过程中经常发生。检查脚本可以这样写import os from PIL import Image img_dir images/train label_dir labels/train img_files os.listdir(img_dir) label_files os.listdir(label_dir) img_names {os.path.splitext(f)[0] for f in img_files} label_names {os.path.splitext(f)[0] for f in label_files} print(有图无标签:, len(img_names - label_names)) print(有标签无图:, len(label_names - img_names)) # 检查越界 for txt_name in label_files: base os.path.splitext(txt_name)[0] img_path os.path.join(img_dir, base .jpg) if not os.path.exists(img_path): continue with Image.open(img_path) as im: w, h im.size with open(os.path.join(label_dir, txt_name), r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue _, x_center, y_center, box_w, box_h map(float, parts) xmin (x_center - box_w / 2) * w xmax (x_center box_w / 2) * w ymin (y_center - box_h / 2) * h ymax (y_center box_h / 2) * h if xmin 0 or ymin 0 or xmax w or ymax h: print(f{txt_name} 中越界框: {line.strip()}) break注意边界框轻微越界比如0.5个像素以内通常问题不大YOLO训练时会自动裁剪。但明显超出图像范围的框一定得处理否则会在数据增强时暴露出大量空白区域干扰模型学习。3.3 data.yaml配置与数据划分YOLOv8训练时需要一个data.yaml配置训练集和验证集路径、类别数量、类别名称train: /path/to/dataset/images/train val: /path/to/dataset/images/val test: /path/to/dataset/images/test nc: 5 names: [apple_scab, apple_rust, brown_spot, mosaic, anthracnose]如果你只有一份train.txt和val.txt路径列表也可以直接用YOLO自带的工具划分python -c from ultralytics.data.utils import check_det_dataset; check_det_dataset(data.yaml)划分时建议训练:验证:测试按8:1:1如果图片数量少可以提高到9:0.5:0.5但验证集数量太少会导致评估指标波动很大不推荐低于200张。4. 基于YOLOv8的完整训练流程与参数调整4.1 环境准备与数据集放置方式训练YOLOv8需要安装ultralytics库Python 3.8以上PyTorch 1.8以上pip install ultralytics数据集的放置方式我建议直接把images和labels放到同一个父目录下并且保持训练集、验证集的子目录名称一致。YOLOv8默认的逻辑是如果train是图片目录路径那么它会在同级的labels目录中找对应的TXT文件。目录结构如下dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml这种结构是YOLOv8最常见的读取方式强烈建议不要改动。有些同学把labels和images分开放在不同磁盘或不同命名空间里后面所有脚本都要手动指定路径徒增烦恼。4.2 训练参数设置batch、epochs、imgsz怎么定官方推荐的基础训练命令yolo detect train data/path/to/data.yaml modelyolov8s.pt epochs100 batch16 imgsz640 device0参数选择的实际经验model建议从yolov8s.pt开始。s版本比n版本精度高不少比m版本快很多在农业这种通用物体检测场景下性价比最高。如果先试跑验证流程用yolov8n.pt更快。batch显存允许范围内尽量大。8G显存跑640分辨率yolov8s大概能开batch16如果开到16报OOM调到8不要硬撑。batch太小比如2、4容易导致BN层统计量不稳定收敛慢。epochs建议先跑50个epoch观察曲线如果验证集损失还在下降继续跑到100或150。迁移学习场景下100个epoch基本够用从零训练则需要200以上。imgsz训练分辨率。640是速度和精度的平衡点。如果你要检测的病害斑块面积很小可以尝试imgsz960但显存占用会大幅增加。用前先确认原始图片的分辨率分布如果大部分图只有800x600强行上960只会把图像放大并不会增加有效信息。一个经验公式假设你的显卡是NVIDIA RTX 3060 12G训练yolov8s、640分辨率、batch16大约每小时能完成4000到6000张图的epoch训练。21119张图跑100个epoch大约需要3到5小时这个时间成本是可以接受的。4.3 训练过程的监控与效果评估训练启动后终端会实时输出每个epoch的loss、mAP50、mAP50-95、precision、recall等信息。训练结束后重点看这三个指标mAP50IoU阈值0.5下的平均精度衡量“框大致准不准”。农业病害检测场景mAP50到0.85以上算不错。mAP50-95IoU阈值从0.5到0.95逐步提升的平均精度更严格。这个值在0.6以上说明模型定位精度和分类能力都过硬。F1-conf曲线综合precision和recall的指标用来帮你挑置信度阈值。不同类别的最佳阈值可能不一样预测时可以按类别分别设阈值。训练完成后验证集预测结果可视化文件在runs/detect/train/val_batchX_pred.jpg可以直接查看预测框和真实框的对比。如果预测框有严重的重复框或漏检说明NMS阈值conf和iou需要调。4.4 训练结果推理测试训练完成后对单张图片推理yolo detect predict modelruns/detect/train/weights/best.pt source/path/to/test/image.jpg conf0.25conf0.25是默认置信度阈值。实际测试时可以在0.1到0.5之间多试几次找到视觉效果最好的阈值。如果模型对某类病害漏检严重可以单独注意该类别的置信度分数适当调低阈值。对测试集批量推理并计算指标yolo detect val modelruns/detect/train/weights/best.pt data/path/to/data.yaml splittest这里有个容易被忽略的点splittest必须指定否则默认只跑验证集。如果你的data.yaml里没有定义test字段这一步会直接报错。5. 训练过程中最常见的5个坑与排查方法5.1 无法加载标签文件报Error loading label这个提示是YOLO系列的经典报错。通常原因TXT文件里某行不是5个字段或者坐标值不是0到1之间的数字。类别索引超出nc范围比如nc5但TXT中出现了cls_id5。图片和TXT文件名不一致。排查方式很简单看报错信息里具体是哪个文件打开检查一下。如果数量不多直接手动修正如果整个数据集大面积出错回到第3节的检查脚本去批量处理。5.2 训练集损失下降验证集指标却很低典型的过拟合信号。数据集只有几千张图时很常见。应对手段有两个方向数据增强YOLOv8默认开启Mosaic、HSV扰动、翻转等增强。可以适当调高hsv_h、hsv_s、hsv_v的数值模拟不同光照条件下苹果叶片的颜色变化。正则化调低dropout或用weight_decay控制权重衰减。YOLOv8里增加weight_decay0.0005通常能压一压过拟合。另外要注意如果验证集的病害形态和训练集相差太大比如训练集全是晴天拍摄验证集全是阴天拍摄那模型泛化能力不足的本质不是过拟合是数据分布差异太大。这种情况需要重新划分数据集或者补充更多样化的图片。5.3 叶片上的小病斑总是漏检苹果黑星病和炭疽病的斑点在早期只有几个像素大小在640分辨率的特征图上很容易被下采样丢掉。解决办法提高imgsz到960或1280直接放大输入图像小目标对应更多的特征像素。使用SAHISlicing Aided Hyper Inference方案把大图切块后分别推理再合并结果。这个方案对小目标检测提升非常明显代价是推理时间增加。如果只是个别类别漏检检查一下该类别的标注框是否过小。YOLO默认的anchor偏好中等偏大的目标极小目标需要专门调。5.4 数据增强策略对植物病害检测的影响注意一个农业场景的细节植物叶片病害的识别很多特征依赖真实的颜色和纹理。YOLOv8默认的hsv_h0.015、hsv_s0.7、hsv_v0.4对于颜色敏感的病害检测HSV饱和度扰动到0.7可能有点过了。比如苹果锈病的橙色病斑颜色被过度增强后可能变得不典型模型学到的颜色特征会偏。我一般会把hsv_s调到0.3左右hsv_v调到0.2既能模拟不同光照又不会让颜色失真太严重。这个参数调整没有绝对标准最好拿着验证集效果来回试。5.5 显存不足与训练速度优化跑大图高分辨率时显存不够几个实用的招调小batch但不要低于8。开启amp混合精度训练YOLOv8默认开启能省约30%显存速度还更快。使用梯度累积比如batch8配合accumulate4等效于batch32的效果但训练时间会变长。在数据加载瓶颈明显时调大workersDataLoader线程数到CPU核心数的2倍以内能让GPU利用率明显提升。Windows上workers0有时反而更快因为多进程开销大。我实际遇到过一种情况workers8时CPU占用直接拉满GPU利用率掉到60%左右把workers降到4之后反而稳定在95%以上。所以这个参数真的要结合实际机器来调别盲信默认值。6. 从模型到落地苹果叶病害检测的扩展与实用建议6.1 模型部署到移动端与边缘设备如果你要把训练好的模型部署到果园现场的边缘设备比如树莓派、Jetson Nano、手机端YOLOv8提供了导出功能yolo export modelbest.pt formatonnx imgsz640导出ONNX后可以再转成TensorRTNVIDIA设备或NCNN移动端推理速度能提升数倍。需要注意导出时imgsz必须和训练时一致否则输出层的anchor尺寸会不匹配推理结果会错乱。边缘设备上的推理建议把输入图像先做等比例缩放然后在上下或左右补灰边到640x640而不是直接拉伸。直接拉伸会让病斑的形状比例失真检测框位置也会偏移。另外模型量化到INT8可以进一步减小体积和加速但精度会有一定损失。对苹果病害检测这种任务来说少量精度损失通常可以接受前提是你验证集上的mAP50还能保持在0.8以上。6.2 后续如何扩充数据集让模型更鲁棒这个数据集虽然有两万多张图但如果你要把模型用到不同地区、不同品种的果园现场数据分布大概率会偏移。我建议按以下优先级补充数据不同光照和天气条件下的叶片图正光、逆光、阴天、雨天。不同生长阶段的叶片嫩叶、老叶对病害的呈现差异很明显。不同拍摄设备手机、无人机、固定摄像头的分辨率和色彩风格差异。叶片互相遮挡、多种病害混合发生的场景这种最难标但对落地最有用。补充数据后的标注可以先用现有模型做自动预标注生成YOLO格式的TXT再用标注工具人工修正。这个流程能把标注时间缩短一半以上。我自己试下来模型越训越好的关键不是单次训练调到多完美而是建立“收集数据-预标注-人工校正-增量训练”的循环每次训练都比上一次多覆盖一些真实场景。在实际操作中我还有个体会训练结果好坏很多时候不取决于模型结构而取决于训练前花多少时间做数据检查。有些数据集拿到手你以为标签是好的实际一查一堆越界框和错误类别训练出来的模型外行看着还行内行一看PR曲线就知道有问题。花一个小时跑一遍体检脚本后面能省一整周调试的时间这笔账怎么算都划算。本文还有配套的精品资源点击获取