资讯动态

大豆叶片病害图像分类数据集实战:从标签检查到迁移学习

发布时间:2026/9/28 17:00:09 来源:尧图企业网站定制
简介面向植物病理与计算机视觉交叉领域研究者、农业智能装备开发者及图像分类入门学习者这是一份带标注的大豆叶片病害图像分类数据集。资源共约6000张真实叶片图像划分为Diabrotica speciosa叶甲危害、健康、Caterpillar毛虫危害三个类别并已按训练集、测试集分目录存放方便直接用于深度学习模型训练与评估。压缩包共含2000个文件主体为1998张jpg图像另附1个json类别配置文件与1个Python可视化脚本可快速查看各类样本分布与标注情况整体约808.63MB。目前已有135人学习下载适合用于病害识别算法验证、迁移学习实验或农业智能诊断系统原型开发。通过该数据集可自行训练分类模型验证不同网络结构在大豆叶片病害识别上的表现也可结合图像增强、数据划分等技巧完成完整实验流程为后续农业病害自动检测提供可靠实验基础。1. 大豆叶片病害图像分类数据集拿回来先做三件事做图像分类最耗时间的从来不是写模型而是找一份能直接训练的数据集。这份大豆叶片病害图像分类数据集约6000张已标注图像一共三类Diabrotica speciosa叶甲类虫害、健康healthy、Caterpillar毛毛虫训练集和测试集已经按类别目录划分好附带JSON标签文件和show可视化脚本。对刚接触图像分类、正在做网络改进对比实验、或者需要快速验证迁移学习效果的从业者来说最合适的用法就是把数据流一次跑通把精力省给模型本身。不过拿到手别急着开训目录结构、标签顺序、图片完整性三件事先确认能少踩一半的坑。2. 目录与标签体系JSON里藏着类别的最终答案2.1 目录结构训练集和测试集怎么组织的这份数据集是按图像分类最常见的组织方式存放的顶层分train和test两个目录各自再按类别建子目录每个目录里放同一类的图片。文件名类似healthy (871).jpg这种格式括号里的编号只是原始采集顺序和标签没有关系。目录结构大致如下dataset/ ├── train/ │ ├── Diabrotica speciosa/ │ ├── healthy/ │ └── Caterpillar/ ├── test/ │ ├── Diabrotica speciosa/ │ ├── healthy/ │ └── Caterpillar/ ├── dataset.json └── show.py这种组织方式的直接好处是PyTorch的ImageFolder可以零改动读取。要快速统计每个类别的图片数量用一行shell命令就能完成# 统计训练集里每个类别的图片数量 find train -type f -name *.jpg | awk -F/ {print $2} | sort | uniq -c-F/指定以斜杠作为分隔符$2取的是路径第二段也就是类别子目录名最后uniq -c逐类计数。跑完你就能看到三个类的分布。注意一个容易忽略的细节类名中间带空格例如Diabrotica speciosa在bash脚本或批处理里如果直接用路径拼接必须给路径加引号否则空格会被当成参数分隔符这也是用find而不用手写路径的原因。2.2 JSON标签文件先打印keys再决定怎么解析摘要里明确写了具体查看json文件说明类别的规范定义在JSON里而不是靠目录名猜。目录名是给人看的JSON里的映射是给代码用的。拿到JSON第一件事不是直接解析而是打印它的结构import json with open(dataset.json, r, encodingutf-8) as f: data json.load(f) print(data.keys()) # 常见输出: dict_keys([classes, train, test]) 或 dict_keys([labels])encodingutf-8这一步在Windows上特别重要很多标注工具导出的JSON默认带中文注释或用UTF-8编码不指定编码容易直接抛UnicodeDecodeError。打印出顶层keys之后再进一步看类别字段具体是什么结构。常见做法是classes或labels是一个列表列表里每个元素是类别名字符串顺序就是模型训练时数字标签的顺序。我一般会顺手把类别到索引的映射打印出来class_names data.get(classes, data.get(labels)) for idx, name in enumerate(class_names): print(idx, name)这里关键要看两个地方第一类别的顺序和目录里子文件夹的字母序是否一致第二数字标签是从0开始还是从1开始。这两个问题如果没对齐后面训练出来的模型会出现验证集准确率很高、实际推理全错的典型翻车现场。2.3 show脚本九宫格抽检比看准确率更直观数据集配套的show脚本是用来可视化图像的它解决的问题是标注信息对不对一眼就能看出来。通常这类脚本会随机抽一批图像把原图和对应的标签名同时显示在画布上。运行方式最常见的是直接执行python show.py --data_dir train --num_samples 9--data_dir指向你想抽查的目录--num_samples控制抽样数量9张会排成3×3网格方便快速浏览。如果脚本里没做参数解析那就直接python show.py跑默认配置。建议在三个类别里各抽9张看一遍重点确认叶甲和毛毛虫的标注有没有混——因为虫害早期叶片症状相似人工标注时很容易把同一片叶子标成不同类。这一步花五分钟后面省下来的是反复调模型的几天。3. 从文件路径到DataLoader一次跑通训练数据流3.1 选型ImageFolder还是自定义Dataset对这个数据集来说优先用torchvision.datasets.ImageFolder因为它要求的就是根目录下按类别分子目录的格式train和test两个目录都是天然符合的。ImageFolder会自动扫描子目录名并生成class_to_idx映射这比手写自定义Dataset快得多代码量少一半以上。但前提是你确认过2.2里JSON的类别顺序和目录字母序一致如果不一致就得在读取后手动重置标签映射。只有一种场景建议换成自定义Dataset你要在这个数据集基础上继续做病害分割、或者要同时读取掩膜图。纯分类任务用ImageFolder是务实的选择。我一般先用ImageFolder把完整流程跑通确认模型能正常收敛再按需改造成自定义的数据流水线。3.2 完整的数据加载与预处理代码图像分类数据集的加载链路是固定的读图 → 变换 → 打包成batch → 喂给模型。下面这段代码可以直接替换到你的训练脚本里预处理参数针对这个数据集的实际尺寸做了适配同时也兼顾了迁移学习的通用要求import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader import json # 1. 先读JSON打印类别映射确认顺序 with open(dataset.json, r, encodingutf-8) as f: meta json.load(f) class_names meta.get(classes, meta.get(labels)) print(JSON类别顺序:, {i: name for i, name in enumerate(class_names)}) # 2. 训练集预处理随机翻转颜色抖动抑制过拟合 transform_train transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomHorizontalFlip(), transforms.ColorJitter(brightness0.2, contrast0.2), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) # 3. 测试集预处理只resize和归一化不做数据增强 transform_test transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) # 4. ImageFolder根据目录自动映射标签 train_set datasets.ImageFolder(train, transformtransform_train) test_set datasets.ImageFolder(test, transformtransform_test) tarin_loader DataLoader(train_set, batch_size32, shuffleTrue, num_workers4) test_loader DataLoader(test_set, batch_size32, shuffleFalse, num_workers4)Resize((224, 224))是这一系列配置里的关键参数ResNet、ViT等主流分类网络默认输入尺寸都是224且ImageFolder读进来的图片尺寸各不相同不统一size会在DataLoader打包batch时报维度不一致错误。Normalize的mean和std用的是ImageNet数据集的统计值这套值在迁移学习场景下是标准配置不要随意改成0.5或你自己算的均值。shuffleTrue只在训练集开测试集保持False这样才能保证评估时batch顺序稳定保存的预测结果能和文件名一一对应。3.3 类别不均衡加权采样比换模型更直接这类实地采集的植物病害数据集天然存在类别不均衡问题——健康叶片好采集虫害叶片要等虫情爆发期才拍得到。先看分布再决定要不要处理处理手段优先选WeightedRandomSamplerfrom torch.utils.data import WeightedRandomSampler # 统计每个类别的样本数权重取倒数 counts [len(train_set.targets[train_set.targets i]) for i in range(3)] weights [1.0 / c for c in counts] sample_weights [weights[t] for t in train_set.targets] sampler WeightedRandomSampler(sample_weights, num_sampleslen(train_set), replacementTrue) train_loader DataLoader(train_set, batch_size32, samplersampler, num_workers4)sample_weights是一个和训练集长度相同的列表每张图被抽到的概率和它的类别样本数成反比少数类通常是有虫害的类每张图被抽中的权重更高replacementTrue允许多次重复采样同一张图。这样每个epoch里少数类参与的梯度更新次数明显变多。注意改了采样器之后shuffle参数必须保持False二者互斥。评估阶段不要用准确率当唯一指标重点看少数类的recall和F1-score否则模型只要全部预测健康叶片准确率就能轻松超过80%。4. 常见问题与避坑排查五条实战记录与修复4.1 高发问题清单与修复下面五条是这个数据集和同类标注数据集的典型踩坑记录按现象 → 原因 → 解决整理遇到了可以直接照着处理。问题一JSON类别顺序和ImageFolder的标签映射对不上模型训练异常。现象训练loss正常下降验证集准确率波动但保存模型后推理结果完全错乱比如把健康叶片全部识别成毛毛虫。原因ImageFolder按子目录名字母序生成class_to_idx而JSON里的classes数组顺序不一定是字母序两边数字标签错位。解决打印对比两边映射按JSON顺序重建索引。# 用JSON里的类别顺序覆盖ImageFolder的自动排序 train_set.class_to_idx {name: i for i, name in enumerate(class_names)} train_set.targets [train_set.class_to_idx[name] for name in train_set.samples]class_to_idx是ImageFolder读取目录时自动生成的字典手动覆盖后targets也要同步更新因为samples里存的还是旧的类别名。这一步做完再打印几个样本确认标签值能过滤掉大部分推理时错位的诡异问题。问题二Windows下跑show脚本报FileNotFoundError。现象在Windows命令行运行python show.py --data_dir train报错提示找不到train/healthy目录但用资源管理器明明看得到。原因类名Diabrotica speciosa中间有空格命令行把路径截断了。解决路径加双引号或者临时把类别目录里的空格替换成下划线后建立软链接。python show.py --data_dir train/Diabrotica speciosa --num_samples 9Linux和macOS上空格问题不那么致命但Windows的cmd和PowerShell会把空格当成参数分隔符。封装成Python脚本时建议内部用os.path.join拼接路径避免手写带空格的完整走。问题三DataLoader在第一个batch就报维度不匹配。现象RuntimeError: stack expects each tensor to be equal size报错位置在DataLoader内部。原因数据集里的图像分辨率不一致有的可能是手机拍的4032×3024有的是设备截图几百像素Resize没有生效或没套在对应分支上。解决确认预处理在加载路径上且统一Resize目标尺寸。# 快速检查所有图像的原始尺寸分布 from PIL import Image import glob sizes set() for path in glob.glob(train/**/*.jpg, recursiveTrue): with Image.open(path) as im: sizes.add(im.size) print(图像尺寸种类:, sizes)输出结果应该是单一尺寸比如{(224, 224)}如果出现多个不同尺寸说明有路径写错导致跳过Resize直接检查transform是否应用到了所有split上。问题四训练准确率很高但实际效果差怀疑标注有噪声。现象验证集准确率98%但模型挑出来的虫害叶片里混了大量健康叶片边缘。原因虫害早期和健康叶片的纹理差异很小标注阶段容易把轻微失绿的叶片标错。解决用show脚本随机抽100张做人工复核python show.py --num_samples 100按类别统计疑似错标比例。超过5%就建议用清洗策略过滤——把置信度低的样本挑出来让人复核而不是直接从训练集删掉因为少数类的样本本来就少。问题五迁移学习模型改完分类头特征提取层参数被误冻结。现象用ResNet18做迁移学习改了fc层输出为3但训练几轮后loss纹丝不动。原因有的教程会教你for param in model.parameters(): param.requires_grad False但如果你忘了把最后一层设回True整个网络包括新加的分类头都不更新。解决检查冻结逻辑只冻结特征提取层保持分类头可训练。model torchvision.models.resnet18(weightsIMAGENET1K_V1) for param in model.parameters(): param.requires_grad False model.fc torch.nn.Linear(512, 3) # 新层的requires_grad默认为True这里有一个细节model.fc被新构造的nn.Linear替换后新层参数的requires_grad默认就是True不需要额外设置但如果你在替换之前执行了循环冻结替换后新层也不受影响。踩坑的人往往是用了model.load_state_dict之后分不清哪些层被覆盖了。4.2 排查方法三步定位标签错乱遇到标签相关的问题别急着调模型先用下面三步定位。第一步打断点看映射。把class_to_idx和JSON的classes打印出来并排对比确认数字标签含义。第二步随机抽一批图像显示原图和预测结果用第2章的show脚本做可视化。第三步保存一个batch的真实标签和预测标签到CSV逐行比对差异集中在哪些类别上。import random from PIL import Image import matplotlib.pyplot as plt from torchvision import transforms # 随机抽查一张训练图确认标签和图像内容是否一致 idx random.randint(0, len(train_set) - 1) img, label train_set[idx] inv_normalize transforms.Normalize( mean[-0.485 / 0.229, -0.456 / 0.224, -0.406 / 0.225], std[1 / 0.229, 1 / 0.224, 1 / 0.225] ) plt.imshow(inv_normalize(img).permute(1, 2, 0).numpy()) plt.title(flabel{label}: {class_names[label]}) plt.show()inv_normalize的作用是把归一化后的像素值还原回原始RGB范围否则显示出来的图像是偏色的。permute(1, 2, 0)把CHW的Tensor顺序转换成HWC——matplotlib的imshow只认这个排布。这一步跑通了说明数据和标签的链路是通的后面再出问题就可以放心往模型结构上排查。5. 训练前最后一道检查show脚本加两个统计习惯最后一个技巧分享一个我每次处理标注数据集都会走的固定流程计算类别分布、检查图像尺寸、跑一个完整epoch的冒烟测试三步做完再正式开始训练。类别分布和图像尺寸前面已经给了脚本冒烟测试的配置有个参考写法import torchvision model torchvision.models.resnet18(weightsIMAGENET1K_V1) model.fc torch.nn.Linear(512, 3) # 替换分类头适配3类weightsIMAGENET1K_V1在最新版torchvision里是推荐写法替代老版的pretrainedTrue这样做的好处是权重来源明确可追溯。model.fc torch.nn.Linear(512, 3)这一行的原理是ResNet18的骨干输出512维特征原来的全连接层是1000类ImageNet替换成3类输出。只需要改这一层前面的特征提取能力全部保留这是迁移学习在这个数据规模下最合理的做法——6000张图从头训练一个深度网络大概率过拟合但微调预训练模型效果会很稳。冒烟测试只跑一个epoch观察两件事loss有没有下降趋势、训练速度是否在可接受范围。如果loss一点没动先查学习率和数据加载如果速度太慢考虑减小图像尺寸或降低num_workers。从那以后我每次拿到新数据集都强制走一遍这个流程先看分布再看尺寸最后跑冒烟。数据集的坑大多集中在数据本身模型反而很少出问题。这套习惯帮我挡掉了至少十次训练一晚上、结果标签全错位的翻车事故希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑