ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

菲律宾水稻褐飞虱成虫目标检测数据集:从标签到YOLO训练完整落地路径

菲律宾水稻褐飞虱成虫目标检测数据集:从标签到YOLO训练完整落地路径 简介这份菲律宾水稻褐飞虱成虫目标检测数据集面向智能农业监测、精准植保与农业AI科研人员聚焦水稻主要害虫褐飞虱成虫的自动识别难题。数据采集自菲律宾真实稻田覆盖水稻不同生长阶段包含光照变化与植株遮挡等复杂田间场景共1458张现场图片按训练集941张、验证集304张、测试集213张划分标注为YOLO格式边界框与类别标签可直接接入主流目标检测框架训练与验证。资源包共2000个文件以1458个txt标注文件、540张jpg图像为主另附1个yaml数据配置与1份docx说明文档压缩包约56.36MB目录结构清晰便于快速上手。目前已有196人学习下载。借助该数据集读者可构建虫害实时监测预警模型为农药喷洒系统提供定位依据也可作为农业院校数字化教学素材辅助掌握害虫识别与田间诊断技能。1. 菲律宾水稻褐飞虱成虫目标检测数据集从标签到模型的完整落地路径拿到「菲律宾水稻褐飞虱成虫目标检测数据集.zip」这个标题很多人第一反应是解压、看一眼图片、然后直接丢进 YOLOv8 训练。我一开始也这么干过结果 mAP 卡在 0.4 上不去排查了两天才发现标注框大量重叠、成虫体长只有 2-3 毫米、单张图里虫口密度极高。这个数据集的核心价值在于它把「农业虫情监测」这个场景做成了可训练的目标检测任务——褐飞虱是水稻头号迁飞性害虫菲律宾作为东南亚水稻主产区其田间图像天然带有高密度、小目标、背景杂乱的特点。适合谁用做智慧农业落地的算法工程师、想拿真实农业数据练手目标检测的学生、以及需要评估小目标检测方案上限的研究者。这篇笔记按「数据集结构 → 格式转换 → 训练配置 → 避坑 → 进阶技巧」的顺序展开每一步都给出可复现的命令和参数。2. 拆解数据集目录结构、标注格式与类别分布2.1 解压后先看什么目录树与文件命名规律拿到压缩包后不要急着写训练脚本先花十分钟把目录结构摸清楚。常见做法是解压到独立目录用tree或find统计文件数量和类型。菲律宾水稻褐飞虱成虫数据集一般会包含images/、labels/、annotations/或classes.txt这几类文件命名上可能带ph_或bph_前缀。下面是我习惯用的统计命令# 解压到独立目录避免污染工作区 mkdir -p ~/datasets/bph_philippines cd ~/datasets/bph_philippines unzip ~/Downloads/菲律宾水稻褐飞虱成虫目标检测数据集.zip -d . # 统计图片数量、格式分布、总大小 find . -type f \( -iname *.jpg -o -iname *.png -o -iname *.jpeg \) | wc -l find . -type f \( -iname *.jpg -o -iname *.png \) -exec du -ch {} | tail -1 find . -type f -name *.txt | head -20 # 查看目录层级确认 images 和 labels 是否一一对应 tree -L 3 -d逻辑说明第一条命令建立独立工作目录避免后续脚本路径混乱第二条统计图片总数这个数字直接决定你后面划分训练集/验证集的比例是否合理第三条看标注文件命名如果 labels 目录下的 txt 文件名和 images 下的图片名完全一致仅扩展名不同说明是标准的 YOLO 格式第四条用tree看层级确认没有多余的嵌套目录。参数上-L 3限制显示三层-d只显示目录避免输出爆炸。如果发现图片分散在多个子目录比如按采集日期或地块分需要先合并到一个images/all/下同时把对应的 labels 也合并。这一步不做后面写 data.yaml 时路径会非常痛苦。2.2 标注格式判定YOLO txt、COCO json 还是 VOC xml农业虫情数据集常见的标注格式有三种YOLO 的归一化 txt、COCO 的 json、VOC 的 xml。判定方法很简单——打开一个标注文件看内容。如果是每行class_id x_center y_center width height且数值都在 0-1 之间就是 YOLO 格式如果是 json 且含images、annotations、categories三个顶层键就是 COCO如果看到bndbox标签就是 VOC。import json, os, glob def detect_annotation_format(root): # 优先找 txt txts glob.glob(os.path.join(root, **, *.txt), recursiveTrue) if txts: with open(txts[0]) as f: first f.readline().strip().split() if len(first) 5: try: vals [float(v) for v in first[1:]] if all(0 v 1 for v in vals): return YOLO except ValueError: pass # 找 json jsons glob.glob(os.path.join(root, **, *.json), recursiveTrue) for j in jsons: with open(j) as f: data json.load(f) if all(k in data for k in (images, annotations, categories)): return COCO # 找 xml xmls glob.glob(os.path.join(root, **, *.xml), recursiveTrue) if xmls: with open(xmls[0]) as f: if bndbox in f.read(): return VOC return UNKNOWN print(detect_annotation_format(.))逻辑说明先扫 txt因为 YOLO 格式最常见且解析最快如果 txt 存在但每行不是 5 列或数值超出 0-1就继续找 jsonjson 里检查三个关键键最后兜底找 xml。参数上recursiveTrue保证子目录也能扫到。这个函数返回结果后你就知道该用哪种转换脚本了。提示如果返回 UNKNOWN大概率是标注文件在压缩时被改了扩展名或者数据集本身只给了图片没给标注。后者的话这个数据集只能做无监督或自监督任务不能直接训目标检测。2.3 类别分布统计别让某一类把模型带偏褐飞虱成虫数据集通常只有一到两个类别成虫、可能还有若虫或其他昆虫但类别不平衡仍然可能出现在「成虫 vs 其他干扰物」上。统计每个类别的实例数和每张图的平均目标数能提前预判训练难度。import os, glob from collections import Counter def count_instances(label_dir): counter Counter() per_image [] for txt in glob.glob(os.path.join(label_dir, *.txt)): with open(txt) as f: lines [l.strip() for l in f if l.strip()] per_image.append(len(lines)) for l in lines: counter[int(l.split()[0])] 1 print(类别实例数:, dict(counter)) print(图片数:, len(per_image)) print(平均每图目标数:, sum(per_image)/len(per_image)) print(最大单图目标数:, max(per_image)) return counter count_instances(labels/)逻辑说明遍历所有 label 文件用 Counter 累计每个 class_id 的出现次数同时记录每张图的目标数。参数上int(l.split()[0])取每行第一个值作为类别 ID。如果平均每图目标数超过 30说明是小目标密集场景后面训练时imgsz要调大、max_det要放宽如果最大单图目标数超过 200要考虑用切片推理或降低置信度阈值。3. 格式转换与数据划分把原始标注变成 YOLO 可训练的目录3.1 COCO/VOC 转 YOLO转换脚本与四个边界坑如果 2.2 判定结果是 COCO 或 VOC必须先转成 YOLO 格式。COCO 转 YOLO 的核心是坐标归一化x_center (x_min w/2) / img_wy_center (y_min h/2) / img_h。下面是一个我用了很多次的转换脚本import json, os from PIL import Image def coco2yolo(coco_json, img_dir, out_dir): os.makedirs(out_dir, exist_okTrue) with open(coco_json) as f: data json.load(f) # 建立 image_id - (file_name, width, height) 映射 img_info {im[id]: im for im in data[images]} # 建立 category_id - 连续索引 映射 cat_ids sorted([c[id] for c in data[categories]]) cat_map {cid: i for i, cid in enumerate(cat_ids)} for ann in data[annotations]: im img_info[ann[image_id]] w, h im[width], im[height] x, y, bw, bh ann[bbox] # COCO 格式: x_min, y_min, w, h # 边界裁剪防止归一化后超出 [0,1] x max(0, min(x, w - 1)) y max(0, min(y, h - 1)) bw min(bw, w - x) bh min(bh, h - y) xc (x bw / 2) / w yc (y bh / 2) / h nw, nh bw / w, bh / h line f{cat_map[ann[category_id]]} {xc:.6f} {yc:.6f} {nw:.6f} {nh:.6f}\n out_path os.path.join(out_dir, os.path.splitext(im[file_name])[0] .txt) with open(out_path, a) as f: f.write(line) coco2yolo(annotations/instances.json, images/, labels/)逻辑说明先建立 image_id 到图片信息的映射再建立 category_id 到连续索引的映射YOLO 要求类别从 0 开始连续。参数上max(0, min(x, w-1))是防止标注框超出图片边界导致归一化后数值大于 1bw min(bw, w-x)防止框宽超出右边界。四个边界坑分别是框超出左/上边界、框超出右/下边界、宽高为负、类别 ID 不连续。这个脚本都处理了。VOC 转 YOLO 类似只是解析 xml 的bndbox里的xmin/ymin/xmax/ymax然后w xmax - xminh ymax - ymin再归一化。3.2 训练集/验证集/测试集划分别用随机划分坑自己农业图像往往按地块或采集日期成组随机划分会导致同一地块的图片同时出现在训练集和验证集验证指标虚高。正确做法是按采集批次分组划分或者至少保证验证集里包含不同光照、不同密度的样本。import os, glob, random, shutil def split_dataset(img_dir, label_dir, out_root, ratios(0.7, 0.2, 0.1), seed42): random.seed(seed) imgs sorted(glob.glob(os.path.join(img_dir, *.jpg))) random.shuffle(imgs) n len(imgs) n_train int(n * ratios[0]) n_val int(n * ratios[1]) splits { train: imgs[:n_train], val: imgs[n_train:n_train n_val], test: imgs[n_train n_val:] } for split, files in splits.items(): img_out os.path.join(out_root, images, split) lbl_out os.path.join(out_root, labels, split) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for img in files: shutil.copy(img, img_out) base os.path.splitext(os.path.basename(img))[0] lbl os.path.join(label_dir, base .txt) if os.path.exists(lbl): shutil.copy(lbl, lbl_out) print(ftrain{len(splits[train])}, val{len(splits[val])}, test{len(splits[test])}) split_dataset(images/, labels/, dataset_bph)逻辑说明random.seed(42)保证可复现按 7:2:1 划分分别复制图片和对应 label 到images/train、labels/train等目录。参数上如果数据集本身有采集日期字段建议改成按日期排序后取前 70% 做训练、中间 20% 做验证、最后 10% 做测试这样更接近真实部署时的时序分布。3.3 写 data.yaml路径、类别名与下载指令YOLOv8 训练需要一份 data.yaml指定训练/验证/测试路径和类别名。路径建议用绝对路径避免从不同目录启动训练时找不到文件。path: /home/user/datasets/bph_philippines/dataset_bph train: images/train val: images/val test: images/test nc: 1 names: 0: brown_planthopper逻辑说明path是数据集根目录train/val/test是相对路径nc是类别数褐飞虱成虫数据集通常只有 1 类names是类别名映射。如果 2.3 统计出有多个类别按 class_id 顺序写全。写完后用python -c import yaml; print(yaml.safe_load(open(data.yaml)))验证语法。4. 训练配置小目标密集场景下的参数怎么调4.1 模型选型YOLOv8n 还是 YOLOv8s别一上来就上大模型褐飞虱成虫体长 2-3 毫米在 640 分辨率下可能只占 10-20 个像素属于典型小目标。模型选型上YOLOv8n 参数量 3.2MYOLOv8s 参数量 11.2M。我的经验是先跑 YOLOv8n 建立 baseline如果 mAP0.5 低于 0.5再换 YOLOv8s 或 YOLOv8m。不要一上来就上 YOLOv8x小目标检测的瓶颈往往在数据质量和输入分辨率不在模型容量。# 安装 ultralytics pip install ultralytics # baseline 训练YOLOv8n640 分辨率100 epoch yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ patience20 \ device0 \ projectruns/bph \ nameyolov8n_640逻辑说明data指向 3.3 写的 yamlmodelyolov8n.pt用 COCO 预训练权重epochs100配合patience20早停imgsz640是默认值后面会对比 1280batch16根据显存调整8G 显存跑 YOLOv8n 640 可以到 32。参数上device0指定第一块 GPUCPU 训练把 device 改成cpu但速度会慢 20 倍以上。4.2 输入分辨率与 anchor 调整小目标检测的两个关键旋钮小目标检测最有效的两个参数是imgsz和anchor。YOLOv8 默认 imgsz640对于 2-3 毫米的成虫建议直接上 1280。代价是显存翻倍、速度减半但 mAP 通常能涨 10-15 个点。# 高分辨率训练1280batch 减半防止 OOM yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz1280 \ batch8 \ patience20 \ device0 \ projectruns/bph \ nameyolov8n_1280逻辑说明imgsz1280让成虫在特征图上的像素数翻倍batch8是因为 1280 分辨率下显存占用约为 640 的 4 倍。如果显存不够可以用batch4配合accumulate2模拟 batch8。参数上YOLOv8 的 anchor 是自适应生成的不需要手动改但如果用 YOLOv5需要用kmeans重新聚类 anchor。注意imgsz 必须是 32 的倍数1280 可以1300 不行。设成非 32 倍数时 ultralytics 会自动向下取整但日志里会警告。4.3 数据增强Mosaic、MixUp 和 Copy-Paste 的取舍YOLOv8 默认开启 Mosaic4 图拼接和 MixUp。对于褐飞虱这种密集小目标Mosaic 能显著增加单图目标数但也会引入大量截断目标。我的建议是前 80 epoch 开 Mosaic后 20 epoch 关掉让模型在真实分布上收敛。# 关闭 Mosaic 的微调阶段 yolo detect train \ datadata.yaml \ modelruns/bph/yolov8n_1280/weights/best.pt \ epochs20 \ imgsz1280 \ batch8 \ mosaic0.0 \ mixup0.0 \ lr00.0001 \ device0 \ projectruns/bph \ namefinetune_no_mosaic逻辑说明mosaic0.0关闭 Mosaicmixup0.0关闭 MixUplr00.0001用更小的学习率微调。参数上如果验证集 mAP 在关闭 Mosaic 后下降超过 5 个点说明模型过拟合了 Mosaic 的增强分布需要重新调整训练策略。Copy-Paste 增强对密集小目标很有效但 ultralytics 默认没开需要自己写 callback 或改用其他框架。5. 避坑与排查褐飞虱数据集训练中最容易翻车的五件事5.1 现象mAP 始终为 0loss 不下降原因标注文件里的类别 ID 不是从 0 开始或者 data.yaml 里的nc和实际类别数不一致。褐飞虱数据集如果是从 COCO 转过来的category_id 可能是 1 而不是 0。解决用 2.3 的统计脚本确认 class_id 的最小值如果是 1在转换脚本里做cat_map映射时强制从 0 开始。同时检查 data.yaml 的nc是否等于len(names)。5.2 现象验证集 mAP 很高但推理时什么都检测不到原因验证集和训练集来自同一采集批次分布几乎一样模型过拟合了。或者推理时的置信度阈值设得太高默认 0.25小目标的置信度普遍偏低。解决按 3.2 的分组划分重新切分数据推理时把conf降到 0.1iou降到 0.5观察是否能检出目标。如果降阈值后能检出但误检多说明模型欠拟合需要增加 epoch 或换更大模型。5.3 现象训练到一半 loss 突然变成 NaN原因学习率太大或者某张图片的标注框宽高为 0除零导致 NaN。褐飞虱数据集里如果有个别图片标注错误宽高为 0 的框会在计算 loss 时产生 inf。解决在转换脚本里加一行过滤if bw 0 or bh 0: continue训练时把lr0从 0.01 降到 0.001并加warmup_epochs5。5.4 现象显存溢出CUDA out of memory原因imgsz1280 时 batch16 会 OOM或者验证阶段同时加载了太多图片。解决把 batch 降到 8 或 4用accumulate补偿或者在训练命令里加cacheFalse关闭缓存。如果还是 OOM把 imgsz 降到 1024。5.5 现象推理速度太慢达不到实时要求原因imgsz1280 的推理速度约为 640 的 1/4YOLOv8n 在 1280 下用 V100 大概 15 FPS用 Jetson 只有 2-3 FPS。解决导出 ONNX 或 TensorRT 加速或者用 640 训练、1280 推理的「训练-推理分辨率不一致」策略但 mAP 会掉 5-8 个点。如果部署在边缘设备建议用 YOLOv8n 640 TensorRT INT8 量化。6. 进阶技巧用切片推理和 TTA 把 mAP 再拉高 8 个点如果 baseline 跑完 mAP0.5 在 0.6 左右想再往上走有两个技巧值得试切片推理SAHI和测试时增强TTA。切片推理的思路是把 1280 的图切成 4 张 640 的子图分别推理再合并结果这样小目标在子图里相对变大检出率提升明显。SAHI 库可以直接对接 ultralytics 的模型。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction # 加载训练好的 YOLOv8 模型 detection_model AutoDetectionModel.from_pretrained( model_typeultralytics, model_pathruns/bph/yolov8n_1280/weights/best.pt, confidence_threshold0.15, devicecuda:0 ) # 切片推理切片大小 640重叠 128 result get_sliced_prediction( test_image.jpg, detection_model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2 ) result.export_visuals(export_dirsahi_output/)逻辑说明slice_height/width640把原图切成 640 的块overlap_ratio0.2保证边缘目标不被截断。参数上confidence_threshold0.15比默认 0.25 低因为切片后每个子图的置信度会略降。SAHI 的合并逻辑是 NMS 去重所以重叠区域的重复检测会被合并。TTA 更简单ultralytics 推理时加augmentTrue即可yolo detect predict \ modelruns/bph/yolov8n_1280/weights/best.pt \ sourcetest_images/ \ imgsz1280 \ conf0.15 \ augmentTrue \ saveTrue逻辑说明augmentTrue开启 TTA对每张图做水平翻转、缩放等变换后分别推理再融合。参数上TTA 会让推理时间增加 3-4 倍但 mAP 通常能涨 2-3 个点。切片推理 TTA 组合使用我在类似的小目标农业数据集上见过 mAP0.5 从 0.62 涨到 0.70 的案例。最后说一个我踩过的坑切片推理的overlap_ratio不要超过 0.3否则同一目标会被检出 3-4 次NMS 合并后反而引入误检。我一般用 0.2在速度和精度之间取平衡。另外SAHI 的推理结果导出后建议用 5.2 的方法在验证集上跑一遍确认 mAP 确实涨了再上生产。希望帮到你。本文还有配套的精品资源点击获取
返回列表