简介:一套面向甘蔗病害识别场景的YOLO格式目标检测数据集,包含约3,300张已标注图片,覆盖健康、黄叶病、锈病等4个类别,适合计算机视觉学习者和农业智能化研究人员进行模型训练。数据集已完成训练集、验证集、测试集划分,附带show可视化脚本,可方便查看标注与图片对应效果。压缩包共2,000个文件,以jpg图像和txt标注文件为主(1,679个标签、320张图片,另有1个Python脚本),大小约68.58MB,目录结构清晰。已有148人学习下载。搭配作者博客中的YOLOv5改进实战专栏,可了解从数据准备到模型改进检测的完整流程;样本包含锈病、黄叶病等典型症状的田间实拍图,特别适合迁移学习、病害识别等方向的实验与评估。
1. 甘蔗病害目标检测:3300 张 YOLO 标注图值不值得当成训练底子
做甘蔗病害目标检测,最卡人的往往不是模型,而是标注数据。手里这份约 3300 张已标注的甘蔗病害图像,是 YOLO 格式的现成训练底子,解压后直接喂给 YOLOv8 就能训练,不用下田采集,也不用人工框标。对想快速出病害检测原型、又不想把两周时间耗在标框上的团队来说,省掉的正是最枯燥的那段活。
它的价值边界也要说透:3300 张属于中小规模,能撑起可演示、可调优的检测模型,但别指望一步覆盖所有田间光照和病害阶段。我一般拿它做基座数据,先跑通流程拿到基线,再叠加实地采集的样本迭代。适合智慧农业算法工程师、农业院校病虫害课题组,以及想评估甘蔗病害检测落地可行性的产品负责人。
2. 把标注格式看得明明白白:YOLO txt 坐标、目录结构与 data.yaml 的匹配规则
YOLO 标注格式看着简单,就一个 txt 文件几行数字,但坑全藏在约定里。下面先把格式拆开讲清楚,再给一套拿到数据后必做的体检流程。别急着开训,先花十几分钟确认这份标注能被框架正确读进去,后面省的调试时间远超过这个投入。
2.1 一张图对应一个同名 txt:类别 id 与归一化坐标的换算逻辑
YOLO 检测格式的核心约定:每张图像对应一个同名文本文件。图像是 IMG_0012.jpg,同目录或对应 labels 目录下就有 IMG_0012.txt,basename 必须一致。txt 每行代表一个目标框:
0 0.3125 0.4167 0.2083 0.2778 1 0.1234 0.5678 0.0456 0.0890 0 0.7521 0.1833 0.0984 0.1120一行五个值:类别 id(从 0 开始)加四个归一化坐标 x_center、y_center、width、height。三个容易忽略的点。第一,坐标是除以图像宽高后的比例,范围必须在 [0,1],否则训练 loss 直接出 NaN,这是后面要展开的第一个大坑。第二,中心点和宽高都是归一化后的,想还原像素位置要按原图尺寸换算。第三,类别 id 的顺序以数据包自带的 classes.txt 或 data.yaml 的 names 列表为准,排在 index 0 的就是 0,凭感觉猜会错位。
换算逻辑不难:原图 1920x1080,人工框了一个左上角 (400,300)、右下角 (800,600) 的像素框,cx=(400+800)/2/1920=0.3125,cy=(300+600)/2/1080=0.4167,w=(800-400)/1920=0.2083,h=(600-300)/1080=0.2778。如果这份数据是用 LabelImg 或 X-AnyLabeling 导出 YOLO 格式,坐标通常已经归一化;如果是从 VOC 的 xml 自转的,转换脚本里最容易忘的就是除以宽高,坐标全变成像素值,后面第 4 章专门讲。
2.2 目录组织方式:images/labels 分置与 data.yaml 三个关键字段
单个 txt 看懂只是第一步,框架是按目录约定读数据的。常见做法是 images 和 labels 平行,各自分 train、val、test:
sugarcane_disease/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamltrain/val/test 的划分比例看数据包自带情况。有的包给好了三份目录,有的只给全部图像和标签,需要自己按约 8:1:1 划分。我习惯划分前先按类别分布做分层抽样,避免某个病害类别全被分进 val,那样验证集会失真。labels 目录和 images 目录要保持同名结构,Ultralytics 读 train 图像目录时会自动把路径里的 images 换成 labels 去定位 txt,目录名改乱会报 label not found。
data.yaml 是训练入口,Ultralytics 靠它定位数据和类别。三个关键字段:
train: ./images/train val: ./images/val test: ./images/test nc: 5 names: 0: red_rot 1: smut 2: white_leaf 3: mosaic 4: brown_stripenames 里的类别名我只列了甘蔗病害里最常见的几种做示意(赤腐、黑穗、白叶、花叶、褐条),实际命名以你手里包的 classes.txt 为准。nc 必须和 names 长度一致,也必须和 txt 里出现的最大类别 id +1 一致,三者对不上训练到一半就会报 index out of range。
注意:路径用相对路径时,data.yaml 和 images、labels 的相对位置不能乱动;如果把 data.yaml 挪到别处,要么改用绝对路径,要么用
path:字段指定数据集根目录。
2.3 拿到数据先做四步体检:哪些问题必须在下刀前处理
我拆过不少标注包,经验是拿到手先跑一遍体检脚本,把格式问题消灭在训练之前。四步:数量核对、坐标边界、空标签、可视化抽检。前三步用一段脚本搞定:
from pathlib import Path img_dir = Path('images/train') lbl_dir = Path('labels/train') imgs = sorted(list(img_dir.glob('*.jpg')) + list(img_dir.glob('*.png'))) txts = sorted(lbl_dir.glob('*.txt')) img_names = {p.stem for p in imgs} txt_names = {p.stem for p in txts} print(f'images={len(imgs)} labels={len(txts)}') print('missing_label:', len(img_names - txt_names)) print('orphan_label:', len(txt_names - img_names)) oob, empty = 0, 0 for t in txts: lines = [ln.split() for ln in t.read_text().splitlines() if ln.strip()] if not lines: empty += 1 for ln in lines: vals = list(map(float, ln[1:5])) if any(v < 0 or v > 1 for v in vals): oob += 1 print(f'oob_boxes={oob} empty_txts={empty}')输出三组关键信息:图像与标签数量差、越界框数量、空标签数量。missing_label 不为 0 说明有图没标,训练会跳过但浪费样本;orphan_label 不为 0 说明有多余 txt,多半是标注工具残留。oob 只要大于 0 就必须修,否则训练 loss 出 NaN 或 mAP 永远上不去。empty 的 txt 要区别对待:放进 val 可以当背景负样本检验误报,放进 train 会让模型在这张图上学“什么都不输出”,量少没事,多了直接拉低召回。
可视化抽检我用 ImageDraw 或 OpenCV 把框画回图上,随机抽 60 张,重点看三类样本:病斑边缘不清晰的、互相遮挡的、尺寸很小的目标。框偏离病斑边缘超过半个病斑的样本占比大于 5%,这份标注就得先修再训,这个投入比训练十轮后发现效果不对再回头,便宜得多。
3. 用这份数据训练 YOLOv8 模型:环境配置、训练命令与指标判读
格式体检过了、目录结构摆好了,就可以让这 3300 张标注真正发挥作用。下面从环境安装一路走到推理验证,每一步给出可直接复制的命令,并解释为什么这么设。
3.1 环境准备:ultralytics 安装与预训练权重选型
训练 YOLOv8 最少只需要 ultralytics 一个库,它会连带装好 PyTorch。Python 建议 3.9-3.11,PyTorch 2.x 起步。CPU 也能训,但 3300 张图 imgsz=640 训 100 轮要十几个小时,有 NVIDIA 显卡务必装 CUDA 版,装完先验证:
pip install ultralytics python -c "import torch; print(torch.cuda.is_available())"返回 True 才继续。模型选型上,甘蔗病斑在整幅田间图里经常只占很小面积,属于小目标为主的任务。我一般用 yolov8s 起步:yolov8n 对极小目标漏检严重,yolov8m 以上在 3300 张规模下容易过拟合,s 是性价比平衡点。显存只有 4-6G 就退回 n 或把 imgsz 降到 512。预训练权重直接用官方 yolov8s.pt,它在 COCO 上学到的纹理和边缘表征对病害识别是有迁移价值的,比从零训练收敛快得多。
3.2 训练命令逐行拆解:epochs、imgsz、batch 的取值逻辑
命令行标准写法:
yolo task=detect mode=train \ model=yolov8s.pt \ data=sugarcane_disease.yaml \ epochs=120 imgsz=640 batch=16 \ patience=20 workers=4 device=0| 参数 | 建议值 | 取值逻辑 |
|---|---|---|
| model | yolov8s.pt | 用 COCO 预训练权重做起点,不是从零建模型 |
| imgsz | 640 | 甘蔗病斑小,640 是底线,降到 512 会明显掉小目标精度 |
| batch | 16 | 看显存,显存不够降到 8 或 4,同时拉长 epochs 补偿梯度噪声 |
| epochs | 120 | 3300 张配 batch16 约 200 step/轮,120 轮足够配合早停收敛 |
| patience | 20 | 验证集 mAP 连续 20 轮不涨就停 |
| workers | 4 | Windows 上建议 0-2,防 DataLoader 报错 |
等价 Python 写法便于在训练前后插入自定义逻辑:
from ultralytics import YOLO model = YOLO('yolov8s.pt') model.train( data='sugarcane_disease.yaml', epochs=120, imgsz=640, batch=16, patience=20, workers=4, device=0, project='runs/sugarcane', name='exp1' )epochs 别盲目设大。300 轮但 patience 设大了,只会把时间浪费在过拟合后的指标震荡上。早停的意义在于:验证集指标连续不涨时自动截断,把剩下的时间留给调参而不是空转。
3.3 训练过程看什么指标:损失曲线、mAP50 与 mAP50-95
训练开始后终端每轮打印一列指标,关键四列是 box_loss、cls_loss、mAP50、mAP50-95。box_loss 和 cls_loss 持续下降说明模型在正常学习;如果某轮后 loss 开始反弹而 mAP 不再涨,过拟合开始了,早停会在附近截断。
mAP50 是 IoU 阈值 0.5 下的平均精度,回答“框大概框中了没有”。病害检测以发现为目标,mAP50 是核心指标。mAP50-95 把 IoU 从 0.5 到 0.95 平均,对框的精确位置更敏感。甘蔗病斑边界天然模糊,mAP50-95 通常比通用数据集低一截,不用慌。我自己的参照线:mAP50 在 0.75 以上、mAP50-95 在 0.45 以上,这个模型就有田间试运行的价值;如果 mAP50 不到 0.6,先回看标注质量而不是急着调参。
训练结束在 runs/sugarcane/exp1/weights/ 下生成 best.pt 和 last.pt。best.pt 是验证集最优权重,后续推理、部署都用它。results.png 里是 loss 和 PR 曲线的汇总,建议每条都扫一眼;PR 曲线右下角明显塌陷,说明召回差,对应漏检多,要去补小目标和遮挡样本。
3.4 一次推理验证:把权重跑到真实图片上
指标抽象,把检测框画到图上才直观:
from ultralytics import YOLO model = YOLO('runs/sugarcane/exp1/weights/best.pt') results = model.predict( source='field_test/', # 目录、单张图或视频都行 conf=0.30, # 置信度阈值,病害场景 0.25-0.35 是安全区间 imgsz=640, save=True, save_txt=True )conf 设 0.30 是平衡点:太低会把健康叶片的纹理误报成病害,太高会漏掉早期小病斑。结果在 runs/detect/predict/ 下。这一步不只看效果,也是评估标注质量的反馈回路:如果推理框明显比标注框大一圈,或同一目标框的位置反复晃,说明这个类别的标注本身不一致,回头修标注比加数据更划算。
4. 避坑指南:甘蔗病害标注数据最常见的五个翻车现场
这章是拆数据包、跑训练踩出来的记录,每条按现象、原因、解决展开,复现时遇到同类问题直接照方抓药。
4.1 标签坐标越界:训练 loss 直接爆成 NaN
现象:训练到第 2-5 轮,box_loss 突然变成 nan,之后所有指标全是 nan,训练中止。原因:txt 里有框的归一化坐标大于 1,最常见的来源是 VOC 转 YOLO 时忘了除以图像宽高。比如原图 1920 宽,框宽 800 像素,转换后直接写成 800 而不是 0.4167。解决:用 2.3 节的体检脚本定位越界文件,逐个框重新归一化;如果是整批转换出错,回到转换脚本补上除以宽高的逻辑重新生成所有标签,别在单个文件上打补丁。
4.2 类别 id 错位:模型把黑穗病认成赤腐病
现象:训练 loss 正常、mAP 也正常,但推理结果张冠李戴,某些类别被稳定地认成另一个。原因:data.yaml 的 names 顺序和导出标注时用的顺序不一致,txt 里第一列写 0,data.yaml 说 0 是赤腐病,实际标注时 0 指的是黑穗病。解决:训练前随机开几个 txt,和包内 classes.txt 或 data.yaml 逐个 id 核对。顺序错了就写脚本做 id 映射,改 txt 或改 data.yaml 二选一,改完重跑体检脚本确认没有越界 id。
4.3 空标签图片混进训练集:验证 mAP 虚高,真实场景误报爆炸
现象:val mAP 高得离谱,但换到真实田块推理,误报率完全不能接受。原因:数据包里“有图无框”的干净样本被分进了 val,模型只要学“什么都不检测”就能拿高分,验证指标完全失真。解决:先把空标签 txt 单独筛出来。数量不大,统一放到 val 当负样本,注意这会略微拉低真实场景的置信度;数量很大,说明采样阶段把健康田块成片拍进来了,这类负样本应该少量均匀撒进 train 和 val,而不是堆成一堆。
4.4 小目标病斑漏检:imgsz 和最小框不匹配
现象:mAP50 能看,recall 在 0.3 附近,早期小病斑大面积漏检。原因:病斑在 1920x1080 原图里可能只有 30x30 像素,resize 到 640 后只剩 10x10,特征几乎被压没。YOLOv8 对极小目标本来就是弱项。解决:第一,imgsz 提到 768 或 896,显存够就上 896,小目标召回会明显回升;第二,统计所有标注框的面积分布,如果大量框小于最终输入尺寸的 3%,考虑切片推理,切块检测再合并结果;第三,把小目标样本单独过采样,这个放到第 5 章。
4.5 数据增强把病斑颜色洗没了
现象:训练集 mAP 正常,验证集和真实场景都掉点,尤其红褐色病斑几乎失明。原因:Ultralytics 默认开 hsv_h、hsv_s、hsv_v 颜色增强,色相偏移过大会把赤腐病的红棕洗成健康绿,模型学到的是增强后的伪分布。解决:训练参数里收窄颜色增强幅度。病害这类颜色敏感任务,我一般用 hsv_h=0.01、hsv_s=0.3、hsv_v=0.3,保留几何增强。调完看 runs 下 train_batch*.jpg 的增强预览图,确认病斑颜色没有被破坏再开训。
5. 把 3300 张标出上万张的效果:类别不均衡、数据增强与迁移学习
数据量就这么多,想再上一个台阶得从数据利用效率下手。下面讲三件事:盘类别家底、增强怎么不伤病害特征、迁移学习怎么用才划算。
5.1 先做类别分布统计,再决定要不要调 loss
训练前把每个类别的框数量盘一下:
from collections import Counter from pathlib import Path counts = Counter() for t in Path('labels/train').glob('*.txt'): for ln in t.read_text().splitlines(): if ln.strip(): counts[int(ln.split()[0])] += 1 print(dict(sorted(counts.items())))输出形如 {0: 1800, 1: 620, 2: 380, 3: 145, 4: 95},具体数值以你拿到的包为准。对照 data.yaml 的 names 就能看出哪个类别框数明显偏少。甘蔗病害数据常见的失衡是某一种高发病害占了大半,另一种早期症状只有几十框。我的处理分三档:框数中等偏少,过采样该类图片就够,不用动 loss;框数特别少(少于一百框),先查标注质量,再看有没有同源数据可补,硬训只会让模型把它学成噪声;整体失衡但每类都过百框,可以调 cls_loss 权重,但实际经验是过采样和增强更可控、更直观。
过采样的实现很简单:把稀有类别的图片连同标签复制一份进训练目录。注意 YOLO 不会自动去重,同一个文件名的两次出现以最后一次读取为准,所以复制后要把文件名改掉,比如加 _dup 后缀。这样做比调 loss 权重直接,因为模型确实多看了这些样本。
5.2 增强策略要贴着甘蔗病害的物理特征来
增强不是越多越好,要让模型看到真实田间会出现的变化。甘蔗病害检测有三类增强是安全的:几何类(旋转正负 15 度以内、平移、缩放、翻转),模拟拍摄角度变化;亮度对比度扰动,模拟早中晚光照差异;高斯噪声和模糊,模拟手机对焦不准。要极其小心的是颜色偏移,甘蔗病害诊断往往就靠颜色,红棕的赤腐、黑色的黑穗、黄化的花叶,色相偏移等于把诊断依据抹掉。
实操直接在训练参数里指定强度:
model.train( data='sugarcane_disease.yaml', epochs=150, imgsz=640, batch=16, hsv_h=0.01, hsv_s=0.3, hsv_v=0.3, degrees=10, translate=0.1, scale=0.4, fliplr=0.5, mosaic=1.0 )degrees 设 10 而不是更大,因为甘蔗叶片是长条状,旋转角度太大会生成田间不存在的朝向,模型会把朝向当成特征去学,换场景就崩。mosaic 拼接增强保留默认,它能让模型在遮挡和小目标上更鲁棒。核心权衡只有一句话:几何和光照增强可以放开,颜色与形态相关的增强必须克制,这是病害检测和通用目标检测最大的区别。
5.3 迁移学习:预训练权重和冻结骨干的正确节奏
3300 张属于小数据集,从零训练容易过拟合,正确做法是从 COCO 预训练权重起步。加载 yolov8s.pt 时框架会自动替换最后的检测头,保留骨干特征提取能力。这里有个节奏问题,我一般前 30 轮冻结骨干只训检测头,让头先学会用现有纹理特征输出病害框;30 轮后解冻全部参数,用更小学习率微调骨干。冻结骨干能防止梯度噪音在小数据集上扰动骨干,训练更稳,速度也更快。
# 第一阶段:冻结骨干,只训检测头 model = YOLO('yolov8s.pt') model.train(data='sugarcane_disease.yaml', epochs=30, freeze=10, ...) # 第二阶段:解冻微调 model = YOLO('runs/sugarcane/exp1/weights/best.pt') model.train(data='sugarcane_disease.yaml', epochs=120, lr0=0.001, ...)freeze=10 表示冻结前 10 层骨干。想确认到底冻了哪些层,加载模型后打印 model.model 结构,对照参数名看骨干范围;不同 YOLOv8 版本的层数命名略有差异,以你装的版本为准。显存小的时候冻结骨干还有个附带好处:梯度不需要回传骨干,显存占用明显下降,batch 可以适当加大。解冻阶段把初始学习率从 0.01 降到 0.001,否则骨干在微调初期被大步长扰动,loss 会反弹。整个策略的目标是:保持 COCO 学到的通用特征,同时尽可能拟合甘蔗病害的纹理和边缘。
6. 验证别只信指标:野外复现、混淆矩阵与一个收敛习惯
训练跑完只是开始,真实病害检测在田里,不在验证集上。最后给三个验证与调试的习惯,我每次都会强制走一遍。
6.1 野外复现测试与混淆矩阵
权重落地的第一关是换场景。我习惯拿手机在田间、温室、实验室各拍三五十张,覆盖晴天正午、阴天、傍晚三种光照,直接喂给 best.pt。这一步暴露两类问题:正午强光把浅色病斑洗白,模型漏检;低照度下绿色通道噪声放大,误报上升。对应解法是回训练数据补对应光照的样本,或加强亮度扰动重训。
第二关看混淆矩阵。训练生成的 confusion_matrix.png 里对角线以外的值就是混淆对,甘蔗病害里最经典的组合是赤腐病初期和褐条病,颜色纹理都接近。如果某对类别混淆率超过 5%,先别急着加数据,回看这两类的标注是不是早期样本标混了,标注噪声是混淆矩阵异常的常见元凶,修标注比加数据便宜得多。
6.2 一个收敛习惯:先体检、后冻结、再看矩阵
我拆标注数据包有个固定习惯。第一步永远是体检脚本,确认格式、坐标、类别映射干净;第二步永远是冻结骨干跑 30 轮拿一个不震荡的基线;第三步才是全量微调和野外复现。这三步走完,再考虑数据增强、类别权重这些精细化手段。
这一套流程走下来,3300 张标注数据的价值能榨到八九成,剩下那部分要靠你自己下田补拍的实地样本来填,这也是模型真正落地必须走的路。拿到这份数据后,直接按第 3 章的流程跑一个基线,再按第 4 章排查、按第 5 章提精度——数据是死的,流程是活的,希望帮到你。
本文还有配套的精品资源,点击获取