简介:这份资源面向从事农业视觉检测、目标检测算法学习与落地的开发者,提供玉米叶片缺陷检测的YOLOv5格式数据集,解决病害识别中样本获取与标注成本高的问题。数据按YOLOv5标准目录组织,包含训练集与验证集,可直接投入训练,无需额外转换。压缩包共约2000个文件,以txt标注文件为主,另附一个可视化py脚本,整体大小约298.96MB;训练集含1558张图片及对应标签,验证集含667张图片及对应标签,图像为2000至3000像素的大分辨率RGB图,边界框标注清晰、图像完整,类别为infected单类。可视化脚本随机传入一张图片即可绘制并保存边界框,无需修改即可运行,便于快速核验标注质量。目前已有165人学习下载,适合需要现成数据开展玉米叶缺陷检测实验、模型训练与效果验证的读者。
1. 玉米叶片缺陷检测数据集:1 类别、训练集与验证集到底怎么用
玉米叶片缺陷检测这个方向,真正卡住大多数人的从来不是模型结构,而是数据。你拿到手的往往是一批田间拍的叶片照片,标签只有一类——缺陷,没有细分病斑类型,也没有像素级掩码,就是框出有问题的区域。这种单类别数据集看起来简单,实际用起来坑不少:正负样本极度不均衡、背景干扰大、叶片重叠导致框粘连。标题里说的「1 类别,包含训练集、验证集」,意味着这是一个已经切分好的目标检测数据集,直接对应 YOLOv5 的训练格式,省掉了你自己标注和划分的环节。适合谁用?做农业视觉巡检的、搞植保无人机巡检的、以及想拿一个真实场景数据集跑通 YOLOv5 全流程的工程师。下面从数据组织、训练配置、验证策略到避坑,一步步拆开讲。
2. 单类别玉米叶片数据集的组织方式与 YOLOv5 格式对齐
2.1 为什么单类别数据集反而更容易翻车
单类别目标检测在标注上省事,但在训练动态上比多类别更敏感。YOLOv5 的损失函数里分类分支只有一类,正样本的置信度目标恒为 1,负样本为 0。问题在于玉米叶片缺陷区域往往面积小、边缘模糊,如果锚框匹配策略没调好,正样本数量会少得可怜。常见做法是先用kmeans重新聚类锚框,而不是直接套用 COCO 的预设。另外,单类别下nc=1,YOLOv5 会自动把分类损失权重降低,但不会帮你平衡正负样本,所以hyp里的cls和obj权重需要手动微调。
数据集目录结构必须严格对齐 YOLOv5 的要求,否则训练脚本会在第一轮就报No labels found。标准布局是:
corn_leaf_defect/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamlimages/train和labels/train里的文件名必须一一对应,只是扩展名不同。标签文件是.txt,每行格式为class_id x_center y_center width height,全部归一化到 0~1。单类别下class_id恒为 0。
2.2 从原始标注到 YOLO txt:转换脚本与边界检查
如果你拿到的原始标注是 VOC XML 或 LabelMe JSON,需要转成 YOLO 格式。下面这个脚本处理 VOC 转 YOLO,同时做边界裁剪,防止坐标越界导致训练时AssertionError。
import xml.etree.ElementTree as ET import os from PIL import Image def voc_to_yolo(xml_dir, img_dir, out_dir, class_map): os.makedirs(out_dir, exist_ok=True) for xml_file in os.listdir(xml_dir): if not xml_file.endswith('.xml'): continue tree = ET.parse(os.path.join(xml_dir, xml_file)) root = tree.getroot() img_name = root.find('filename').text img_path = os.path.join(img_dir, img_name) with Image.open(img_path) as im: w, h = im.size lines = [] for obj in root.iter('object'): cls_name = obj.find('name').text if cls_name not in class_map: continue cls_id = class_map[cls_name] bbox = obj.find('bndbox') x1 = float(bbox.find('xmin').text) y1 = float(bbox.find('ymin').text) x2 = float(bbox.find('xmax').text) y2 = float(bbox.find('ymax').text) # 边界裁剪,防止越界 x1 = max(0, min(x1, w - 1)) y1 = max(0, min(y1, h - 1)) x2 = max(0, min(x2, w - 1)) y2 = max(0, min(y2, h - 1)) if x2 <= x1 or y2 <= y1: continue xc = (x1 + x2) / 2.0 / w yc = (y1 + y2) / 2.0 / h bw = (x2 - x1) / w bh = (y2 - y1) / h lines.append(f"{cls_id} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}") out_file = os.path.join(out_dir, os.path.splitext(xml_file)[0] + '.txt') with open(out_file, 'w') as f: f.write('\n'.join(lines)) voc_to_yolo( xml_dir='raw_annotations', img_dir='raw_images', out_dir='corn_leaf_defect/labels/train', class_map={'defect': 0} )逻辑说明:先读 XML 拿到原图宽高,再把 VOC 的左上右下坐标转成 YOLO 的中心点加宽高,全部除以宽高做归一化。边界裁剪那几行是关键,田间拍摄的叶片经常有标注框超出图像边缘的情况,不裁剪的话 YOLOv5 的 dataloader 会直接抛异常。class_map里只保留defect一类,其他类别直接跳过,保证单类别纯净。
参数说明:xml_dir是 VOC 标注文件夹,img_dir是原图文件夹,out_dir是输出标签文件夹。class_map根据你的标注名称改,如果标注里写的是「病斑」就改成{'病斑': 0}。归一化保留 6 位小数足够,YOLOv5 内部会再处理。
2.3 data.yaml 的五个必填字段与路径陷阱
YOLOv5 通过data.yaml定位数据和类别。单类别数据集最容易写错的是names列表和nc的对应关系。
path: /home/user/corn_leaf_defect train: images/train val: images/val nc: 1 names: ['defect']path是数据集根目录,train和val是相对路径。注意val指向的是图像目录,YOLOv5 会自动去同级labels目录找同名 txt。如果验证集图像和标签不在同级目录,训练时验证阶段会报No labels found。常见错误是把val写成绝对路径但path又写了相对路径,导致路径拼接后找不到文件。建议全部用绝对路径,或者全部用相对路径并确认工作目录正确。
提示:
names列表里字符串不要带空格或特殊字符,单类别直接写['defect']即可。如果后续要扩展类别,nc和names必须同步改,且标签文件里的class_id要重新映射。
3. 用 YOLOv5 训练单类别玉米叶片缺陷模型:参数怎么设、日志怎么看
3.1 从预训练权重到自定义数据集的迁移训练命令
YOLOv5 官方仓库提供了train.py,单类别数据集不需要改网络结构,只需要指定data.yaml和nc。下面这条命令是我在 6GB 显存上跑 640 尺寸的常用配置:
python train.py \ --weights yolov5s.pt \ --data corn_leaf_defect/data.yaml \ --img 640 \ --batch-size 16 \ --epochs 200 \ --hyp data/hyps/hyp.scratch-low.yaml \ --optimizer SGD \ --lr0 0.01 \ --lrf 0.01 \ --cache ram \ --device 0 \ --project runs/train \ --name corn_defect_v1逻辑说明:--weights yolov5s.pt加载 COCO 预训练权重,单类别数据量通常不大,从预训练迁移比从头训收敛快很多。--img 640是输入尺寸,玉米叶片缺陷区域如果偏小,可以提到 1024,但显存占用会翻倍。--batch-size 16在 6GB 显存下比较稳,如果报 OOM 就降到 8。--cache ram把图像缓存到内存,加速数据加载,但要求内存足够,数据集超过 10GB 就别开。--hyp选hyp.scratch-low.yaml是因为单类别下分类损失简单,低增强策略能减少过拟合。
参数说明:--lr0初始学习率,SGD 下 0.01 是常用值,如果 loss 震荡就降到 0.005。--lrf是最终学习率因子,余弦退火到lr0 * lrf。--epochs 200对单类别通常够用,看mAP@0.5在验证集上是否还在涨,不涨就可以停。
3.2 单类别下超参数 hyp 的微调重点
YOLOv5 的hyp.scratch-low.yaml里几个关键参数对单类别影响很大:
| 参数 | 默认值 | 单类别建议 | 原因 |
|---|---|---|---|
box | 0.05 | 0.05~0.08 | 缺陷区域边界模糊,框回归权重可略高 |
cls | 0.5 | 0.3~0.5 | 单类别分类简单,过高反而干扰 |
obj | 1.0 | 1.0 | 保持默认,正负样本平衡靠数据 |
fl_gamma | 0.0 | 0.0 | 单类别不建议开 focal loss |
mosaic | 1.0 | 0.5~1.0 | 田间背景复杂,mosaic 增强有帮助 |
mixup | 0.0 | 0.0~0.1 | 单类别 mixup 容易产生无意义样本 |
调整方式是在data/hyps/下复制一份改名为hyp_corn.yaml,然后--hyp data/hyps/hyp_corn.yaml。改完不用动源码,YOLOv5 会自动读取。
3.3 训练日志里必须盯住的四个指标
训练启动后,控制台每轮输出一行,重点看这四个:
box_loss:框回归损失,正常从 0.08 左右降到 0.02 以下。如果一直不降,检查标签归一化是否正确。obj_loss:目标置信度损失,单类别下这个值通常比多类别高,因为负样本比例大。降到 0.01 以下算收敛。mAP@0.5:验证集上的平均精度,单类别下就是该类别的 AP。0.85 以上算可用,0.9 以上算好。Precision和Recall:精确率和召回率。如果 Recall 低但 Precision 高,说明模型漏检多,可以降低conf-thres或增加正样本。
日志里出现nan通常是学习率太大或标签有非法值(比如宽高为 0)。出现No labels found是路径问题。出现CUDA out of memory就降 batch 或 img-size。
注意:单类别数据集如果验证集里没有负样本(全是缺陷叶片),
mAP会虚高。建议验证集里混入 10%~20% 无缺陷叶片,否则模型上线后会把正常叶片也框出来。
4. 验证集评估与推理:单类别模型的指标解读和误检排查
4.1 val.py 跑评估:命令与输出解读
训练完用val.py在验证集上跑一次完整评估:
python val.py \ --weights runs/train/corn_defect_v1/weights/best.pt \ --data corn_leaf_defect/data.yaml \ --img 640 \ --batch-size 16 \ --conf-thres 0.25 \ --iou-thres 0.45 \ --task val \ --device 0逻辑说明:--conf-thres 0.25是置信度阈值,低于这个值的框直接丢弃。--iou-thres 0.45是 NMS 的 IoU 阈值,单类别下如果叶片重叠严重,可以降到 0.3 减少框粘连。--task val表示只评估不保存预测图,如果要看可视化结果改成--task test并加--save-txt。
输出里all那一行就是整体指标。单类别下mAP@0.5和mAP@0.5:0.95差距大是正常的,因为缺陷区域边界模糊,高 IoU 阈值下匹配困难。如果mAP@0.5高但mAP@0.5:0.95很低,说明框的位置不够准,可以尝试提高box损失权重或增加标注精度。
4.2 误检和漏检的排查路径
单类别模型上线后最常见的两个问题:把正常叶片纹理当成缺陷(误检),或者小病斑没框出来(漏检)。排查顺序如下:
先看验证集的可视化结果,用detect.py跑一批图:
python detect.py \ --weights runs/train/corn_defect_v1/weights/best.pt \ --source corn_leaf_defect/images/val \ --img 640 \ --conf-thres 0.25 \ --save-txt \ --project runs/detect \ --name val_check跑完去runs/detect/val_check看标注图。误检多的话,检查训练集里是否混入了正常叶片但被标了框,或者背景里有类似病斑的纹理。漏检多的话,看小目标是否在img-size下被缩得太小,可以尝试--img 1024重新训练。另外--conf-thres调低到 0.1 看能不能召回更多,但会引入更多误检,需要权衡。
4.3 单类别数据集的划分比例与验证集独立性
标题里说「包含训练集、验证集」,但没给具体比例。常见做法是 8:2 或 7:3。单类别下验证集不能只放容易的样本,要覆盖不同光照、不同叶片角度、不同缺陷程度。如果验证集和训练集来自同一批拍摄,指标会偏高。我一般会按拍摄批次划分:比如上午拍的做训练,下午拍的做验证,这样更能反映模型在新数据上的表现。
验证集里必须包含负样本(无缺陷叶片),否则Precision会虚高。负样本不需要标签文件,只要图像放在images/val下,YOLOv5 在评估时会自动把没有对应labels/valtxt 的图像当作背景。但注意,如果labels/val下有一个空的 txt 文件,YOLOv5 会认为该图有标注但内容为空,行为不一样。正确做法是负样本图像不要放对应的 txt 文件。
5. 玉米叶片缺陷检测避坑:5 条血泪经验
5.1 现象:训练 loss 正常下降但 mAP 始终为 0
原因:标签文件里的class_id不是 0,或者data.yaml里nc写成了大于 1。单类别下nc必须是 1,names长度必须是 1。如果标签里写了1作为类别 ID,YOLOv5 会认为有第二类,但names里没有,导致所有预测都被过滤。
解决:检查所有 txt 文件第一列是否全为 0。用awk '{print $1}' labels/train/*.txt | sort -u快速查看。如果有非 0 值,批量替换成 0。
5.2 现象:验证集 mAP 很高但实际推理时框出一堆背景
原因:验证集和训练集同分布,且验证集里没有负样本。模型学会了「只要像叶片就框」,而不是「只有缺陷才框」。
解决:验证集里混入 20% 无缺陷叶片,重新评估。如果 mAP 下降明显,说明模型泛化差,需要增加训练集里负样本的比例,或者在hyp里提高obj权重。
5.3 现象:训练到一半突然报 CUDA out of memory
原因:--cache ram把图像缓存到内存后,如果数据集图像尺寸不一致,YOLOv5 会在训练时动态 resize,导致显存波动。另外mosaic增强会拼接 4 张图,等效 batch 变大。
解决:关掉--cache,或者把--batch-size降到 8。如果还不行,把--img从 640 降到 512。单类别数据集通常不大,关缓存对速度影响有限。
5.4 现象:推理时同一个缺陷被框了多个重叠框
原因:NMS 的iou-thres设得太高,或者锚框尺寸和缺陷尺寸不匹配,导致多个锚框都响应同一个目标。
解决:把--iou-thres从 0.45 降到 0.3。如果还不行,用kmeans重新聚类锚框:python utils/autoanchor.py --data corn_leaf_defect/data.yaml --img 640。单类别下锚框数量可以适当减少,比如从 9 个降到 6 个。
5.5 现象:验证集指标波动大,每次跑结果不一样
原因:单类别数据集样本量小,随机划分验证集时如果某类难样本恰好分到验证集,指标就会掉。另外--seed没固定,数据加载顺序每次不同。
解决:固定随机种子--seed 42,并且用分层抽样划分训练验证集,确保缺陷程度分布一致。如果数据集本身小于 500 张,建议用交叉验证而不是单次划分。
6. 单类别检测的进阶技巧:从能跑到好用
单类别目标检测的进阶方向不是换更大的模型,而是把数据质量和后处理做细。第一个技巧是难例挖掘:用训练好的模型在训练集上跑推理,把置信度在 0.1~0.3 之间的预测框对应的图像挑出来,人工复核。这些是模型「犹豫」的样本,重新标注后加入训练集,通常能带来 3~5 个点的 mAP 提升。第二个技巧是测试时增强(TTA):在detect.py里加--augment,对图像做翻转、缩放后分别推理再融合,单类别下能提升召回率,但速度会慢 2~3 倍,适合离线批量处理。
第三个技巧是锚框定制。YOLOv5 默认锚框是基于 COCO 的,玉米叶片缺陷的宽高比和 COCO 目标差异大。用autoanchor重新聚类后,把结果写回data/hyps/hyp_corn.yaml的anchors字段。我一般会跑三次autoanchor,取best possible recall最高的那组。第四个技巧是推理时的conf-thres和iou-thres联合调参:在验证集上跑一个网格搜索,conf从 0.1 到 0.5 步长 0.05,iou从 0.3 到 0.6 步长 0.05,找 F1 最高的组合。这个组合往往和默认值差很远,单类别下conf通常要降到 0.15~0.2 才能召回小病斑。
最后一个习惯:每次改完数据或超参数,先跑 10 个 epoch 看 loss 曲线,不要直接跑 200 轮。单类别数据集小,10 轮就能看出趋势,省下的时间用来检查标签质量。我踩过最大的坑就是标签里混了 30 张图把正常叶片标成了缺陷,导致模型上线后误检率 40%,回头查了两天才定位到。数据干净比模型大小重要得多。希望帮到你。
本文还有配套的精品资源,点击获取