
简介面向谷物仓储与智能农业监测场景的YOLO格式目标检测数据集聚焦仓储环境中常见害虫的识别与定位适合农业害虫监测系统开发、智能农机集成以及高校计算机视觉课程实训与科研基线训练。压缩包共1376个文件打包约22.76MB主体为687张真实谷物环境JPEG图片及对应的687个txt标注文件另含1个yaml配置文件和1个docx说明文档结构与YOLOv5、YOLOv8等主流框架直接兼容下载解压即可用于训练、验证和推理。已有230人学习下载。该数据集标注了精确的边界框类别集中于害虫单类检测可降低建模复杂度便于快速验证算法效果配套说明文档对数据构成、适用场景和训练要点进行了整理适合需要从数据准备到模型搭建完整走通目标检测流程的开发者、研究者和农业信息化项目人员。1. 谷物害虫目标检测数据集为什么它比网上爬来的图集更值得用做粮仓害虫识别的人多半会先遇到同一个问题模型不缺缺的是干净的带标签图片。有人从搜索引擎爬了几千张图用标注工具标了半个月训练出来的模型一进粮仓就原形毕露——光线一变目标一多检测框乱跳。这时候一份打包好的谷物害虫目标检测数据集.zip 就比零散图集值钱得多它把图片、标注、类别定义一次性给你解压后就能进 YOLO、Faster R-CNN 这类目标检测流程省掉的是“从零攒数据”最脏最累的阶段。这篇笔记面向粮油仓储智能化、农产品质检的算法工程师和数据科学方向的学生讲清楚拿到这种数据集后怎么验证、怎么转换、怎么训练、又在哪些地方最容易翻车。2. 拆开谷物害虫数据集目录结构、标注格式与标签体系2.1 先看文件清单一个合格的数据集 zip 里该有什么收到“谷物害虫目标检测数据集.zip”这个文件第一件事不是双击解压而是先看压缩包内部清单。Windows 上用 WinRAR 或 7-Zip 打开预览Linux 或 macOS 上直接跑一条命令unzip -l 谷物害虫目标检测数据集.zip这条命令只列出压缩包内文件不实际解压。重点看三类东西目录层级、文件后缀、有没有划分文件。一个能直接投入训练的数据集内部通常是这样组织的谷物害虫目标检测数据集/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── annotations/ │ ├── train/ │ └── val/ ├── classes.txt └── trainval.txtclasses.txt是类别清单每一行一个类别名trainval.txt是图片路径清单告诉训练脚本哪些图进训练集、哪些进验证集。如果压缩包里只有一堆.jpg和.xml没有划分文件和类别清单那就不能叫数据集只能叫图集。图集也不是不能用只是你得先花时间做划分和验证等于把别人的半成品拿回来自己补完。另一个容易被忽略的点是文件命名。我见过不少数据集图片名是IMG_20240321_1023.JPG标注文件却叫img_20240321_1023.xml大小写不一致。目标检测训练脚本按文件名关联图片和标签一旦匹配不上训练时会出现“图片没有标签”或“标签没有图片”的警告。先跑一个快速检查看图片与标注是否一一对应ls images/train | wc -l ls annotations/train | wc -l两个数字差的特别大时不要急着训练先查是不是有子目录嵌套或者文件名后缀被改了。常见的坑是 zip 压缩时保留了 Mac 的__MACOSX目录Linux 上解压后会多出一堆隐藏文件训练脚本误把.DS_Store当成图片。这个后面避坑章节再细说。2.2 标注格式VOC 与 YOLO 两种最常见的选择谷物害虫目标检测数据集里的标注文件通常有两种格式VOC XML 和 YOLO TXT。VOC 格式是 PASCAL VOC 比赛留下来的标准XML 文件里用object标签描述每一个目标的类别和边界框YOLO 格式是 Darknet/YOLO 系列训练器直接支持的文本格式每一行写“类别索引 x_center y_center width height”坐标都归一化到 0~1。两者各有各的使用场景先看对比表维度VOC XMLYOLO TXT文件关联一张图片对应一个同前缀 .xml一张图片对应一个同前缀 .txt坐标表示绝对像素xmin, ymin, xmax, ymax相对坐标归一化的中心点与宽高标注工具labelImg 默认输出labelImg 切换格式后输出LabelStudio 可导出可读性人眼可读便于调试机器友好直接喂给 YOLO转换成本需要脚本转 YOLO也可转回 VOC但需注意归一化坐标还原为什么会有这种并存因为 labelImg 和 LabelStudio 这类目标检测常用标注工具导出时默认给的是 VOC 或 COCO 格式而 YOLO 系列训练要求的是 TXT 格式。网上流传的谷物害虫数据集很多是作者用 labelImg 标完直接打包上传的所以拿到手多半是 XML。另外还有一个细节YOLO TXT 文件里类别索引是从 0 开始的classes.txt里第一行对应索引 0第二行对应索引 1顺序一旦弄错训练出来的模型就会把“玉米象”当“谷蠹”。这也是为什么我强烈建议拿到数据集后先把classes.txt打出来看一眼再决定要不要转换。2.3 把 zip 里的 VOC 转成 YOLO最小可跑代码现在的常见做法是写一个 Python 脚本循环读取 XML把边界框坐标从像素转成归一化值写出对应的 TXT 文件。我一般会把这个脚本放在数据集根目录下作为一个可重复执行的转换工具因为后续每次补充标注都要再跑一遍。下面是最小可用版本import os import xml.etree.ElementTree as ET from glob import glob # 类别清单顺序必须与 classes.txt 一致 CLASSES [sitophilus, tribolium, rhizopertha] # 玉米象、赤拟谷盗、谷蠹 def voc_to_yolo(xml_path, output_dir): tree ET.parse(xml_path) root tree.getroot() img_name os.path.splitext(os.path.basename(xml_path))[0] # 图片真实宽高XML 里通常带 size 节点 img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): cls obj.find(name).text if cls not in CLASSES: continue cls_id CLASSES.index(cls) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 换算归一化中心坐标与宽高 x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) out_path os.path.join(output_dir, img_name .txt) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines)) if __name__ __main__: os.makedirs(labels/train, exist_okTrue) os.makedirs(labels/val, exist_okTrue) for xml in glob(annotations/train/*.xml): voc_to_yolo(xml, labels/train) for xml in glob(annotations/val/*.xml): voc_to_yolo(xml, labels/val)逻辑说明很简单先用ElementTree遍历 XML找到size节点里的图片宽高再遍历所有object拿到类别名和bndbox四个坐标。归一化的核心公式是中心点 (最小坐标 最大坐标) / 2 / 图片边长宽度和高度则直接做差后除以边长。这样做的好处是任何图片尺寸都能统一到 0~1 的范围训练时 YOLO 会在缩放图片后依然能还原目标位置。这里有三个参数必须根据实际数据集调整。第一是CLASSES列表它的顺序和内容要严格等于数据集自带的classes.txt否则索引错位不会报错只会让模型学错目标。第二是xml_path的目录这个脚本假设标注放在annotations/train和annotations/val如果你的 zip 解压后目录叫VOC2007/Annotations那 glob 路径也要改。第三是输出目录labels/train和labels/valYOLOv8 要求标签目录名和图片目录名在同一层级下后面训练章节会讲到这个目录结构。3. 用 YOLOv8 在自己的数据上训练数据准备与关键参数3.1 把数据集改造成 YOLOv8 能直接吃的目录结构YOLOv8 的训练脚本对数据集目录有固定要求。它不是看文件后缀而是按images和labels两个目录找对应关系。同一张图片images/train/xxx.jpg的标签必须放在labels/train/xxx.txt前缀一致否则训练时会被静默跳过。很多初学者把 VOC xml 转成了 txt却散放在同一个目录里结果训练了一百轮mAP 一直是 0就是因为这个目录结构不对。我们从 zip 解压后最好先手工整理成下面这样再用 YAML 文件指给 YOLOgrain_pest_dataset/ ├── images/ │ ├── train/ │ │ ├── grain_001.jpg │ │ └── grain_002.jpg │ └── val/ │ ├── grain_100.jpg │ └── grain_101.jpg ├── labels/ │ ├── train/ │ │ ├── grain_001.txt │ │ └── grain_002.txt │ └── val/ │ ├── grain_100.txt │ └── grain_101.txt └── data.yaml这里的data.yaml是训练入口里面写图片和标签的绝对路径或相对路径以及类别清单。YOLOv8 要求类别的数量必须和标签文件里出现的最大索引一致。如果你的classes.txt里有 5 个类别但某些 txt 里写了索引 5训练时会直接报class index out of range。这种错在数据集很大时很隐蔽因为只在加载到那个文件时才崩。下面是一个可以直接改用的data.yamlpath: /home/user/grain_pest_dataset train: images/train val: images/val nc: 3 names: 0: sitophilus 1: tribolium 2: rhizoperthapath指数据集的根目录train和val是相对根目录的图片路径nc是类别数量names是类别名到索引的映射。这里有一个常见做法如果 zip 解压后结构已经是images和labels分目录就不要再套一层VOC2007之类的壳YOLOv8 对嵌套目录的检索不够智能路径一深就容易出问题。3.2 训练命令与五个必调参数数据整理好后训练命令本身不复杂。以 YOLOv8 为例一条最基础的训练命令是yolo detect train datadata.yaml modelyolov8s.pt epochs100 imgsz640 batch16modelyolov8s.pt表示从官方预训练权重初始化这会显著加速收敛。epochs100对于谷物害虫这种类别少、目标密集的场景通常够用。imgsz640是输入图片尺寸如果害虫很小建议改成 960 或 1280代价是显存占用上升。batch16取决于显卡8GB 显存跑 640 尺寸时batch 设为 16 可能已经接近极限跑不动就降到 8。但真正的血泪经验在于五个容易被低估的参数第一个是cacheTrue。加入这个参数后训练脚本会把预处理后的图片缓存到内存或磁盘二次训练速度能快 30% 以上。命令写成cacheram可以放内存cachedisk放磁盘推荐磁盘内存容易爆。第二个是patience30。YOLOv8 默认开启早停如果验证集 mAP 连续多个 epoch 不涨训练就会提前终止。patience控制的是“连续多少个 epoch 不涨就停”。谷物害虫数据集如果很小比如只有几百张图模型可能在第 50 轮就开始过拟合这时候patience50反而会浪费训练时间改成patience20更合理。第三个是amp。混合精度训练默认开启能省显存但在某些数据集上会造成精度不稳定。如果你发现 loss 曲线在后期剧烈抖动试着加ampFalse让训练退回到全精度。第四个是project和name。训练中间产物默认写到runs/detect/train跑多次后会变成train2、train3。我会习惯每次训练指定projectruns/sitophilus_experiment namebaseline_640这样不同实验的结果不会互相覆盖后面要看曲线和权重也方便。第五个是seed0。不设种子的话随机划分会产生不同结果复现实验很痛苦。特别是做类别不平衡处理时固定种子能让你确认效果变化来自模型还是来自随机性。把种子固定下来之后再调参才算是在做实验。实际训练命令就像这样yolo detect train \ datadata.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ cachedisk \ patience20 \ ampFalse \ projectruns/grain_pest \ nameexp_s_640 \ seed0参数说明都在上面了。跑完以后别急着看 mAP先看训练日志里的警告——如果出现 “found no labels” 或 “image 1/500: ignoring corrupt image”说明数据准备阶段有问题重新检查目录和文件名比继续往下调参更优先。3.3 验证用混淆矩阵和 PR 曲线判断数据是否干净训练结束后YOLOv8 会在输出目录里生成confusion_matrix.png和PR_curve.png。这两个图是判断数据集质量的捷径。混淆矩阵里对角线越亮越好但如果你发现某一行整行都暗说明那一类在验证集里几乎没有正确预测这往往不是模型问题而是数据问题。我最常用的验证方法是打开labels.jpg。这张图把训练集中所有标注框按类别画在图片上类别不同颜色不同。如果看到某些框超出图片边界或者某张图里目标密集到完全重叠那就是转换脚本出了问题——归一化坐标算错或者 XML 里的宽高和图片实际尺寸不一致。数据经过这种问题训练出来的模型会学出畸形的特征。还可以手动跑一个快速检测用训练好的权重预测验证集里的几张图片看看标注框是否贴合目标边缘。如果框明显偏大偏小先回去查转换脚本不要急着调模型。因为谷物害虫的体积差异很大谷蠹只有两毫米玉米象稍大如果转换时坐标四舍五入到小数点后三位小目标的框就可能偏掉几个像素。我一般会把{w:.6f}的精度至少保留到六位这个细节对小型害虫目标尤其重要。检查数据干净后再回去看PR_curve.png。这张图的曲线下面积接近 1 时说明当前特征下数据可分性很好如果曲线快速掉头向下说明训练集和验证集分布不一致检查是不是划分时把同一批粮仓的照片都塞进了验证集。4. 谷物害虫数据集的避坑与常见问题排查从 zip 到训练都有坑4.1 zip 解压后标注文件是空的现象解压 zip 后annotations目录里能看到一堆.xml文件但用脚本转成 YOLO TXT 时输出的 txt 文件是 0 字节训练时提示找不到标签。原因最常见的原因是 xml 结构里object节点没有bndbox子节点只有name。有些标注工具在画框中途保存框坐标缺失。另一个原因是解压时中文文件名乱码——zip 里的中文名用了 GBK 编码而 Linux 默认按 UTF-8 解压文件名里的“玉米象”变成乱码字符脚本按.xml后缀匹配时匹配不到对应文件自然生成空标签。解决先用unzip -O gbk重新解压一次再用 Python 打印任意一个 xml 的内容unzip -O gbk 谷物害虫目标检测数据集.zip -d grain_pest_data然后写一行检查脚本import xml.etree.ElementTree as ET tree ET.parse(annotations/train/grain_001.xml) for obj in tree.getroot().iter(object): print(obj.find(name).text, obj.find(bndbox) is not None)如果输出True说明坐标存在问题出在文件名乱码如果输出False说明标注本身不完整。处理不完整的标注文件要么删掉对应图片和 xml要么自己重新补标没有第三条捷径。4.2 标签名不一致导致训练报错现象数据集来自多个标注人员合并classes.txt里写的是Sitophilus oryzae但某些 xml 里写的是sitophilus oryzae大小写不同或者叫sitophilus_oryzae。转换脚本把这两个当成不同类别训练时出现“expected 3 classes, but found 4”或者类别索引越界。原因标注时没有统一标签字典labelImg 的自动补全功能也没拦截手工输入。目标检测数据集的标签体系一旦混乱自动处理很难完全修好。解决写一个归一化脚本把 xml 里的name统一映射到标准类别名。映射表写死为实际数据中的“标准名到别名”字典ALIAS_MAP { sitophilus_oryzae: sitophilus, Sitophilus oryzae: sitophilus, tribolium: tribolium, rhizopertha: rhizopertha, } for obj in root.iter(object): raw obj.find(name).text obj.find(name).text ALIAS_MAP.get(raw, raw)跑完后再统计一遍所有 xml 里出现的类别确认数量与classes.txt一致。这里建议把ALIAS_MAP保留在转换脚本里方便以后新增数据时继续复用。4.3 类别不平衡少数类被当成背景现象训练后的模型在玉米象上检测得很好但对谷蠹几乎没有召回验证集里谷蠹的 AP 是 0。打开混淆矩阵看到谷蠹这一行完全暗掉。原因数据集中谷蠹样本太少或者标注框太小模型在锚点分配阶段就把这些小目标当成背景忽略了。谷物害虫数据天然不平衡——主要害虫可能占 80%次要害虫只占 5%如果不处理训练会被多数类主导。解决先统计每个类别的框数量用一条命令快速看分布import glob from collections import Counter count Counter() for txt in glob.glob(labels/train/*.txt): for line in open(txt): cls int(line.split()[0]) count[cls] 1 print(count)统计完后针对少数类别做两层处理。第一层是离线增强把含少数类的图片做随机旋转、平移、亮度变化生成新图片和对应标签增加样本数。第二层是训练时按类别加权YOLOv8 没有直接暴露 class weights 参数但你可以通过data.yaml中调整每类损失权重或者用oversample的方式把少数类图片复制几份放进训练集。复制时要注意复制后的图片名不能和原图重复否则会被 YOLO 的缓存机制判重。4.4 zip 伪加密与损坏解压工具的取舍现象双击 zip 时提示“需要密码”但下载页面或说明里并没有给密码。用常见的解压软件试了几次都失败一度怀疑是文件损坏。原因这个 zip 可能不是真加密而是伪加密。zip 格式里有一个 4 字节的通用位标志其中第 0 位表示文件是否加密。有些打包工具或修改软件把这个标志位置 1但文件数据本身没有加密导致解压工具误以为需要密码。解决用 7-Zip 打开时如果它能直接列出文件内容说明只是伪加密。这种文件不需要“破解密码”只需要忽略加密标志强制解压。Linux 上可以用 Python 的zipfile模块手动修复把中央目录里的标志位改回来import struct with open(谷物害虫目标检测数据集.zip, rb) as f: data f.read() # 找到中央目录头修改通用位标志 # 这里只演示思路实际操作前先备份文件 # 也可以用 7-Zip 的 -p 空密码配合命令行强制解压不推荐的操作用 7-Zip 并输入空密码很多伪加密文件在这种情况下能直接解开。如果解压到一半报 CRC 错误说明文件真的损坏重新下载或向发布者要校验值不要试图用修复工具盲目修补修复出来的图片可能带花屏训练时会造成标签和像素错位。5. 让数据更值钱用半自动标注和伪标签扩展你的谷物害虫数据集数据集 zip 里的规模终究有限到了现场你会发现还有新的虫种、新的拍摄角度、新的光源条件。我的做法是训练一个初版模型让它帮我做半自动标注而不是把数据集当成一次性用品。具体流程分三步。第一步用已经训练好的权重对一批完全没标注的粮食害虫照片做推理导出预测框。第二步写一个过滤脚本把所有置信度低于 0.5 的框删掉只保留模型很有把握的结果。第三步把保留下来的预测框转换成 VOC 或 YOLO 格式打开 LabelStudio导入这批预标注人工只改错框和漏框比从零画框快很多。伪标签过滤脚本可以这样写from ultralytics import YOLO import os model YOLO(runs/grain_pest/exp_s_640/weights/best.pt) results model.predict( sourceunlabeled_images, conf0.5, # 低于该置信度的框直接丢弃 save_txtTrue, # 保存成 YOLO 格式标签 save_confTrue, # 在标签文件里附置信度方便复核 imgsz640, ) for r in results: if len(r.boxes) 0: os.remove(r.path .txt) # 干净图片不留空标签逻辑说明conf0.5是过滤阈值调太高会留下太少伪标签调太低会把模型幻觉当成真实目标。我一般先用 0.7 跑一遍看漏检的数量再决定降到 0.5 还是升到 0.8。save_confTrue会把第五列写成置信度人工复核时可以直接按这个值排序优先处理低置信度样本。这里有一条踩坑经验伪标签合并进数据集后一定要重新统计类别分布。因为模型对多数类更自信伪标签会进一步拉大不平衡让少数类更吃亏。我自己曾经在谷蠹数据上偷懒直接把伪标签全部混入训练集结果模型对谷蠹的召回率反而下降了。后来养成习惯每次合并伪标签前先跑一遍 4.3 的统计脚本把补充进来的样本控制在少数类上。另一个常用做法是给伪标签文件加一个source后缀训练时可以把这些文件单独放一个目录和人工标注区分开。这样即使伪标签出了错也能随时抽走不会污染整份数据。这算是给自己留后悔药。如果你用的标注工具是 LabelStudio它支持把模型预测结果作为预标注导入导入后在页面上会显示浅色框人工点击就能确认比手工标记更快。但要注意 LabelStudio 的版本有的版本要求模型输出 COCO 格式YOLO 的 txt 需要先转成 COCO JSON 才能导入。转换脚本不复杂但每换一个工具就要多一步转换这也是我在小团队里倾向直接用脚本生成伪标签文件的原因——少绕一段路。回到开头那句话谷物害虫目标检测数据集.zip 的价值不在于压缩包本身而在于它能不能快速变成你模型改进的起点。先用它跑通转换和训练流程再用它作为基础数据去扩展你的私有数据。模型做出来的检测框能帮你放大成几百张新标注但前提是每次合并之前都保持谨慎。希望帮到你。本文还有配套的精品资源点击获取