苹果叶片病害识别数据集实战:1700张标注图像训练CNN分类模型
简介苹果叶片病害图像识别数据集面向计算机视觉与农业智能化方向的学习者和研究者用于训练和评估叶片病害分类模型帮助果农快速识别与防治苹果树病害。数据集已专业标注共约1700张图片划分为健康、生锈、痂三个类别并区分训练集与验证集便于模型学习与泛化能力评估。压缩包共1733个文件以1730张jpg图像为主体另含1个py可视化脚本、1个png与1个json标注说明文件整体约354.45MB目录按类别与训练/验证划分结构清晰。运行show脚本可直观查看样本分布与图像特征便于发现数据问题并优化模型。资源同时适配CNN分类网络与YOLOv5分类方案配套项目链接可辅助搭建识别系统。目前已有340人学习下载适合入门图像分类、开展课程设计或农业AI应用实践。1. 苹果叶片病害识别数据集1700 张已标注图像能跑出什么结果果园里最怕的不是虫是叶片上那层说不清是锈还是痂的斑。等肉眼分辨出来往往已经错过最佳防治窗口。这份苹果叶片病害图像识别数据集就是冲着这个场景来的约 1700 张实拍叶片图已经按“健康”“生锈”“痂”三类标注好训练集和验证集分开存放还附带一个 show 脚本用来可视化。它适合两类人——一类是想拿真实农业图像练 CNN 分类的算法工程师另一类是做农业技术落地、需要快速验证识别可行性的开发者。数据集本身不复杂但“已标注”三个字背后有不少细节决定你能不能一次跑通比如类别是否均衡、验证集怎么划、图像尺寸是否统一。下面按“先看清数据、再跑通训练、最后避开标注坑”的顺序拆一遍。2. 先看清数据再动手目录结构、类别分布与 show 脚本拿到一个标注数据集最忌讳直接往模型里灌。苹果叶片这三类里“健康”和“生锈”在颜色上差异明显但“生锈”和“痂”在早期症状上容易混淆如果验证集里这两类样本比例失衡准确率会虚高。所以第一步不是写网络是把数据摸清楚。2.1 目录结构与文件命名规律从项目正文给出的文件名看训练集图片采用Train_数字.jpg的命名方式例如Train_1616.jpg、Train_948.jpg、Train_254.jpg。这种命名说明数据在整理时做过统一重命名好处是避免中文路径和特殊字符导致的读取失败坏处是文件名本身不携带类别信息。类别信息一定藏在配套的 json 文件或按类别分好的子目录里。常见做法是目录长这样dataset/ ├── train/ │ ├── healthy/ │ ├── rust/ │ └── scab/ ├── val/ │ ├── healthy/ │ ├── rust/ │ └── scab/ └── classes.json如果你拿到的不是按类别分目录而是所有图混在一起加一个 json 标注文件那就需要先解析 json 再拆分。先确认这一点再决定后面用ImageFolder还是自定义Dataset。2.2 用 show 脚本做可视化与类别核对资源里带了 show 脚本这是最省事的入口。我一般会先跑它把每个类别随机抽 9 张拼成一张大图看一遍。原因很直接标注错误在数字上看不出来但眼睛扫一遍就能发现“这张明明是健康却被标成生锈”的问题。如果 show 脚本是 Python 写的典型逻辑是读类别目录、随机采样、用 matplotlib 拼图。你可以按下面方式改造它加上类别计数import os import random import matplotlib.pyplot as plt from PIL import Image root dataset/train classes sorted(os.listdir(root)) fig, axes plt.subplots(len(classes), 6, figsize(15, 3 * len(classes))) for i, cls in enumerate(classes): folder os.path.join(root, cls) imgs os.listdir(folder) print(f{cls}: {len(imgs)} 张) # 类别数量直接打印判断是否均衡 samples random.sample(imgs, min(6, len(imgs))) for j, name in enumerate(samples): img Image.open(os.path.join(folder, name)) axes[i][j].imshow(img) axes[i][j].set_title(f{cls} {img.size}) # 标题带尺寸顺便看分辨率是否统一 axes[i][j].axis(off) plt.tight_layout() plt.savefig(check_grid.png, dpi120)这段代码的关键在print那行和set_title里的img.size。类别计数让你知道有没有哪类样本特别少尺寸显示让你知道要不要统一 resize。如果三类数量差距超过 3 倍训练时就得考虑加权采样否则模型会偏向多数类。2.3 训练集与验证集的划分逻辑摘要里明确说“划分了训练集、验证集”但没有给具体比例。农业图像数据集常见做法是 8:2 或 7:3。你需要确认验证集是不是从同一批图里随机抽的——如果是按时间或地块抽的泛化评估会更真实如果是纯随机验证准确率通常会偏高。一个快速判断方法看训练集和验证集里同一类别的图片有没有高度相似的比如同一片叶子的不同角度。如果有说明划分时没做去重验证集分数会虚高。我一般会算一下训练集和验证集的感知哈希重复度超过阈值就重新划。提示如果验证集准确率一开始就 95% 以上先别高兴大概率是训练集和验证集有近重复图。3. 用 CNN 跑通三分类从 DataLoader 到训练循环数据看清之后下一步是把它喂给一个能跑通的分类网络。摘要里给了 CNN 分类网络项目和 YOLOv5 分类两条参考路线。对于 1700 张图、3 个类别的任务直接上 ResNet18 或 MobileNetV3 就够了没必要一上来就上大模型。这一章给一套能直接抄的 PyTorch 训练流程。3.1 数据增强与 DataLoader 配置苹果叶片图像的特点是背景相对单一、叶片占画面主体所以增强策略要克制。水平翻转、轻微旋转、颜色抖动够用垂直翻转要慎用因为叶片正反面纹理不同翻了可能改变类别语义。import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader train_tf transforms.Compose([ transforms.Resize((224, 224)), # 统一到 224适配 ResNet 输入 transforms.RandomHorizontalFlip(p0.5), # 水平翻转模拟不同拍摄方向 transforms.RandomRotation(15), # 小角度旋转避免叶片出画 transforms.ColorJitter(brightness0.2, contrast0.2), # 应对不同光照 transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) # ImageNet 统计量 ]) val_tf transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) ]) train_ds datasets.ImageFolder(dataset/train, transformtrain_tf) val_ds datasets.ImageFolder(dataset/val, transformval_tf) train_loader DataLoader(train_ds, batch_size32, shuffleTrue, num_workers4) val_loader DataLoader(val_ds, batch_size32, shuffleFalse, num_workers4) print(train_ds.class_to_idx) # 确认类别索引映射后面看混淆矩阵要用参数说明batch_size32在 1700 张规模下比较稳显存不够就降到 16num_workers4在 Windows 上如果报错就改成 0Normalize用的是 ImageNet 统计量因为后面用预训练权重这一步不能省。class_to_idx打印出来是为了后面分析混淆矩阵时知道 0、1、2 分别对应哪一类。3.2 迁移学习与训练循环1700 张图从头训 CNN 容易过拟合常见做法是加载 ImageNet 预训练权重只微调最后几层。下面这套循环里我加了早停和验证准确率记录避免跑完才发现过拟合。import torch.nn as nn import torch.optim as optim from torchvision import models device torch.device(cuda if torch.cuda.is_available() else cpu) model models.resnet18(weightsmodels.ResNet18_Weights.DEFAULT) model.fc nn.Linear(model.fc.in_features, 3) # 改成 3 分类 model model.to(device) criterion nn.CrossEntropyLoss() optimizer optim.Adam(model.parameters(), lr1e-4) # 微调用小学习率 scheduler optim.lr_scheduler.StepLR(optimizer, step_size7, gamma0.1) best_acc 0.0 for epoch in range(20): model.train() for imgs, labels in train_loader: imgs, labels imgs.to(device), labels.to(device) optimizer.zero_grad() loss criterion(model(imgs), labels) loss.backward() optimizer.step() model.eval() correct total 0 with torch.no_grad(): for imgs, labels in val_loader: imgs, labels imgs.to(device), labels.to(device) pred model(imgs).argmax(1) correct (pred labels).sum().item() total labels.size(0) acc correct / total scheduler.step() print(fepoch {epoch1}, val_acc {acc:.4f}) if acc best_acc: best_acc acc torch.save(model.state_dict(), best_apple.pth) # 只存最好的逻辑说明lr1e-4是微调常用值比从头训练的 1e-3 小一个量级StepLR每 7 个 epoch 降一次学习率帮助后期收敛保存best_apple.pth而不是最后一个 epoch是因为验证准确率往往在中途达到峰值。如果训练 5 个 epoch 后验证准确率还在 33% 附近说明数据加载或标签映射出了问题先回去查class_to_idx。3.3 混淆矩阵看“生锈”和“痂”有没有混三分类任务里整体准确率会掩盖类别间的混淆。跑完训练后一定要在验证集上算混淆矩阵重点看“生锈”被预测成“痂”的比例。from sklearn.metrics import confusion_matrix import seaborn as sns import matplotlib.pyplot as plt model.eval() all_preds, all_labels [], [] with torch.no_grad(): for imgs, labels in val_loader: imgs imgs.to(device) preds model(imgs).argmax(1).cpu().numpy() all_preds.extend(preds) all_labels.extend(labels.numpy()) cm confusion_matrix(all_labels, all_preds) sns.heatmap(cm, annotTrue, fmtd, xticklabelstrain_ds.classes, yticklabelstrain_ds.classes) plt.xlabel(预测) plt.ylabel(真实) plt.savefig(confusion.png, dpi120)如果“生锈”和“痂”之间的非对角线数字明显大于其他错误说明这两类在特征空间里太近。解决办法有两个一是对这两类做更强的颜色增强二是考虑先做二分类健康 vs 病害再在病害里细分。不要盲目加网络深度1700 张图撑不起太深的模型。4. 避坑与排查标注数据集的五个血泪经验标注数据集用起来翻车往往不是模型问题是数据问题。下面五条是我在类似农业图像项目里踩过的按“现象 → 原因 → 解决”写清楚。4.1 验证准确率异常高但实际预测一塌糊涂现象训练时验证集准确率 98%拿几张新拍的叶片图进去预测结果随机跳。 原因训练集和验证集里有近重复图模型记住了纹理而不是学到了病害特征。 解决对训练集和验证集做感知哈希去重重复的只保留在训练集或者按拍摄批次划分验证集确保验证集图片和训练集不是同一批。4.2 某一类召回率极低混淆矩阵里整行错现象健康类识别很准但“痂”几乎全被预测成“生锈”。 原因两类样本数量差距大或者“痂”的标注里混入了早期“生锈”的图。 解决先统计三类数量差距大就用WeightedRandomSampler做加权采样再随机抽“痂”类图片人工看一遍把标错的挑出来重标。4.3 训练 loss 不下降准确率卡在 33%现象loss 一直在 1.1 附近验证准确率等于随机猜。 原因ImageFolder读到的类别目录为空或者标签全是同一个值。 解决打印train_ds.class_to_idx和len(train_ds)确认三个类别都被读到再检查 json 标注文件里的类别名和目录名是否一致大小写和空格都算差异。4.4 图像尺寸差异大导致训练报错现象RuntimeError: stack expects each tensor to be equal size。 原因数据集里图片分辨率不统一Resize写在了ToTensor后面或者漏了Resize。 解决确保transforms.Resize((224, 224))在ToTensor()之前如果要做多尺度训练用RandomResizedCrop替代固定Resize。4.5 show 脚本跑出来全是黑图或报路径错误现象可视化脚本打开图片是黑色或者提示FileNotFoundError。 原因中文路径、空格路径或者图片实际是 RGBA 四通道而 matplotlib 按 RGB 读。 解决把数据集路径改成全英文无空格读图时统一Image.open(path).convert(RGB)避免四通道和灰度图干扰。注意标注数据集的价值在标注质量不在图片数量。1700 张里如果有 100 张标错对三分类任务的影响可能比少 300 张图还大。5. 进阶技巧用 YOLOv5 分类和 TensorBoard 验证训练是否真的在学摘要里提到数据集也支持基于 YOLOv5 的分类任务。YOLOv5 的分类分支和 CNN 分类在数据组织上略有不同它要求按类别分目录但不需要 json 标注文件。如果你已经按train/healthy、train/rust、train/scab整理好直接指向--data参数即可。python classify/train.py \ --data dataset \ --model yolov5s-cls.pt \ --epochs 30 \ --batch-size 32 \ --img 224 \ --project runs/train-cls \ --name apple_exp参数说明--data指向包含 train 和 val 的根目录--model用预训练分类权重--img 224和 CNN 保持一致方便对比--name指定实验名方便在runs/train-cls/apple_exp里找结果。YOLOv5 分类默认会输出混淆矩阵和 top-1/top-5 准确率省去自己写评估代码。但工具换了不代表问题消失。我一般会再加一步 TensorBoard 看训练曲线确认模型是在学特征而不是在背数据。from torch.utils.tensorboard import SummaryWriter writer SummaryWriter(runs/apple_cnn) # 在训练循环里加 writer.add_scalar(loss/train, loss.item(), epoch) writer.add_scalar(acc/val, acc, epoch) # 训练结束后 writer.close()跑tensorboard --logdir runs之后重点看两条线训练 loss 是否稳定下降验证准确率是否在某个 epoch 后不再涨。如果训练 loss 降但验证准确率平就是过拟合回去加增强或减模型容量如果两条都平就是学习率太小或数据有问题。从那以后我每次拿到新的标注数据集都强制先跑一遍 show 脚本、打印类别计数、算一次训练验证重复度再动模型。这三步花不了十分钟但能省掉后面几小时的无效训练。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

PADS VX2.7 Gerber输出实战指南:从设计到可投产制造包

PADS VX2.7 Gerber输出实战指南:从设计到可投产制造包

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 15:47:10 阅读更多 →
刀具识别数据集实战:VOC转YOLO训练与避坑指南

刀具识别数据集实战:VOC转YOLO训练与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 15:47:09 阅读更多 →
基于C++与EasyX的飞机大战小游戏开发实战

基于C++与EasyX的飞机大战小游戏开发实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 15:47:08 阅读更多 →

最新新闻

智能体自主迭代实战:反馈机制、多智能体与工程落地指南

智能体自主迭代实战:反馈机制、多智能体与工程落地指南

2024年下半年开始,AI领域讨论最多的已经不只是“哪个模型更强”,而是“智能体到底能不能自己变强”。朋友圈和社区里,智能体、自主迭代这两个词几乎绑定出现:有人拿Coze搭客服机器人,有人用Dify做企业内部知识库问答&a…

2026/10/7 16:26:51 阅读更多 →
oneTBB 读写锁升级与降级:upgrade_to_writer / downgrade_to_reader 实战指南

oneTBB 读写锁升级与降级:upgrade_to_writer / downgrade_to_reader 实战指南

并发编程高性能计算 【免费下载链接】oneTBB oneAPI Threading Building Blocks (oneTBB) 项目地址: https://gitcode.com/gh_mirrors/on/oneTBB 点击查看 免费下载 本文基于 oneAPI Threading Building Blocks(oneTBB)用户指南中的 Upgrade…

2026/10/7 16:26:51 阅读更多 →
C语言 <time.h> 头文件详解

C语言 <time.h> 头文件详解

C语言 time.h 头文件详解一、头文件详解1. 引言2. 核心类型2.1 time_t2.2 struct tm2.3 clock_t3. 常用函数3.1 time() — 获取当前时间3.2 localtime() 与 gmtime() — 时间转换3.3 strftime() — 格式化时间输出3.4 mktime() — 将 struct tm 转回 time_t3.5 difftime() — 计…

2026/10/7 16:26:51 阅读更多 →
用Claude Code打造AI营销技能包:SEO、CRO与Analytics自动化实践

用Claude Code打造AI营销技能包:SEO、CRO与Analytics自动化实践

1. 从"marketingskills"这个标题说起:它到底想解决什么问题第一次看到"marketingskills"这个标题,我脑子里冒出来的第一个念头是:这大概率不是一个单纯的营销理论合集,而是一套把营销动作拆成可执行技能模块的…

2026/10/7 16:26:51 阅读更多 →
Context-Mode实战:用结构化上下文解决AI内容生成跑偏问题

Context-Mode实战:用结构化上下文解决AI内容生成跑偏问题

如果你正被各种“满屏弹窗”似的提示折腾得够呛,那么“context-mode”这个概念值得好好掰扯掰扯。它不是某个新出的社交APP,也不是什么玄乎的流量密码,而是我在实际项目里反复打磨出来的一套内容生成与对话组织模式。说得直白一点&#xff0c…

2026/10/7 16:26:51 阅读更多 →
软考网规第三版-综合知识历年真题考点分布

软考网规第三版-综合知识历年真题考点分布

软考网规第三版综合知识历年真题考点分布 第一章计算机网络基础 软考网规:第一章计算机网络基础历年真题分布(已更新)-CSDN博客 1.1 计算机网络概念 1.2 计算机网络体系结构 考试题型:选择题 分值:1-2分 考试重点:掌握OSI和TCP/IP模型、每个层次功能、协议层次 1.…

2026/10/7 16:25:49 阅读更多 →

日新闻

ROS2机械臂仿真与运动控制:从URDF建模到Gazebo实战全解析

ROS2机械臂仿真与运动控制:从URDF建模到Gazebo实战全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:01:58 阅读更多 →
用浏览器直接改ESP32的WiFi密码:NVS键值配置工具设计与实现

用浏览器直接改ESP32的WiFi密码:NVS键值配置工具设计与实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:02:00 阅读更多 →
芯片封装缺陷检测:扫描声学显微镜(SAT)原理与实操指南

芯片封装缺陷检测:扫描声学显微镜(SAT)原理与实操指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 1:02:00 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 14:34:12 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 14:34:13 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 9:29:10 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 14:34:12 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 11:43:46 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 13:34:55 阅读更多 →