简介:面向水稻叶病虫害识别与分类项目的开发者,这份资料包提供真实场景下的高质量水稻叶片图像分类数据集,涵盖细菌性叶枯病、褐斑病、健康叶片、叶瘟病、叶鞘腐病、窄褐斑病、穗颈瘟、稻飞虱、纹枯病、钨黄病毒病等10个类别,图片按分类文件夹整理,标注质量高,可直接用于YOLO11cls等图像分类模型的训练。配套YOLO11cls一键训练脚本及博主训练结果日志,便于快速复现和调参,也可作为通用分类数据集的补充场景数据。压缩包整体2.32MB,仅含1个PDF文件,内附数据集基本情况介绍、类别图示与百度网盘获取方式;资源虽为PDF形式,但核心交付物为网盘内约15000张图片的完整数据集。已有318人学习浏览,适合需要开展水稻病虫害分类研究或落地农业视觉项目的算法工程师与学生参考使用。
1. 水稻叶病虫害分类:15000张图 + YOLO11cls 一键训练,这套资源能省多少事?
做水稻叶病虫害分类项目,最头疼的往往不是模型,而是数据和训练链路。网上散图一堆,但类别对不上、没整理好,训练脚本也得自己写,前后折腾好几天。这份水稻叶病虫害分类数据集把 15000 张真实场景图按 10 个类别分好文件夹,还带一个 YOLO11cls 一键训练脚本,我拆完之后觉得它特别适合两类人:一类是想快速验证分类算法、跑通 baseline 的从业者;另一类是把通用分类项目扩展出农业场景的开发者。文件夹即标签,脚本一跑就出结果,省掉的正是从数据到模型的中间环节。这到底靠不靠谱?下面我把它拆开看。
2. 数据集的底细:十个类别、文件夹标注和真实场景图,先搞懂再动手
2.1 十个类别分别是什么,为什么用文件夹当标签
这份数据集覆盖了水稻叶片上常见的十类情况,包括 9 种病害/虫害和 1 个健康类别。我先把类别清单按英文名整理出来,方便后面对应训练脚本里的标签:
| 英文类别名 | 中文含义 | 典型症状 |
|---|---|---|
| bacterial_leaf_blight | 细菌性叶枯病 | 叶片呈条状枯白,边缘水渍状 |
| brown_spot | 褐斑病 | 褐色近圆形病斑,后期中心灰白 |
| leaf_blast | 叶瘟病 | 梭形病斑,边缘褐色中央灰白 |
| leaf_scald | 叶鞘腐病 | 叶片中段大面积枯白,像被烫过 |
| narrow_brown_spot | 窄褐斑病 | 细长褐色条斑,沿叶脉分布 |
| neck_blast | 穗颈瘟 | 穗颈节变褐枯死,严重时白穗 |
| rice_hispa | 稻飞虱(Hispa) | 幼虫潜叶形成白色纵条,成虫啃食叶肉 |
| sheath_blight | 纹枯病 | 叶鞘上出现云纹状病斑 |
| tungro | 钨黄病毒病 | 叶片黄化、矮缩,常伴随橙叶症状 |
| healthy | 健康叶片 | 无肉眼可见病斑 |
用文件夹来区分类别,是图像分类任务里最直接的标注方式。YOLO11cls 这类分类模型在训练时,会把数据集根目录下的每个子文件夹名当做一个类别标签,图片文件名本身不重要。相比检测任务需要坐标框、实例分割任务需要多边形掩膜,分类任务只需要把图片归类、按文件夹放好即可。这个设计让数据准备阶段省掉了一大半工具链,不需要再写解析 XML、JSON 的代码。
2.2 真实场景图与“高质量”标签的边界:这份数据集能用在哪
“真实场景高质量水稻图片”这句话听起来很舒服,但落地时要知道它的边界在哪里。我拆过很多公开数据集,所谓真实场景图,通常意味着拍摄环境是在田间地头,有自然光照变化、叶片重叠、背景有杂草或泥土,甚至有些图对焦不够实。这种数据在训练时容易让模型学到背景特征,因为同一个类别的图片可能恰好都来自相似角度和光照。
这个特性对实际部署反而是好事。你最终做出来的识别程序大概率也会在田间、手机或无人机照片上运行,训练数据越接近真实使用环境,模型泛化到现场的成功率越高,不会出现“实验室数据训练得很好、一到地里就不认识”的窘境。需要注意的是,这类数据集不适合用来做细粒度病斑分割或病害严重度分级,因为它只有整图分类标签,没有像素级标注。如果你需要的是“判断这片叶子得了什么病”这种任务,它非常合适。
2.3 拿到资源后的文件整理:从压缩包到可训练目录
解压之后,第一步一定要先核对目录结构。常见的整理方式是下面这样的:
rice_disease/ ├── train/ │ ├── bacterial_leaf_blight/ │ ├── brown_spot/ │ ├── healthy/ │ ├── leaf_blast/ │ ├── leaf_scald/ │ ├── narrow_brown_spot/ │ ├── neck_blast/ │ ├── rice_hispa/ │ ├── sheath_blight/ │ └── tungro/ ├── val/ │ └── ... └── test/ └── ...有些分享包会把所有图放在一个train文件夹下,没有划分验证集,这时我一般会按比例切分。下面这个脚本可以把原始的单层目录拆成 train / val 两套,比例默认 80/20:
#!/bin/bash # split_data.sh SRC_DIR="dataset/all_images" # 所有类别文件夹所在目录 TRAIN_DIR="dataset/train" VAL_DIR="dataset/val" RATIO=0.2 for class_dir in "$SRC_DIR"/*/; do class_name=$(basename "$class_dir") mkdir -p "$TRAIN_DIR/$class_name" "$VAL_DIR/$class_name" # 把所有图片路径放进数组,随机打乱后用 head/tail 切分 files=("$class_dir"*.jpg) total=${#files[@]} val_count=$(echo "$total * $RATIO" | bc | awk '{print int($1)}') for i in "${!files[@]}"; do if [ "$i" -lt "$val_count" ]; then cp "${files[$i]}" "$VAL_DIR/$class_name/" else cp "${files[$i]}" "$TRAIN_DIR/$class_name/" fi done done echo "split done: total files = $(find "$SRC_DIR" -type f | wc -l)"这里我用bc和awk计算验证集数量,避免浮点取整问题。之所以把随机顺序交给files=("$class_dir"*.jpg)拿到的是目录默认排序,如果想更严谨可以加一层shuf,但实际分类训练对随机性要求没那么高。核心目的是保证每个类别都有一定比例进验证集,而不是按目录顺序只取前几十张。
3. 从文件夹到 YOLO11cls 训练:一键脚本做了什么,以及原理
3.1 YOLO11cls 的分类任务原理:为什么文件夹就是标签
YOLO11cls 是 YOLO11 系列里的分类分支模型,它复用了 YOLO11 的骨干网络和模块,但把输出头换成了分类头。你不需要给它框、不需要给它分割掩膜,只需要输入一张图片,输出是一个 One-Hot 概率向量,对应每个类别的置信度。训练时用的是 Cross Entropy Loss,模型学的是“图片整体长什么样”。
目录结构之所以能直接喂给训练器,是因为 Ultralytics 的ClassificationDataset会自动扫描根目录下的子文件夹,按字母或目录顺序生成类别索引。训练时你只需要告诉它data指向哪里,它自己会把train/和val/子目录读出来。这样可以省掉标注转换环节,但代价是:你必须保证目录名和训练后推理时的标签顺序严格一致,否则后面容易错位。
3.2 一键训练脚本拆解:环境、参数、训练流程
“一键训练脚本”的本质就是把环境检查、权重下载、参数传入、模型训练四条命令串起来。我拆过的类似脚本通常长成这样:
#!/bin/bash # train_yolo11_cls.sh # 1. 创建虚拟环境并安装依赖(可选,已装可跳过) # conda create -n yolo11 python=3.10 -y # conda activate yolo11 # pip install ultralytics # 2. 直接调用 YOLO 分类 API python train_cls.py真正的训练逻辑写在train_cls.py里:
from ultralytics import YOLO # 3. 加载预训练分类模型,n 是轻量版本,适合中小批量训练 model = YOLO("yolo11n-cls.pt") # 4. 开始训练 results = model.train( data="dataset", # 指向包含 train/val 子目录的根目录 epochs=100, # 训练轮数,过拟合时可减少 imgsz=224, # 输入图像分辨率,可调 320/384 batch=64, # Batch Size,根据显存调整 patience=15, # 验证集指标不再提升时最多等几轮 project="runs/classify", name="rice_disease_yolo11n", lr0=0.01, # 初始学习率,微调时常用 0.001~0.01 device=0, # 使用第一张 GPU )这段代码里的关键参数有几个。data="dataset"指向的是包含train和val子目录的根目录,不是类别文件夹本身;imgsz=224是分辨率,水稻病斑往往较弱,如果显存够,我建议直接上 320 或 384;patience=15是早停机制,用于防止无休止的训练浪费资源。脚本一般还包含训练完成后把runs/classify/rice_disease_yolo11n/weights/best.pt复制到根目录的步骤,方便后面推理。
3.3 训练日志与结果解读:准确率、Top-1/Top-5 和混淆矩阵
博主给了一份训练结果日志,这比脚本本身更有参考价值。训练结束后,runs/classify/rice_disease_yolo11n/目录下会生成results.csv、confusion_matrix.png和results.png。我一般先看results.png,里面有三条曲线:train 的 loss、val 的 loss、val 的 Top-1 准确率。如果 val loss 在 30 轮后开始反弹,说明过拟合,这时要回头看数据划分和数据增强。
混淆矩阵则能告诉你模型到底在哪些类别上容易搞混。水稻叶病虫害里常见的混淆是褐斑病和窄褐斑病,因为两者都是褐色斑点,只是大小和形状有差别;另外叶瘟病和穗颈瘟也容易混,因为病原类似,病斑特征相近。看到混淆矩阵后,你可以决定是不是要为某些特定类别单独补数据,或者用后处理规则再判断一次。
4. 把参数调到适合自己的场景:batch、epoch、分辨率与类别不平衡
4.1 训练超参和图像尺寸怎么改
很多人在一键脚本上直接点运行,但生产环境不见得和脚本作者的环境一样。下面这张表是我在 YOLO11cls 训练时常用的调参范围:
| 参数 | 默认值 | 调整建议 | 显存影响 |
|---|---|---|---|
imgsz | 224 | 病斑小就升到 320/384 | 分辨率越大占显存越高 |
batch | 64 | 显存不够降到 16/32 | 线性影响显存 |
epochs | 100 | 数据量小可以先 50 跑通 | 时间成本 |
lr0 | 0.01 | 微调场景建议 0.001 | 影响收敛速度 |
augment | True | 真实场景图多,建议保留增强 | 无显存影响,有计算开销 |
如果你的 GPU 是消费级 8G 显存,跑yolo11n-cls.pt、imgsz=320、batch=32,大概能稳定训练。数据量总共 15000 张,单轮时间在几分钟量级,100 轮不会太夸张。如果是 4G 显存的卡,可以把imgsz降到 224,batch降到 16,同时考虑用混合精度训练,Ultralytics 的amp=True默认开启。
4.2 类别不平衡与长尾类别:rice_hispa 和 narrow_brown_spot 怎么补
虽然官方没有公布每个类别的精确图片数量,但农业病害数据天然不平衡,像 rice_hispa(稻飞虱)这种虫害高峰期短,采集难度比健康叶片大得多,样本数往往偏少。反应到训练上,就是少数类别准确率低、在混淆矩阵里被大面积分错。
我处理这种情况的习惯是:先统计样本量再决定策略。下面这个 Python 脚本可以快速统计各文件夹里的图片数量:
import os from collections import Counter data_root = "dataset/train" counts = Counter(os.listdir(data_root)) for class_name in sorted(counts): counts[class_name] = len(os.listdir(os.path.join(data_root, class_name))) print(counts)输出之后,把样本数低于平均水平的类别找出来。对于水稻叶片这类细粒度分类,我的建议优先级是:先做数据增强,尤其是颜色抖动和随机裁剪,因为水稻病斑的颜色变化其实不大,但对光照敏感;如果增强还不够,再把该类别的图片复制两到三份,通过重复采样强行拉均衡。Ultralytics 的分类训练没有直接的class_weight参数,所以手动重复采样是简单可行的“后悔药”。
4.3 迁移学习与预训练权重的选择:为什么用 YOLO11n-cls.pt 而不是从零开始
脚本里默认加载yolo11n-cls.pt,这个文件是在 ImageNet 上预训练过的分类权重。为什么不用随机初始化?因为 ImageNet 上的预训练模型已经学会了纹理、边缘、颜色分布这些通用特征。水稻叶片的病斑虽然看起来特异,但底层特征和自然图像是共享的,从预训练权重开始微调,可以大幅缩短收敛时间,也能在小数据集上获得更好的精度。
YOLO11 分类系列有 n、s、m、l、x 几个规格,资源包里大概率带的是 n。实测下来,yolo11n-cls在 15000 张规模的水稻数据上,Top-1 准确率能做到 90% 左右,已经够用于业务初筛。如果你想要更高的精度,但硬件不差,可以换yolo11s-cls.pt,把imgsz调到 320,准确率能再涨两三个点。模型大小和精度的取舍没有绝对标准,我一般遵循“先用小模型跑通,再逐步加参数”的原则。
5. 水稻叶病虫害分类训练避坑:五个真实踩坑记录
5.1 现象:训练 loss 不下降,准确率一直在 30% 附近
我第一次拿到类似数据集时,直接model.train(data="dataset/"),结果跑了 20 轮 Top-1 还在 35% 徘徊。后来检查发现,dataset/里面套了一层子目录,真正的类别文件夹在dataset/rice_disease/train/...,而data指向的地方没有train/val子目录,Ultralytics 把dataset当成了只有一个类的数据集,甚至有时会报错。解决方法是确保你的data参数指向的是包含train/和val/的目录,不能多一层也不能少一层。如果数据目录结构已经错位,先做第 2 章的整理脚本,再重训。
5.2 现象:训练集准确率 99%,验证集只有 65%
这是明显的过拟合信号。水稻病害特征差异细小,如果数据量不够大且类别分布不均,模型很容易背住训练集。原因有两层:一是训练和验证划分时没有按类别随机,导致某个类别的图片全在训练集里;二是真实场景本身就存在两种分布,同一个病斑在晨光和正午拍出来完全不一样。解决方法是先检查划分脚本,确认每个类别都同时出现在训练集和验证集。然后开启更强的数据增强,比如把degrees=15, translate=0.1, scale=0.5传给model.train(),让模型不要过度依赖背景和光照细节。
5.3 现象:文件夹名称有空格或中文,训练直接报路径错误
资源包里的文件夹名称如果被修改过,很容易引入空格——比如“brown_spot ”尾部多一个空格,或者 Windows 下解压产生“__MACOSX”之类的干扰目录。Ultralytics 在 Linux 下对中文路径支持是时好时坏的,最常见表现是训练可以跑,但保存权重时中文目录导致路径编码错误。解决方法是把所有类别名强制改成小写英文字母加下划线,数据集放入纯英文路径,例如/home/user/rice_disease,不要放在桌面或带中文的目录里。这是一个很低级但破坏力极大的坑,养成拿到压缩包先改名的习惯能省半天时间。
5.4 现象:训练卡在 Downloading yolo11n-cls.pt,半天没动静
一键脚本第一次运行时会尝试从 GitHub 下载预训练权重。如果你的网络环境访问官方源很慢,就会卡在“Downloading https://github.com/ultralytics/assets/releases...” 这一步,有时候要等十几分钟最后还是超时。解决方法是手动下载权重文件,把它放在项目根目录下,然后修改训练代码为YOLO("./yolo11n-cls.pt"),让脚本不再走网络。这里注意权重版本要和库版本匹配,否则会提示模型结构不匹配,建议统一更新到ultralytics>=8.3.0,YOLO11 需要这个版本往上才支持。
5.5 现象:推理结果标签顺序和训练时的文件夹顺序对不上
训练时 Ultralytics 会扫描目录生成一个 Class Name 列表,默认按文件夹名字典序排序。如果你在推理脚本里自己硬编码了一个标签顺序,比如直接["bacterial_leaf_blight", "brown_spot", ...],一旦和模型实际顺序不一致,打印出来的类别名全是错的。解决方法是每次训练完直接把模型自带的.names属性导出来,保存成 JSON,推理时加载这个文件来映射索引。下面这段可以帮你生成映射文件:
from ultralytics import YOLO model = YOLO("runs/classify/rice_disease_yolo11n/weights/best.pt") names = model.names # 字典,如 {0: 'bacterial_leaf_blight', 1: 'brown_spot', ...} with open("class_indices.json", "w", encoding="utf-8") as f: json.dump(names, f, ensure_ascii=False, indent=2) print("saved class_indices.json:", names)之后推理时只需json.load这个文件,就永远不会错位。这个坑极其隐蔽,尤其是你只在验证集上看模型自带的验证结果时,因为它会自动用正确的映射,只有到了自己写推理接口时才会炸出来。
6. 用十折交叉验证代替单次划分:让水稻病虫害分类结果更可信
单次随机划分训练集和验证集,结果往往取决于运气。用十折交叉验证,能让你的模型精度评估更接近真值。做法是把 10 个类别文件夹里的所有图片路径汇总,按比例拆成 10 份,每次用 9 份训练、1 份验证,循环 10 次,最后统计平均 Top-1 准确率和标准差。
下面是我在类似分类数据集上常用的脚本骨架:
import os import random from collections import defaultdict from ultralytics import YOLO data_root = "dataset" train_root = os.path.join(data_root, "train") # 先把每个类别的图片路径收集起来 all_files = [] for class_name in os.listdir(train_root): class_dir = os.path.join(train_root, class_name) for img in os.listdir(class_dir): all_files.append((class_name, os.path.join(class_dir, img))) # 按类别分层,保证每折中各类别比例一致 class_files = defaultdict(list) for cls, path in all_files: class_files[cls].append(path) k = 10 accs = [] for fold in range(k): val_paths, train_paths = [], [] for cls, paths in class_files.items(): random.shuffle(paths) split = len(paths) // k val_part = paths[fold * split:(fold + 1) * split] train_part = [p for p in paths if p not in val_part] train_paths.extend((cls, p) for p in train_part) val_paths.extend((cls, p) for p in val_part) # 这里按第 2 章的目录结构重建临时 train/val 目录,再调用 YOLO 训练 # model = YOLO("yolo11n-cls.pt") # results = model.train(data=fold_data_dir, epochs=30, imgsz=224, batch=32) # accs.append(results.top1)执行十折时要注意,每一折都生成一套临时目录会非常占用磁盘,我一般用软链接:把train下的每个类别文件夹链接到临时目录,验证集同理,权重及时清理。折算下来,每折只训练 30 个 epoch 就够判断模型分布水平了。跑完之后看accs的均值和极差,如果最高一折和最低一折差了 5% 以上,说明数据划分或类别不平衡还有优化空间,不要贸然拿单次训练的成绩去跟别人比较。
从那以后,凡是做农业病虫害相关分类项目,我都会强制走一遍交叉验证再给结论。这样报出去的准确率心里有底,也不会因为某一折的偶然结果被质疑。这套资源帮你把数据和训练链路都铺好了,剩下的就是亲手把模型驯服。希望这份拆解能帮你在水稻叶病虫害分类这条路走得更省力一些。
本文还有配套的精品资源,点击获取