恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

西瓜病识别图像分类数据集实战:从数据拆解到CNN训练全流程

  • 首页
  • 资讯中心
  • /
  • 西瓜病识别图像分类数据集实战:从数据拆解到CNN训练全流程

相关资讯

企业AI服务化落地指南:AI应用架构师如何做好API设计 2026/9/24 19:23:59
行人轨迹搜索实战:从ReID模型训练到向量检索管线 2026/9/24 19:23:59
向量检索怎么选索引:faiss 三大家族速度-召回实测曲线 2026/9/24 19:23:59

最新资讯

肺部结节检测为何首选VOC格式?医学影像数据标准化实战指南
Airflow不是调度器,而是以DAG为契约的分布式工程协议栈
TCP与UDP协议选型指南:从底层原理到工程实践
eVTOL低空经济AI图像处理:机载视觉系统部署与优化实战
奇诺多面体实现虚拟电厂分布式资源安全聚合
金融数学专业如何把定价模型作业改造成有求职说服力的项目经历

今日推荐

JavaWeb购物车系统实现:基于Session存储的完整工程示例
面向对象综合训练:从图书管理系统掌握封装、继承与多态
Lombok与JDK版本冲突引发NoSuchFieldError:根因排查与修复指南

本周热门

BrewUI:给Homebrew套上图形界面,让macOS软件包管理更简单
BrewUI:让Homebrew包管理变得可视化与高效
公式与文本对齐全攻略:从Word到LaTeX的实用技巧

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

西瓜病识别图像分类数据集实战:从数据拆解到CNN训练全流程

发布时间:2026/9/24 19:23:59
西瓜病识别图像分类数据集实战:从数据拆解到CNN训练全流程 简介面向农业图像分类与CNN实践场景一套西瓜病识别图像分类数据集包含约5700张已标注图片覆盖花叶病毒、健康、炭疽病和霜霉病4个类别并预分为训练集与测试集。包内提供json格式的类别/划分说明以及show.py可视化脚本解压后即可按类别文件夹读取数据省去手工整理标注的步骤。图像经由缩放、平移、亮度调整等方式扩充多样性较好可支撑图像分类入门练习、数据增强对比或CNN改进实验。资源共2000个文件主体为1998张jpg图片另含1个python脚本和1个json文件整个压缩包约156.94MB体积适中便于下载和本地复现。已有59人学习下载适合正在开展植物病害识别课题的学生或开发者尤其适合配合CNN网络改进系列教程边做边学快速获得可用训练数据与可视化工具。1. 一份 5,700 张已标注西瓜图像先把“图像分类”踩稳图像分类这个方向看起来就是把图片丢进 CNN 里训练实际上第一步先死在数据组织上的情况非常多。我拆解这份“西瓜病识别图像分类数据集”时它的定位很清晰4 个类别——花叶病毒、健康、炭疽病、霜霉病约 5,700 张图训练集、测试集已经分类存放标签写进了 JSON还配了一个 show 脚本用来快速预览数据。对想练 CNN 图像分类、特别是农业病害方向的人来说它省掉了拍照、裁剪、标注这些最磨人的环节。但“已标注”不等于“一跑就通”类别名称和 JSON 索引对不对得上、训练集和测试集的分布是否合理、show 脚本暴露出的坏图怎么处理这些边界不扫一遍后面训练再久也是白忙。这篇笔记我从数据拆解讲起把读取、训练、评估、单图推理整条链路走完该踩的坑尽量提前排掉。2. 拆开 4 分类数据集JSON 标签、目录结构与 show 脚本2.1 先对一遍 JSON类别索引从 0 开始还是按名称映射拿到这个资源的第一步我建议不要先开训练脚本而是把 JSON 标签文件单独读出来看一遍确认类别 ID 与类名是不是你预期的那套对应关系。很多图像分类数据集为了方便存储会把类名压缩成 0、1、2、3 的数字目录真正的名称只留在 JSON 里。如果代码里写死了label 0 健康而 JSON 里0对应的是花叶病毒训练出来再好看的准确率都是假象。import json with open(label_map.json, r, encodingutf-8) as f: label_map json.load(f) print(type(label_map)) print(label_map)这里有个值得注意的细节读取 JSON 时一定要带上encodingutf-8。这类标签文件如果是在 Windows 环境下用记事本编辑保存的可能是带 BOM 的 UTF-8 或 GBK 编码直接open()不加参数很可能会在键名里混入奇怪的字符。打印出来如果出现\ufeff0这种键就需要用utf-8-sig重新读一次open(file, r, encodingutf-8-sig)。我的习惯是把这个 JSON 的映射关系打印出来之后拿它去和资源文档里写明的“花叶病毒、健康、炭疽病、霜霉病”逐项对一遍确认无误再做下一步这个过程一分钟都花不到却能省掉后面所有标注错位的麻烦。2.2 训练集/测试集目录按文件夹分类的好处与读取规划这组数据的组织方式是训练集和测试集分开目录各自下面再按 4 个类别分子文件夹存放图片。解压之后目录结构大概是下面这种形态西瓜病识别分类数据集/ ├── train/ │ ├── 花叶病毒/ │ ├── 健康/ │ ├── 炭疽病/ │ └── 霜霉病/ ├── test/ │ ├── 花叶病毒/ │ ├── 健康/ │ ├── 炭疽病/ │ └── 霜霉病/ ├── show_script.py └── label_map.json把每个类别的图片放进独立文件夹是最经典也最不容易出错的图像分类数据组织方式。因为你不需要手工维护一张 CSV 名单只要文件夹名称和 JSON 里的类名一致torchvision.datasets.ImageFolder读取时会自动按文件夹名建索引。同时每个文件夹自身的文件数量也能一眼看出来哪个类别样本多、哪个类别样本少这不只是数据统计问题它直接影响后续训练时要不要做类别重采样。在规划读取方式时我一般会强调两点。第一不要在数据读取流程里再写一次类别枚举直接从 JSON 生成文件夹名 - 索引的映射避免两处维护。第二关于文件名是否代表增强方式的判断资源里可以看到IMG_4113_brightened.jpg、IMG_1984_shifted.jpg这类带后缀的图片说明原数据在采集时做了提亮、平移之类的扩增这部分本身没有标准化但模型训练时你不必区分它们到底是否增强过统一当作普通样本读进来即可真正的问题在更后面的数据分布层。2.3 跑通 show 脚本五秒钟看清这 5,700 张图的真面目数据集既然带了可视化脚本我强烈建议先跑一下它直接看几张图而不是闭着眼睛开始训练。常见的做法是这样python show_script.py --data_root ./西瓜病识别分类数据集 --num_show 5这个脚本做的事通常就是随机从每个类别里抽几张图用一行画布把 4 个类别展示出来。跑完之后要正着看三处图像有没有损坏、标签和画面对不对得上、不同类别之间的视觉差异有多大。看到花叶病毒和炭疽病有相似的斑块区域要意识到这不是数据集的缺点而正是模型训练时容易混淆的特征重叠后面评估阶段要多关注类别之间的具体错分流向不能只看整体准确率。如果脚本运行时报ModuleNotFoundError: No module named matplotlib直接pip install matplotlib补上就行。show 脚本还有一层容易被忽略的作用验证读取路径里的编码问题。Windows 下跑脚本如果目录名里的中文成了乱码图像路径会读不出来此时用ls或资源管理器看一下当前目录的实际名称和代码里的--data_root是否完全一致即可。脚本本身很小偶尔也会遇到牵扯到pyplot.show()暂停的阻塞问题加一个后端参数或者在脚本里注释掉阻塞窗体设置通常就能解决。3. 从数据集到可训练基线CNN 选型与训练脚本要点3.1 用 ImageFolder 把文件夹变成可取用的 DataLoader确认完目录结构和标签映射后接下来该把文件夹交给 PyTorch 的训练管线。我这里一直采用的读取方式是torchvision.datasets.ImageFolder它天然适配上一章那种“每个类别一个文件夹”的结构且会按文件夹名称的字典序生成固定的类别到索引的映射。注意它建索引的顺序和你手动指定的顺序不一定一致所以尽量通过dataset.class_to_idx显式暴露出来再配合 JSON 映射做一次核对。from torchvision import datasets, transforms from torch.utils.data import DataLoader train_transform transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomHorizontalFlip(p0.5), transforms.RandomRotation(10), transforms.ColorJitter(brightness0.2, contrast0.2), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) test_transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) train_dataset datasets.ImageFolder(西瓜病识别分类数据集/train, transformtrain_transform) test_dataset datasets.ImageFolder(西瓜病识别分类数据集/test, transformtest_transform) train_loader DataLoader(train_dataset, batch_size32, shuffleTrue, num_workers4) test_loader DataLoader(test_dataset, batch_size32, shuffleFalse, num_workers4) print(train_dataset.class_to_idx)这里对参数做个简单说明Resize((224, 224))是大多数 ImageNet 预训练模型的默认输入尺寸保持一致可以减少迁移学习的适配成本RandomHorizontalFlip、RandomRotation、ColorJitter属于数据增强作用在训练集上让模型对空间翻转和光线波动不那么敏感。测试集就没有做翻转和旋转这是为了防止同样的图片在评估时出现两种完全不同的预测结果保证指标可复现。num_workers4是根据常见 CPU 核心数配置的如果你的机器比较老改成 2 或 0 反而更稳。3.2 为什么我不一上来就选最新的图像分类模型看到 5,700 张图、4 分类任务有人习惯性去翻最新的图像分类模型论文想把最前沿的架构直接搬过来。我的建议是不要。这里的原则和模型本身好坏无关而是这份数据集的规模决定了训练成本5,700 张属于中小型数据集直接用超大模型即使加载了预训练权重微调时也容易在几十个 epoch 后陷入严重过拟合表现为训练集准确率很高、测试集滞后很多。行业内对这个场景的经典选型是 ResNet18 或 ResNet34它们结构成熟、显存占用低并且有大量可用的 ImageNet 预训练权重正好匹配农业图像分类这类样本量不太大的任务。如果你追求更低的参数量和更快的推理速度可以换 MobileNetV3。改起来也很简单把模型构造那一行的resnet18换成mobilenet_v3_small再把最后一层全连接的输出维度改成 4 就行。EfficientNet 处于两者之间轻量但需要稍微仔细调一调学习率。总的来说先跑通一个小而稳的基线确认数据和流程没问题再向更大模型迭代这样的顺序在工程上最省时间。3.3 训练脚本骨架损失函数、优化器与模型保存细节搭好数据加载后训练主体其实很固定。下面这段是骨架代码适用于这个 4 分类数据集也可以平移到你后面其他的图像分类任务上import torch 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) num_classes 4 model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) model.fc nn.Linear(model.fc.in_features, num_classes) model model.to(device) criterion nn.CrossEntropyLoss() optimizer optim.SGD(model.parameters(), lr0.001, momentum0.9, weight_decay1e-4) scheduler optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max30) best_acc 0.0 for epoch in range(30): model.train() running_loss 0.0 for images, labels in train_loader: images, labels images.to(device), labels.to(device) optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() running_loss loss.item() * images.size(0) scheduler.step() # 简单验证逻辑每次训练完看一下当前 epoch 的测试表现 model.eval() correct 0 total 0 with torch.no_grad(): for images, labels in test_loader: images, labels images.to(device), labels.to(device) outputs model(images) _, predicted torch.max(outputs, 1) total labels.size(0) correct (predicted labels).sum().item() acc correct / total print(fEpoch {epoch1}: loss{running_loss/len(train_dataset):.4f}, acc{acc:.4f}) if acc best_acc: best_acc acc torch.save(model.state_dict(), best_watermelon_model.pth) print(fBest model saved, acc{best_acc:.4f})关键参数有三个。学习率lr0.001是迁移学习场景下比较稳妥的起点等于一个“先试探再调整”的量级如果发现 loss 来回震荡可以降到 0.0003weight_decay1e-4是 L2 正则化对缓解过拟合有帮助数据集本身不大这个值不建议拿掉CosineAnnealingLR的设计意图是让学习率随训练周期平滑下降比固定学习率更容易逼到更好的局部最优点。模型保存我用了state_dict()而不是整个模型对象前者只保存参数文件更小换脚本加载时也更灵活后面写单图推理时会用到相同的加载方式。4. 西瓜病识别实操排查5 个最容易翻车的情况4.1 坑一show 脚本界面弹出但显示全黑或乱码图片现象运行 show 脚本可以看到图片窗口但部分图呈现全黑或者颜色明显错乱某些图辨识不出西瓜轮廓。原因这类情况多半不是图片本身损坏而是原图可能带 EXIF 方向信息PIL 在读取时没有做方向校正旋转信息没被应用图像就会横着或倒着显示另外如果 show 脚本里用了归一化参数直接对[0,1]区间的数据进行imshow也会出现整体偏白或偏黑。解决在脚本里对每张图用ImageOps.exif_transpose(img)做方向修正或者显示前统一检查通道顺序。图像打印出来确认是 BGR 还是 RGB我在做这方面数据时被坑过一次有些脚本基于 OpenCV 读取保存的预览图整体偏蓝后来在imshow前重新组合了通道才正常。遇到黑图不要急着删数据大多数只是显示端的问题。4.2 坑二JSON 里的类别顺序和训练脚本里的索引对不上现象训练代码显示训练完成准确率也不错但画出混淆矩阵或者查看class_to_idx时发现“健康”和“炭疽病”的索引和实际输出完全错位。原因ImageFolder在创建类别索引时按文件夹名的字典序自动排序不保证和 JSON 里的排列顺序一致。比如 JSON 写的是“花叶病毒、健康、炭疽病、霜霉病”而文件夹用数字命名时排序会变成0, 1, 2, 3前者又很容易被误以为是按这个顺序建的索引。解决不要手写类名列表直接在代码里打印train_dataset.class_to_idx与label_map做对照。我自己现在的做法是以class_to_idx为唯一标准反向把 JSON 映射修正为类别名 - class_to_idx后续所有计算指标都以这个映射为准。或者更省心在ImageFolder构造后立刻断言两边类别集合一样不一致就让程序直接报错绝不带病训练。4.3 坑三训练集准确率接近 98%测试集准确率却只有七成现象训练后期 loss 降得很低训练集准确率到了 98 甚至 100但测试集停在 70 上下而且连续多个 epoch 没有起色。原因这是典型的过拟合。5,700 张图对 4 分类任务不算海量模型容量一大或训练轮次一多就会开始背训练样本的个性化特征而不是学到病害的共性质地。类间视觉重合度高花叶病毒和炭疽病初期斑块相似也会加剧这种背题现象。解决优先给训练集增强加码比如把随机旋转从 10 度提高到 15 度增加RandomResizedCrop让模型每次看到的叶子区域都不一样。其次建议把训练轮次缩短到 3040 并配合早停策略验证集连续 5 个 epoch 不加就停止训练。最后还可以适当加大weight_decay到5e-4。这三个手段按顺序加不要一上来就换更大的模型。4.4 坑四测试集里混进了“被增强过”的样本导致结果虚高或虚低现象查看 test 目录文件名时发现brightened、shifted、zoomed等后缀把这些图纳入测试集后某一次的测试准确率有明显波动且不稳定。原因资源在构造训练集时对部分图片做了亮化、平移和缩放增强有些文件同时存在原图和增强后的版本如果测试集划分时没做好去重就可能出现“同一张图的原图在训练集、增强图在测试集”的相近样本穿帮测试分数容易虚高。反过来如果增强后的图和原图风格差异太大模型没见过这种亮度分布分数又会偏低。解决先跑一次统计脚本对所有文件名去后缀后保留主编号把主编号相同而增强后缀不同的图片标记出来人工或自动确认这些样本是否跨集合存在。对于训练集和测试集的划分如果你不确定原始划分是否独立就跑一遍交集检测发现有重叠就把重叠样本从测试集剔除宁可用少一点但干净的测试集。这个方法做一次只要几分钟但直接决定你报告的指标能不能服众。4.5 坑五类别不均衡被忽略整体准确率掩盖单一病灶失效现象模型整体准确率到了 85% 以上但单独统计每个类别的召回率发现某种病害比如炭疽病的召回率只有四成大量图片被误判成健康。原因4 个类别的图片数量并不完全相等数据采集时健康的瓜拍得多病害早期样本少。模型在类别不均衡时倾向于把不确定样本分到数量较多的类别整体准确率被大类别拉高小众类别的表现就被掩盖了。解决训练前先数一下每个文件夹里的图片数如果最大类别与最小类别差距超过 2 倍就要做类别重采样或用加权损失。最简单的做法是在CrossEntropyLoss里传入weight参数按类别样本数倒数归一化得到权重让少数类的误差贡献更大。更好的做法是用WeightedRandomSampler在采样层面平衡这两种在第 6 章会给出具体代码参考。5. 评估这一版分类器混淆矩阵与分病种指标5.1 别只看 accuracy用 macro-F1 判断模型才算数为什么单一准确率对农业病害不靠谱因为病害分类任务在应用中更关心的是“漏检”和“误检”的代价把一个生病的西瓜判成健康比把健康瓜误判为生病更严重。所以每个类别的单独表现比一个总体均值重要得多。我建议在训练结束后至少看 4 个指标每个类别的 Precision、Recall、F1-score以及所有类别 F1 取平均后的 macro-F1。指标计算方式这份场景里的意义Precision预测为某类的样本中真正属于该类的比例预测“炭疽病”之后到底有多少是真的炭疽病Recall该类样本中被正确找回的比例真实的霜霉病样本有没有被漏掉F1-scorePrecision 与 Recall 的调和平均两者平衡避免只押一边Macro-F1各类别 F1 的算术平均反映 4 个类别的平均表现不受样本量影响如果accuracy高但 macro-F1 明显偏低基本可以断定大类别把整体拉上去了小类别实际效果并不可用。对农业病害这种误判成本高的场景我宁肯挑 macro-F1 更高但原 accuracy 稍低一两个点的模型因为它在少数类上真的分得开。5.2 混淆矩阵看到底哪些类别在被互相错认光看指标还不够要排除“模型为什么错”的疑问混淆矩阵是最直接的呈现。下面这段脚本从测试集跑一遍把预测和真实标签交给sklearn生成矩阵import torch from sklearn.metrics import confusion_matrix, classification_report import seaborn as sns import matplotlib.pyplot as plt model.eval() all_preds [] all_labels [] with torch.no_grad(): for images, labels in test_loader: images images.to(device) outputs model(images) _, preds torch.max(outputs, 1) all_preds.extend(preds.cpu().numpy()) all_labels.extend(labels.numpy()) cm confusion_matrix(all_labels, all_preds) print(classification_report(all_labels, all_preds, target_nameslist(train_dataset.class_to_idx.keys()))) plt.figure(figsize(8, 6)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelslist(train_dataset.class_to_idx.keys()), yticklabelslist(train_dataset.class_to_idx.keys())) plt.xlabel(Predicted) plt.ylabel(True) plt.tight_layout() plt.savefig(confusion_matrix.png, dpi150)跑完之后重点看混淆矩阵中偏离对角线的位置。真实类别是花叶病毒却被识别成炭疽病说明这两个类的纹理和颜色特征过于接近可以考虑专门收集这两类的难例继续微调。如果真实健康被误判成各种病通常是健康样本在训练增强时被改得太狠颜色发生了偏移。从混淆矩阵反推数据增强的参数这是看指标时容易忽略的暗线。5.3 类别不均衡与损失函数权重让模型少盯着大类别看前面第 4 章提到了类别不均衡的连带问题这里把具体解法补完。先统计每个类的数量然后直接对损失加权from collections import Counter import numpy as np label_counts Counter([label for _, label in train_dataset.samples]) total_count sum(label_counts.values()) class_weights [] for cls_idx in range(num_classes): class_weights.append(total_count / (num_classes * label_counts[cls_idx])) class_weights torch.tensor(class_weights, dtypetorch.float32).to(device) criterion nn.CrossEntropyLoss(weightclass_weights)这里class_weights的计算思路是某个类别样本越少权重越大最终每个类别对损失的贡献趋于均衡。注意换用加权损失之后原训练脚本里打印出的数值会和之前不在同一量纲上不要拿两套 loss 直接比较。更精细一点还可以配合评估指标做早停比如每个 epoch 保存的是 macro-F1 最大化时的权重而不是 accuracy 最大时的权重。对于已经遇到过一个类召回率偏低的情况加了这个权重之后通常能改善几个点代价是数量多的健康类可能误报率上升这是类别均衡化的自然取舍。6. 单图推理验收把训练好的模型用到一张真实西瓜照片上6.1 推理脚本的预处理细节训练时跑通了整套流程还剩下最后一步把这个模型从验证环境挪到单图推理环境。单图推理最容易出错的地方不是模型本身而是预处理不一致。训练时图片走的是Resize(224, 224)加上一套 mean/std 标准化推理时必须用同一套参数少一步归一化输出结果就可能跟训练时完全不是一回事。from PIL import Image import torch import torchvision.transforms as transforms import torch.nn.functional as F def predict_image(img_path, model, class_names, device): transform transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) img Image.open(img_path).convert(RGB) img transform(img).unsqueeze(0).to(device) model.eval() with torch.no_grad(): outputs model(img) probs F.softmax(outputs, dim1) score, pred torch.max(probs, dim1) return class_names[pred.item()], score.item() class_names [花叶病毒, 健康, 炭疽病, 霜霉病] result, conf predict_image(test/炭疽病/test_001.jpg, model, class_names, device) print(f预测类别: {result}, 置信度: {conf:.4f})一个我在实际使用中养成的习惯是推理结果除了给出类别一定要把置信度也打印出来并设一个阈值比如低于 0.7 就标记为“待人工确认”。农业病害图在野外采集时光线、遮挡、叶面阴影变化很大模型给出一个五五开的置信度时直接自动判断的风险很高。带置信度输出的推理脚本不复杂却能让你在真机上被反复询问“这个准不准”时拿得出依据。另外一个小技巧如果你后面想把这份数据扩展到检测任务而不是只做图像分类可以直接复用当前训练集文件夹用标注工具把病害区域框出来再按 YOLOv8 训练自己的数据集时要求的目录格式重新整理。分类模型给出的是“这张图有没有病、是什么病”的结论检测模型还能进一步回答“病斑在叶子的哪个位置”你在这一年里做的数据清洗、增强策略验证全部可以迁移过去不需要重头再来。这类把分类数据集转成检测数据集的路径在做农业 AI 项目时很常见。从拆 JSON 到单图推理整条链路走完最大的心得其实就一句话很多所谓“分类模型不准”的问题根源在数据边界没探明。从那以后我每次拿到一个新分类数据集第一轮都会强制自己先跑 show 脚本核对标签再检查类别分布最后才写训练循环这个顺序一步不省。希望这份拆解能帮到你特别是正拿着 5,700 张西瓜病害图不知道从哪下手的人。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号