简介:面向农作物害虫识别与图像分类任务的现成数据集,含蛀虫、健康无虫、螨虫等4个类别,训练集与验证集已按文件夹划分,可直接配合ImageFolder加载使用,也适配yolov5的分类训练流程。全套共676个文件,以673张jpg图像为主,另附1个json分类字典、1个Python可视化脚本和1张说明预览图,压缩后约53.89MB;其中训练集620张、验证集53张,目录结构简洁,无需额外预处理。资源已吸引277人浏览学习,适合刚接触图像分类数据集整理或需要快速验证模型效果的开发者。除图像数据外,json文件给出了4个类别的映射关系,可视化脚本无需修改即可随机抽取4张图片并保存展示结果,便于快速核对样本与标签是否对应。整体包体小而规整,既能作为入门级分类实战数据,也可作为害虫识别算法评测的补充数据,省去自行采集标注的耗时环节。
1. 庄稼害虫分类数据集:4 分类 673 张图,拿来就能跑通的图像分类起点
做图像分类项目最烦的不是写模型,而是先花两三天整理数据。手工从网上抓图、去重、改文件名、按类别分文件夹,一套下来比训模型还累。这个 4 种庄稼害虫分类数据集走的是另一个路子:下载解压就是现成的 ImageFolder 结构,train 620 张、test 53 张,打开就能训,省掉的正是整理数据这步最磨人的活。
数据覆盖的 4 个类别是蛀虫、健康无虫、螨虫这几类实际农田里常见的状态。对刚入门图像分类或者想快速验证某个分类网络效果的开发者来说,这份数据能直接当实验台用;对做农业植保相关项目的工程师,它也可以作为预训练前的起点数据。另外作者还配了一个可视化脚本和一个 4 分类的字典 json,方便你第一时间确认数据长什么样。下面我把这份资源从头到尾拆一遍,包括目录怎么组织、ImageFolder 怎么对接、有哪些用起来的注意事项,以及最容易踩的几个坑。
2. 看一眼数据长什么样:目录结构、文件名规则和类别划分逻辑
2.1 从 Roboflow 导出的命名规则说起
文件名里有23327_jpg.rf.809a1904da5ba707827adc7343253f26.jpg这种带.rf.的格式,说明这批图最初是从 Roboflow 平台导出的。.rf.后面那串是图片的唯一哈希 ID,用来保证导出过程中不会重名。这种命名习惯在实际项目里很常见,但它对人对不友好——你没法只看文件名判断这张图属于哪个类,因为类别信息全在文件夹路径上,不在文件名里。
data/ ├── train/ │ ├── 蛀虫/ │ │ ├── 23327_jpg.rf.809a1904da5ba707827adc7343253f26.jpg │ │ └── 23327_jpg.rf.9614ec7b0e4c86fcc7135ea6d1a654a5.jpg │ ├── 健康无虫/ │ │ └── ... │ └── 螨虫/ │ └── ... └── test/ ├── 蛀虫/ │ └── ... ├── 健康无虫/ │ └── ... └── 螨虫/ └── ...这种按文件夹划分的组织方式,恰好是 PyTorch 的torchvision.datasets.ImageFolder最标准、最省事的输入格式。你不需要写一堆数据加载逻辑,直接一句ImageFolder(root='data/train')就能把所有图片按子文件夹名自动标好类别。
2.2 训练集验证集划分比例:620 比 53 偏小,但足够跑通流程
train 620 张、test 53 张,总量 673 张,在图像分类数据集里属于轻量级。这个体量你去训 ResNet 从零开始肯定过拟合,但用来做三件事非常合适:第一,验证你的训练代码和评估流程正确性,数据小意味着单 epoch 跑得快,调试效率高;第二,做迁移学习实验,用 ImageNet 预训练权重微调这个 4 分类任务,620 张图虽然不算充裕,但配合数据增强也能收敛到可接受的水平;第三,当作 YOLOv5 或 YOLOv8 分类模型的入门数据,跑通命令行训练再换大数据集。
有一点需要留意:train 和 test 的类目分布是否均衡,描述里没有明确给出。我在实际使用这类 Roboflow 导出的数据时发现,目录结构是手工整理过的测试集还好,但如果当初是随机按比例切分,小数据集容易出现某个类在 test 里只有几张图的情况。拿到数据后先统计一下每个子文件夹的文件数再动手训练,这一步花不了两分钟,能帮你避免后续 evaluation 结果失真。
2.3 数据能用在哪:纯分类、YOLO 分类子任务和教学演示
这套数据的核心用途就是图像分类,但它的适用面不限于 PyTorch。因为目录结构是train/类别名/图片这种通用组织方式,Keras 的image_dataset_from_directory、FastAI 的ImageDataLoaders.from_folder、以及 YOLO 系列自带的分类训练命令都能直接吃进这个结构。
我在做作物病虫害相关项目时有过一个感受:农田里拍回来的虫害照片,绝大多数问题不是模型选得不够好,而是数据本身样本不一致——有些叶子背面才有虫,有些光线极暗,有些图里虫只占画面的百分之几。这套数据虽然没标检测框,但作为分类任务的实验数据,它能帮你先验证一个问题:在正常拍摄条件下,4 分类能不能分得开。先跑出基线,再考虑该不该上检测模型,这个思路比一上来就 YOLO 更稳。
3. 用 ImageFolder 直接打开:三行代码把数据喂进 PyTorch
3.1 标准加载代码与参数说明
描述里明确说了“用 ImageFolder 打开,无需额外处理”,那这段代码就是整个数据集复现的核心。我一般会加上train_test_transforms和 DataLoader 的配置,凑成一个可以直接跑的脚本:
import torch from torchvision import datasets, transforms from torch.utils.data import DataLoader # 训练集和测试集用不同的预处理策略 train_transforms = transforms.Compose([ transforms.Resize((224, 224)), # 统一尺寸,ResNet 系列输入要求 transforms.RandomHorizontalFlip(), # 水平翻转,针对 4 分类数据增强 transforms.RandomRotation(10), # 小角度旋转,模拟拍摄角度抖动 transforms.ToTensor(), # 转张量,像素值归一到 [0,1] transforms.Normalize(mean=[0.485, 0.456, 0.406], # ImageNet 均值 std=[0.229, 0.224, 0.225]) # ImageNet 方差 ]) test_transforms = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) # ImageFolder 自动把子文件夹名映射为类别索引 train_dataset = datasets.ImageFolder(root='./data/train', transform=train_transforms) test_dataset = datasets.ImageFolder(root='./data/test', transform=test_transforms) train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=4) test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=4) print("训练集类别映射:", train_dataset.class_to_idx) print("训练集样本数:", len(train_dataset)) print("测试集样本数:", len(test_dataset))这段代码里ImageFolder做的事是:遍历root下的所有子文件夹,把每个文件夹名当作类别名,按字母序生成索引,然后返回(image, class_index)的样本对。class_to_idx在训练类别不多且英文名规范时顺序尚可,但如果子文件夹是中文名(比如这里的「蛀虫」「健康无虫」),你训练时就看不到类别名只能看到数字索引,后面推理阶段得靠 json 字典对应回来。
这里有个小细节:normalize用的均值和方差是 ImageNet 预训练模型的默认值,不是这套数据自己的统计值。你如果从零训练,理论上应该用数据集的真实均值和方差。不过你如果打算微调预训练模型,那就保持 ImageNet 的归一化参数,别改。常见错误是一套代码同时在两种训练模式里复用,导致从零训练时归一化分布和输入分布不一致,损失曲线抖动得厉害。
3.2 验证可直接运行:先用统计代码确认数据完整性
拿到数据的第一步,除了跑训练代码,我更建议先跑一个纯统计脚本,不加载图片只数文件数,确认目录对得上再往下走:
find data/train -type f -name "*.jpg" | wc -l find data/test -type f -name "*.jpg" | wc -l另外看看每个子类的文件个数是否接近,这一步能提前暴露数据切分不均的问题。我在一个实际项目中遇到过类似情况——某个稀有类别在训练集里近 200 张但测试集只有 3 张,这种比例偏差会让准确率波动极大。如果碰到这种问题,解法一般是按类别分层切分测试集,或者用 K 折交叉验证代替单次划分。
3.3 不开代码直接看数据:可视化脚本的用法
这个数据集附带的可视化 py 脚本是「随机传 4 张图展示并保存到当前目录」,省去了自己写 matplotlib 拼接的功夫。它的基本原理是读取一堆图、随机挑 4 张、用plt.subplot(2,2)拼成一张大图后savefig保存。运行它会输出类似visualize.png的文件到当前目录。
python visualize.py这一步强烈建议放到加载训练之前先做一遍。原因很简单:图像分类数据集的标签可信度是所有后续工作的前提。如果某个类别的图片里混入了其他类别的图,或者某张图本身是损坏的、全黑的、带水印的,这些都会干扰训练。可视化脚本存在的意义就是让你用几秒钟添加人眼先验,把明显的脏数据在训练前剔除掉。
4. 把这份数据用到 YOLO 分类任务里:格式转换与训练命令
4.1 YOLO 分类数据格式:本质是目录结构,不需要转成 txt
网上搜「yolov5 训练自己的数据集」,大部分教程在讲检测任务的标注格式(每张图配一个 txt,内容是class_id cx cy w h)。但你要做的是图像分类的话,事情简单得多——YOLO 官方分类训练直接吃目录结构,和 ImageFolder 完全同构。所以这份数据的 Roboflow 导出结构已经可以直接供给 YOLO 分类任务用,你唯一要做的只是确认类别名不要有空格和特殊字符。
# YOLOv5 分类任务目录要求 # datasets/庄稼害虫/ # ├── train/ # │ ├── 蛀虫/ # │ ├── 健康无虫/ # │ └── 螨虫/ # └── val/ # ├── 蛀虫/ # ├── 健康无虫/ # └── 螨虫/ # 注意:YOLO 分类任务期望验证集目录名是 val,不是 test cd data mv test val这里有一个谁都会忽略的坑:torchvision.ImageFolder对验证集目录名没有要求,你叫test叫val都行;但 YOLO 系列跑分类训练时,命令行里--data参数默认指向的是{data_dir},脚本内部会去找{data_dir}/train和{data_dir}/val这两个子目录。如果你直接把这个数据集的test文件夹原封不动拿给 YOLO 用,训练时就会报错「val split not found」。这是最典型的格式假设不一致问题,解决方式就是上面那样把test重命名成val,或者用--val参数显式指定。
4.2 用 YOLOv5 分类命令训练与关键参数说明
假设你已经把目录调整成上面的结构,训练命令如下:
python classify/train.py \ --model resnet18 \ --data /path/to/庄稼害虫 \ --epochs 30 \ --img 224 \ --batch-size 32 \ --pretrained对这份 620 张的数据来说,我建议epochs给 30~50 之间,多了几乎肯定过拟合;batch-size看显存,32 是一个起点,显存不够降到 16;--pretrained强烈建议打开,因为你的训练样本数量级不足以支撑从零收敛出一个深层网络。如果用 YOLOv8,命令等价为:
yolo classify train model=yolov8n-cls.pt data=/path/to/庄稼害虫 epochs=30 imgsz=224 batch=32YOLOv8 的yolov8n-cls.pt是一个轻量级分类模型,参数量大约 3M 出头(记不太清了,但它小到 CPU 也能跑推理),在 600 张图的数据量上收敛很快,训练时间按分钟计。这类小模型反而适合这份数据,因为数据量本身就撑不起大模型的容量。
逻辑上,YOLO 分类训练的本质和 torchvision 里跑的 ResNet 微调没有区别,都是加载预训练权重然后把最后一层全连接换成 4 分类输出。你选择用 YOLO 而不是纯 PyTorch 脚本的原因主要是两条:一是命令行方便,免写训练循环;二是未来想从分类升级到检测任务时,模型系列和工具链能统一起来。
4.3 关于类别名:建议训练前先转成英文
一个容易忽略的细节:这份数据的类别名是中文,比如「蛀虫」「健康无虫」「螨虫」。直接拿中文目录名去训练,在 Windows 上可能没事,但在 Linux 服务器上跑 YOLO 时的部分第三方库对非 ASCII 路径支持不算好,轻则日志打印乱码,重则在某些数据加载环节出编码异常。稳妥做法是先做一层软链接或目录复制,把中文类别名映射成英文字母:
cd 庄稼害虫 mkdir train_en mv "train/蛀虫" train_en/borer mv "train/健康无虫" train_en/healthy mv "train/螨虫" train_en/mite # 继续处理其他类别类别名转完英文还有个额外好处:后面看混淆矩阵、分析分类错误时,英文标签在绘图时的排版和可读性都明显好于中文。train/test 的 json 字典文件也一并改成新的映射关系,别只改目录名不改字典,不然推理后处理时类别 ID 对不上。
5. 避坑指南:我在这类小数据集上翻过的四个车
5.1 类别不均衡导致准确率虚高
现象:训练完看准确率挺高,90% 以上,但仔细看测试集每个类别的召回率发现某个类接近 100%,另一个类只有 50% 多。
原因:train 和 test 的类别分布不一致,或者训练集里某个类样本过多,模型直接学会偏向多数类。这个数据集共 673 张图,类别一多平均到每个类就 150 张上下,某类多 50 张少 50 张差别就非常显著。
解决:训练前用Counter(Counter(train_dataset.targets))打印每个类的数量,再打印 test 的分布。多数类给欠采样或降低 loss 权重,少数类做额外增强(比如旋转角度加大、加色彩抖动)。对一个 4 分类任务,最理想的情况是每个类样本数量在一个量级上,最好相差不超过 20%。
5.2 图像损坏导致的「随机」训练崩溃
现象:跑着跑着 loss 突然跳到 NaN,或者 DataLoader 报EOFError、Cannot identify image file。
原因:Roboflow 导出的图片本身基本是完整的,但如果你下载解压时中间断了、或者手动从网盘转存之后文件损坏,就会出现某张图只有文件头没有数据。ImageFolder 加载时并不验证文件完整性,是训练到那个 batch 时解码才炸。
解决:拿到数据后先跑一遍 PIL 解码验证,把坏文件筛出来:
from PIL import Image from pathlib import Path for img_path in Path('./data').rglob('*.jpg'): try: with Image.open(img_path) as im: im.load() except Exception as e: print(f'损坏文件: {img_path} -> {e}')我一般习惯把这一步和可视化脚本放在一起执行,一次就把数据集完整性检查和内容抽查做掉。
5.3 中文目录名在 Linux 环境下的编码坑
现象:在 Windows 上训练正常,把数据传到 Linux 服务器后训练时,某些图片加载报 FileNotFoundError,路径打印出来是乱码。
原因:中文目录名在文件系统层是 UTF-8 编码,和系统 locale 设置不一致时,Python 的os.listdir拿到的是解码后的字符串,而文件系统接口用的是字节串,一旦 locale 不是 UTF-8 就会出现「看起来存在但打不开」的诡异现象。
解决:这类数据我现在的习惯是一律先转英文目录名再训练,不做任何心存侥幸的尝试。还有一招是设置环境变量PYTHONUTF8=1,能缓解一部分问题,但根治不了。
5.4 YOLO 分类任务里把 test 目录当 val 用
现象:按 YOLO 命令训练,刚启动就报错AssertionError: Train: ... does not exist或 val 相关的路径错误,但明明数据目录里文件都在。
原因:YOLO 分类脚本内置的数据集目录搜索逻辑默认拼接data_dir / 'train'和data_dir / 'val',这套数据的验证集目录叫test,所以找不到。
解决:要么把test文件夹重命名为val,要么在 YOLO 的命令行里手动指定--val参数对应到 test 目录。这个坑特别容易发生在从 torchvision 生态转过来的人身上,因为它俩对「验证集目录叫什么名字」的约定完全不同。
6. 验证你训出来的模型:从准确率到「它真的认虫」的三步检查
6.1 第一步:用脚本输出每类别的精确率和召回率
光看整体准确率对 4 分类任务是不够的——如果某类占比高,模型全猜这个类都能有很高准确率。标准做法是用classification_report把每个类的精确率、召回率、F1 都打出来:
from sklearn.metrics import classification_report import numpy as np all_preds = [] all_labels = [] model.eval() with torch.no_grad(): for images, labels in test_loader: outputs = model(images) _, preds = torch.max(outputs, 1) all_preds.extend(preds.numpy()) all_labels.extend(labels.numpy()) print(classification_report(all_labels, all_preds, target_names=list(test_dataset.class_to_idx.keys())))我一般会盯着两个数字看:召回率最低的那个类,以及它和最高类的差距。如果差距在 10 个点以内,这套数据的基础质量是过关的;如果某个类召回率明显塌陷,通常不是模型问题,而是数据里那个类的成像条件太混乱——阴影、遮挡、景深不一致,这类问题加数据增强往往改善有限,要找原始拍摄数据来补。
6.2 第二步:跑一张没见过的照片做端到端验证
分类准确率是说给实验听的,最终你还要回答一个问题:这个模型到田里拍一张照,能不能给出符合直觉的判断。我会用训练时同一套 transform 的推理代码,传一张训练集和测试集之外的实拍图,看一眼输出概率分布:
def predict_single_image(image_path, model, class_names, transform): img = Image.open(image_path).convert('RGB') img_tensor = transform(img).unsqueeze(0) model.eval() with torch.no_grad(): outputs = model(img_tensor) probs = torch.softmax(outputs, dim=1).squeeze() for name, prob in zip(class_names, probs.numpy()): print(f'{name}: {prob:.4f}')关键不是看 top1 对没对,而是看概率分布是不是「犹豫」——如果前两个类别的概率都在 0.4 左右,说明模型在特征空间里没把这两个类分开,这时候回头看数据里这两个类的样本差异才是正道。
6.3 第三步:顺手做一个最朴素的过拟合测试
在 600 张图上做一个快速冒烟测试:选训练集的子集(比如每个类 10 张),训 20 个 epoch,看训练集本身的准确率能不能收敛到 95% 以上。如果连这个小实验都学不动,那问题大概率不在数据量上,而是代码、学习率、模型结构配置里至少有一处是错的。这个测试 10 分钟就能跑完,但它能在你花一小时调超参数之前就帮你排除掉最大的不确定性。
我自己的习惯是:每次拿到新的分类数据,不管项目多急,都会强制把这个流程走一遍——统计分布、看可视化、跑冒烟测试、训练验证集评估。这套流程不复杂,但它帮我拦截过坏图、类别不均衡、目录名编码三四个大坑。这套 673 张的庄稼害虫数据虽然小,但结构清晰、开箱即用,拿它把整套流程跑顺一遍,之后换大数据集时你会特别感谢现在这个动手验证的习惯。希望这篇拆解能帮你把数据真正用起来,少走几步弯路。
本文还有配套的精品资源,点击获取