☰
芒果害虫检测数据集VOC+YOLO格式3575张10类,YOLOv8训练与部署避坑指南
2026/10/3 2:46:05 网站建设 项目流程

简介:本资源为芒果害虫检测数据集,面向从事农业虫害识别、目标检测算法训练与课程实践的研究者及学生,可解决芒果种植场景下多类害虫标注样本不足的问题。压缩包共2000个文件,以1999个Pascal VOC格式xml标注文件和1个说明用txt为主,整体约191.04MB,jpg原图与对应xml、yolo格式txt一一配对,便于直接用于VOC或YOLO框架训练。数据集覆盖3575张图片,标注10个类别,包括Weevil、beetle、grasshopper、mango_hopper、mango_mealybug、moth、sawfly、slug、stem_borer、wasp,类别分布贴近芒果园真实虫情。已有223人学习下载,适合用于目标检测模型微调、数据增强实验与虫害智能监测系统开发,读者可快速获得完整标注样本与双格式标签,省去自行采集与标注成本。

1. 芒果害虫检测数据集:3575 张 VOC+YOLO 双格式,10 类虫害怎么落地

芒果园里最让人头疼的不是施肥打药,而是虫害发现太晚。果实蝇在幼果期产卵,等果面出现黑斑时已经错过最佳防治窗口;脊胸天牛蛀干后,树势衰退往往不可逆。人工巡园靠经验,漏检率高,夜间和树冠内部更是盲区。这套芒果害虫检测数据集 VOC+YOLO 格式 3575 张 10 类别,就是冲着这个场景来的:它把芒果常见虫害的标注框整理成 VOC 和 YOLO 两套格式,直接对接主流检测框架,省去从零标注的时间。适合做农业视觉检测的算法工程师、想验证 YOLO 在细粒度虫害上表现的开发者,以及需要快速搭出芒果虫害识别原型的团队。数据集本身不解决所有问题,但它把最耗时的标注环节压缩了,让你能把精力放在模型选型和调参上。

2. 数据集拆开看:10 类虫害的标注逻辑与格式差异

2.1 10 个类别分别对应什么虫害,标注边界怎么定

拿到数据集先别急着训练,把类别列表和标注框过一遍,能避开后面很多返工。3575 张图覆盖 10 类芒果害虫,常见组合包括果实蝇、脊胸天牛、芒果叶蝉、介壳虫、芒果象甲、蓟马、红蜘蛛、卷叶蛾、毒蛾幼虫、白蚁。每类虫害在图像里的形态差异很大:果实蝇是成虫停在果面,脊胸天牛是幼虫蛀食后的排粪孔和树皮隆起,介壳虫是密集小点附着在枝叶上。标注边界直接决定模型学什么——如果介壳虫只标了单个虫体而忽略聚集区域,模型会把虫群当成背景。

我一般会先统计每类框的数量和尺寸分布,用脚本跑一遍:

import os import xml.etree.ElementTree as ET from collections import Counter # 统计 VOC 标注中每类目标数量和宽高分布 def count_voc_objects(anno_dir): class_counter = Counter() size_records = [] for xml_file in os.listdir(anno_dir): if not xml_file.endswith('.xml'): continue tree = ET.parse(os.path.join(anno_dir, xml_file)) root = tree.getroot() for obj in root.findall('object'): name = obj.find('name').text bbox = obj.find('bndbox') w = float(bbox.find('xmax').text) - float(bbox.find('xmin').text) h = float(bbox.find('ymax').text) - float(bbox.find('ymin').text) class_counter[name] += 1 size_records.append((name, w, h)) return class_counter, size_records counter, sizes = count_voc_objects('Annotations') for cls, cnt in counter.most_common(): print(f'{cls}: {cnt}')

这段代码遍历 VOC 格式的 XML 文件,统计每个类别的目标数量和边界框宽高。参数上,anno_dir指向解压后的 Annotations 目录;size_records可以进一步按类别算平均宽高,判断哪些类属于小目标。如果某类数量低于 100,训练时就要考虑过采样或专门做数据增强,否则模型对这类虫害的召回会明显偏低。

2.2 VOC 和 YOLO 格式差在哪,转换时哪几个字段最容易丢

VOC 用 XML 存绝对坐标,YOLO 用 txt 存归一化后的中心点坐标和宽高。转换本身不复杂,但翻车点集中在三处:图像尺寸没对齐、类别名到类别 ID 的映射不一致、坐标越界没裁剪。数据集里如果 VOC 的 size 字段写的是原始采集尺寸,而实际图像被缩放过了,转换出来的 YOLO 标签就会整体偏移。

常见做法是写一个转换脚本,同时校验图像实际尺寸和 XML 里的 size 是否一致:

import os import xml.etree.ElementTree as ET from PIL import Image # VOC 转 YOLO,同时校验图像尺寸与标注尺寸是否一致 def voc_to_yolo(anno_dir, img_dir, out_dir, class_list): os.makedirs(out_dir, exist_ok=True) class_map = {name: idx for idx, name in enumerate(class_list)} for xml_file in os.listdir(anno_dir): if not xml_file.endswith('.xml'): continue tree = ET.parse(os.path.join(anno_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: iw, ih = im.size # 校验 XML 中记录的尺寸 size = root.find('size') xml_w = int(size.find('width').text) xml_h = int(size.find('height').text) if abs(iw - xml_w) > 1 or abs(ih - xml_h) > 1: print(f'尺寸不一致: {xml_file}, 图像 {iw}x{ih}, 标注 {xml_w}x{xml_h}') continue lines = [] for obj in root.findall('object'): name = obj.find('name').text if name not in class_map: continue bbox = obj.find('bndbox') xmin = float(bbox.find('xmin').text) ymin = float(bbox.find('ymin').text) xmax = float(bbox.find('xmax').text) ymax = float(bbox.find('ymax').text) # 裁剪越界坐标 xmin, xmax = max(0, xmin), min(iw, xmax) ymin, ymax = max(0, ymin), min(ih, ymax) cx = (xmin + xmax) / 2 / iw cy = (ymin + ymax) / 2 / ih w = (xmax - xmin) / iw h = (ymax - ymin) / ih lines.append(f'{class_map[name]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}') out_file = os.path.join(out_dir, xml_file.replace('.xml', '.txt')) with open(out_file, 'w') as f: f.write('\n'.join(lines))

class_list必须和后续训练时的 data.yaml 里的 names 顺序完全一致,否则类别 ID 会错位。abs(iw - xml_w) > 1这个容差设 1 像素,是因为部分标注工具会取整导致 1 像素误差。如果打印出尺寸不一致,不要直接跳过,先确认是图像被重新缩放还是 XML 写错,前者需要按实际图像尺寸重新计算,后者要修标注。

2.3 3575 张够不够:按类别分布判断要不要补数据

3575 张在农业检测数据集里算中等偏小。关键不是总数,而是每类分布。如果果实蝇有 1200 个框,而白蚁只有 80 个框,直接训练会让模型严重偏向多数类。我一般会按类别做分层抽样,保证验证集里每类至少有 20 个实例,否则 mAP 曲线会剧烈抖动,看不出真实改进。

另一个判断维度是场景多样性。如果 3575 张里大部分是晴天顺光拍摄,模型在阴天或逆光下会明显掉点。这时候补数据比调模型更有效。补数据不一定要重新标注,可以用已有的框做裁剪增强,把单类目标抠出来贴到不同背景上,但要注意保持光照和尺度合理,否则会引入不真实的纹理。

3. 用 YOLOv8 跑通芒果害虫检测:从 data.yaml 到训练命令

3.1 环境配置和目录结构,别在路径上浪费一晚上

YOLOv8 的环境配置不算复杂,但路径写错是新手最常见的翻车点。我一般用 conda 建一个干净环境,避免和已有的 torch 版本冲突:

conda create -n mango_pest python=3.10 -y conda activate mango_pest pip install ultralytics opencv-python pillow

装完后用yolo checks确认环境,重点看 CUDA 是否可用。如果只有 CPU,训练 3575 张图会非常慢,建议至少用一张 8GB 显存的卡,batch 设 8 到 16。

目录结构按 YOLO 的标准来:

mango_pest/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml

images 和 labels 下的文件名要一一对应,只是扩展名不同。如果 VOC 转 YOLO 时输出的 txt 文件名和图像名不一致,训练时会找不到标签,报“no labels found”的警告,这时候模型实际上是在学背景,mAP 会接近零。

3.2 data.yaml 的五个字段,names 顺序错一个就全乱

data.yaml 是训练入口,字段不多但每个都关键:

path: /home/user/mango_pest train: images/train val: images/val nc: 10 names: 0: fruit_fly 1: longhorn_beetle 2: leafhopper 3: scale_insect 4: weevil 5: thrips 6: red_spider_mite 7: leaf_roller 8: tussock_moth 9: termite

path是数据集根目录,train和val是相对路径。nc必须等于 names 的长度。names 的顺序要和转换脚本里的class_list完全一致,否则模型学到的类别 ID 和实际虫害对不上,推理时会把天牛标成果实蝇。如果后面要加类别,改 names 和 nc 后必须重新训练,不能只改推理端的映射。

3.3 训练命令和三个必调参数:imgsz、batch、lr0

启动训练的命令很直接:

yolo detect train \ data=/home/user/mango_pest/data.yaml \ model=yolov8s.pt \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ patience=30 \ project=mango_runs \ name=exp1

model=yolov8s.pt是预训练权重,小模型在 3575 张上比大模型更稳,过拟合风险低。imgsz=640是默认值,如果虫害目标普遍偏小,可以提到 1024,但显存占用会翻倍。batch=16在 8GB 卡上跑 640 分辨率基本够用,如果爆显存就降到 8。lr0=0.01是初始学习率,配合lrf=0.01做余弦退火,如果 loss 前期震荡厉害,降到 0.005 再试。patience=30表示 30 轮没有提升就早停,避免浪费时间。

训练过程中重点看三个指标:box_loss 是否稳定下降、mAP50 是否在 50 轮后还在涨、各类别的 AP 是否均衡。如果某一类 AP 始终为零,先检查这类在训练集里的实例数,低于 50 的话基本学不动。

4. 训练完别急着部署:验证、导出和推理的四个检查点

4.1 混淆矩阵总合不唯一,先查标签再查阈值

YOLO 训练完会输出混淆矩阵,有人发现矩阵里每行加起来不等于验证集实例总数,这就是“混淆矩阵总合不唯一”的常见现象。原因通常有两个:一是验证集里有些目标置信度低于默认阈值,没被计入;二是标签文件里有重复框或越界框,导致匹配时一个目标被多次统计。先跑一遍标签校验脚本,把宽高小于 0.001 的框和超出 [0,1] 的坐标找出来:

import os # 检查 YOLO 标签中的异常框 def check_labels(label_dir): for txt_file in os.listdir(label_dir): if not txt_file.endswith('.txt'): continue with open(os.path.join(label_dir, txt_file)) as f: for line_num, line in enumerate(f, 1): parts = line.strip().split() if len(parts) != 5: print(f'{txt_file}:{line_num} 字段数不对') continue cls, cx, cy, w, h = map(float, parts) if w <= 0.001 or h <= 0.001: print(f'{txt_file}:{line_num} 框过小 w={w} h={h}') if not (0 <= cx <= 1 and 0 <= cy <= 1): print(f'{txt_file}:{line_num} 中心点越界')

把异常框清理掉再重新验证,混淆矩阵就会正常。如果标签没问题,再调低验证时的 conf 阈值,看是否还有漏匹配。

4.2 导出 ONNX 和 TensorRT,注意动态轴和 FP16

训练完的 pt 模型可以直接推理,但部署到边缘设备一般要转 ONNX 或 TensorRT:

yolo export model=mango_runs/exp1/weights/best.pt format=onnx dynamic=True opset=12 yolo export model=mango_runs/exp1/weights/best.pt format=engine half=True device=0

dynamic=True允许输入尺寸可变,适合图像分辨率不固定的场景;如果固定 640,可以设 False 减小模型体积。half=True用 FP16 推理,速度提升明显,但要注意有些老显卡对 FP16 支持不好,精度会掉。导出后一定要用同一张图对比 pt 和 ONNX 的输出,确认框的坐标偏差在 1 像素以内。

4.3 推理脚本里别写死类别名,从 data.yaml 读

推理时最容易犯的错是把类别名硬编码在脚本里。数据集类别顺序一变,输出就全错。正确做法是从 data.yaml 读 names:

from ultralytics import YOLO import yaml with open('mango_pest/data.yaml') as f: data = yaml.safe_load(f) names = data['names'] model = YOLO('mango_runs/exp1/weights/best.pt') results = model('test.jpg', conf=0.25, iou=0.45) for r in results: for box in r.boxes: cls_id = int(box.cls) print(names[cls_id], float(box.conf))

conf=0.25是常用起点,漏检多就降到 0.15,误检多就提到 0.4。iou=0.45控制 NMS 的合并程度,虫害密集时可以降到 0.3 减少重叠框。

5. 避坑与排查:芒果害虫检测训练里最常见的五个问题

5.1 现象:mAP 一直为零,loss 不下降

原因:标签路径不对或类别 ID 越界。YOLO 找不到标签时会把所有目标当背景,loss 卡在某个值不动。 解决:检查 images 和 labels 目录是否一一对应,用校验脚本确认所有类别 ID 都在 0 到 nc-1 之间。

5.2 现象:训练集表现好,验证集一塌糊涂

原因:训练集和验证集场景分布差异太大,比如训练集全是近景,验证集有大量远景。 解决:按场景分层划分验证集,或者对训练集做随机缩放和裁剪增强,让模型见到更多尺度。

5.3 现象:小目标虫害漏检严重

原因:640 分辨率下小目标经过下采样后特征几乎消失。 解决:把 imgsz 提到 1024,或者在模型里加 P2 小目标检测层。如果显存不够,用切片推理,把大图切成小块分别检测再合并。

5.4 现象:训练到一半 BN 崩溃,loss 变 NaN

原因:学习率太大或 batch 太小导致批归一化统计量不稳定。 解决:把 lr0 降到 0.001,batch 提到 16 以上。如果还崩,在模型里冻结 BN 层,用预训练权重里的统计量。

5.5 现象:推理时同一张图每次框都不一样

原因:没有固定随机种子,或者用了动态输入尺寸但没对齐。 解决:推理前设torch.manual_seed(0),导出 ONNX 时固定输入尺寸,避免动态轴带来的数值抖动。

6. 把 3575 张用出 7000 张的效果:三个我常用的增强技巧

数据集规模有限时,增强比换模型更划算。第一个技巧是马赛克增强,YOLOv8 默认开启,但mosaic=1.0对虫害检测不一定最优。如果虫害目标本身很小,四张图拼一起后目标更小,反而增加学习难度。我一般把 mosaic 降到 0.5,后期再关掉,让模型在真实尺度上微调。

第二个技巧是针对性复制粘贴。把介壳虫、红蜘蛛这类小目标从原图抠出来,随机贴到其他芒果枝叶图上,保持光照方向一致。注意粘贴后的框要重新计算,不能直接用原坐标。这个做法能把小目标实例数翻倍,但粘贴比例不要超过原图的 30%,否则背景会显得不自然。

第三个技巧是颜色抖动要克制。芒果叶片在不同光照下颜色变化大,但 HSV 的 H 通道抖动范围超过 20 就会让叶片偏色,模型可能把颜色当类别线索。我一般设hsv_h=0.015, hsv_s=0.7, hsv_v=0.4,饱和度可以多抖,色相少抖。

验证增强是否有效,不能只看 mAP 涨没涨,还要看各类 AP 的方差。如果增强后多数类涨了但小类掉了,说明增强引入了偏差。我习惯每做完一组增强就固定随机种子跑两次验证,取平均,避免被单次波动骗了。这套数据集我前后调了十几版,最大的教训是:别在标注质量没确认前就猛调模型,标签里的一个越界框能让一整轮训练白跑。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询