简介苹果叶片病害图像识别数据集面向计算机视觉与农业智能识别方向的学习者和研究者用于训练和评估叶片病害分类模型。数据已专业标注共分健康、生锈、痂三个类别并预先划分训练集与验证集方便直接开展模型训练与泛化能力检验。压缩包共1733个文件以1730张jpg图像为主体另含1个json标注文件、1个py可视化脚本和1个png示例图整体约354.45MB目录按训练与验证分别存放同类图片结构清晰。运行包内show脚本可快速可视化数据分布便于检查样本质量与类别特征。资源同时适配CNN分类网络与基于YOLOv5的分类方案配套项目链接可辅助搭建和优化识别系统。目前已有340人学习下载适合希望快速上手苹果叶片病害分类任务、验证模型效果的读者参考使用。1. 苹果叶片病害图像识别数据集1700 张已标注数据能跑出什么结果果园里最怕的不是虫是叶子先出问题。斑点落叶、褐斑、灰斑、锈病、黑星病早期症状在叶片上只占几个像素等人眼看出大面积枯黄防治窗口已经过了。这也是为什么「苹果叶片病害图像识别数据集」这类资源一直有人找它把田间拍到的叶片图整理成带标签的样本让检测或分类模型能直接吃进去训练。约 1700 张、已标注这个体量不算大但足够跑通一条从数据检查到模型验证的完整链路适合做课程设计、小课题验证、或者给果园巡检设备做原型。真正决定成败的不是模型选得多新而是这 1700 张里类别是否均衡、框是否贴边、有没有重复图。下面按我实际处理这类数据集的顺序讲清楚。2. 先看清数据长什么样类别、标注格式与划分策略拿到一个「已标注」的数据集第一件事不是写训练脚本而是把标注文件打开看。苹果叶片病害常见的标注形态有两种一种是整图分类标签一张图一个类别一种是目标检测框一张图里多个病斑位置。这两种决定了后面完全不同的技术路线选错了模型再强也白搭。2.1 分类标注与检测标注的判断方法判断方法很直接看标注文件里有没有坐标。如果每张图对应一个类别名或类别编号就是分类数据集如果标注里出现xmin, ymin, xmax, ymax或归一化的cx, cy, w, h就是检测数据集。苹果叶片病害里早期病斑小且分散检测框能定位到具体病斑对精准施药更有价值但如果标注只到叶片级别硬做检测就是给自己找麻烦。我一般会先统计每个类别的图片数量用一段脚本跑出来import os from collections import Counter # 假设标注是 YOLO 格式的 txt每行: class_id cx cy w h label_dir labels/train counter Counter() for name in os.listdir(label_dir): if not name.endswith(.txt): continue with open(os.path.join(label_dir, name), r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue cls_id line.split()[0] counter[cls_id] 1 # 输出每个类别的标注框数量判断是否严重不均衡 for cls_id, num in sorted(counter.items(), keylambda x: -x[1]): print(fclass {cls_id}: {num} boxes)这段脚本做的是逐文件读取标注、按类别累计框数。label_dir指向存放 txt 标注的目录cls_id是类别编号。跑完你会看到类似「class 0 有 900 个框class 4 只有 60 个框」的结果这就是后面要处理的不均衡信号。如果某个类别框数不到总数的 5%训练时几乎必然被忽略。2.2 训练集、验证集、测试集怎么切才不翻车1700 张的体量常见做法是 7:2:1 或 8:1:1。但苹果叶片数据有个坑同一片叶子可能被连拍多张或者同一棵树不同角度拍了很多。如果随机切分训练集和验证集里出现几乎相同的图验证指标会虚高上线就露馅。我的习惯是按「拍摄批次」或「叶片编号」分组切分而不是按图片随机切。具体做法是给每张图打一个 group id比如文件名前缀同一 group 的图只能进同一个集合。下面是一个按前缀分组的切分脚本import os import random from collections import defaultdict img_dir images groups defaultdict(list) # 用文件名前缀作为分组依据例如 leaf012_03.jpg - leaf012 for name in os.listdir(img_dir): if not name.lower().endswith((.jpg, .png, .jpeg)): continue group_id name.split(_)[0] groups[group_id].append(name) group_ids list(groups.keys()) random.seed(42) random.shuffle(group_ids) n len(group_ids) train_end int(n * 0.8) val_end int(n * 0.9) split_map {} for g in group_ids[:train_end]: split_map[g] train for g in group_ids[train_end:val_end]: split_map[g] val for g in group_ids[val_end:]: split_map[g] test # 打印每个集合的图片数确认比例合理 for split in [train, val, test]: count sum(len(groups[g]) for g in groups if split_map[g] split) print(split, count)random.seed(42)保证切分可复现group_id取文件名下划线前的部分。跑完看三个集合的图片数如果 test 少于 100 张指标波动会很大可以考虑改成 8:1:1 并把 test 合并进 val 做交叉验证。这一步做完数据才算真正可用。3. 用 YOLOv8 跑通苹果叶片病害检测的最小闭环数据集检查完接下来就是训练。苹果叶片病害检测目前最省事的路线是 YOLOv8安装简单、文档全、对小目标有专门优化。1700 张的规模单卡消费级显卡就能跑不需要多机多卡。这一章从环境到训练到推理给一条能直接抄的路径。3.1 环境安装与数据目录组织先建一个干净的 Python 环境避免和系统里的包打架conda create -n apple_leaf python3.10 -y conda activate apple_leaf pip install ultralytics opencv-pythonultralytics包里已经带了 YOLOv8 的训练和推理接口opencv-python用于后面做可视化和数据增强检查。装完可以用yolo checks确认环境正常。数据目录按 YOLO 的标准结构放apple_leaf_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamldata.yaml是训练入口内容如下path: ./apple_leaf_dataset train: images/train val: images/val test: images/test names: 0: alternaria_leaf_spot 1: brown_spot 2: gray_spot 3: rust 4: scabpath是数据集根目录train/val/test是相对路径names里按你的实际类别改。类别名建议用英文避免训练时编码问题。如果标注里类别编号和这里对不上训练会直接报错或学出乱七八糟的结果务必核对。3.2 训练命令与关键参数怎么设最小训练命令yolo detect train \ dataapple_leaf_dataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/apple_leaf \ nameexp1逐项说明modelyolov8s.pt是预训练权重1700 张数据从零训练容易过拟合用预训练权重收敛更快epochs100配合patience2020 轮验证指标不提升就早停省时间imgsz640是默认输入尺寸如果病斑特别小可以提到 960但显存占用会明显上升batch16在 8GB 显存上比较稳显存不够就降到 8lr00.01是初始学习率数据量小的时候可以降到 0.005 减少震荡。训练过程中重点看mAP50和mAP50-95两个指标。苹果叶片病害这种小目标场景mAP50到 0.7 以上算可用mAP50-95通常低不少别拿它当唯一标准。如果训练 loss 一直不降先检查标注框有没有越界或宽高为 0。3.3 推理与结果可视化训练完用最好的权重跑推理from ultralytics import YOLO import cv2 model YOLO(runs/apple_leaf/exp1/weights/best.pt) results model.predict( sourceapple_leaf_dataset/images/test, conf0.25, iou0.45, saveTrue, projectruns/predict, nametest_result ) # 打印每张图的检测框数量快速判断漏检情况 for r in results: print(r.path, len(r.boxes))conf0.25是置信度阈值低于它的框不输出iou0.45控制重叠框合并病斑密集时可以调到 0.5 以上减少误合并saveTrue会把画框后的图存到runs/predict/test_result。跑完翻几张图看如果框明显偏大或偏小多半是标注时框没贴紧病斑边缘需要回标注环节修。提示推理结果里如果出现同一病斑被多个框重复标注先调iou再考虑用 NMS 后处理不要直接改模型结构。4. 数据增强与不均衡处理让 1700 张发挥出 3000 张的效果1700 张在深度学习里属于小数据集直接训练容易过拟合少数类别还会被多数类别淹没。这一章讲两个实操方向增强策略怎么选以及类别不均衡怎么补。4.1 适合叶片病害的增强方式与参数YOLOv8 内置了增强参数在训练命令里直接加yolo detect train \ dataapple_leaf_dataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4 \ degrees15 \ translate0.1 \ scale0.5 \ fliplr0.5 \ mosaic1.0 \ mixup0.1hsv_h/s/v控制色调、饱和度、亮度扰动田间光照变化大这三个值可以适当放大degrees15允许小角度旋转叶片方向不固定时有用scale0.5做随机缩放模拟不同拍摄距离fliplr0.5水平翻转叶片左右对称翻转不会改变类别mosaic1.0是 YOLOv8 默认的四图拼接增强对小目标检测帮助明显mixup0.1做图像混合比例别太高否则病斑边界会糊。要注意的是垂直翻转flipud对叶片病害不一定合适因为叶片正反面症状不同翻过来可能变成另一个类别。我一般保持flipud0.0。4.2 少数类别过采样与损失加权如果统计发现某个类别框数特别少有两种补法。第一种是过采样在训练时让包含少数类别的图片被重复采样。YOLOv8 不直接提供按类别采样但可以复制图片和标注文件到临时目录人为提高比例import os import shutil src_img apple_leaf_dataset/images/train src_lbl apple_leaf_dataset/labels/train dst_img apple_leaf_dataset/images/train_oversample dst_lbl apple_leaf_dataset/labels/train_oversample os.makedirs(dst_img, exist_okTrue) os.makedirs(dst_lbl, exist_okTrue) rare_class_id 4 # 假设类别 4 是少数类 repeat 3 for name in os.listdir(src_lbl): if not name.endswith(.txt): continue with open(os.path.join(src_lbl, name), r) as f: lines f.readlines() has_rare any(l.strip().startswith(rare_class_id ) for l in lines if l.strip()) shutil.copy(os.path.join(src_img, name.replace(.txt, .jpg)), dst_img) shutil.copy(os.path.join(src_lbl, name), dst_lbl) if has_rare: for i in range(repeat - 1): shutil.copy(os.path.join(src_img, name.replace(.txt, .jpg)), os.path.join(dst_img, fos{i}_ name.replace(.txt, .jpg))) shutil.copy(os.path.join(src_lbl, name), os.path.join(dst_lbl, fos{i}_ name))这段脚本把包含少数类的图片复制多份文件名加前缀避免冲突。repeat3表示少数类图片出现三次。过采样后要重新生成data.yaml指向新目录并注意验证集不要过采样否则指标失真。第二种是损失加权YOLOv8 的分类损失默认按类别频率计算可以在自定义训练时调整cls权重但改动成本较高。对 1700 张这个量级过采样通常够用。注意过采样后训练集图片数会变多epochs可以适当减少否则训练时间线性增长。5. 苹果叶片病害数据集常见问题与排查清单这一章是我处理这类数据集时踩过的坑按「现象 → 原因 → 解决」写遇到问题可以直接对号入座。5.1 训练 loss 正常但 mAP 一直是 0现象训练日志里 box_loss、cls_loss 都在降但验证集 mAP50 始终为 0 或极低。原因最常见的是data.yaml里的names和标注文件里的类别编号对不上或者标注文件路径写错模型实际在学空标签。另一个可能是图片和标注文件名不一致YOLO 按同名匹配找不到标注就当成背景。解决先跑一遍数据检查脚本确认每张图都有对应 txt且 txt 里类别编号不超过names的长度。再打印几张图的标注框看坐标是否在 0 到 1 之间。归一化坐标如果写成像素值框会全部跑到图外。5.2 验证集指标很高换一批图就崩现象验证集 mAP 0.85拿果园新拍的图测试漏检严重。原因切分时没有按叶片或拍摄批次分组训练集和验证集里有大量近似重复图模型记住了背景而不是病斑特征。解决回到 2.2 节的分组切分用文件名前缀或拍摄时间做 group确保同一片叶子的图只出现在一个集合。如果已经训练完重新切分后再训一次指标会降但更真实。5.3 小病斑全部漏检现象大块病斑能检出早期小斑点一个都框不出来。原因imgsz640下原图里几十像素的病斑缩到几个像素特征太弱。另外默认 anchor 尺寸偏向中大目标。解决把imgsz提到 960 或 1280显存不够就减小batch同时检查标注框的宽高如果大量框小于 10 像素考虑在标注阶段放大病斑区域或改用分类分割方案。YOLOv8 的mosaic增强对小目标有帮助保持开启。5.4 类别混淆严重锈病被认成褐斑现象混淆矩阵里锈病和褐斑互相误判比例高。原因这两个类别在早期颜色接近标注时边界模糊不同标注人员标准不一致。1700 张里如果混了多个来源的标注风格差异会放大这个问题。解决抽 50 张混淆最多的图人工复核标注统一标准。训练时提高hsv_h和hsv_s扰动让模型更关注纹理而不是颜色。如果仍然分不开考虑把两个类合并成「叶斑病」一个大类先保证检出率。5.5 训练到一半显存爆了现象前几个 epoch 正常后面突然 CUDA out of memory。原因mosaic增强在拼接时会产生尺寸不一致的中间张量某些批次占用显存波动大。另外如果开了cacheTrue把图片缓存到内存数据量大时也会挤占显存。解决把batch降到 8 或 4关闭cache或者设置ampFalse排除混合精度带来的波动。如果还是爆把imgsz从 960 降回 640先跑通再逐步加。6. 从 1700 张到可用模型验证方法与一个提点技巧训练完不是终点怎么判断这个模型能不能用比训练本身更重要。我一般会做三件事看混淆矩阵找系统性错误、用 t-SNE 看特征聚类、拿真实果园图做盲测。混淆矩阵在runs/apple_leaf/exp1/下重点看对角线以外的值如果某个类别被大量误判到另一个类别说明标注或特征有问题。t-SNE 可以把 backbone 输出的特征降维可视化类别分得开说明模型学到了判别性特征混在一起说明特征空间没拉开。盲测是最实在的。从果园随机拍 30 到 50 张图不挑角度、不挑光照直接跑推理人工数漏检和误检。如果 mAP 掉到 0.5 以下说明数据集和真实场景差距大需要补拍数据。补拍时优先拍模型错得多的类别和光照条件不要平均用力。一个提点技巧是测试时增强TTA。YOLOv8 推理时加augmentTrue会对输入做多尺度翻转再合并结果小目标召回通常能提几个点results model.predict( sourcetest_images, conf0.2, iou0.5, augmentTrue, saveTrue )augmentTrue会成倍增加推理时间适合离线批量处理不适合实时巡检。conf可以比训练时低一点配合 TTA 把漏检压下去误检靠后续人工复核兜底。我自己做这类项目的习惯是先把数据切分和标注检查做扎实再谈模型。1700 张不算多但标注质量高、切分合理的话YOLOv8s 在苹果叶片病害上跑到可用水平完全没问题。最怕的是一上来就换模型、调超参最后发现是标注文件里类别编号写错了。希望帮到你。本文还有配套的精品资源点击获取