简介:面向计算机视觉与农业智能化方向的图像分类数据集,包含15000张真实场景水稻叶病虫害图片,覆盖细菌性叶枯病、褐斑病、叶瘟病、稻飞虱、纹枯病等10个常见类别。资源以PDF形式交付,共1个文件、2.32MB,文档内附数据集基本情况介绍及百度网盘获取方式;图片数据按类别文件夹整理,标注质量高,可直接用于YOLO11cls等分类算法的训练,并附带一键训练脚本和博主训练结果日志,利于快速验证与对照。目前已有318人学习,适合需要开展水稻病虫害识别、通用分类数据集补充或算法训练实践的读者。
1. 水稻叶病虫害分类实战:15000张数据与YOLO11cls能替你解决什么
做农业视觉任务的人应该都有同感:水稻叶病虫害识别看起来只是图像分类,真正动手才发现瓶颈不在模型,而在数据整理和训练流程。一个典型的场景是——田间采集了几千张叶片照片,按病害类别放在不同文件夹里,看起来“已经能用”,实际离训练还差着数据校验、目录格式对齐和训练脚本三件事。这篇文章想要解决的问题,就是当你手里有一份“15000张图+对应分类文件夹整理+YOLO11cls一键训练脚本”的水稻叶病虫害分类数据集时,怎么把它真正跑通,并且跑出靠谱的准确率。
YOLO11cls是Ultralytics YOLO11系列里的图像分类分支,输入一张叶片图,输出它属于哪个病害类别,比如稻瘟病、白叶枯病、胡麻斑病或者健康叶。和检测模型不同,cls模型不需要画框,只需要类别标签,所以它的数据组织天然适合“按文件夹分类”的形式。下面我会按拿到数据后实际要做的顺序来讲:先检查数据和目录,再搭环境,再写训练脚本,最后说训练里最常遇见的坑和验证方法。适合正在做水稻病害识别、打算用分类模型快速出首版结果的同学参考;如果你是第一次碰YOLO11cls,跟着步骤走也能把完整流程跑通。
2. 拿到数据集先检查:目录格式、图像完整性与类别分布
2.1 分类文件夹结构与YOLO11cls期望的目录差异
常见的水稻叶病虫害数据集会这样组织:一个根目录下面按病害类别建子文件夹,每个子文件夹里放对应类别的叶片图片。这在人眼里很直观,但直接把它扔给YOLO11cls是不行的——Ultralytics的ImageClassifier要求把数据内容放在一个名为images的子目录里,并且images下面按类别分子文件夹,同时还有一个与训练集结构完全一致的val目录用于验证。
我习惯先把原始数据复制到一个新目录再调整,而不是在原目录上动手。调整后的结构应该长这样:
rice_leaf_cls/ ├── images/ │ ├── train/ │ │ ├── rice_blast/ │ │ │ ├── blast_001.jpg │ │ │ └── ... │ │ ├── bacterial_blight/ │ │ └── healthy/ │ └── val/ │ ├── rice_blast/ │ ├── bacterial_blight/ │ └── healthy/ └── dataset.yaml注意几个细节:类别文件夹名最终会成为模型的类别名,建议先用英文名,等训练完再映射成中文显示;每个类别在train里至少有几十张图,否则验证会抖动得厉害;val的数量不需要很大,但必须覆盖全部类别。
2.2 用脚本盘点图像数量、尺寸与损坏文件
15000张图听起来体量不小,但实际上这个规模用普通单卡训练并不吃力。在开始训练之前,我建议先写一个快速的盘点脚本来确认三件事:每个类别各有多少张图、图片尺寸是否统一、有没有损坏或无法解码的文件。很多训练中断问题,根子都在这一段没查。
import os from collections import Counter from PIL import Image root = "rice_leaf_cls" counter = Counter() size_set = set() for split in ["train", "val"]: split_root = os.path.join(root, "images", split) for cls_name in os.listdir(split_root): cls_dir = os.path.join(split_root, cls_name) if not os.path.isdir(cls_dir): continue for fname in os.listdir(cls_dir): if not fname.lower().endswith((".jpg", ".jpeg", ".png")): continue path = os.path.join(cls_dir, fname) counter[f"{split}/{cls_name}"] += 1 try: with Image.open(path) as im: size_set.add(im.size) except Exception: print("损坏文件:", path) os.remove(path) # 训练前直接删掉坏图 print("各类别数量:", dict(counter)) print("所有图片尺寸集合:", size_set)这段脚本的逻辑很简单:先遍历train和val目录,按“切分/类别”计数;再用PIL打开每一张图验证可解码性,遇到打不开的损坏文件直接删除,防止训练中途报错。最后打印的尺寸集合很重要——若尺寸不统一,YOLO11cls内部会自动resize,所以不要求全图一致,但如果你发现大量图片的长宽比差异非常大,比如有横图也有竖图,可能要考虑训练时统一成正方形后的裁切影响。
脚本跑完后重点看输出里的数量分布。健康叶往往占比偏高,而某些不常见的病害图只有几百张,这就是后续可能需要做类别加权或数据增强的信号。15000张的规模下,类别间差距在3倍以内通常不需要特别干预,超过5倍就建议关注后面训练脚本里的augment和类别权重设置。
2.3 类别分布审查与train/val划分
如果你的数据集里没有现成的val目录,需要自己划分。常见的做法是每个类别随机抽出10%-15%作为验证集,注意不能直接对整个文件夹随机抽,否则某些类别的验证图可能全落在同一个拍摄批次里,让验证分数虚高。我一般会按类别做分层抽样:
python - <<'EOF' import os, random, shutil src = "原始数据根目录" dst = "rice_leaf_cls/images" val_ratio = 0.12 random.seed(42) os.makedirs(f"{dst}/train", exist_ok=True) os.makedirs(f"{dst}/val", exist_ok=True) for cls in os.listdir(src): cls_path = os.path.join(src, cls) if not os.path.isdir(cls_path): continue imgs = [f for f in os.listdir(cls_path) if f.lower().endswith((".jpg", ".jpeg", ".png"))] random.shuffle(imgs) n_val = max(1, int(len(imgs) * val_ratio)) val_imgs = imgs[:n_val] for name in val_imgs: os.makedirs(f"{dst}/val/{cls}", exist_ok=True) shutil.copy(os.path.join(cls_path, name), f"{dst}/val/{cls}/{name}") for name in imgs[n_val:]: os.makedirs(f"{dst}/train/{cls}", exist_ok=True) shutil.copy(os.path.join(cls_path, name), f"{dst}/train/{cls}/{name}") print(cls, "总数", len(imgs), "验证集", n_val) EOF固定随机种子很关键,同一个数据集每次划分结果一致,后面复现和排查问题都方便。15000张、12类以下的场景,这个划分比例够用;如果你的个别类别只有几十张图,验证集会偏小,此时更稳妥的做法是改成k折交叉验证,但脚本复杂度会上去,第一版不建议。
3. YOLO11cls训练环境的搭建:版本、依赖与模型选择
3.1 为什么分类任务选YOLO11cls,而不是YOLOv8n-cls或自己写CNN
你可能会问:水稻叶病害分类这种任务,用ResNet、EfficientNet甚至更轻量的MobileNet不也行吗?确实行,但YOLO11cls有一个实际优势:训练和推理脚本是同一套Ultralytics接口,后续如果要把分类结果和检测任务组合,能少写不少代码。而且YOLO11在主干结构上做了优化,分类准确率在同参数量级下并不输给经典的ResNet系模型。
对于15000张图的水稻叶片数据,我的选型建议是:第一版先用YOLO11s-cls或YOLO11m-cls跑通流程。n版本太小,复杂病害特征容易欠拟合;x版本对这个数据量来说容易过拟合且训练慢。s和m是精度与速度的折中点。训练时长上,单张消费级显卡用m版本跑15000张图,大约1到2小时能完成,完全在可接受的范围内。真实项目中,模型翻车从来不是因为慢,而是因为流程里有玄学一般的问题没排查干净,这部分我会放到第5章专门说。
3.2 安装与最小验证跑通
Ultralytics的安装习惯上直接pip一把梭,但要注意Python版本和PyTorch版本的兼容性。这里建议在虚拟环境里操作,不要直接装到系统Python,否则后面换版本会很痛苦。
conda create -n yolo11 python=3.10 -y conda activate yolo11 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics yolo checksyolo checks会输出环境信息并快速验证依赖是否正常。如果这里报CUDA不可用,多半是PyTorch版本和显卡驱动不匹配,不要急着往下走,先解决驱动问题。装完后可以跑一个最基础的分类训练,用YOLO11自带的示例数据验证整条链路通不通:
yolo classify train model=yolo11s-cls.pt data=/path/to/dataset.yaml epochs=1 imgsz=640这步只需要确认能开始迭代就行,不需要等它跑完。真正改参数是在后面的一键训练脚本里。
3.3 预训练权重选择与数据加载流程
YOLO11cls的预训练权重是在ImageNet上训练得到的,下载后放在项目根目录或任意位置都行。训练时用pretrained=True(默认状态)会加载这些权重,对水稻叶病害这种医学图像性质较强的任务有明显帮助——因为ImageNet提供了丰富的纹理特征先验,可以让模型在训练前期就聚焦到叶片病斑的细节上,而不是从头学习边缘和颜色。
数据加载流程上,Ultralytics分类器会把dataset.yaml里train和val字段指向的路径扫描一遍,自动建立类别索引。注意它不读取txt标签文件,分类任务的标签完全由目录名决定,所以第2章里的目录结构就是整个任务的唯一监督信号源。这意味着任何目录名拼写错误都会直接映射成错误标签,训练前一定确认每个类别文件夹名和实际病害对得上。
4. 一键训练脚本的核心逻辑:参数怎么设、输出怎么看
4.1 train_leaf_cls.py 脚本框架
所谓“一键训练脚本”,本质就是把训练命令、数据路径和超参数固化成一个可重复执行的Python脚本。好处是当数据更新或迁移到新机器时,不需要回忆当初在命令行里敲过什么。下面是我针对这个任务写的脚本框架,核心逻辑注释在代码里。
# train_leaf_cls.py from ultralytics import YOLO DATA_YAML = "rice_leaf_cls/dataset.yaml" # 数据配置,需手动确认路径 MODEL_NAME = "yolo11s-cls.pt" # 预训练权重 EPOCHS = 60 IMGSZ = 640 BATCH = 32 LR0 = 0.003 DEVICE = 0 # GPU编号,CPU训练填"cpu" if __name__ == "__main__": model = YOLO(MODEL_NAME) results = model.train( data=DATA_YAML, epochs=EPOCHS, imgsz=IMGSZ, batch=BATCH, lr0=LR0, device=DEVICE, optimizer="SGD", augment=True, seed=42, name="rice_leaf_cls_exp", project="runs/classify", patience=15, plots=True, ) print("训练结束,最佳权重保存在:", results.save_dir)这段脚本的逻辑很直白:先加载YOLO11s-cls的预训练权重,再调用train方法启动训练。seed=42保证结果可复现;plots=True会在每个epoch结束后生成曲线图和混淆矩阵,方便观察趋势;patience=15意味着验证集指标连续15个epoch不改善就提前停止,防止无效的长时间迭代。
4.2 训练超参数的落地推荐
这套参数不是随手填的,而是结合水稻叶病害数据和15000张图的规模定的。下面按参数逐条说明:
epochs=60:对15000张图来说,60轮足够让模型收敛。如果数据增强开得猛,可以适当放到80,但再多就存在过拟合风险。imgsz=640:这是处理速度和精度之间的平衡点。水稻叶片病害的纹理细节较多,用320会明显掉点,用1280显存占用会翻倍而精度提升有限。640是多数农业视觉任务的第一选择。batch=32:由显存决定,这里默认针对12GB左右显存。如果你只有8GB,改成16;如果用的是24GB专业卡,可以尝试64。lr0=0.003:这个值看起来偏大,但配合后续的余弦退火调度,在60轮里可以自然衰减。如果发现loss震荡严重,降到0.001。optimizer="SGD":对中小规模数据集,SGD+Momentum的泛化能力通常优于Adam系列,尤其在验证集上不容易出现“训练好、验证差”的情况。
还要说明augment=True的含义。Ultralytics分类器默认开启轻度增强,包括随机翻转、色彩抖动等。对水稻叶片而言,色彩抖动很有用,因为田间拍摄时光照变化大;但要注意如果病害颜色本身是重要特征,比如黄化类病斑,色彩抖动过强反而会干扰判断。默认值先跑一版,如果发现验证集指标上不去,优先检查默认增强强度,再考虑关闭部分增强。
4.3 训练产物和日志解读
训练开始时终端会输出一个表格,逐轮显示train/loss、val/loss、top1_acc等指标。新手容易犯的错误是盯着训练loss看,其实对分类任务来说,真正的判别标准是验证集top1准确率。训练loss下降但验证acc不涨,是过拟合前兆;两者同步下降,则是健康状态。
训练结束后,runs/classify/rice_leaf_cls_exp目录下会生成weights/best.pt和weights/last.pt,前者是验证集上表现最好的权重,后者是最后一轮的权重。日常使用和后续部署都直接用best.pt即可。confusion_matrix.png能直观展示每个类别被错分成了什么,这比单看准确率数有意义得多——比如模型老是把稻瘟病和白叶枯病混在一起,那你的注意力就该放在这两个类的特征差异上,而不是盲目加数据。
5. 训练避坑与常见问题排查
5.1 现象:loss正常下降,top1_acc始终在某个低水平徘徊不动
这是我处理水稻叶数据时遇到最多的情况。原因通常是数据本身存在类别混淆,比如“稻瘟病”和“胡麻斑病”在叶片外观上本来就相似,而标注时又不够严格。模型学不到稳定区分的特征,准确率自然卡住。
解决思路分两步:先看混淆矩阵,确认到底是哪几个类别互相错分;再检查这些类的样本,如果确实存在大量标签贴错的图,需要回去修正。另外可以考虑把相似病害合并成一个大类,比如把“稻瘟病”和“胡麻斑病”合并为“叶部斑点病”,这在生产环境下完全可行——因为农户并不关心具体的病理亚型,只要系统能告诉他们“需要打药”还是“不用打药”。
5.2 现象:训练到一半报错“no space left on device”或磁盘被占满
数据集本身有15000张图,约几GB到十几GB,但很多人忽略了训练过程中Ultralytics还会做缓存:小数量的数据集会直接缓存到内存,15000张这种规模则可能把预处理后的图像写到磁盘缓存目录里。如果系统盘空间不足,训练后期就会突然中断。
解决方法是把缓存目录指向空间富余的硬盘。Linux下设置环境变量ULTRALYTICS_CACHE_DIR或直接指定数据集的cache=False参数。我一般建议保留缓存,因为重复训练能省大量时间;前提是先确认磁盘至少有数据集体积1.5倍以上的空间。
5.3 现象:训练正常但在验证集上准确率很高,换一批图片立即变差
这属于典型的过拟合或数据来源单一问题。水稻叶数据如果全部来自同一个拍摄环境,模型可能学到的是背景颜色而不是病斑纹理。区分办法是把每张图随机截取中间一块放大来看模型特征;更直接的做法是在验证集中混入另一批次拍摄的图片,看看指标能跌多少。
解决方向是增加数据来源的多样性,或者在训练时加入更强的背景增强:augment=True的基础上,对图像做随机旋转、缩放、亮度调整。切忌为了让验证集好看而反复调整随机种子直到选出“好结果”,那会让模型在生产环境中彻底失效。
5.4 现象:显存溢出导致的训练中断(RuntimeError: CUDA out of memory)
这类问题通常不是单张图像太大,而是batch大小和imgsz共同决定的显存占用超过了你显卡的上限。很多人第一反应是把batch减半,但这样会明显影响收敛速度。
更合理的顺序是:如果显存报错,先看是否开着其他占用显存的程序,关掉即可;然后考虑把imgsz从640降到512,这样显存占用下降约三成,而分类精度下降很小。如果还不够,再把batch从32降到16。同时检查Ultralytics的batch参数是否被写死,有时候脚本复制自别的项目,里面残留了不相干的大batch数值。
5.5 现象:训练曲线严重震荡,loss上下跳但整体不降
震荡的原因常见有两个:学习率设置过大,或batch内部类别不均衡。15000张图如果某个类别只有两三百张,每个epoch里该类的样本反复出现,就会导致loss抖动。
我的处理习惯是先把lr0下调到原来的三分之一试一轮,如果震荡缓解再考虑在dataset.yaml里不用额外配置类别权重,而是直接在数据划分阶段做类别均衡——让每个batch通过采样器尽量均匀地覆盖各类别。Ultralytics分类器没有暴露这个参数,所以最简单的均衡手段仍然是回第2章重新划分数据,给少数类增加复制或增强样本,让它和多数类数量差距控制在3倍以内。
6. 验证与落地:混淆矩阵、指标判断与部署技巧
6.1 验证集评估
训练完别急着收工,先跑一个标准评估脚本,把验证集整体过一遍,重点输出每个类别的精确率、召回率和F1分数。以水稻叶病害分类为例,8个以上类别时,top1准确率只能反映整体水平,真正暴露问题的永远是个别类别的细节。
from ultralytics import YOLO model = YOLO("runs/classify/rice_leaf_cls_exp/weights/best.pt") metrics = model.val( data="rice_leaf_cls/dataset.yaml", split="val", batch=32, ) print("top1_acc:", metrics.top1) print("top5_acc:", metrics.top5)如果val目录本身就来自训练集同一批拍摄数据,这个指标只能证明模型“记住了特征”。更进一步,我会从原始数据目录里手动抽出每个类别10张完全未参与训练的照片,单独建立一个“盲测集”,用model.predict逐一预测并人工核对结果。盲测集上的准确率才是生产环境可期待的上限。
6.2 导出与部署
验证通过后,把best.pt导出成TorchScript格式,可以脱离原Python环境部署,也可以在手机或嵌入式设备上推理:
model.export(format="torchscript", imgsz=640)导出后的模型是单文件,配合一段简单的预处理代码(resize到640、归一化、取softmax后最大概率对应的类别),就能接入小程序、Web后端或边缘网关。值得注意的是,导出后务必用同一张测试图分别跑pt和导出版本,确认输出一致,我在这上面翻过一次车——不同导出格式的输入预处理细节略有差别,直接上线会导致概率分布完全错乱。
最后说一个我养成的习惯:每次训练结束,把训练脚本、数据划分日志、关键超参数和最终验证指标一起提交到项目仓库里。这样不管过多久,只要拿到这批文件就能完整复现整个训练过程。版本管理做得越认真,后续换数据重新训练时越省心。希望这篇文章能帮你把水稻叶病虫害分类这个项目顺顺利利跑通。
本文还有配套的精品资源,点击获取