
简介这份菲律宾水稻褐飞虱成虫目标检测数据集是一套面向农业AI与植保应用的专业标注数据集适合智能农业监测系统开发、精准植保决策支持及农业院校教学研究。资源合计1458张真实农田采集的水稻现场图片其中训练集941张、验证集304张、测试集213张以YOLO格式进行边界框与类别标注聚焦褐飞虱成虫这一主要水稻害虫目标标注经农业专家校验可直接适配主流目标检测框架。压缩包共2000个文件以txt标注文件与jpg现场图片为主体另含yaml配置与docx说明文档包体56.36MB整体紧凑且分层清晰便于按训练、验证、测试分工直接使用。数据覆盖水稻生长周期不同阶段真实呈现光照变化、植株遮挡等复杂田间条件聚焦褐飞虱防治关键痛点为害虫自动识别模型训练、田间实时监测与预警系统落地提供有力支撑已有197人学习适合需要快速构建水稻害虫检测模型的AI工程师与农业科研人员。1. 稻田里的虫子比检测框更会躲1,458 张褐飞虱目标检测数据集值不值得下做农业视觉的朋友大概率都有过这种体验公开数据集里干净背景的猫猫狗狗一大堆真到了田间地头水稻叶片互相遮挡、阳光忽明忽暗、虫子小得跟米粒似的预训练模型直接翻车。所以我看到这份「菲律宾水稻褐飞虱成虫目标检测数据集」的第一反应是总算有份贴近实战的农牧业目标检测数据集了。它一共 1,458 张真实农田现场图片训练集 941 张、验证集 304 张、测试集 213 张全部是 YOLO 格式的 txt 标注类别只有一种——褐飞虱成虫。类别单一这件事看着简单其实恰恰把问题聚焦在「小目标 复杂背景」这个真正的难点上。适合谁用呢想拿真实农业数据练手的目标检测初学者、正在做田间虫害监测系统的开发者以及需要标准化数据做算法验证的研究人员。如果你手头的项目正好卡在「有 GPU 没数据」这份资源值得先拆开看个仔细。2. 拆开 YOLO 数据集目录结构、标注解析与训练前合规检查2.1 拿到压缩包先做三件事核对文件、看目录、确认同名我刚拿到这份数据集时压缩包里是一堆形如01758_jpg.rf.e7169bd54d4777d1e5ab942ba0afc004.jpg的长文件名图片外加一份文档并没有看到规整的images/train和labels/train目录。这种情况在从标注平台导出的数据集里非常常见文件名里那串哈希是平台自动生成的唯一 ID图片和标签靠这个名字一一对应。所以第一步不是急着训练而是把所有图片和同名 txt 按训练、验证、测试三个集合归位。常见做法是写个小脚本扫描目录按文档记录的划分比例941/304/213把图片分到三个目录同时把对应标签也拷贝过去。需要特别注意的是如果压缩包里图片和标签混在一起千万不能在移动时丢标签否则后面训练时 YOLO 会报image not found或label not found。我一般会先跑一遍统计命令确认三类文件数量对得上。# 假设图片都在当前目录txt 也混在其中 mkdir -p datasets/bph/{images/{train,val,test},labels/{train,val,test}} # 按文件名前缀分配图片 # 先将你手里的划分名单train.txt / val.txt / test.txt准备好 while read line; do img${line}.jpg txt${line}.txt mv $img datasets/bph/images/train/ mv $txt datasets/bph/labels/train/ done train.txt这里train.txt里每一行是不带后缀的文件名主名也就是那一长串01758_jpg.rf.e7169bd54d4777d1e5ab942ba0afc004。mv前建议先跑一条ls | wc -l确认文件总数免得移动过程中被 shell 通配符坑掉。划分文件一般从数据集的文档里可以提取出来如果文档只给了比例那你需要按比例随机抽取务必固定随机种子保证每次复现结果一致。2.2 看懂那一行 YOLO 标注归一化坐标与边界框验证YOLO 格式的 txt 每一行是class_id x_center y_center width height所有值都相对于图片宽高做了归一化。这份数据集只有褐飞虱成虫一个类别所以 class_id 恒为 0。但正因为只有一个类很多人容易忽略坐标值的正确性直接拿去训练结果 loss 下降挺好一推理全框在背景上。拿到数据后先挑几张图解析标注看看框的位置是否符合直觉。我用下面这段 Python 把归一化坐标转回像素坐标并在原图上画出框来做人工目检import cv2 import numpy as np img_path datasets/bph/images/train/01758_jpg.rf.e7169bd54d4777d1e5ab942ba0afc004.jpg label_path datasets/bph/labels/train/01758_jpg.rf.e7169bd54d4777d1e5ab942ba0afc004.txt img cv2.imread(img_path) h, w img.shape[:2] with open(label_path, r) as f: for line in f: cls, cx, cy, bw, bh map(float, line.split()) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(check_bbox.jpg, img)这段代码的关键是把归一化值乘回图片宽高并减去半宽半高得到左上角坐标。画完框之后建议连续看几十张图重点观察两个问题第一框是否紧贴虫子身体而不是把整片叶子包进去第二是否存在漏标——画面里明显有虫子但没有任何框。这一步做扎实后面训练可以省掉大量排查时间。常见情况是数据集中存在少量坐标越界比如 x1 小于 0 或 x2 大于 w遇到这种标签后处理时需要截断到图像边界。2.3 训练前清洗剔除坏图、无标注图和重复图田间现场拍摄的照片不像互联网爬图那样干净很可能会出现少量无法解码的损坏文件、全黑过曝的废图以及因为平台同步原因产生的重复图片。YOLO 训练时遇到 OpenCV 读不出来的图会直接报CV_RGB相关异常轻则跳过这张图重则中断训练进程。所以训练前做一次清洗脚本是值得的。import os from PIL import Image img_dir datasets/bph/images/train label_dir datasets/bph/labels/train bad_imgs [] no_label [] for name in os.listdir(img_dir): base name.split(.)[0] img_path os.path.join(img_dir, name) label_path os.path.join(label_dir, base .txt) try: with Image.open(img_path) as im: im.load() except Exception: bad_imgs.append(name) continue if not os.path.exists(label_path) or os.path.getsize(label_path) 0: no_label.append(name) print(损坏图片数量:, len(bad_imgs)) print(缺失/空标签数量:, len(no_label)) # 有问题的文件移动到 backup 目录避免在原目录删除 for name in bad_imgs no_label: os.rename( os.path.join(img_dir, name), os.path.join(backup, name) )这里用 PIL 做解码校验因为它对损坏文件的识别比 OpenCV 更敏感。缺失标签和空标签要区分对待空标签文件可能是标注时确实没有虫子的负样本也可能是导出失败。对单类别数据集来说我建议把空标签的图片也移走因为纯背景图在训练里容易变成“预测哪里有虫”的噪声如果要做负样本增强应该单独建一个背景图目录而不是混在训练集里。这个步骤看起来不起眼但它直接决定你后面训练能不能一次跑通。3. 用 YOLOv8 复现训练模型选型、data.yaml 配置与超参调整3.1 模型选型为什么这份数据用 n 或 s 版本更合适数据集类别只有一个目标数量在画面里通常不多但虫子本身很小所以模型的选择要在“小目标检测能力”和“过拟合风险”之间平衡。YOLOv8 系列从 n 到 x 参数量递增对这份 1,458 张图的小数据集来说直接上 YOLOv8x 很容易过拟合训练速度慢且效果不见得好。我一般会先跑 YOLOv8n 和 YOLOv8s 各一次用验证集比较后再决定最终模型。为了更直观列出常见选型的相对差异模型版本参数量级推理速度小目标表现这份数据上的适用性YOLOv8n最小最快一般先用它建立基线YOLOv8s偏小快中等偏上推荐主力训练版本YOLOv8m中等中等较好数据量不足时容易过拟合YOLOv8l/x大慢好不推荐除非做迁移学习选择 n 或 s 的另一个原因是嵌入式部署。田间监测设备大多是边缘计算盒子或 Jetson 系列模型尺寸直接决定推理帧率训练出来的模型最终要落到设备上选 n/s 版本从源头控制了部署成本。如果你只有 CPU 环境n 版本也能完成验证流程只是每轮训练会比 GPU 慢很多。3.2 写 data.yaml 并启动第一次训练YOLOv8 需要一份data.yaml告诉框架图片路径、标签路径和类别列表。这里最容易翻车的是路径写成绝对路径换机器后直接失效。我习惯把整个数据集目录结构固定下来然后在命令里直接传数据集根目录相对位置。# datasets/bph/bph.yaml path: ./datasets/bph train: images/train val: images/val test: images/test nc: 1 names: 0: brown_planthopper_adult这份配置里path使用相对路径前提是你从项目根目录执行训练命令。nc: 1表示只有一个类别names里的名称会显示在推理结果上。如果压缩包的文档里没有给出类别映射你需要自己确认标注文件中 class_id 是不是从 0 开始。很多标注平台默认从 0 开始但遇到从 1 开始的导出版本不处理的话训练会报class index out of range。启动训练的命令如下yolo detect train \ modelyolov8s.pt \ datadatasets/bph/bph.yaml \ imgsz640 \ epochs80 \ batch16 \ projectruns/bph \ nameexp01modelyolov8s.pt会加载 COCO 预训练权重对这份数据很重要——1,458 张图从头训练很难收敛迁移学习能显著缩短训练时间。imgsz640是常规输入尺寸如果发现框偏小可以试imgsz960代价是显存占用和训练时间同步上升。epochs80对单类别小数据集够用我试过跑到 120 轮后面的提升很微弱。batch16取决于 GPU 显存6GB 显存跑 s 版没问题如果显存不够就降到 8。第一次训练建议把save_period参数加上每 10 轮存一个检查点防止后期过拟合时想回退却没权重可用。3.3 超参调整的两个方向多尺度与类别权重训练开始后很多人只盯 loss 曲线但单类别数据集的 loss 很容易“原地踏步”。第一次跑通后优先调两件事输入分辨率和数据增强强度。针对小目标最直接的手段是开启多尺度训练。YOLOv8 的mosaic增强默认开启它对小目标有正面帮助但在田间场景下4 张图拼接会让一半目标被裁剪掉。常见的做法是把mosaic在前 10 轮关闭后面再开或者直接固定mosaic0.5降低拼接概率。另一个改动是scale参数YOLO 默认在每轮迭代中会随机缩放输入图片把scale从默认值调大到 0.9可以让模型更多看到不同大小的虫子。yolo detect train \ modelyolov8s.pt \ datadatasets/bph/bph.yaml \ imgsz640 \ epochs80 \ batch16 \ mosaic0.5 \ scale0.9 \ fliplr0.0 \ projectruns/bph \ nameexp02这里fliplr0.0是我在农业场景下的习惯——左右翻转对虫子检测本身没影响但会让模型对叶片朝向的适应性变差。菲律宾稻田的光照条件跟国内有差异颜色分布也不一样所以hsv_h、hsv_s这类颜色增强参数建议保持默认不要用力过猛。跑完 exp01 和 exp02 后对比验证集的 mAP50 和 mAP50-95优先选高者但如果两者差距不到 1%选推理速度更快的那个留给部署余量。4. 避坑指南训练褐飞虱数据集最容易翻车的五个环节4.1 标签路径错位导致训练时 label 全部丢失现象训练启动时报WARNING: no labels found in ...loss 一直不降验证集的 PR 曲线完全不对。原因图片名和 txt 名的前缀不一致。数据集的图片名是一长串带.jpg的文件名但某些 txt 文件名可能因为平台导出问题多了一个后缀或少了.rf那一段。YOLO 按同名匹配图片和标签前缀对不上就找不到标签。解决训练前写脚本把每张图片对应的 txt 存在与否查一遍。我在 2.3 节已经给了检查代码这里再强调检查维度不只是在不在还要打开看行数是否为 0。文件名匹配这种问题最好的预防措施是在划分目录时统一用图片名作为唯一主键txt 全部按图片主名.txt重命名。4.2 类别编号从 1 开始导致数组越界现象训练日志里出现IndexError: index 1 is out of bounds for axis 0 with size 1进程直接崩溃。原因这份数据集标注里 category_id 写的是 1而不是 0。YOLO 的 class_id 只能是[0, nc-1]单类别时只能是 0。解决批量替换 txt 里的行首数字。写一个循环处理所有 txt 文件把每行第一个数字改成 0。注意不要用全局字符串替换那样会把边界框坐标值里的数字也改了。安全做法是按空格分割后只改第一段。4.3 稻田背光和叶片遮挡让目标框严重偏移现象训练时 loss 正常验证集 mAP50 也不错但打开推理结果一看很多框框在叶子上虫子的边缘根本没贴合。原因数据集里大量图片是在强阳光下拍摄的虫子背部反光与叶片颜色接近标注人员在勾框时会多包进一些叶片区域。YOLO 学到的不是“虫子”而是“叶片上的高光区域”。解决把置信度阈值调低后逐张查看置信度在 0.3~0.5 之间的预测框重点观察误检是不是集中在背光的叶片上。如果是考虑用 CLAHE 对图片做对比度增强或者训练时把hsv_s增强加大迫使模型关注形状特征而不是颜色。这类问题很难完全消除能接受的做法是部署时加一个位置约束框的中心点必须在叶子主脉附近。这个后处理逻辑在完成后我会在代码里跑一遍。4.4 验证集图片在训练集中重复出现现象训练集 loss 下降很稳验证集 mAP50 高得离谱但测试集上表现崩了。原因数据划分时没有做去重。同一个场景连续拍的几张照片可能一张被分到训练集另一张进了验证集本质上是数据泄露。解决用图片的感知哈希做一次去重。常见做法是计算每张图的 pHash 值两两比较汉明距离距离小于阈值的图片归为一组只保留一组内的其中一张。这个步骤在训练前做比较费时间但对只有 1,458 张图的数据集来说几分钟就能跑完。另外还有一种更隐蔽的重复不同文件名但像素完全相同的图片用md5sum也可以查出来。4.5 显存溢出和训练中断后没有后悔药现象训练到第 37 轮显存溢出直接退出从头再来又得 4 个小时。原因batch16在 8GB 显存机器上跑 YOLOv8s输入尺寸 640 时问题不大但一旦开了多尺度或把imgsz提到 960显存就会爆。解决训练命令里务必加save_period5并且开ampTrue混合精度训练。AMP 能降低约 30% 显存占用代价是略微损失精度对这份数据影响很小。我自己的习惯是每 10 轮保存一个检查点万一中途翻车用resumeTrue接着跑不用从头再来。这样看似多占了一点磁盘省下来的是反复调试的时间。5. 验证不只是看 mAP阈值选择与田间场景的漏检分析5.1 用验证集算出 PR 曲线和混淆矩阵训练完成后验证集上的 mAP50 只是第一个指标。褐飞虱检测的难点在于漏检——虫子比叶片上的斑点大不了多少模型很容易把真目标当作背景。所以在进入部署前我会跑一次带验证的推理输出 PR 曲线和混淆矩阵。yolo detect val \ modelruns/bph/exp02/weights/best.pt \ datadatasets/bph/bph.yaml \ imgsz640 \ conf0.25 \ iou0.5YOLOv8 会在runs/bph/exp02/下生成confusion_matrix.png和一系列曲线图。对单类别模型混淆矩阵就两行两列真正例和假正例。重点看假正例那一列如果大量预测框落在背景上问题不在阈值而在模型把叶片纹理当成了虫子。反过来说如果真正例那一行数值偏低比如只有 0.7 左右说明近三成的虫子完全没被框出来。这时候调阈值是无效的要回头查 4.3 节提到的遮挡问题。5.2 置信度阈值不是越高越好很多同学在验证后直接把置信度调到 0.5 去部署但在褐飞虱检测这种场景下高置信度阈值会牺牲大量被遮挡的目标。我的做法是跑一遍数据统计画一条置信度-召回率曲线看看阈值从 0.1 到 0.9 每档的召回变化。# VAL 结束后从 runs/bph/exp02/predictions.json 提取结果做阈值分析 import json with open(runs/bph/exp02/predictions.json) as f: preds json.load(f) for conf_thr in [0.1, 0.2, 0.3, 0.4, 0.5]: det_count 0 for p in preds: det_count sum(1 for d in p[boxes] if float(d[conf]) conf_thr) print(fconf{conf_thr}, total_detections{det_count})输出结果里检测数量从 0.1 到 0.5 之间的落差如果超过 40%说明模型的大部分预测都集中在低置信度区间这类低置信度框未必是错的很多是遮挡严重的真实目标。田间监测系统追求的是「宁可多框不可漏报」所以部署阈值我一般设在 0.25 左右然后通过后处理把明显重叠的框合并。这个思路与做 COCO 竞赛的思路相反提前想清楚场景需求能避免后期反复改阈值。5.3 针对小目标的专项验证按框面积分组看指标褐飞虱成虫在 640x640 分辨率下框面积通常只有几百到两千像素属于典型小目标。整体 mAP 高不代表小目标表现好所以我会把验证集的检测框按面积分三档看小于 32x32、32x32 到 96x96、大于 96x96。YOLOv8 的 val 模式不直接输出分组指标需要自己写后处理脚本从predictions.json里筛出小目标框和真值框做 IoU 匹配统计小目标一档的召回率。如果发现小目标档的召回率低于 0.5就回到训练侧改imgsz960或增加scale增强。这一步虽然多花半小时但能把“看起来能用”变成“确实能用”。6. 可视化排查与部署前检查把结果框印回原图三分钟分清好坏训练、验证都通过后我习惯写一个可视化脚本随机从测试集抽 50 张图把模型输出的框画在原图上带置信度一起存成 JPEG逐张翻看。这一个动作能发现所有指标看不出来的问题框偏移、重复框、置信度虚高、小目标漏检。直接贴代码这份逻辑在部署到边缘设备前基本就是最终推理流程的简化版。import cv2 from ultralytics import YOLO model YOLO(runs/bph/exp02/weights/best.pt) img cv2.imread(datasets/bph/images/test/07014_jpg.rf.d0573f6b4990a7e0f250741d1979c892.jpg) results model.predict(img, conf0.25, iou0.5) for r in results: for box in r.boxes: x1, y1, x2, y2 map(int, box.xyxy[0].tolist()) conf float(box.conf[0]) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, f{conf:.2f}, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) cv2.imwrite(visualize_result.jpg, img)这段代码里conf0.25是推理阈值iou0.5是 NMS 参数测试时如果发现同一只虫子上有两个重叠框就把 IoU 阈值调高到 0.6如果发现正对镜头的虫子被漏掉把置信度降到 0.2 再看。可视化检查也是和甲方或同事沟通的最直接方式——不需要解释 mAP 是什么一张图画几个框大家心里就有数了。从那以后我每次拿到一份农业目标检测数据集都强制自己先走一遍「拆包 → 看标注 → 清洗 → 训基线 → 避坑排查 → 可视化」这六步跑完才会开始调模型。这么做最大的好处是心里有底知道数据里的坑在哪儿训练中途遇到问题也不会慌。希望这份菲律宾褐飞虱数据集的拆解笔记能帮你少踩几个我踩过的坑把时间花在真正影响效果的事情上。本文还有配套的精品资源点击获取