农业害虫检测数据集制作与YOLO训练部署全流程实践

发布时间:2026/10/14 14:33:52
农业害虫检测数据集制作与YOLO训练部署全流程实践
农业害虫检测这块我前后折腾了将近一年从最初到处扒公开数据集凑合着跑YOLO到最后痛下决心自己拍、自己标了3200张中间踩的坑比预想的多得多。这套数据集不算大但它是我实测下来够用和不够用的分水岭也是让我把YOLOv8、YOLOv9乃至后来导出ONNX、部署到Jetson Orin上这一整条链路跑通的根基。这篇文章不聊空泛的智慧农业前景就实打实说说这套农业害虫检测数据集怎么做出来的、YOLO训练时哪些参数要命、标注环节如何避免返工以及在田里实际部署时最容易翻车的几个细节。如果你也正在为害虫检测数据集用哪个YOLO训练自己的数据老是不收敛这类问题发愁这篇文章应该对你有直接帮助。1. 为什么花了三个月自己做数据集而不是直接下载公开的先说明一下这套农业害虫检测数据集的构成3200张实拍图像覆盖大田作物和部分设施蔬菜场景下的常见害虫图像分辨率以1920x1080为主部分近景为3000x2000标注格式是YOLO的txt格式按类别分文件夹存放。这个体量在深度学习数据集里属于中小规模但它解决了一个关键问题公开数据集和真实大田环境之间隔着一道肉眼可见的鸿沟。1.1 公开数据集的三处硬伤我最早用的公开数据集主要来自几个科研机构发布的水稻害虫、玉米害虫图像库还有一些从论文里扒下来的RGB图像集。用的时候发现三个问题特别痛第一背景太干净。学术数据集里大量图像是受害虫样本摆到白色背景前拍摄的或者虫子单独在叶面上、背景虚化得非常厉害。可真到了大田里背景是土、是秸秆、是杂草、是别的昆虫残体模型在干净背景上练出来的特征根本扛不住复杂背景的干扰。我把公开数据集训练出的模型拿到田里一测误报率高得离谱草叶的阴影、土壤的纹理都能触发检测框。第二目标尺寸分布失衡。公开数据集里很多图像都是把害虫拍得很大占了画面三分之一甚至一半这种样本训练出来的模型对大目标很敏感但农业监测常用的设备——无论是球机还是虫情测报灯下的工业相机——拍摄距离普遍较远害虫在画面里往往只有几十个像素。YOLO系列在小目标上的表现本来就需要专门优化如果数据里没有足够多的小目标样本模型的AP50虽然不难看真正跑起来却经常漏检。第三类别体系对不上。做植保的人都知道稻飞虱、蚜虫这类小型刺吸式害虫和草地贪夜蛾、棉铃虫这类鳞翅目幼虫在防治策略上完全是两回事。但很多公开数据集把害虫拢在一起或者只区分害虫/益虫这对实际生产指导没有太大意义。我需要的是能够识别具体类目的模型而不只是这里有害虫的提醒。1.2 这套数据集的定位不是拼数量是拼场景覆盖3200张在动辄数万张的大型数据集面前确实不算多但我的思路是精标场景让每一张图像都有不可替代的样本价值。收集时重点照顾了四类最让人头疼的情况逆光与强光照正午叶子反射强光、虫子身体过曝或欠曝这类图像占10%左右用来逼模型学会看轮廓而不是看纹理。密集虫口一张叶面上同时有十几头蚜虫小框挨着小框训练模型避免NMS把相邻目标合并掉。伪装色背景尺蠖趴在枝条上、叶蝉躲在叶背这一类最难标注但对实际检测最有价值。不同生育期同一种害虫的幼虫、蛹、成虫外观差异非常大数据集里每个类别尽量覆盖至少两个发育阶段。这样设计下来3200张图虽然不多但训练出来的模型在我的三个试验田块上实测mAP50达到了0.86左右误报率比直接用公开数据训练降低了将近一半。从这个角度说场景覆盖度比纯数量更重要这是我做这套数据最大的体会。2. 从大田到标注框数据采集与清洗的几个关键决策2.1 采集设备与拍摄策略很多做农业AI的人会纠结要不要上专业设备我的建议是看你检测什么害虫再决定装备。对于蚜虫、飞虱这类体长只有几毫米的小虫手机主摄确实不够用我租了一段时间的微距镜头配合工业相机但对于粘虫、棉铃虫幼虫这类体长两三厘米的目标其实一台支持手动对焦的普通相机甚至高端手机就够用。拍摄时有三件事影响后续标注入特别深固定焦距模式。不要用自动对焦大田里风吹草动自动对焦会不停拉风箱拍出来的图像模糊率极高。我一般锁定在2到5米的对焦距离靠走动来调整构图。同一个目标拍多角度。俯拍、侧拍、逆光各来一张尤其是体型较大的鳞翅目幼虫侧面的姿态特征对识别很关键。带上小尺寸标定物。这个是我后来加的做法图像角落放一个已知尺寸的硬币或者色卡方便在标注时估算目标实际大小也方便后期做数据增强时确认尺度是否合理。2.2 清洗原则宁缺毋滥我第一轮采集了将近6000张原图最后筛到3200张清洗掉了将近一半。这个比例看着心疼但非常必要。清洗时主要剔除三类图严重模糊的运动目标。害虫不会静止等你拍风吹叶片一晃拍出来的虫子轮廓都是拖影。这类图不要指望标注框能救回来YOLO学到的会是模糊特征直接影响泛化。过曝和欠曝超过两个档位的图像。后期可以调对比度但动态范围损失的信息补不回来。存在遮挡超过50%的目标。这里有个值得讨论的地方部分遮挡的样本是不是完全没用我最终保留了一部分遮挡在30%以内的图用于提升模型的抗遮挡能力但超过一半的被遮挡目标全部剔除。因为农业害虫的形态高度相似遮挡过大时人工判断类别都可能有分歧喂给模型只会增加标注噪声。2.3 采样时间与天气的选择逻辑这里有个我在实践中总结出来的规律不同时间段拍摄的图像模型的泛化能力差异巨大。早晨和傍晚光线角度低阴影长目标与背景的对比度弱正午阳光直射叶面反光严重。一开始我贪图方便主要集中在上午十点到下午两点之间拍摄后来发现模型在早晨的检测率明显下降。补拍了大量早晨和傍晚的逆光图像后这个问题才算解决。如果条件允许阴天其实是最好的拍摄天气。云层相当于一个天然的柔光箱光线均匀阴影柔和害虫的纹理特征保留得最完整。我的数据里特意保留了20%左右的阴天图像实测对模型鲁棒性帮助很大。3. 标注规范决定了YOLO模型的天花板很多人把注意力放在训练参数上但就我的经验来看标注质量对YOLO检测效果的影响远大于网络结构和超参数调整。这个环节做得糙后面一切优化都是给烂地基装修。3.1 类别体系怎么设计才科学农业害虫标注最容易犯的错误是太细或太粗。太细比如把棉铃虫和烟青虫分成两个类但它们外观极其相似连植保专家有时都要靠显微特征才能区分模型学不到可靠区别只会引入标注噪声。太粗比如把所有蚜虫标成一类又不能区分棉蚜和桃蚜——虽然防治上它们有差异但从图像特征看确实很难分开。我最终采用的是**形态可区分原则**凡是在普通光学图像下肉眼能分辨的类别就单列分辨不了的就合并。这套数据集共分了12个类别包括稻飞虱、蚜虫、叶蝉、棉铃虫、甜菜夜蛾、斜纹夜蛾、草地贪夜蛾、粘虫、玉米螟、二化螟、瓢虫作为常见益虫参照类、以及其他害虫兜底类。加其他害虫是挺关键的决策。大田里的物种极其丰富总会有不在定义范围内的虫子出镜如果没有兜底类模型会把它硬归到相近类别里产生大量难以排查的误报。3.2 小目标标注的三个实操技巧图像中像素数小于32x32的目标在YOLO官方定义里就算小目标。我的数据集中这类目标占比接近四成标注时如果按常规方式处理模型很容易学偏。我总结了三招分享出来供参考第一招画框宁小勿大。很多标注员习惯把虫子身体的边缘留一点余量但对于小目标多留的余量可能比虫子本身还宽。检测框和真实边界之间超出一定比例会让IoU计算失真模型收敛后框的位置总偏。我要求标注小目标时框必须紧贴目标的最外围像素误差不超过3个像素。第二招编组标注后做Tiled切割。这一步对YOLO训练特别重要但经常被人忽略。我的做法是先把高分辨率原图按512x512窗口做重叠切割切割时允许同一个目标反复出现在不同子图里这样既保证了小目标在缩放后不至于变成一两个像素的灰点又相当于天然做了数据增强。训练阶段用切割后的子图推理阶段再用原图效果最稳。第三招训练时单独配置anchor。YOLOv8虽然默认的anchor策略已经比较智能但遇到小目标密集场景我还是会基于数据重新聚类anchor。我的经验是把anchor尺寸整体缩小到默认值的60%左右并且增加一个特别小的anchor尺度用来抓那些10像素级的目标。聚类操作在ultralytics里可以直接跑不复杂但对小目标类别的召回率提升明显。3.3 多人协作标注时的流程管理我前后找了几个同学帮忙标注最大教训是一致性远比速度重要。不同人对于这个虫子是不是被遮挡这个残体算不算目标的判断差异极大如果没有一份清楚的标注规范文档后期改标注的成本比重新标还高。我的做法是先统一学习一套标注规则代码仓库里放一份规则说明之后每天抽10张图交叉复标计算标注员之间的一致性。如果框的重叠度低于85%当天要求重标并找出分歧原因。另外标注文件必须定期用脚本检查比如检查框中点是否落在图像范围内、类别ID是否越界这些低级错误一旦进入训练集非常难排查。4. YOLO训练的实操记录从PyCharm环境到损失函数的真实表现4.1 环境搭建PyCharm里最容易卡的三个地方说到在PyCharm里安装配置YOLO很多新手用户卡住的不是深度学习的代码而是环境问题。我用的是PyCharm Python 3.9 CUDA 11.8的组合环境搭建有四处特别提醒一下虚拟环境选择。建议在PyCharm设置里new一个虚拟环境不要直接用系统的全局Python。深度学习的依赖版本变化太快今天装的torch版本和明天装的ultralytics可能就不兼容虚拟环境能帮你隔离混乱。PyTorch版本与CUDA匹配。这个是最常见的坑。装PyTorch时用项目官网的pip命令它会自动匹配CUDA版本不要自己手动下载torch的whl然后乱装。我见过太多人CUDA装好了但torch是CPU版本导致训练速度慢几十倍还找不到原因。Ultralytics的依赖自动安装。跑YOLO训练不用手动一个个装依赖ultralytics包会在首次import时自动检查并安装缺的包但你需要在PyCharm的设置里确保它使用的pip来源畅通否则这个自动检查过程会卡住。如果用的是jetson orin这类ARM平台安装过程和PC端不完全一样。我在Orin上用的是JetPack 5.1自带的CUDA 11.4PyTorch要选对应arm版的预编译包pip默认源里没有得手动指定平台标签。这块网上资料不少但版本对应关系容易错建议装之前先查清楚。4.2 数据集划分与目录结构YOLO训练对数据集目录结构有严格约定我踩过坑后才规范起来的dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── data.yaml └── train.pydata.yaml里要特别注意两点path字段用绝对路径还是相对路径取决于你的训练脚本在哪个目录执行我建议统一用相对路径并固定工作目录避免换个机器跑就要改一堆配置nc和names必须和实际类别数保持一致这个看似简单但我确实见过有人改漏了训练一个多小时才发现loss不太对一查发现少了一个类别。划分比例我用的是8:1:1也就是2560张训练、320张验证、320张测试。对于小规模数据集验证集太少会导致调参时评估结果振荡剧烈测试集太少则无法判断模型真实泛化水平。另外划分前一定要按图像来源做分组隔离同一个场景连拍的图像不能同时出现在训练集和验证集里否则验证分数虚高换到真正的新场景立刻现原形。4.3 训练参数与损失值的经验参考我试过YOLOv8n、YOLOv8s、YOLOv9c这几个体积档位简单做个对比模型版本参数量级单卡训练耗时mAP50小目标AP推理耗时YOLOv8n~3.2M约2.5小时0.810.42约6msYOLOv8s~11.2M约4小时0.840.51约9msYOLOv9c~25.5M约7小时0.860.58约14ms上面是单张RTX 3060的实测结果输入尺寸统一为640x640。可以看出小目标AP和模型容量强相关但如果部署端性能有限YOLOv8s是比较均衡的选择。训练时几个关键参数我推荐这样设置epochs小数据集建议300起步配早停机制。我的模型大概在180到220轮之间收敛稳定。batch显卡允许范围内尽量大我常用16。batch太小会让BN层统计不稳定小目标特征更难学。imgsz如果检测目标普遍很小可以考虑把训练尺寸提到896或1024但推理尺寸要相应调整否则尺度不一致会掉点。optimizerSGD配动量0.937是稳的选择AdamW在小数据集上偶尔会收敛更快但最后精度不一定更好。关于损失值这里多说一句很多人一看到loss不降了就急着调参但不同迭代阶段的loss行为差异很大。我在训练日志里留意到box_loss在前50轮下降很快而cls_loss需要更长时间。如果训练到了150轮box_loss已经降到0.04左右、cls_loss还在0.3附近波动这种状态其实是正常的不用太焦虑。反而是val_loss在训练中后期出现明显回升趋势说明过拟合或者验证集划分有问题需要停下来排查。4.4 数据增强的取舍该开的开不该开的别乱开ultralytics默认开启Mosaic、Flip等增强策略但农业害虫检测场景里有些增强反而有害。举几个具体的例子Mosaic增强把四张图拼在一起帮助模型学习小目标在复杂背景下的表现强烈建议保留。但当目标极小、每张图里目标数量又少的时候Mosaic后的图像里目标可能被切割到边角我遇到过切没了的情况导致标注框消失。解决办法是把mosaic概率从默认的1.0调低到0.5。随机旋转不要开太大角度。害虫的朝向有一定的生物习性规律比如幼虫通常沿叶片主脉方向爬行旋转90度会让样本失真。我限制在±15度以内。HSV增强很有用但饱和度不要拉满。大田环境下不同光照会让虫子颜色发生偏移适度做HSV增强能提升模型的抗光照能力我设置hsv_h0.02、hsv_s0.5、hsv_v0.4。5. 从YOLO训练结果到田间部署导出ONNX和实测翻车记录模型在电脑上跑得好不代表在田里就能用。这一步我翻过好几次车把过程梳理出来给大家避坑。5.1 模型导出ONNX的常见报错训练好的模型要部署到边缘设备一般先把pt权重导出成ONNX或TensorRT格式。导出命令并不复杂但要留意几点from ultralytics import YOLO model YOLO(runs/train/exp/weights/best.pt) model.export(formatonnx, imgsz640, simplifyTrue, opset12)constraint是输入尺寸必须和训练时保持一致或者至少是训练尺寸的整数倍。我一开始图省事训练时用640导出时用512想减小计算量结果小目标检测率掉了将近一半。后来才明白YOLO的检测头和特征金字塔对输入尺度很敏感训练和部署尺寸不一致等于让模型面对它不熟悉的成像条件。simplifyTrue这个参数值得开它会在导出后对计算图做简化去掉一些冗余结构对推理速度有帮助。如果在导出时遇到opset版本过高导致部署端不支持的报错把opset从17降到12基本能解决问题。5.2 在Jetson Orin上部署的实测配置我把最终选定的模型部署在一块Jetson Orin NX上配合虫情测报灯进行周期性拍照识别。部署链路是pt - ONNX - TensorRT engine精度用FP16。部署时几个重要参数供参考配置项我的设置说明TensorRT精度FP16比FP32快约1.5倍精度损失可接受最大batch1拍照单张推理不需要大batchworkspace4GB太小会在build engine时报显存不足输入尺寸640x640原图实测后没有再压缩推理耗时约8ms比RTX 3060上慢一点点但完全够用实测中还有个问题是Jetson平台的CPU端图像预处理。YOLO的预处理包括resize、归一化、通道变换这些在PC上毫秒级完成但在ARM平台如果没做优化耗时可能比模型推理本身还长。我一开始没注意到后来发现单张图总耗时达到60ms其中前处理占了40ms。解决办法是改用TensorRT自带的有效内存的预处理方式或者用CUDA加速的resize函数总耗时降到15ms以内。5.3 田间实测不理想的三类典型案例部署完成后我跑到田里做了连续两周的实测效果总体可用但有几类情况每次都会出问题阴雨天湿气大、镜头起雾。这个和模型无关但直接导致检测率崩到30%。后来在硬件层面加了镜头加热丝才算解决。距离过远导致目标只有十几个像素。这种情况在PC端测试时被我忽略了因为测试集里小目标像素平均在25到40之间。真到了大田测报灯拍摄距离超过3米时目标可能就十几像素模型基本束手无策。后来调整了架设高度把有效成像距离控制在1.5到2米才明显好转。晚上补光灯下的色偏。虫情测报灯或夜间监测必然要用人造光源但LED补光灯的色温和太阳光差异很大害虫体表的特征颜色会发生偏移。我在数据集中补了不少夜间灯照下的图像把夜间场景单独归入训练模型的夜间检测率从0.55提升到了0.79。6. 数据集的迭代维护别让模型在两个月后变废农业场景最大的特点是季节性。六月份的虫口构成和九月份完全不是一回事如果你的模型只在一个时段采集的数据上训练过两个月就可能严重掉点。这套数据集我到现在还在持续维护核心就两件事新增数据和校验旧标注。6.1 新增类别时如何最小化返工随着监测范围扩大免不了要往数据集里增加新类别。最错误的做法是把新类别数据和旧数据混在一起直接重新训练这样容易灾难性遗忘——模型可能学会新类别但旧类别的精度明显下滑。我推荐两阶段训练思路第一阶段用全部旧数据 部分新数据冻结骨干层参数微调让模型适应新类别第二阶段解冻全部参数用完整数据集以较低学习率做整体精调。这样做下来旧类别精度几乎没有下降新类别也能在相对较少的数据量下达到可用水平。新类别起步阶段不要只加几十张就丢进去训练。我建议至少采集200到300张、覆盖5个以上场景的新类别数据否则模型很容易把新类别学成背景纹理的某种变体测试时大量误检。6.2 定期用误报反查标注质量模型部署到田间后每周都会产生大量带检测框的现场图像。我是这么利用它们的把所有置信度高于0.5但实际是误报的框单独存下来定期人工复查如果发现某类误报集中出现回去查标注文件。举一个真实案例我的模型在七月份频繁把某种杂草的叶片误检成甜菜夜蛾查了训练数据才发现早期标注里有30多张图把这种杂草卷曲的叶片标成了害虫。当时因为叶片卷曲形态和幼虫有点像标注员按疑似害虫标了结果就是在模型里种下了一个系统性误报源。把错误标注修正后该类误报直接降了70%以上。所以我的习惯是每隔一个月就抽查一部分标注可视化结果把标注框叠加到原图上人工扫一遍。这个环节看起来笨但对保持部署模型长期可靠非常关键。6.3 数据集的开放心态比起独占不如共建最后说点个人体会。农业害虫检测这个方向数据的稀缺性其实远大于算法本身的难度。单靠某个人或某个团队去采集数据覆盖的地域作物类型始终有限。我做完这套3200张数据集后最大的感受是单个数据集的场景覆盖是有上限的但多个数据集交叉验证的方式能大幅提升模型的可靠性。我现在和几个做植保的朋友尝试的方式是各自维护自己区域的局部数据集但通过统一的类别定义和数据规范定期做联合评估。模型在一个地区训练拿到另一个地区做zero-shot测试这个分数比本地验证集分数更真实地反映了模型的落地能力。如果你也在做类似的数据集建议大家从一开始就把类别命名、标注规范这些底层约定做统一以后合并数据时才能省去大量格式转换和重标注的时间。农业害虫检测这条路算法开源工具已经很成熟了真正拉开差距的就是数据和实战经验。这套3200张的数据集帮我跑通了从采集、标注、训练、部署到长期迭代的全部流程也希望这篇记录能帮你在自己的项目里少走几个弯路。