ARTICLE DETAIL

资讯详情

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

基于深度学习的农业病虫害检测:从数据标注到YOLOv8部署实战

基于深度学习的农业病虫害检测:从数据标注到YOLOv8部署实战 简介基于深度学习的农业病虫害检测系统是一套完整可运行的源码工程主要面向农业AI开发者、计算机视觉学习者以及智慧农业从业者用于解决农作物叶片病虫害的自动识别与分类问题。工程共包含876个文件压缩包约102.24MB其中Python文件169个承担模型训练、推理与数据处理JPG图片222个作为样本集与可视化素材YAML配置80个用于模型与训练参数设定Markdown文档343个提供说明与文档注释另有C、Rust等辅助代码便于理解跨语言工程结构。目前已吸引313人学习下载。整套代码体现了从数据划分、模型搭建到测试部署的完整流程涉及ResNet、YOLOv8等主流深度学习架构并借助Ultralytics工具链实现实时检测适合希望结合真实农业场景进行深度学习项目实战、模型调优与算法复现的开发者参考学习。1. 农业病虫害检测系统为什么偏选深度学习——先想清楚再写第一行代码一张水稻叶片照片里40 只稻飞虱若虫挤在叶鞘上每只只有几个像素。传统图像处理先做颜色分割再做形态学筛选光照一变化整套逻辑就失效。基于深度学习的农业病虫害检测系统本质上是把“有没有病、病在哪里、有多少”三个问题压缩成一个目标检测问题输入田间图像输出类别、边界框和置信度。这套方案适合两类人手里有一批作物图像、但不知道怎么组织标注的农业工程师以及想从分类 demo 走向可部署检测系统的深度学习开发者。下面按数据、模型、训练、调参、部署这条线展开给出能直接落地的源码骨架和参数设置。2. 农业病虫害检测系统的数据与标注先把模型选型的边界画出来2.1 分类、检测、分割先选清楚目标检测是默认答案纯分类模型只能回答“这张图里有没有稻瘟病”回答不了“病斑在哪个位置、面积多大”。农业现场要给定点喷药设备、无人机巡田或手机拍照诊断提供支持都需要定位能力。目标检测输出稀疏的边界框足够支撑计数和定位实例分割输出像素级掩膜适合病斑融合成片、形状不规则的场景但标注成本高出不少。如果核心诉求是虫害计数检测框加 NMS 去重后直接数框就行不必上分割。这个系统默认把核心任务定为目标检测源码结构也按检测任务组织。选型时还要考虑部署端检测模型在 CPU 上能跑分割模型在嵌入式设备上往往要降分辨率。先用检测框跑通闭环后续确有形状分析需求再升级成分割头是更稳的演进路径。2.2 公开数据集与自采数据直接拿 IP102 训练就下田会掉点公开数据集主要有两类。一类是 PlantVillage 这类叶片图像集背景单一、病斑居中适合做分类预训练直接用来检测会出现大量误检另一类是 IP102 这类大田作物病虫害数据集覆盖作物和类别更广但类别极不均衡部分类别只有几十张图且图像尺度差异大。常见做法是把公开数据集用于预训练或特征学习真正部署前用自采田间照片微调。自采数据时拍摄要覆盖清晨露水未干、正午强光、阴天、背光等条件还要包含不同生育期和不同品种叶色。负样本占比建议不低于 15% 到 20%否则模型会把土壤、杂草、水滴都当病斑。标注时有一个容易忽视的原则框住病斑本身而不是框整张叶子虫体密集时标注最具代表性的 15 到 20 只即可不必全标否则极端密集的标签会让模型学到的 NMS 参数失真。2.3 COCO 标注转 YOLO 格式的脚本训练前最容易出错的一步标注工具通常导出 COCO JSON 或 PASCAL VOC而 YOLO 系列训练需要的是归一化 txt。转换出错时训练不会直接报错而是 mAP 极低或在验证阶段框全部偏移。下面这段脚本把 COCO 的 bbox 转成 YOLO 格式import json from pathlib import Path def coco_to_yolo(json_path: str, out_dir: str) - None: with open(json_path) as fp: coco json.load(fp) # 类别重新编号YOLO 要求 id 从 0 连续递增 cats {c[id]: i for i, c in enumerate(coco[categories])} img_map {im[id]: im for im in coco[images]} out_dir Path(out_dir) out_dir.mkdir(parentsTrue, exist_okTrue) for ann in coco[annotations]: im img_map[ann[image_id]] out_txt out_dir / (Path(im[file_name]).stem .txt) x, y, w, h ann[bbox] # COCO 存左上角坐标和宽高先转中心点再归一化 cx, cy x w / 2, y h / 2 line ( f{cats[ann[category_id]]} f{cx / im[width]:.6f} {cy / im[height]:.6f} f{w / im[width]:.6f} {h / im[height]:.6f} ) with out_txt.open(a) as fp: fp.write(line \n) if __name__ __main__: coco_to_yolo(annotations/instances_train.json, datasets/labels/train)代码逻辑分三步先把 COCO 的类别 ID 映射成从 0 开始的自增编号这是 YOLO 训练硬性要求漏掉这步最常见再把左上角坐标加半宽半高换算成中心点最后除以原图宽高归一化。转换完成后抽查 30 到 50 张图把 txt 绘制回原图检查框位。数据划分时建议按地块或拍摄日期分组切分而不是纯随机切分否则同一地块相似背景会进入训练集和验证集造成数据泄漏指标虚高。3. 用 PyTorch 搭出农业病虫害检测系统的源码骨架3.1 为什么绕着 YOLOv8 转而不是手写检测网络手写检测网络涉及 Anchor Assignment、NMS、损失函数分配和正负样本采样入门者一次调稳的概率很低。农业检测系统更看重迭代速度和对田间条件的适应能力所以工程上一般选择 PyTorch 生态里封装完善的检测库。ultralytics 就是典型的一层封装训练入口、评估指标、模型导出全部打通适合做源码骨架。跟随《动手学深度学习》路线从零写网络适合打基础但作为交付源码YOLOv8n 或 YOLOv8s 是性价比更高的起点。如果团队有算法能力可以在 YOLOv8 骨架上替换或新增注意力模块比如跨窗口自注意力结构作为研究分支单独验证而不是一开始就重构整个检测头。做农业场景时骨干网络的效率比结构的先进程度更关键因为推理端经常是 Jetson 或国产加速卡这类资源受限设备。3.2 最小可复现的目录结构、数据 YAML 与训练入口源码工程按下面结构组织训练、转换、推理三个目录职责分离agriculture-det/ ├── configs/ │ └── agriculture.yaml ├── scripts/ │ ├── coco2yolo.py │ └── split_data.py ├── datasets/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/ └── train.py数据 YAML 指向图片目录并声明类别注意路径建议用相对路径避免换机器后失效train: ./datasets/images/train val: ./datasets/images/val nc: 12 names: [aphid, leafhopper, rice_blast, bacterial_blight, stemborer, planthopper, downy_mildew, rust, mite, thrip, healthy, soil]训练入口用 Python API 更好传参和记录实验脚本化执行时再改用命令行from ultralytics import YOLO model YOLO(yolov8n.pt) # 预训练权重后续可换 s/m 尺寸 model.train( dataconfigs/agriculture.yaml, epochs200, imgsz640, batch16, device0, patience50, lr00.01, cos_lrTrue, plotsTrue, projectruns/agriculture, namepest-exp01, )epochs 给到 200 但配合 patience 早停农业小数据集通常在 80 到 120 轮收敛硬跑满反而过拟合。imgsz 默认 640 是性价比点蚜虫这类小目标多时可以试 1024显存不够就减小 batch。lr0 与 batch 联动batch 翻倍时学习率也要相应上调。device0 表示第一张 GPUCPU 训练则写 devicecpu。打开 plotsTrue 后会自动输出混淆矩阵、PR 曲线和 loss 曲线排错时非常有用。3.3 五个值得先动的数据增强参数数据增强配置可以直接写到训练参数或超参文件里。农业田间照片的光照变化远比公开数据集大我一般先把 HSV 扰动调高hsv_h: 0.02 hsv_s: 0.8 hsv_v: 0.6 translate: 0.2 scale: 0.6 fliplr: 0.5 mosaic: 1.0hsv_s 和 hsv_v 分别控制饱和度和明度扰动模拟早晚不同色温下的拍摄差异但 hsv_v 调到 0.6 以上时黄化病斑容易被洗白产生假阴性。translate 和 scale 对应拍摄距离和构图变化scale 调大对小目标训练有帮助。mosaic 把四张图拼成一张能显著提升密集虫体的检测效果但如果训练集本身来自同一种植区、背景单一持续使用强 mosaic 会让模型学到不自然的边界上下文。后段训练把 mosaic 降到 0.5 甚至关闭是稳定最终精度的常用做法。4. 训练、验证与阈值调参让农业病虫害检测模型稳定收敛4.1 epoch、batch size 与学习率的联动关系epoch、batch size、学习率是训练里三件联动的事。batch size 增大后梯度更平滑但学习率不跟着提收敛会变慢学习率提太多农业小样本下极易震荡。YOLOv8 默认 lr0 是 0.01batch 从 16 增加到 64 时我会把 lr0 提到 0.02 到 0.04同时打开 warmup 和 cos_lr 让学习率先升后降。农业数据量通常只有几千张warmup 的 warmup_epochs 可以设到 5让骨干网络先适应数据分布。epoch 不是越大越好。训练时观察 results.csv 里的 val/box_loss 和 val/cls_loss如果验证损失连续 30 轮不下降早停比硬跑完更划算。patience 参数就是干这个的设 50 意味着 50 轮无进步就停止最终保存的 best.pt 始终是验证集上最优的权重而不是最后一轮的权重。4.2 评估指标怎么读mAP、精确率、召回率与 F1训练完成后输出目录下会生成 results.csv、confusion_matrix.png、PR 曲线等文件。只看 mAP 不够还要看精确率和召回率的差值。指标关注点农业场景怎么读Precision检出的框里有多少是对的农药误喷成本高时精确率优先Recall真实目标里找回了多少病害发生初期漏检更严重召回率优先mAP0.5IoU 阈值 0.5 的平均精度常规汇报和模型对比的主指标mAP0.5:0.95更严苛的框质量评估小目标多时这个指标会明显偏低定喷药策略时我往往更关注 F1 而不是 mAP因为 F1 把误喷和漏喷的代价压到同一个尺度上。验证代码很简单from ultralytics import YOLO model YOLO(runs/agriculture/pest-exp01/weights/best.pt) metrics model.val(dataconfigs/agriculture.yaml, splitval) print(mAP50:, metrics.box.map50) print(mAP50-95:, metrics.box.map) print(Precision:, metrics.box.mp) print(Recall:, metrics.box.mr)如果 P 和 R 相差超过 0.15先别调模型结构回到数据和阈值上找原因。4.3 三类典型故障的排查顺序与验证命令训练 loss 下降但 mAP 不涨第一嫌疑是标签出错。用脚本抽查 txt 是否出现超界坐标、类别 ID 是否连续、负样本是不是被标成了正样本随后关掉 mosaic、降低 hsv_v 再跑一个短实验对比。蚜虫、蓟马这类小目标漏检优先提 imgsz 到 1024同时把 scale 增强调到 0.6 以上并补充密集场景图片。小目标在 640 分辨率下只有 10 个像素不到模型很难学到稳定特征单纯调参填不了数据的分辨率缺口。同一叶片混合发病时模型只输出一种病这是后处理只取最高分类分数的典型问题。YOLO 输出的每个框可以携带多个类别的置信度后处理时保留 topk 而不是 argmax就能让一个框同时报告两种病害。把后处理逻辑单独放到 scripts/postprocess.py 里统一管理不要在推理脚本里复制三份。5. 源码落地推理脚本、模型导出与置信度阈值扫描5.1 单张图片推理的最小脚本训练好的 best.pt 可以直接用于推理conf 和 iou 两个参数决定输出密度from ultralytics import YOLO model YOLO(runs/agriculture/pest-exp01/weights/best.pt) results model(field_20240512.jpg, conf0.35, iou0.45, saveTrue) for r in results: for box in r.boxes: cls_id int(box.cls) conf float(box.conf) x1, y1, x2, y2 box.xyxy.tolist()[0] print(f{model.names[cls_id]} {conf:.3f} ({x1:.1f},{y1:.1f},{x2:.1f},{y2:.1f}))conf 越低召回越高但误检也越多iou 是 NMS 去重阈值虫体密集重叠时设 0.45 合适设太高会让同一个虫被重复计数。5.2 ONNX 导出与推理部署到 Jetson 或国产加速卡前先用 ONNX 做通用导出yolo export modelruns/agriculture/pest-exp01/weights/best.pt formatonnx imgsz640 dynamicTrue用 onnxruntime 做最小推理验证import onnxruntime as ort import numpy as np from PIL import Image sess ort.InferenceSession(best.onnx) input_name sess.get_inputs()[0].name img Image.open(leaf.jpg).resize((640, 640)) arr np.array(img).astype(np.float32) / 255.0 arr arr.transpose(2, 0, 1)[None] out sess.run(None, {input_name: arr})[0] print(out.shape) # [1, 16, 8400]16 4 坐标 12 类别ONNX 只导出网络前向不包含 NMS后处理要自己实现或引入部署框架的 NMS 算子。INT8 量化对蚜虫这类小目标影响明显量化校准集必须用田间实拍图不能用公开数据集凑数。5.3 用验证集扫描置信度阈值而不是拍脑袋定 confconf 定多少不该靠肉眼。下面这段脚本在验证集上扫描不同置信度的 F1选出最优值from ultralytics import YOLO model YOLO(runs/agriculture/pest-exp01/weights/best.pt) for conf in (0.15, 0.25, 0.35, 0.45, 0.6): m model.val(dataconfigs/agriculture.yaml, confconf, verboseFalse) p, r m.box.mp, m.box.mr f1 2 * p * r / (p r 1e-9) print(fconf{conf:.2f} P{p:.3f} R{r:.3f} F1{f1:.4f})把扫描结果写进runs/agriculture/thresholds.json推理服务启动时读取这个文件而不是把阈值硬编码在源码里。更换地块或新增作物数据后重跑一遍扫描阈值会随数据分布漂移这时手动改参只会越调越偏。本文还有配套的精品资源点击获取
返回列表