简介:一套面向农作物病虫害识别与图像分类实践的图像数据集,由1000余张真实场景高质量作物图片组成,覆盖腰果(Cashew)、木薯(Cassava)、玉米(Maize)、番茄(Tomato)四大类作物的22个常见状态,既包含炭疽病、细菌性疫病、叶斑病、花叶病毒病、枯萎病等多种病害,也包含健康植株样本,可作为农作物病虫害检测项目的数据基础,或作为通用分类数据集的有效补充。图片按类别分文件夹整理,无需额外转换即可配合YOLO11cls等分类算法直接训练。资源以单个PDF文档形式交付,大小约5.63MB,文档内除完整数据集介绍、类别清单和获取方式外,还附赠YOLO11cls一键训练脚本,并提供博主训练结果日志供效果参考。目前已有63人学习,适合需要快速获取标准分类数据并验证训练流程的算法工程师、科研人员及农业信息化开发者。
1. 1000 张病虫害图做目标分类:YOLO11cls 一键脚本的真实边界
做过农作物病虫害识别的朋友都有体会:真正卡住项目的不是模型选哪个,而是数据从哪来、怎么整理、训练时能不能一次跑通。这套标题里的方案——1000 张病虫害图、按分类文件夹整理、配一份 YOLO11cls 一键训练脚本——本质上是把「数据整理 + 分类训练」封装成了一条最小可用流水线。对于植保站的技术员、农业科技公司的算法工程师、或者做毕业设计的学生,它能让你在拿到图集后的当天晚上就见到第一个精度数字。
要先把话说透:1000 张图做图像分类,属于典型的小样本场景。YOLO11cls 的优势在于它的分类头轻量、预训练权重成熟、脚本调用足够简单,但你千万别指望它凭空变出泛化能力。这套方案能不能成,七成取决于你对分类文件夹的整理规约和验证集的划分是否讲究,三成才取决于训练参数。下面我把整条链路拆开,从目录结构讲到参数取舍,再讲几个我实际踩过的坑。
2. 分类文件夹的整理规约:目录结构、标签映射与坏图清洗
2.1 为什么 YOLO11cls 认目录不认标注:ImageFolder 风格的数据约定
很多从目标检测转过来的用户,第一反应是找 JSON 或 XML 标注文件。但 YOLO11cls 跑的是图像分类,它遵循的是 PyTorch 里 ImageFolder 那一套约定:类别就是文件夹名,文件夹里放对应类别的图片。
如果你的数据是别人整理好的「分类文件夹」形态,那恭喜你,省掉了最脏的一步。但即便是整理好的,你也必须先检查它的组织方式是否满足三个要求:
- 类别文件夹名必须是英文短名,不能有空格、括号、中文。比如
rice_blast可以,稻瘟病(3)这种名字会在训练脚本读取类别列表时出各种奇怪问题。 - 图片格式统一为
.jpg或.png,且不要混着放。混格式本身不影响训练,但会在后续做数据增强和预处理时增加不必要的类型判断逻辑。 - 每个类别下的图片数量要提前摸底。1000 张图如果分到 10 个类,每个类 100 张是相对健康的分布;如果某类只有 20 张,训练时的 loss 波动会让你怀疑人生。
这三条检查做完,再谈训练。
2.2 用一段脚本完成数据集划分、映射生成与坏图过滤
拿到整理好的分类文件夹后,第一件事不是直接开训,而是先做三件事:划分训练集和验证集、生成类别映射文件、过滤坏图。我一般习惯把这三步写进一个prepare_data.py,跑完之后数据集目录就变成 YOLO11cls 可以直接消费的结构。
import os import random import shutil from PIL import Image # 原始数据路径:每个类别一个子文件夹,子文件夹里是图片 SRC_ROOT = "raw_dataset" # 例如 raw_dataset/rice_blast/*.jpg OUT_ROOT = "dataset" # 输出目录,会生成 train/ 和 val/ VAL_RATIO = 0.2 # 验证集比例,1000张图建议20% SEED = 42 # 1. 对每一类做划分 for class_name in os.listdir(SRC_ROOT): class_dir = os.path.join(SRC_ROOT, class_name) if not os.path.isdir(class_dir): continue images = [f for f in os.listdir(class_dir) if f.lower().endswith((".jpg", ".jpeg", ".png"))] random.seed(SEED) random.shuffle(images) val_count = int(len(images) * VAL_RATIO) val_images = images[:val_count] train_images = images[val_count:] # 2. 复制到新目录,保持 类别名/图片名 结构 for split, split_images in [("train", train_images), ("val", val_images)]: out_dir = os.path.join(OUT_ROOT, split, class_name) os.makedirs(out_dir, exist_ok=True) for img_name in split_images: src_path = os.path.join(class_dir, img_name) dst_path = os.path.join(out_dir, img_name) shutil.copyfile(src_path, dst_path) print(f"{class_name}: train={len(train_images)}, val={len(val_images)}") # 3. 坏图过滤:打不开的、非RGB的、尺寸异常的,直接剔除 for split in ["train", "val"]: split_dir = os.path.join(OUT_ROOT, split) for class_name in os.listdir(split_dir): class_dir = os.path.join(split_dir, class_name) for img_name in os.listdir(class_dir): img_path = os.path.join(class_dir, img_name) try: with Image.open(img_path) as im: im.load() if im.mode != "RGB": # 转成RGB,避免后续训练时通道数不一致 rgb_img = im.convert("RGB") rgb_img.save(img_path) except Exception: os.remove(img_path) print(f"removed broken image: {img_path}")这段脚本的逻辑分三段:第一段按类别遍历,把每类的图片随机打乱后按 8:2 划开;第二段把图片复制到dataset/train/类别名/和dataset/val/类别名/,复制而不是移动,这样原始数据还在,划分错了有后悔药;第三段用 Pillow 逐张打开图片,打不开的直接删掉,非 RGB 的转成 RGB。
参数上你最需要关注的是VAL_RATIO。1000 张图我一般取 0.2,也就是验证集 200 张、训练集 800 张。不要低于 0.15,否则验证集太小,精度指标的置信度很低;也不要高于 0.3,否则训练数据不够,模型学不到东西。
SEED固定成 42 的意义在于,你划分完一次之后,后续调参对比的都是同一份验证集,结果才可比较。这点很容易被忽略,但它是小样本实验里「可复现」的基石。
2.3 数据集体检:检查每类张数、尺寸分布与类别均衡
划分完目录之后,别急着训练,先做一次体检。我见过太多人拿到数据集直接跑脚本,训了 50 轮发现 loss 不降,回过头来查才发现某个类别文件夹里只有 5 张图。
# 统计每个类别的图片数量 find dataset/train -type f -name "*.jpg" | cut -d/ -f3 | sort | uniq -c find dataset/val -type f -name "*.jpg" | cut -d/ -f3 | sort | uniq -c # 查看图片尺寸分布(以一张典型图为例) python -c "from PIL import Image; im=Image.open('dataset/train/rice_blast/001.jpg'); print(im.size)"这个统计的价值在于暴露两类问题:第一是类别不均衡,某类张数明显偏少;第二是尺寸分布离谱,比如有的图是 6000×4000 的田间原图,有的是 128×128 的缩略图,训练时统一缩放会产生严重的形变差异。
如果发现某类图片特别少,常见做法是先把该类在训练集中的图片做几组基础增强(翻转、轻度旋转、色偏)再放进目录,而不是直接在训练时依赖在线增强。在线增强每次迭代随机变化,但对每 epoch 见过的图来说,信息量还是那么点;离线增强是把「见过的图」这个基数先撑大。两个都做,效果最稳。
3. 从命令到脚本:YOLO11cls 一键训练的完整拆解
3.1 YOLO11 分类模式与检测模式的区别:cls 任务在跑什么
YOLO11 不是只有目标检测,它和 YOLOv5、YOLOv8 一样内置了分类(cls)训练模式。分类模式和检测模式的区别很本质:检测模式输出的是「框 + 类别」,模型要同时学定位和分类两个任务;分类模式只输出「整张图属于哪个类别」,没有定位压力,模型结构也更轻。
标题里写的是「YOLO11cls」,指的就是用 YOLO11 的分类权重做训练。常见做法是用官方发布的yolo11n-cls.pt或yolo11s-cls.pt这类预训练分类权重做初始化,而不是从零训练。预训练权重在 ImageNet-1k 上见过大量真实图像,它的浅层特征对小样本病虫害图非常宝贵——你的 1000 张图只需要微调高层语义特征,而不需要重新学边缘和纹理。
这也解释了为什么标题强调「一键训练脚本」:YOLO11cls 的训练入口极其简单,核心就一行model.train(...)。但简单不等于不会出错,参数设不对、路径给错、权重文件名写错,都会让这一行直接翻车。
3.2 一键训练脚本:参数配置、训练入口与输出落盘
下面是我按照这类数据集整理的形态,写的一份可直接落地的训练脚本。它做的事情是加载预训练分类权重、指定数据集根目录、配置训练参数,然后启动训练。
from ultralytics import YOLO # 1. 加载预训练分类权重 # yolo11n-cls.pt 是官方发布的轻量级分类权重,速度最快 model = YOLO("yolo11n-cls.pt") # 2. 启动训练 results = model.train( data="dataset", # 数据集根目录,下面必须有 train/ 和 val/ epochs=100, # 最大训练轮数 imgsz=224, # 输入图片尺寸,小样本不建议直接用640 batch=32, # 批大小,显存不够就降到16 patience=20, # 早停:验证集指标20轮不提升就停 lr0=0.01, # 初始学习率 augment=True, # 开启在线数据增强 seed=42, # 随机种子,保证可复现 device="0", # 使用 GPU 0;没有 GPU 就写 "cpu" project="runs/classify", # 输出目录 name="pest_cls_v1", # 本次实验的名字 pretrained=True, # 使用预训练权重做迁移学习 )这段脚本在跑的时候,你会在终端看到每个 epoch 的训练 loss、验证 loss、top1 accuracy 和 top5 accuracy 的实时更新。训练结束后,runs/classify/pest_cls_v1/目录下会生成weights/best.pt和weights/last.pt,以及results.csv和confusion_matrix.png。
参数里最需要解释的是data的传法。这里传的是数据集根目录路径,YOLO11cls 会自动识别下面的train和val子目录,并根据子目录下的文件夹名生成类别映射。所以你在第 2 章里整理出来的目录结构,直接决定了这里的data参数能不能生效。
imgsz=224是分类任务里非常稳妥的默认值。你可能觉得 224 对小目标病害不友好,比如稻瘟病的初期病斑只有几十个像素,但这 1000 张图的病虫害分类,绝大多数是叶片级别的症状,224 足够。真要用 640 或更高,显存和训练时间都会翻倍,而且小样本下收益很有限。
patience=20是早停机制。小样本训练最大的特点就是收敛快、过拟合也快,100 轮里往往在第 30 到 40 轮就已经到最优了,后面全是震荡。设置 patience 的意义在于自动停止,避免浪费算力,也避免过拟合继续加深。
3.3 训练日志与结果文件:哪些指标决定模型能不能用
训练完成后,你会得到一堆文件,但不是每个文件都有同等价值。我一般按下面的优先级来看:
results.csv:训练过程的完整记录,每一行是一个 epoch 的 loss 和 accuracy。这份文件是调参的主要依据,我会用它画 loss 曲线来判断是否欠拟合或过拟合。confusion_matrix.png:验证集上的混淆矩阵。对于 1000 张图的小样本分类,这张图的信息量比 accuracy 大得多,它能告诉你哪两个类容易被混淆。weights/best.pt:验证集指标最优的权重。部署和后续推理永远用这个文件,不要用last.pt。
如果你用的是 GPU 训练,logs 里还会记录显存占用和单轮耗时。1000 张图、224 分辨率、batch 32 的情况下,一张消费级显卡(比如 8GB 显存)单轮也就几秒钟,整个训练过程可能不到 5 分钟就触发早停。这也是这个方案最吸引人的地方:它对算力的要求极低,快速迭代验证数据质量是它的核心使用方式。
4. 小样本分类训练避坑:1000 张图翻车的五类常见问题
4.1 验证集划分不合理导致评估虚高
现象:训练时 loss 逐渐下降,验证集 top1 accuracy 在某个 epoch 突然跳到 90% 以上,但你把训练好的模型拿到田间新拍的照片上测试,准确率直接跌到 60%。
原因:验证集和训练集来自同一批整理好的文件,如果划分前没有打乱,或者原始数据本身是按拍摄时间、地点存放的,那么验证集里很可能有和训练集高度相似的图片——甚至同一片叶子拍了两张。模型记忆了背景信息,验证集指标自然虚高。
解决:划分前先shuffle,然后人为检查验证集图片是否和训练集有重复。更严格的做法是,如果你的数据里有多张图来自同一株作物或同一批采样,把「组」作为划分单位,而不是把「张」作为单位,避免同一组图片被切开分到两个集合。
4.2 类别不平衡被 accuracy 掩盖
现象:训练完成后 accuracy 88%,看起来不错。看混淆矩阵才发现,模型把「稻曲病」全部识别成了「稻瘟病」,只是因为稻瘟病样本多,这个错误被淹没在整体 accuracy 里。
原因:1000 张图分到 10 个类,每类 100 张算是均衡;但如果某类 300 张、某类 30 张,模型会倾向于把不确定的样本预测到高频类上。
解决:第一,看 confusion_matrix.png 而非只盯 accuracy;第二,对少数类做第 2.3 节说的离线增强,把它的训练样本基数撑起来;第三,如果脚本支持class_weight参数,给少数类加权。
4.3 坏图与元数据问题在训练中段爆发
现象:训练到第 20 轮,突然报PIL.UnidentifiedImageError,训练中断。你检查数据目录,发现某张图后缀是.jpg,但实际上是网页存的 WebP 格式;或者某张图是 16-bit PNG,通道数不对。
原因:数据整理阶段只看了文件名和后缀,没有逐张验证图片内容。部分来自搜索引擎或手机截图的数据尤其容易带这类问题。
解决:第 2.2 节的坏图过滤脚本是必跑的,不能省。但注意转 RGB 的代码要处理im.mode != "RGB"的所有情况,包括RGBA、L、P模式。最稳妥的方案是:im.convert("RGB")之后重新保存为.jpg,而不是保留原格式。
4.4 随机种子与预训练权重不一致导致复现失败
现象:你用同样的脚本、同样的数据集训练了两次,一次 accuracy 85%,一次 91%。你以为是数据增强的随机性,但调参时根本没法判断某个改动是好是坏。
原因:训练脚本里没有固定seed,或者两次运行时yolo11n-cls.pt权重文件被意外覆盖/更新。数据增强里的随机翻转、裁剪、色偏会让训练过程天然抖动,种子不固定就完全无法对比实验。
解决:在model.train()里显式传seed=42,并且把预训练权重文件复制到你的项目目录下,用相对路径引用,不要每次从缓存目录加载。这样两次训练之间,除了你改的参数,其他变量全部可控。
4.5 训练脚本里的路径硬编码毁了二次训练
现象:第一次训练成功,你改了数据集路径或者换了机器,脚本直接报FileNotFoundError。查了半天发现脚本里写的是data="/home/user/dataset",换台机器就得改代码。
原因:路径硬编码是这类一键脚本最常见的坏味道。它看起来方便,但只要你挪动过项目位置或把数据搬到服务器上,脚本就废了。
解决:脚本开头用os.getenv或argparse把DATA_ROOT和PROJECT_ROOT做成环境变量或命令行参数。跑批处理时用--data /新路径/数据集传入,脚本本体一行都不用改。
5. 让 1000 张图训出稳定精度:数据增强、imgsz 与早停的参数平衡
5.1 augment 参数:小数据集最值得调的四项
YOLO11 的分类训练内置了一套在线数据增强,开关是augment=True。默认值对通用场景是合理的,但小样本病虫害分类有它的特殊性——病斑特征往往对颜色和角度敏感,增强参数要「有选择地放开」。
我一般会在model.train()里显式传入下面几个增强参数:
model.train( data="dataset", epochs=100, imgsz=224, batch=32, patience=20, augment=True, hsv_h=0.02, # 色相偏移幅度,默认0.015 hsv_s=0.5, # 饱和度偏移,默认0.7 hsv_v=0.3, # 亮度偏移,默认0.4 degrees=15, # 最大旋转角度 fliplr=0.5, # 水平翻转概率 seed=42, )参数说明:hsv_h、hsv_s、hsv_v控制 HSV 颜色空间的随机扰动。病虫害分类对颜色非常敏感——稻瘟病的典型病斑是褐色边缘加灰白中心,如果饱和度扰动太大,病斑颜色特征会被破坏;但如果完全不扰动,模型会对光线条件过拟合。0.02 / 0.5 / 0.3 是我在类似小样本任务上试出来比较稳的组合。degrees=15是给叶片姿态留一点余量,但不要超过 30 度,否则旋转后的空角填充区域会产生大量无意义的边缘纹理。fliplr=0.5对大多数叶片病害是安全的,因为叶片左右翻转不改变病斑形态。
这里有个血泪经验:增强参数不是越大越好。小样本本身就容易过拟合,大幅度增强会让模型学到的特征被噪声干扰。你可以先跑一版全默认参数,再开增强对比验证集精度,而不是一上来就把所有增强拉到最大。
5.2 imgsz 与 batch:显存和精度的取舍
imgsz对分类模型的影响比很多人想象的小,在 224 到 320 之间,top1 accuracy 的差距通常只有 1 到 2 个百分点。原因在于 YOLO11cls 的分类头输出的是全局特征,对空间细节不敏感。
但imgsz和batch的组合直接决定显存占用。以 8GB 显存的 GPU 为例,imgsz=224, batch=32可以跑得很轻松;升到imgsz=320,batch 就得降到 16 才能塞下。训练时间是线性增长的,而精度收益可能只有 0.5 个百分点。1000 张图的小样本场景,我不建议超过 320。
batch的另一个隐性作用:batch 越小,BN 层的统计量越不稳定,训练 loss 震荡越剧烈。如果你的显存只够 batch 8,优先降低imgsz而不是硬撑高分辨率。
5.3 早停与 checkpoint 选择:别让最后一轮覆盖最优权重
YOLO11cls 默认会同时保存best.pt和last.pt,但你有没有想过best是按什么指标选的?按验证集的 top1 accuracy,这本身没问题,问题是验证集指标在小样本下波动很大,可能第 35 轮蒙对了 91%,第 40 轮又跌回 85%。best.pt选的是第 35 轮的权重,这个权重的泛化能力未必比第 40 轮好。
我一般会在训练结束后做一次「二次验证」:用best.pt对验证集逐张推理,输出每张图的预测概率,然后把置信度低的那批图片挑出来看。如果这些低置信度图片集中在某几个类,说明best.pt可能对这几个类存在病态的高置信度误判,这时候我会回退到last.pt或者用results.csv找到 loss 最平稳的 epoch 对应的权重。
一个务实的做法:patience不要设太大,15 到 20 就够了。小样本训练不存在「再等等就能突破」的剧情,早停越果断,best.pt落在过拟合区间的概率越低。想验证这个说法,你可以看训练后期验证集 accuracy 的曲线,它通常是一条剧烈震荡的平线,而不是稳稳上升的斜线。
| 参数 | 推荐值 | 说明 |
|---|---|---|
| imgsz | 224 或 256 | 小样本不建议超过 320 |
| batch | 16 或 32 | 显存不足先降 imgsz 再降 batch |
| patience | 15 ~ 20 | 避免验证集震荡期的过拟合 |
| hsv_h / s / v | 0.02 / 0.5 / 0.3 | 颜色扰动过大会破坏病斑特征 |
| degrees | 10 ~ 15 | 旋转过度产生无效填充区域 |
| seed | 固定值 | 不固定种子就无法做对比实验 |
6. 用混淆矩阵回捞坏标签:一次训练后最该做的三件事
训练脚本跑通、拿到一个像样的 accuracy 之后,这个项目其实才走了一半。小样本分类的精度提升,往往不在调参而在数据清洗,YOLO11cls 给出的 confusion_matrix.png 就是你的清洗地图。
第一件事,把混淆矩阵里对角线之外的高亮格子找出来——哪两类被模型混得最严重,说明这两类的视觉特征确实接近,或者你的标注标签里就有错。比如「稻曲病」和「稻粒黑粉病」,外行人看症状非常相似,整理数据集的人很可能给部分图片标错了类。我会把这些格子对应的图片逐个翻出来看,每张都重新确认标签。1000 张图的工作量不算大,但每找回一张错标图,验证集 accuracy 都可能上涨一个点,这个回报率比调任何参数都高。
第二件事,统计验证集中的误判样本,按类别聚合。如果某个类的误判率明显高于平均,而且检查后标签没错,说明这个类的类内差异太大——可能包含不同严重程度、不同光照、不同生长阶段。这时候不要急着加数据,先看看这个类别里的图是否风格统一,不统一就按子类拆分或补充同类风格的图。
第三件事,把best.pt跑一遍真实场景的照片。训练集整理得再干净,也不如你下周去田间拍的 20 张照片能说明问题。我会写一个三行的推理脚本,对真实照片逐张输出 top3 类别和概率。如果真实照片的 top1 概率普遍低于 0.7,说明模型学到了一堆「整理后的数据」特有的背景纹理,而不是真正的病斑特征。这时候回头去增强数据多样性,比继续调参有意义得多。
这套「训练 → 混淆矩阵 → 坏标签回捞 → 重训」的循环,是我在小样本分类项目里最常用的迭代方式。它不需要更多的数据来源,只需要你愿意把训练脚本再跑一遍。1000 张图确实不多,但数据质量一旦被纠正到位,YOLO11cls 的预训练特征足以支撑一个能落地的分类模型。希望这个思路能帮你在自己的数据集上少走几步弯路。
本文还有配套的精品资源,点击获取