拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLO11cls农作物病虫害分类实战:数据集构建、训练调参与避坑指南

YOLO11cls农作物病虫害分类实战:数据集构建、训练调参与避坑指南

简介:面向农作物病虫害识别与图像分类训练场景,这份资源提供包含1000张真实图片的分类数据集,覆盖腰果、木薯、玉米、番茄四类作物的22种健康与病害状态,可直接用于YOLO11cls等图像分类模型训练,也适合作为通用分类数据补充。数据按分类文件夹整理,标签清晰、标注质量高,省去手动整理环节;配套一键训练脚本与博主训练结果日志,便于复现实验、对比不同病害类别的识别效果并调整参数。资源包为1个PDF文件,大小5.63MB,内含数据集详细介绍与百度网盘获取方式。目前已有63人学习,适合农作物病虫害分类初学者及需要评估样本形态的算法工程师。

1. 农作物病虫害分类数据集,不只是给 YOLO11cls 用的

收到这份「目标分类-农作物病虫害分类数据集-1000张图+对应分类文件夹整理+YOLO11cls一键训练脚本」时,我第一反应是又一个打包好的小数据集,但解压看过后发现它比很多标称几千张的商用数据集更省心:图片全部来自真实田间场景,类别用文件夹区分,不需要自己写标注格式转换,配的 YOLO11cls 训练脚本改个路径就能跑通。适合正在做农业视觉项目、需要快速验证分类思路、或者想把 YOLO11 分类能力跑一遍的从业者。如果你正处于「手上没有靠谱数据、又不确定分类模型在病虫害场景下能到多少准确率」的阶段,这份资源能直接跳过到处爬图、清洗、重命名的脏活。更关键的是,它把训练入口压缩成一个脚本,降低了从裸数据到模型产出的门槛。

2. 数据到底怎么样:22 个类别、文件夹标注与检查清单

这一章不急着跑训练,先把数据集的结构和内容摸清楚。这份数据集覆盖腰果(Cashew)、木薯(Cassava)、玉米(Maize)和番茄(Tomato)四类作物的主要病虫害与健康状态,归类成 22 个类别。这是典型的植物病害分类任务(Plant Disease Classification),类别列表如下:

作物类别(文件夹名)
腰果 Cashewanthracnose(炭疽病)、gumosis(流胶病)、healthy(健康)、leaf miner(潜叶蝇)、red rust(赤锈病)
木薯 Cassavabacterial blight(细菌性枯萎病)、brown spot(褐斑病)、green mite(绿螨)、healthy(健康)、mosaic(花叶病)
玉米 Maizefall armyworm(草地贪夜蛾)、grasshoper(蝗虫)、healthy(健康)、leaf beetle(叶甲)、leaf blight(叶枯病)、leaf spot(叶斑病)、streak virus(条纹病毒)
番茄 Tomatohealthy(健康)、leaf blight(叶枯病)、leaf curl(卷叶病)、septoria leaf spot(斑枯病)、verticulium wilt(黄萎病)

2.1 文件夹组织方式为什么能直接喂给 YOLO11cls

YOLO 系列做图像分类时,目录结构跟目标检测完全不同——检测需要 JSON/XML/TXT 标注文件,分类只需要把图片按类别放进对应文件夹。这份数据用的就是后者:

dataset/ ├── Cashew_anthracnose/ │ ├── 0001.jpg │ ├── 0002.jpg │ └── ... ├── Cashew_gumosis/ ├── Cassava_mosaic/ ├── Maize_leaf_blight/ ├── Tomato_leaf_curl/ └── ...

Ultralytics YOLO11cls 的数据加载逻辑是:读根目录下的每个子文件夹名作为类别标签,文件夹里的图片自动归入该类。所以拿到手后不用做任何格式转换,只需要把数据按比例拆成 train 和 val 两个大目录即可。常见做法是用 Python 的train_test_split按 8:2 切分,或者shutil逐类移动。我一般会保证每类的验证图片不少于 5 张,否则验证指标波动会很大。

2.2 数据质量检查:训练前必须做的三件事

标注格式干净不代表可以直接开工。第一次跑之前,我建议花十分钟做三项检查:

第一,统计每类图片数量。1000 张分 22 类,必然存在不均衡——健康类往往多于病害类,少数病害类别可能只有二三十张。用以下脚本快速摸底:

import os data_root = "dataset" for cls in sorted(os.listdir(data_root)): cls_path = os.path.join(data_root, cls) if os.path.isdir(cls_path): count = len([f for f in os.listdir(cls_path) if f.lower().endswith(('.jpg', '.jpeg', '.png'))]) print(f"{cls}: {count} 张")

参数说明:cls是类别名,脚本判断路径下的文件后缀来计数,避免把隐藏文件或临时文件算进去。输出会是一张 22 行的统计表,能立刻看出哪些类别是少数类。

第二,随机抽图看尺寸是否统一。YOLO11cls 内部会做letterbox缩放,不要求原始图尺寸一致,但如果混入大量超小图(小于 224×224),模型学到的特征会受限。抽检方法是从每类随机选三张打印shape:

from PIL import Image import random, os sample_cls = "Tomato_leaf_curl" files = os.listdir(f"dataset/{sample_cls}") for f in random.sample(files, 3): img = Image.open(f"dataset/{sample_cls}/{f}") print(f"{f}: {img.size}")

第三,确认图片不是损坏文件。真实场景采集的图片偶尔会有 IO 错误或截断,轻则训练中断,重则 tensor 维度异常。用PIL.Image.verify()遍历一遍能提前排雷,这也是我把这个习惯保留到所有数据集项目的原因——多花五分钟,好过训练到一半崩掉。

3. YOLO11cls 一键训练脚本:结构、参数与正确打开方式

数据摸底做完后,进入真正的训练环节。配套资源里的 YOLO11cls 训练脚本本质上是 Ultralytics 框架的封装,核心逻辑是读数据路径、加载预训练权重、启动训练。这类脚本的好处是参数集中、开箱即用,但如果你准备换数据集或调优,还是得理解每一行在干什么。

3.1 训练脚本里的关键代码块

下面是我按这套资源的标准习惯整理出的训练入口脚本:

from ultralytics import YOLO if __name__ == "__main__": model = YOLO("yolo11s-cls.pt") # 加载分类预训练权重 model.train( data="D:/crop_disease_dataset", # 数据集根目录(含 train/ 与 val/) epochs=50, batch=32, imgsz=224, patience=10, lr0=0.001, optimizer="AdamW", device="0", # 单卡训练 workers=4, project="runs/classify", name="crop_disease_yolo11s", pretrained=True, # 使用预训练权重 seed=42 )

逻辑说明:脚本先加载yolo11s-cls.pt——这是 YOLO11 做图像分类任务的预训练权重,n/s/m/l/x 对应不同的模型容量与推理速度。data指向数据集根目录,Ultralytics 会自动识别 train 和 val 子目录。pretrained=True表示在 ImageNet 分类权重上继续训练,这是小数据集场景下的常规操作——从零训练分类模型在千张图片规模上收敛慢且容易过拟合。

参数说明:

  • epochs=50:对 1000 张图的规模,50 轮训练在 NVIDIA 3060 上大约 15-25 分钟。如果验证准确率在 20 轮后就不再上升,patience=10会早停。
  • imgsz=224:分类任务的标准输入尺寸。YOLO11cls 支持 160-640 区间,但 224 是速度和精度的平衡点;如果你要部署到移动端,可以降到 160,代价是准确率通常下降 1-3 个点。
  • batch=32:显存不足时优先调小这个数,8GB 显存建议 16,6GB 建议 8。
  • optimizer="AdamW":小数据集上 AdamW 收敛比 SGD 稳,适合快速出结果;追求极限精度可以把优化器换回 SGD,配合cos_lr=True,但训练时间会拉长。

3.2 从裸文件夹到可训练目录:还差一步切分

很多第一次用这份数据的人会直接把根目录丢给data参数,结果报错“找不到 train/val”。原因在于原数据只有类别文件夹,没有拆训练验证集。正确做法是先建两个目录,再按比例移动图片:

python -c " import os, shutil from sklearn.model_selection import train_test_split src = 'dataset' train_dir, val_dir = 'crop_disease_split/train', 'crop_disease_split/val' os.makedirs(train_dir, exist_ok=True) os.makedirs(val_dir, exist_ok=True) for cls in os.listdir(src): cls_path = os.path.join(src, cls) if not os.path.isdir(cls_path): continue files = os.listdir(cls_path) train_files, val_files = train_test_split( files, test_size=0.2, random_state=42 ) for split, subset in [(train_dir, train_files), (val_dir, val_files)]: os.makedirs(os.path.join(split, cls), exist_ok=True) for f in subset: shutil.copy(os.path.join(cls_path, f), os.path.join(split, cls, f)) print('切分完成') "

说明:test_size=0.2控制验证集比例,random_state=42固定随机种子,保证每次运行切分结果一致——这一点在复现训练日志时非常重要,种子不同导致数据分布不同,准确率差异会被误判成模型问题。这里用copy而不是move,是避免原始文件夹被破坏,如果你确认不再需要原目录,可以换成move省一半磁盘空间。

3.3 训练启动与日志观察

脚本写好、目录切分完成后,运行入口是一行命令:

python train.py

第一次启动时,Ultralytics 会自动校验数据集结构,输出类似 22 classes、train images 800、val images 200 的摘要。训练过程会实时打印每个 epoch 的 loss、top1_acc、top5_acc。跑完后runs/classify/crop_disease_yolo11s/下会生成weights/best.pt和last.pt,以及results.png训练曲线、confusion_matrix.png混淆矩阵。

这里有个值得注意的点:Ultralytics 的Trainer默认会在yolo11s-cls.pt同目录下找配置文件,如果你环境变量配置得乱,可能加载到缓存里的旧权重。我习惯在model = YOLO("yolo11s-cls.pt")前加一行print(model.model_name)确认模型身份,免得训了半天发现用的是别人的自定义权重。

4. 训练结果日志怎么读:准确率之外要看的四个指标

博主随资源附了训练结果日志,这比脚本本身更值得研究。很多新手拿到日志只会看最后的 top1_acc,但实际项目中,准确率只是及格线,还要看混淆矩阵、每类召回、loss 曲线收敛性和早停位置。

4.1 从 results.png 判断模型是否正常收敛

训练结束后会自动画出results.png,里面通常包含训练损失、验证损失、top1/top5 准确率四张子图。正常收敛的标准是:

  • 训练损失曲线单调下降,最后趋于平台,没有明显拉升
  • 验证损失前期下降、后期轻微上升属于正常波动,但如果训练损失持续下降而验证损失一路走高,就是典型的过拟合,需要提前早停或加大数据增强
  • top1_acc 在 50 轮内达到 80% 以上,说明数据质量是够的

如果看到验证损失曲线的形状像笑脸(先降后升),表示模型在第 20 轮附近就开始记住训练集的噪声。此时不要盲目增加 epochs,而是回看patience设置——Ultralytics 默认 patience=100 对 1000 张图太宽,建议收紧到 10-15,让它在验证集开始恶化时立刻保存最优权重。

4.2 混淆矩阵解读:错误集中在哪类

confusion_matrix.png是 22 行的热力图,行代表真实类别,列代表预测类别。对角线越亮越好,看矩阵时重点找两类问题:

第一,相似病害互相混淆。比如番茄叶枯病(Tomato_leaf_blight)和斑枯病(Tomato_septoria_leaf_spot),叶片症状在视觉上高度相似,混淆率高是正常的。如果项目对这两种病必须严格区分,仅靠 RGB 图像训练到 90% 以上的分类准确率很困难,常见做法是引入多光谱数据或做细粒度分类(fine-grained classification)。

第二,少数类整体偏暗。某个类别的行整体暗淡,代表该类别几乎没被正确预测到,原因是训练样本太少。解决方式不是立刻加数据,而是先给这个类单独打印置信度输出——我在调试时通常把模型输出的probs保存成 CSV,统计每个类别的平均置信度,判断是「模型学不会」还是「模型学会了但置信度被压低了」。

4.3 用博主日志做基准对比,而不是迷信数字

附赠的训练日志最大的价值是给你一个可参考的基准。假设日志里记录的最佳准确率是 97%,你复现时跑到 94%,这 3 个点的差距可能来自:

  • 训练硬件不同导致 batch 行为差异
  • 切分数据时随机种子不同
  • 环境依赖版本不一致(Ultralytics 版本号差异会影响默认超参)

我的做法是把博主日志里的 epoch 数和 loss 值当成「这条数据在这个模型规模下应该有的表现」,而不是「必须达成的目标」。复现时只要曲线趋势一致、最终准确率在 2-3 个点以内浮动,都算正常。

5. 避坑指南:训练农作物分类数据集最容易踩的五个坑

这部分写的是我用这套数据和同类农业数据集时真实遇到过的坑,每条按「现象 → 原因 → 解决」整理,希望能让你少走弯路。

5.1 文件夹路径含有中文,模型直接报错

现象:训练启动后报NotADirectoryError或FileNotFoundError,指向的路径看起来是完整的。

原因:Windows 环境下,如果数据集根目录或类别文件夹名包含中文(比如「番茄_叶霉病」),Ultralytics 底层调用的文件操作在部分编码环境下会失败。

解决:把所有目录名、文件名统一改成英文或拼音,这也是这份数据集中类别全部用英文命名的原因。改动命令:

rename 's/[\x80-\xff]//g' dataset/*/ # Linux 下清除非 ASCII 字符

Windows 用户直接在资源管理器里批量重命名即可,操作完再跑python -c "import os; print(os.listdir('dataset'))"确认路径干净。

5.2 类别极度不均衡,多数类准确率高、少数类全是 0

现象:训练日志显示 top1_acc 高达 95%,但打开混淆矩阵发现某一两个类别完全没有正确预测。

原因:1000 张图分到 22 个类别后,部分病害类别可能只有 20-30 张。模型在训练时把多数类的梯度主导了,少数类的特征完全被淹没。

解决:优先降低多数类的采样权重,而不是直接删数据。Ultralytics 支持通过class_weights参数指定各类别的损失权重,先统计频次再计算权重:

import numpy as np counts = np.array([35, 80, 120, 30, ...]) # 按类别顺序填实际数量 weights = counts.sum() / (len(counts) * counts) model.train(..., class_weights=weights)

如果不想动权重,另一个常见做法是对少数类做离线增强——旋转、亮度抖动、随机裁剪各生成 3 份副本,把单类数据量补到 50 张以上。注意是「补」,不是「超采样同一张图」,后者会让模型记住特定图片而非病害特征。

5.3 验证集没有按类别分层抽样

现象:训练 loss 正常下降,但验证准确率忽高忽低,波动超过 10 个点。

原因:如果用随机切分而不是分层切分,400 张验证集里某些类别只有 1 张图,这一张被预测对还是错,直接影响 2-3 个百分点的整体准确率,造成指标不稳定。

解决:切分时必须按类别分层。train_test_split加上stratify=y,其中y是每条样本对应的类别标签数组。前面给出的切分脚本如果漏了stratify,请务必补上。

5.4 显存不足:OOM 崩溃只在训练到一半时出现

现象:训练前几个 epoch 正常,第 3 轮后报CUDA out of memory。

原因:PyTorch 在训练过程中会缓存中间激活值,显存占用随 batch 累积,不是启动时就能暴露的。另外,如果开了cache=True(把图片加载进内存),也会增加显存压力。

解决:先把batch从 32 降到 16 再降到 8;同时把workers从默认的 8 调低到 2,避免数据加载线程抢占内存。如果还是 OOM,检查imgsz是否被无意中调高——有人会在调试时把imgsz=640跑分类,显存开销直接翻倍。

5.5 复现结果不一致:明明跑同一个脚本,准确率差 5 个点

现象:同一份数据集、同一个脚本,换了台机器或隔了几天重跑,top1_acc 从 93% 掉到 88%。

原因:最常见的是随机种子没固定,其次是 Ultralytics 框架更新导致默认超参变化。YOLO11 的版本迭代很快,v8.2 和 v8.3 的数据增强策略有实际差异。

解决:把所有随机源固定下来。PyTorch 的随机性来自三处——数据加载顺序、权重初始化、数据增强。在脚本开头写入:

import random, torch random.seed(0) torch.manual_seed(0) torch.cuda.manual_seed_all(0)

然后把训练参数里的seed=42固定住。另外,务必在项目里记录 Ultralytics 版本号:pip freeze | grep ultralytics,否则未来环境重建时很难追查指标漂移。

6. 从训练到部署:项目落地前我认为最有用的三个验证

模型训练完不是终点。你如果想要在真实场景里用它,这三个验证步骤我建议一个都别省。

第一步,单张图推理测试。用训练好的best.pt对每类各抽一张图做预测,看输出类别和置信度分布。执行以下命令:

yolo classify predict model=runs/classify/crop_disease_yolo11s/weights/best.pt source=D:/test_images

注意source如果是文件夹,Ultralytics 会遍历所有图片;如果是单张图,直接传图片路径。预测结果会存在runs/classify/predict目录下,包含标注了类别和置信度的输出图。这一步能快速判断模型在「非训练集拍摄条件下」的泛化能力——比如换手机拍、换光照角度。

第二步,导出 ONNX 验证部署可行性。分类模型最终多半要集成到 App 或 Web 服务里,ONNX 是跨平台部署的标准格式:

yolo export model=best.pt format=onnx imgsz=224

导出后会生成best.onnx,可用 ONNX Runtime 在 CPU 上跑。这一步最重要的意义是提前验证模型能不能脱离 PyTorch 环境独立推理,很多项目就是训练阶段跑得好、导出阶段发现算子和版本不匹配,才回头改架构。

第三步,构建最终的分类映射表。训练时用的类别名是英文文件夹名(如Maize_fall_armyworm),但部署时用户看到的是中文名或结构化字典。训练结束后我建议立刻维护一张映射表并写入 JSON 或 YAML:

Maize_fall_armyworm: 玉米草地贪夜蛾 Maize_grasshoper: 玉米蝗虫 Tomato_leaf_curl: 番茄卷叶病

这张表看起来不起眼,但实际部署时几乎每个团队都会折在「模型输出是英文 label,业务系统要的是中文别名」的对接上。开发者觉得是小事,产品那边却要反复确认,耗时远大于建表本身。

从那次之后,我形成了自己的习惯:每次拿到这类带文件夹分类的数据集,强制走一遍「统计类别分布 → 分层切分 → 固定随机种子 → 训练 → 导出 ONNX → 维护映射表」的流程。这套流程走完,模型能不能用、哪里不行、部署有没有坑,基本都心里有数了。希望这份笔记能帮到你,也祝你的农作物分类项目顺利落地。资源获取方式在文末,记得回复对应凭证就行。

本文还有配套的精品资源,点击获取

返回列表