
简介农业害虫目标检测数据集包含378张真实农田监控图像覆盖蚜虫、粘虫成虫/幼虫、黑切虫成虫/幼虫等5类高危害害虫的典型形态所有图像均提供YOLO格式的归一化边界框标注可直接用于目标检测模型训练与验证。压缩包共758个文件包括378张jpg原图、378个txt标注、1个yaml类别配置及1份docx说明文档体积18.11MB目录简洁便于快速接入YOLOv5/v8等主流框架。该数据集可支撑智能农业监测、移动端农事管理、农业AI学术研究及教学演示已有483人下载学习。除边界框定位外还支持害虫分类与计数任务成虫与幼虫分阶段标注有助于精细识别复杂田间背景下的多样姿态也增强了模型野外部署的鲁棒性可为相关项目节省大量数据采集与标注成本。1. 一包农业害虫目标检测数据集zip值不值得拆开看到“农业害虫目标检测数据集22.zip”这个压缩包搞目标检测的人多半会先想我想用YOLOv8训练自己的数据集可里面装的到底是标好的txt、xml还是一堆没标注的害虫照片对这个标题我的第一反应是这包大概率是某个农田害虫识别项目分批次整理出来的原始资产适合做虫情测报灯识别、植保无人机低空调查和农业机器人田间巡检。它可能省掉几个月采集与标注时间但直接解压丢进ultralytics训练很多人会在数据格式、类别分布、图片分辨率上翻车。下面从验包开始讲到把模型真正搬到田里。2. 解压前先体检把 22.zip 变成可用的训练原料2.1 用 zipinfo 和 Python 验包防损坏、防 zip 伪加密拿到zip先别双击解压尤其从网盘或同行手里拷来的数据集。我一般先在命令行做一次性体检看内部结构是否完整有没有被二次压缩或改动过。命令只有两行zipinfo -v 农业害虫目标检测数据集22.zip | head -60 unzip -l 农业害虫目标检测数据集22.zip | head -40zipinfo -v输出每个文件条目包括压缩算法、操作系统属性和加密标志位unzip -l只列目录方便先确认是不是有images/、labels/这类标准结构。如果解压时提示要密码但来源说明里没给就要警惕“zip伪加密”。伪加密不是真用AES或ZipCrypto锁了文件而是有人修改了通用位标记让系统误认为加密。此时别到处找密码先确认来源是否可信再用Python把目录项的加密位拉回来重写一个包不过重打包会丢失原文件的压缩级别而且可能连压缩数据一起破坏所以只有当zip本身完整时才建议这样操作。更可靠的完整校验是用Python逐文件读CRCimport zipfile zpath 农业害虫目标检测数据集22.zip with zipfile.ZipFile(zpath) as zf: bad zf.testzip() if bad: print(损坏文件:, bad) else: print(全部通过条目数:, len(zf.namelist()))testzip()会在内部逐个解压并比对CRC32返回第一个坏文件的名字全部通过返回None。这个校验不依赖额外库速度快。血泪经验是不要把这一步跳过去训练到一半报Image corrupted再回头找原始包比一开始验包痛苦得多。2.2 解压后按 images/labels 标准布局整理农业害虫数据集的特点是原图尺寸大、文件数量多很多包里的目录命名混乱比如jpg22/配xml_old/。我会先把图片和标注分家固定成YOLO的images/和labels/结构mkdir -p dataset22/images/train mkdir -p dataset22/images/val mkdir -p dataset22/labels/train mkdir -p dataset22/labels/val find extracted -type f \( -name *.jpg -o -name *.jpeg -o -name *.png \) all_imgs.txt wc -l all_imgs.txtfind带上括号和-o能同时收集三种常见图片格式wc -l先看总量方便后面按比例分配。这里不建议直接mv到目标目录因为同名图片在不同子目录可能冲突先把路径列表存下来更可控。接着用Python做train/val切分并移动文件import os, random, shutil with open(all_imgs.txt) as f: imgs [line.strip() for line in f if line.strip()] random.seed(7) random.shuffle(imgs) val_count int(len(imgs) * 0.2) val_imgs set(imgs[:val_count]) for path in imgs: dst_root dataset22/images/val if path in val_imgs else dataset22/images/train shutil.move(path, os.path.join(dst_root, os.path.basename(path)))这段代码先把图片洗牌再抽20%做验证集。注意random.seed(7)保证了反复跑得到同样划分换成别的数字会得到不同结果。对于随机独立拍摄的害虫照片这种划分没问题如果图片是视频抽帧必须按片段分组切分否则验证集和训练集会带上同一帧的连续图片模型没学会泛化。关于标注文件怎么跟着走我一般不在这一步移动标注因为VOC xml和YOLO txt的文件一一对应关系不同。等到第3章确定标注格式后统一转换再拷进labels/目录。这样避免中途把xml转txt又转xml的小批处理把文件弄乱。2.3 统计图片资产尺寸分布、损坏图和对应标注训练前要摸清家底。用PIL快速检查每张图能不能打开、分辨率是什么分布同时检查标注文件数量是否对得上from PIL import Image from collections import Counter import os img_exts (.jpg, .jpeg, .png) size_counter Counter() bad_imgs [] missing_ann [] for sub in [train, val]: img_dir fdataset22/images/{sub} for fn in os.listdir(img_dir): if not fn.lower().endswith(img_exts): continue path os.path.join(img_dir, fn) try: with Image.open(path) as im: im.verify() size_counter[Image.open(path).size] 1 except Exception: bad_imgs.append(path) stem os.path.splitext(fn)[0] if not os.path.exists(fextracted_labels/{stem}.txt): missing_ann.append(path) print(尺寸分布Top5:, size_counter.most_common(5)) print(坏图数量:, len(bad_imgs)) print(缺标注图片数量:, len(missing_ann), missing_ann[:5])这段逻辑是verify()只读文件头能过滤大部分截断或假图片再重新打开一次读尺寸记到计数器。missing_ann这里假设标注在extracted_labels/{stem}.txt如果你拿到的xml或json把后缀改了就行。这个统计不是光看数字尺寸分布会直接影响训练参数主流是4032x3024训练imgsz1280才算合理主流已经是640x480说明原作者做过缩放后面不需要再切大图。如果缺标注比例超过2%就要考虑补标或淘汰这批图否则训练时YOLO会跳过没标注的图片。2.4 用蒙太奇缩略图肉眼扫图发现重复帧和错误样本统计数字只能挑出坏文件认不出来内容重复。对几万张图一张张翻不可能常见做法是生成缩略图拼板一张图快速看到几十个样本。from PIL import Image import os, math folder dataset22/images/train files [f for f in os.listdir(folder) if f.endswith(.jpg)][:100] thumb 160 cols 10 rows math.ceil(len(files) / cols) sheet Image.new(RGB, (cols * thumb, rows * thumb), (255, 255, 255)) for i, f in enumerate(files): im Image.open(os.path.join(folder, f)) im.thumbnail((thumb, thumb)) x (i % cols) * thumb y (i // cols) * thumb sheet.paste(im, (x, y)) sheet.save(preview_grid.jpg)缩略图用thumbnail保持比例不拉伸形变超出部分白底。拼板图保存成preview_grid.jpg后用看图软件放大扫一遍重点看三类问题整图过暗、画面模糊、同一条虫在不同图里反复出现。重复帧对模型没增益还会让验证集虚高后面第5章会讲怎么去重。这里先把它标出来就行不用急着删。3. 把 VOC、COCO 和自定义 txt 统一成 YOLO 格式转换脚本与坐标换算3.1 先认命打开目录之前先看标注后缀农业害虫数据集流传最广的有三种格式VOC的xmlPascal VOC、COCO的jsonannotations文件夹和YOLO自己的txt。三种格式并存是常态。用find先摸底find dataset22 -type f | sed s/.*\.// | sort | uniq -c这个管道统计所有文件后缀一眼看出是jpgxml还是jpgtxt。如果既有xml又有txt说明原作者可能发了两个版本优先用txt那一份做训练xml用来溯源检查。对农业场景我更建议用YOLO txt格式因为它直接吃归一化坐标不需要在训练时二次转坐标。VOC的xml好处是包含object name、pose、truncated等额外信息但对模型训练没直接作用。COCO json则适合做数据分析和跨项目复用但每次训练都要解析一遍速度比txt慢几十倍。3.2 XML 转 YOLO把 bndbox 换算成 cx, cy, w, hVOC标注里每个框是xmin, ymin, xmax, ymaxYOLO要求的是中心点x、中心点y、宽、高且都除以图片宽高做归一化。转换脚本import os import xml.etree.ElementTree as ET CLASSES [飞虱, 蚜虫, 棉铃虫, 玉米螟, 菜粉蝶] def convert_xml(xml_path, img_path, out_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) width int(size.find(width).text) height int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASSES: continue cls_id CLASSES.index(name) bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) cx (xmin xmax) / 2.0 / width cy (ymin ymax) / 2.0 / height bw (xmax - xmin) / width bh (ymax - ymin) / height lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))关键点坐标分母必须是xml里size读出的宽高而不是用PIL重新读图宽高。虽然两者多数一致但有些低质量数据集xml的size和真实图片分辨率对不上用PIL读出来的值更可靠。碰到对不上时以PIL实际尺寸为准否则框整体偏移。CLASSES顺序就是训练时的类别索引顺序后面data.yaml必须和它一致这是最常见的坑。3.3 COCO JSON 转 YOLO最容易被类别ID坑的一步COCO数据集里类别定义在json的categories字段一张图片的标注在annotations还要通过images字段拿到图的宽高。很多转换脚本直接硬编码类别ID但COCO的ID不一定是连续整数有的从1开始有的从0开始。import json def coco_json_to_yolo(json_path, out_base): with open(json_path, r) as f: data json.load(f) cat_id2idx {cat[id]: i for i, cat in enumerate(data[categories])} img_info {img[id]: img for img in data[images]} anns_by_img {} for ann in data[annotations]: anns_by_img.setdefault(ann[image_id], []).append(ann) for img_id, img in img_info.items(): w img[width] h img[height] lines [] for ann in anns_by_img.get(img_id, []): cls_id cat_id2idx[ann[category_id]] x, y, bw, bh ann[bbox] cx (x bw / 2) / w cy (y bh / 2) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw/w:.6f} {bh/h:.6f}) stem img[file_name].rsplit(., 1)[0] with open(f{out_base}/{stem}.txt, w) as f: f.write(\n.join(lines))注意ann[bbox]是[x,y,width,height]和VOC的xmin,ymin,xmax,ymax不同别直接复用第3.2节的公式。cat_id2idx把原本稀疏的COCO类别ID映射成连续的YOLO索引这一步必须做。如果漏了训练时类别顺序会和张图不对应mAP会异常低。转换完成后用一张标注好的图可视化验证比跑一轮训练快得多。3.4 写 data.yaml类别名、路径、验证集一个都不能少YOLOv8读的是data.yaml常见错误是把类别列表写错顺序或者train/val路径写相对路径导致找不到图片。标准文件长这样path: /home/user/dataset22 train: images/train val: images/val names: 0: 飞虱 1: 蚜虫 2: 棉铃虫 3: 玉米螟 4: 菜粉蝶path写绝对路径时train和val都相对于它如果path不写则train相对当前工作目录。我一般写绝对路径避免在别的机器或IDE里跑训练时找不到数据。names的类型可以用list也可以用键值对0指第0类必须和转换脚本里的CLASSES.index(name)一致。这个文件是YOLOv8训练自己的数据集时的首要排查点。转换完成后把txt画回原图做抽查。下面这个函数只画单张图适合抽检import cv2 def draw_yolo_label(img_path, txt_path): img cv2.imread(img_path) h, w img.shape[:2] for line in open(txt_path): parts line.strip().split() if len(parts) 5: continue cls, cx, cy, bw, bh parts[:5] cx, cy, bw, bh map(float, (cx, cy, bw, bh)) 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, 200, 0), 2) cv2.putText(img, parts[0], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2) return img画框时先用原图宽高把归一化坐标还原int()取整会丢掉不到一个像素的偏移对训练没影响。抽查重点看两类问题一类是框坐标超出图片边界另一类是目标在图上占得极小、几乎看不见。前者可能是分母用了xml里的错误尺寸后者是标注本身漏标小目标。发现问题后回第3.2节修正不要带着错框往下训练。4. 用 YOLOv8 训练农业害虫检测模型最小命令与必调参数4.1 环境安装ultralytics 一条命令安装YOLOv8最省事的方式是装ultralytics包它会连带拉进torch、opencv-python等依赖。pip install ultralytics如果你有NVIDIA GPU建议先装和本机CUDA匹配的pytorch再装ultralytics否则pip会给你装CPU版torch训练速度差几十倍。装完先跑一条最小预测命令自检yolo predict modelyolov8n.pt sourcedataset22/images/train/000001.jpg这条命令会自动下载yolov8n的COCO预训练权重能跑通说明环境正常。用COCO预训练权重做初始化比从零训练收敛快很多特别是农业害虫这种中小数据集一定要用预训练。不要一上来就自己写训练循环ultralytics的CLI已经覆盖了数据加载、增强、EMA、早停这些细节减少翻车点。4.2 训练命令imgsz、batch、epochs 怎么取值农业害虫检测的训练命令我一般长这样yolo train \ modelyolov8s.pt \ datadataset22.yaml \ epochs100 \ imgsz1280 \ batch16 \ patience20 \ projectruns/pest_yolo \ nameexp1 \ seed42模型用yolov8s还是yolov8m取决于显存和目标尺度。农业害虫的很多目标只有几十像素imgsz1280比默认640有立竿见影的提升代价是显存和训练时间都涨到三倍以上。batch如果太小BatchNorm统计不稳定太大又容易刷爆显存16是常用起点。patience20表示20个epoch没提升就提前停防止过拟合。seed42固定随机性多次对比才有意义。显存不够时常见做法是降batch并同时降imgsz但imgsz对害虫小目标影响更大我更愿意先用yolov8n跑通再用大模型。如果你的验证集mAP很低别急着调模型先确认训练日志里train loss和val loss是不是同时高如果train loss低、val loss高属于过拟合加大数据增强比换大模型有用。极简参数表可以存在笔记里参数建议值说明modelyolov8s.pt数据量1k以下用n/simgsz1280小目标多时提高batch8-32按显存调整epochs100早停patience20optimizerAdamW默认SGD也稳定hsv_h / hsv_s / hsv_v0.015 / 0.7 / 0.5害虫颜色扰动fliplr0.5左右翻转hsv_*这组是颜色增强害虫在田间叶片上颜色接近适度扰动能让模型不依赖单一光照但别调太大否则绿色叶片会变成紫色反而学坏特征。fliplr对非对称害虫也有用但对有方向性的物体要慎开。4.3 训练日志里看什么三线loss、mAP不是唯一标准训练过程会打印box loss、cls loss和dfl lossval栏里看mAP50和mAP50-95。这两个指标差别很大mAP50只关心IoU阈值0.5适合目标稀疏的农业场景mAP50-95对框精度的要求更严格要求框和真值高度重合对施药定位场景才更看重。如果mAP50还可以但mAP50-95很低说明框的位置偏差普遍存在优先检查标注框是否贴边、是否把叶片边缘也标进去了而不是单纯加大epoch。训练结束后权重按epoch里的best.pt和last.pt两个文件保存。best.pt按验证集表现选last.pt是最后一个epoch的权重。如果验证集mAP曲线还在上升但被早停切断把patience调大重跑如果best.pt出现得很早可能是验证集太小数据泄漏问题见第5.4节。4.4 训练中常见故障OOM、CPU卡死、路径带中文农业数据集图片大最容易遇到的就是显存溢出。报错通常是CUDA out of memory解决顺序是先把batch减半再把imgsz降到960还不行就换yolov8n。不要同时调两个参数否则无法判断哪个改动起作用。另一个隐蔽问题是数据读取慢。如果训练时GPU利用率只有20%而CPU打满说明图片解码成了瓶颈。常见做法是用workers8增加预处理进程数并去掉cache或者改用cacheram小数据集直接cacheTrue把图片缓存进内存几十G大图就别开了内存会爆掉。还有路径和文件名不要用中文有些第三方库在Windows下读中文路径会黑匣子式报错改成纯数字名称最省心。5. 农业害虫数据集训练避坑指南五个真实问题与解决顺序5.1 图片分辨率高但目标只有十几个像素整图硬训会翻车现象训练完mAP50有0.8放到田里实际检测小虫一个都框不到只有大个的菜粉蝶能中。原因原图4032x3024训练时统一缩放到1280x1280一只20像素的蚜虫缩放后只剩7像素特征全丢了。解决先把大图切成重叠子图再训练。常见做法是切成4张2016x1512重叠16像素切出来的图尺寸各不相同正好当数据增强。推理时也用同样切法最后把子图检测框映射回大图坐标做NMS合并。这一步比换更大的模型重要得多。5.2 类别样本数差两个数量级模型狂学菜粉蝶现象菜粉蝶几千个框飞虱只有几十个框训练结果飞虱这一类mAP50不到0.1。原因YOLO默认按图片均匀采样少数类被淹没在多数类里。解决先统计每类框数把少数类的标注复制几份或者干脆把含飞虱的图片重复多放几轮。YOLOv8没有直接的class_weight参数我一般用数据层面重复采样少数类图片在images/train里复制3到5份标签同步复制然后打乱。注意别在验证集里复制否则验证分数虚高。5.3 标注框把一整团蚜虫框在一起目标和背景分不清现象训练时cls loss降不下去mAP50曲线震荡。原因蚜虫常成团聚集有的标注把一整团几十只虫框成一个框有的标中间几个虫。框里混入大量叶片背景模型不知道该学虫还是学叶子。解决先用labelimg或X-AnyLabeling这类目标检测常用标注工具打开标注有问题的图把成团虫子的框调小到能包住主要个体或者统一规则“一框一只”。标注一致性比标注数量更重要规则不一致时再增加数据也白搭。5.4 训练loss正常但验证mAP崩同一地块画面泄漏到train和val现象train loss稳定下降val loss也跟着降可mAP50一直很低或者某类高得离谱。原因train和val用了来自同一批视频帧、同一块田的重复画面。特别是按文件名随机切分时相邻帧图片非常像模型在验证集上相当于看图猜图。解决按采集时间或田块编号分组把同一组图片全部放进同一个集合不要让同一场景跨集合。如果没有时间戳就用第2.4节的缩略图拼板肉眼检查再用图片哈希去重确保验证集没有和训练集高度重合的图。5.5 压缩包里混入重复图和损坏图哈希去重是大扫除现象训练报could not be found或者在数据加载阶段卡死偶尔还出现一种目标尺寸mAP特别奇怪。原因zip里可能有重复图片、损坏图片还有标注框坐标超出图片边界的脏数据。解决先跑第2.3节的PIL检查再用文件哈希去重。下面这段代码按图片内容去重比按文件名去重更可靠import hashlib from PIL import Image import os seen {} for sub in [train, val]: folder fdataset22/images/{sub} for fn in os.listdir(folder): if not fn.lower().endswith(.jpg): continue path os.path.join(folder, fn) h hashlib.md5(open(path, rb).read()).hexdigest() if h in seen: print(重复:, seen[h], path) os.remove(path) os.remove(path.replace(images, labels).replace(.jpg, .txt)) else: seen[h] path按MD5去重只对完全相同的图片有效旋转、裁剪过的重复图测不出来但完全重复在网盘打包数据里最常见。删重复图时要同步删对应的txt不然YOLO会拿着一张有标注的txt却找不到图直接报错。6. 验证与进阶把只会在测试集上好看的模型搬到田里训练完先别急着部署留出一批从未进过train和val的独立图片做最终验证。我习惯在每类里额外抽30张存到dataset22/test只跑预测不打乱训练过程。命令用yolo val指定独立数据和best.ptyolo val modelruns/pest_yolo/exp1/weights/best.pt \ datadataset22_test.yaml \ imgsz1280dataset22_test.yaml里的val字段指向test目录train可以留空。这里看的不只是mAP还要逐张看预测框重点看有没有把蜘蛛、瓢虫误识别成害虫。农业场景的FP往往比漏检更麻烦因为防治决策会跟着报警走。进阶方向是按需做切片推理。如果现场设备是Jetson Orin这类边缘盒子整图1280推理可能只有十几帧切图后每块独立推理再把框坐标还原回原图用NMS合并。这样对小目标召回率提升明显但耗时成倍增加适合虫情测报灯这种非实时巡检场景不适合无人机高速巡航。更高阶的做法是用SAHI这类切片辅助推理库已经处理了重叠窗口和映射不过在低算力设备上手工切图加合并更可控。部署方面导出ONNX是最通用的中间格式yolo export modelbest.pt formatonnx imgsz1280 dynamicTrue导出后可以用TensorRT或OpenVINO转成设备后端。我踩过的坑是dynamicTrue在部分板卡上推理变慢如果设备固定输入尺寸改成dynamicFalse并固定imgsz反而更快。部署后要把模型返回的置信度阈值调低一点先收集一周误报样本再挑出“高置信度假阳”加入训练集做增量训练。增量训练时在原始数据里混入部分旧类样本防止模型忘掉常见害虫这个习惯我每次都保留。希望帮到你。本文还有配套的精品资源点击获取