ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

PlantVillage数据集+YOLO训练病害检测模型完整实战指南

PlantVillage数据集+YOLO训练病害检测模型完整实战指南 简介目标检测是计算机视觉的核心任务之一在智慧农业领域应用广泛。一个可靠的检测模型离不开规范的数据集和高效的训练流程。YOLO作为端到端的经典检测框架凭借实时性与精度优势成为工程落地首选。PlantVillage则是植物病害领域最具代表性的公开数据集包含数万张叶片图像为模型训练提供了坚实基础。实际项目中从数据下载、格式转换、标注处理、类别筛选到参数调优每一个环节都直接影响模型性能。合理利用预训练权重、灵活调整数据增强策略与检测阈值可以快速构建适应特定场景的作物病害识别模型。本文基于真实落地经验系统拆解用PlantVillage训练YOLO检测模型的完整链路覆盖数据准备、训练配置、评估优化及部署推理并总结常见踩坑与解决方案助力开发者快速复现并迁移到田间真实场景。1. 从 PlantVillage 到 YOLO一条被很多人走过的路做物体检测的朋友对 PlantVillage 和 YOLO 这两个词应该都不陌生。前者是植物病害图像领域的公开数据集后者是端到端目标检测的经典框架。把 PlantVillage 拿来训练 YOLO几乎是每一个入门农业视觉、或者想快速上手检测流程的人都会尝试的组合。这个搭配之所以流行是因为 PlantVillage 数据量够大、类别清晰、背景相对干净而 YOLO 又恰好是“你给它标注好的图片它就能学会框出目标”的典型代表两者结合起来能让你在很短时间内跑通一个完整的检测训练流程。这篇文章不是从零讲 YOLO 原理也不是单纯介绍 PlantVillage 有什么文件而是想以一个实际落地过的项目视角把“用 PlantVillage 训练 YOLO 检测模型”这条路上的关键环节拆开揉碎数据怎么下载、格式怎么转、类别怎么处理、训练参数怎么选、踩过的坑有哪些以及最终怎么部署到实际推理场景中。无论你是刚接触检测的学生还是准备把作物病害识别落到农业项目里的工程师这套流程都可以直接参考复现。2. 数据集认识PlantVillage 到底长什么样2.1 数据规模与目录结构PlantVillage 最初是面向图像分类任务整理的原始数据集包含大约 54000 多张叶片图像覆盖 14 种作物、38 个类别其中既包括健康叶片比如健康番茄、健康马铃薯也包括各种病害叶片比如番茄晚疫病、苹果黑星病、玉米叶斑病等。每张图片是单叶片的近景拍摄背景以灰卡、白纸或自然光照下的简单背景为主分辨率一般在几百像素到上千像素之间以 JPG 格式存储。官方数据的目录结构大概是这样的PlantVillage/ ├── Apple___Apple_scab/ ├── Apple___Black_rot/ ├── Apple___Cedar_apple_rust/ ├── Apple___healthy/ ├── Blueberry___healthy/ ├── Cherry___Powdery_mildew/ ├── Corn___Cercospora_leaf_spot Gray_leaf_spot/ ├── Corn___Common_rust/ ├── Corn___Northern_Leaf_Blight/ ├── Corn___healthy/ ├── Grape___Black_rot/ ├── Grape___Esca_(Black_Measles)/ ├── Grape___Leaf_blight_(Isariopsis_Leaf_Spot)/ ├── Grape___healthy/ ├── Orange___Haunglongbing_(Citrus_greening)/ ├── Peach___Bacterial_spot/ ├── Peach___healthy/ ├── Pepper,_bell___Bacterial_spot/ ├── Pepper,_bell___healthy/ ├── Potato___Early_blight/ ├── Potato___Late_blight/ ├── Potato___healthy/ ├── Raspberry___healthy/ ├── Soybean___healthy/ ├── Squash___Powdery_mildew/ ├── Strawberry___Leaf_scorch/ ├── Strawberry___healthy/ ├── Tomato___Bacterial_spot/ ├── Tomato___Early_blight/ ├── Tomato___Late_blight/ ├── Tomato___Leaf_Mold/ ├── Tomato___Septoria_leaf_spot/ ├── Tomato___Spider_mites Two-spotted_spider_mite/ ├── Tomato___Target_Spot/ ├── Tomato___Tomato_Yellow_Leaf_Curl_Virus/ ├── Tomato___Tomato_mosaic_virus/ └── Tomato___healthy/每个文件夹就是一个类别文件夹名就是类别名。这个命名方式对分类任务非常友好直接把文件夹名当作标签就行。但到了检测任务里问题就来了我们拿到的是一张“单叶片居中、背景干净”的图而不是“田间多叶片、多目标、自然背景”的图。这意味着如果你直接把整张图当作一个检测框目标就是整片叶子也不是不行但模型学到的东西会比较受限换个田间场景基本没法用。这里要说明一下YOLO 官方网站和不少第三方仓库都有“PlantVillage YOLO 格式数据集”的打包版本这些版本通常是把原图按 640x640 缩放然后对每片叶子生成一个接近整图大小的标注框。这类打包数据适合验证流程但真正的工业落地我建议你还是要结合自己的田间数据一起训练。2.2 从分类到检测数据集格式的“翻译”问题PlantVillage 原始数据没有标注框只有类别标签这是它训练 YOLO 前需要跨过的第一道坎。YOLO 系列从 v5 到 v8 及以后的标准标注格式是 TXT 文件每一行代表一个目标框格式如下class_id x_center y_center width height其中 x_center、y_center、width、height 都是相对于图片宽高的归一化比例值取值范围是 0 到 1。比如一张 640x640 的图片框左上角在 (160, 320)、右下角在 (480, 640)那换算出来就是x_center (160 480) / 2 / 640 0.5 y_center (320 640) / 2 / 640 0.75 width (480 - 160) / 640 0.5 height (640 - 320) / 640 0.5对应标注文件的一行就是0 0.5 0.75 0.5 0.5如果你是拿已打包好的 PlantVillage-YOLO 版本转换环节可以跳过。如果是自己从原始数据集出发最常见的做法是写一个脚本自动读取每个类别文件夹下的图片然后生成一个覆盖整张叶片区域的“虚拟标注框”。也就是说框住整张图片内容的主体区域。这里有个细节直接框整张图如 0 0.5 0.5 1 1不是最优选择因为叶片的边缘通常不会完全贴住图片边界建议用图像分割或边缘检测比如 OpenCV 的 Canny findContours先找到叶片轮廓再用轮廓外接矩形作为检测框。这样框的准确度高对后续模型收敛也有帮助。2.3 哪些类目值得做检测PlantVillage 的 38 个类目中并不是所有类别都适合做检测。从实际应用角度出发我一般会把类别分成三档档位代表类别特点检测难度推荐优先Tomato___Late_blight、Tomato___Early_blight、Potato___Late_blight、Corn___Common_rust、Apple___Black_rot病害特征在叶片表面有明显斑块/孢子堆视觉差异大低适中Tomato___Leaf_Mold、Grape___Black_rot、Peach___Bacterial_spot病斑较小或与叶脉颜色相近需要更细粒度特征中较难Tomato___Spider_mites Two-spotted_spider_mite、Squash___Powdery_mildew虫害或粉状霉层边界模糊与健康区域对比不明显高我个人的经验是第一次跑通流程时挑 5-8 个典型类别就够了类别太多会显著增加训练时间而且部分类别样本量不均衡容易出现“大类压小类”的问题。等流程验证稳定、评估指标达到预期后再逐步把类别扩到全量。3. 环境准备与数据集下载3.1 硬件与软件选型训练 YOLO 模型显卡是最关键的硬件。如果你的显卡显存是 6GB如 GTX 1660 或 RTX 2060可以跑 YOLOv8s 或 YOLOv5s 这类小模型batch size 设为 16 左右。如果是 8GB 以上如 RTX 3060 或更高可以考虑 YOLOv8m。再往上12GB 以上可以直接上 YOLOv8l 或 YOLOv8x。没有独显也不用灰心用 CPU 训练小模型、小数据集也能跑只是速度慢一些一个 epoch 可能要十几分钟。软件方面我推荐直接用下面的组合Python 3.8 或 3.10建议 3.10兼容性最稳PyTorch 2.x选择与 CUDA 版本对应的预编译包Ultralytics YOLO 库直接 pip install ultralytics版本尽量保持在 8.1 以上OpenCV用于图像读写和预处理LabelImg 或 Roboflow用于手动标注或数据集管理如果做自动标注则用脚本安装 ultralytics 库时如果网络不好可以用国内镜像源pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple装完以后可以快速验证一下环境是否正常from ultralytics import YOLO model YOLO(yolov8n.pt) # 如果网速慢可以先下载权重文件再指定路径 print(model)能正常打印模型信息就说明环境没问题了。3.2 数据集获取的几种方式PlantVillage 原始数据集可以从官方公开渠道下载但不同渠道的稳定性和速度差别很大。目前比较靠谱的三条路第一种是 Kaggle 上的 PlantVillage 数据集页面下载的是原始分类图片。Kaggle 需要注册账号下载时可以用 kagglehub 命令行工具速度比较稳定kaggle datasets download -d abdallahalidev/plantvillage-dataset第二种是 GitHub 上一些做农业 AI 的仓库自带 PlantVillage 下载链接或脚本。这类仓库通常已经帮你把数据集整理成了 YOLO 格式下载解压后就能直接用于训练。比如某些仓库把整张叶片按检测框标注好了并且附带 data.yaml 文件。选择时要留意数据集版本和标注质量先看 README。第三种是 Roboflow 平台上的公共数据集。Roboflow 上的 PlantVillage 变体通常已经做好 train/valid/test 划分甚至可以直接导出为 YOLOv8 格式。如果你不想处理格式问题用这种方式最省事。下载和解压后建议检查一下图片数量和标注文件数量是否一一对应。如果发现某些图片缺失标注文件在训练前一定要处理掉否则 ultralytics 库在加载数据时会报错或者跳过这些样本影响训练稳定性。3.3 目录结构组织无论从哪里获取数据我都建议统一整理成下面的目录结构datasets/ ├── plantvillage/ │ ├── images/ │ │ ├── train/ │ │ ├── val/ │ │ └── test/ │ ├── labels/ │ │ ├── train/ │ │ ├── val/ │ │ └── test/ │ └── data.yamldata.yaml 文件是训练入口内容如下path: /path/to/plantvillage train: images/train val: images/val test: images/test names: 0: Tomato___Late_blight 1: Tomato___Early_blight 2: Potato___Late_blight 3: Corn___Common_rust 4: Apple___Black_rot这里有一个很容易踩的坑path 字段不要写相对路径“plantvillage”要写绝对路径或相对于当前工作目录的正确路径否则训练时会报“Dataset not found”错误。如果你把数据集放在和训练脚本同级的 datasets 目录下path 可以写成datasets/plantvillage但前提是你要在项目的根目录下执行训练命令。划分 train/val/test 时我采用随机划分比例一般为 7:2:1。如果某些类别的图片数量特别少比如只有二三十张建议用分层采样保证每个类别在训练集和验证集中都有一定比例避免某个类别在验证集里一张都没有。4. YOLO 训练全流程拆解4.1 配置文件与模型选择YOLOv8 是当前最成熟、社区生态最好的版本之一。以 YOLOv8n 为例整个模型结构相当紧凑适合在算力有限或需要快速迭代的场景下使用。而 YOLOv8s 是在 n 的基础上适当加宽加深精度更高推理速度也仍然很快。对于 PlantVillage 这种背景相对单一的叶片图像YOLOv8n 其实已经能出不错的效果但如果你后续要部署到田间复杂背景建议至少用 YOLOv8s甚至在数据足够多时尝试 YOLOv8m。在数据集不大比如只有几千张的前提下我一般直接加载官方在 COCO 上预训练好的权重作为起点这样做的好处是模型已经学会了通用的特征提取能力叶片纹理、边缘、颜色的基础特征可以直接迁移比从零训练收敛快得多。训练命令如下yolo detect train datadatasets/plantvillage/data.yaml modelyolov8s.pt epochs100 imgsz640 batch16 patience20这里几个参数需要解释一下epochs100训练轮数。PlantVillage 数据类别间差异明显加上预训练权重50 轮左右损失就开始趋于平稳100 轮足够。imgsz640输入图片尺寸。YOLO 系列内部会把图片 resize 到统一尺寸。对于叶片病害检测640 是速度和精度比较均衡的选择如果目标是病斑这种小目标建议用 1280但显存占用会明显上升。batch16批大小。这是根据你显存大小定的16 是比较保守的值。如果显存不够调成 8 或 4但训练效果可能略有波动。patience20早停轮数。如果连续 20 轮验证集指标没有提升训练自动停止可以有效防止过拟合并节省时间。4.2 训练过程中的观察指标训练时终端会实时打印每个 epoch 的 loss 和指标我习惯重点看这几个box_loss检测框回归损失反映预测框和真实框的差距应该持续下降并最终趋于平稳。cls_loss分类损失反映类别判断的准确度同样的趋势。precision精确率即预测为某病害的框中真正是这种病害的比例。recall召回率即某病害所有真实样本中被正确检测出来的比例。mAP50IoU 阈值为 0.5 时的平均精度这是最常用的判断指标一般能到 0.9 以上说明模型效果很好。mAP50-95IoU 从 0.5 到 0.95 的平均精度要求更严格用来判断检测框的精准程度。如果你的训练过程中cls_loss下降不明显而mAP50已经很高很可能是数据集中某些类别本身视觉差异就小模型难以区分。这时候优先检查类别配置和标注质量而不是盲目加大模型。别急着调参先把训练日志翻一遍看 loss 曲线和验证集上的预测样例图往往比改参数更能发现问题。训练结束后模型会保存到runs/detect/train/weights/best.pt。这个 best.pt 是根据验证集指标选出来的最优权重后续推理和部署都使用它。4.3 常见训练参数调整有一个我反复强调的参数是mosaic。ultralytics 默认开启了马赛克数据增强也就是把四张图拼成一张。这个增强对提升模型泛化能力很有帮助但它生成的图片和真实田间场景差异较大而且如果数据集本身已经有了不少重复背景马赛克增强可能会导致模型学了太多“拼接痕迹”。如果训练时发现验证集 mAP 波动很大可以试着把增强关掉一部分yolo detect train datadatasets/plantvillage/data.yaml modelyolov8s.pt epochs100 imgsz640 batch16 mosaic0.0另外hsv_h、hsv_s、hsv_v这三个参数分别控制色调、饱和度、明度的随机变换范围。叶片图像在真实拍摄环境中光照变化很大把hsv_s从默认的 0.7 调高到 0.9可以提升模型对光照变化的鲁棒性。但要记得改动增强参数后模型训练时间会变长因为每个 epoch 的数据变换计算更多了。如果检测目标很小比如早期病斑只有几个像素可以开sahi切片推理或者用 YOLO 的--rect参数让模型训练时按宽高比分组 batch减少 resize 带来的形变影响yolo detect train datadatasets/plantvillage/data.yaml modelyolov8s.pt epochs100 imgsz640 batch16 rectTrue4.4 评估模型不只盯着一张 P-R 曲线训练完后用验证集评估是最基本的一步yolo detect val datadatasets/plantvillage/data.yaml modelruns/detect/train/weights/best.pt命令行会输出每个类别的详细指标包括 precision、recall、mAP50、mAP50-95。但只看这个还不够我建议你实际跑一张图片看一下检测效果。用 ultralytics 的预测接口直接跑验证集里的图片from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict(sourcedatasets/plantvillage/images/val/0a1b2c3d.jpg, saveTrue, conf0.25)conf0.25表示置信度阈值低于 0.25 的框会被过滤掉。在实际场景中这个阈值需要根据你的需求调整。如果是做病害普查希望不漏检阈值可以放低到 0.1如果是做自动喷药决策希望尽量减少误报阈值调到 0.5 以上更合适。我自己在跑 PlantVillage 时经常发现一个问题模型对健康叶片healthy 类的置信度非常高但对某些早期病害的置信度普遍偏低。这时候我倾向于把健康类单独作为一个类别保留而不是删掉它。因为在实际应用中模型必须能区分“健康”和“染病”如果你只训练病害类模型会把所有叶片都框出来并给出一个病害标签这在田间是致命的误报。5. 常见问题与排查技巧实录5.1 数据集问题标注文件缺失或大小为零。这种情况在从网上下载的打包数据集中非常常见。训练时 ultralytics 会在加载数据阶段跳过这些图片但可能静默处理导致实际参与训练的图片比预期少很多。我的排查方案是写个脚本扫描一下import os from pathlib import Path img_dir Path(datasets/plantvillage/images/train) label_dir Path(datasets/plantvillage/labels/train) missing [] for img in img_dir.glob(*.jpg): label label_dir / (img.stem .txt) if not label.exists() or label.stat().st_size 0: missing.append(img.name) print(fMissing or empty labels: {len(missing)}) for name in missing[:10]: print(name)类别编号错位。YOLO 标注文件里的第一个数字是类别 ID这个 ID 必须和 data.yaml 里的顺序严格一致。很多人从 Roboflow 导出后又手动改了 data.yaml 的类别顺序而忘记改标注文件里的 ID结果就是模型训练的类别和真实类别完全错位。训练之前做个抽样检查读几个 TXT 文件看看第一列数字的范围是否在 0 到类别数-1之间。图片通道问题。PlantVillage 偶有灰度图或 PNG 带透明通道的图YOLO 训练会把图片统一转成 RGB如果原图是 4 通道部分版本的 OpenCV 读取时会出错。统一在预处理脚本里转一次img cv2.imread(str(path)) if img is None: print(fCannot read: {path}) continue if img.shape[2] 4: img cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)5.2 训练问题Loss 不降或 NaN。Loss 不降的常见原因是学习率过大或数据集太脏。YOLOv8 默认学习率是 0.01对于小数据集可以尝试调低到 0.001。出现 NaN 时先检查图片里有没有全黑或全白的坏图、标注框坐标有没有超出 0-1 范围再用--cache参数把图片缓存到内存中排除磁盘读取问题。GPU 显存不足。典型报错是CUDA out of memory。最快的解决方式是调小 batch 和 imgsz但如果你不想牺牲太多精度可以用梯度累积。ultralytics 没有直接的梯度累积参数但可以通过增大 batch 的等效效果来实现把 batch 调小一半同时把 epochs 翻倍。另外可以关掉--cache避免缓存图片占显存。验证集 mAP50-95 很低但 mAP50 很高。这说明模型能大致框出目标但框的位置还不够精准。优先检查标注框是否贴边、是否比实际叶片大了很多。如果你是用脚本自动生成的虚拟框这个问题几乎是必然的。解决办法有两个一是手动精修验证集和测试集里的标注框只修几百张也够了二是用更精细的自动标注方案比如先用分割模型提取叶片掩膜再取掩膜外接矩形这样可以显著提升检测框的质量。5.3 推理部署问题YOLO 模型训练完了最终目标是部署到实际应用中。ultralytics 支持导出多种格式yolo export modelruns/detect/train/weights/best.pt formatonnx yolo export modelruns/detect/train/weights/best.pt formatengine device0 # TensorRTONNX 格式适合跨平台推理和 CPU 部署TensorRT 适合 NVIDIA GPU 上的高性能实时候选。部署时有一个细节ONNX 模型输出的结果是 [1, 84, 8400] 的三维数组84 是 4 个坐标 80 类如果是 COCO 预训练模型或 4 类别数。如果你直接用官方 ONNX 导出输出维度可能需要你手动做 NMS非极大值抑制后处理而 ultralytics 的 Python 推理接口内部已经帮你处理了。差异要特别注意否则部署代码很容易出问题。还有一个非常实用的小技巧导出 ONNX 时输入尺寸是固定 640x640如果你的实际推理图片大小不是 640模型会自动 resize但检测框的坐标也会随之缩放。因此推理时一定要记录原始图片尺寸并将模型输出的坐标按比例映射回去否则画框会错位。这个坑我见过至少三次每次都是部署阶段才暴露出来。6. 实际扩展从 PlantVillage 到真实场景6.1 数据增强与域适应PlantVillage 数据集的干净背景在训练时是优势但部署到现实场景就成了短板。田间的叶片有泥土遮挡、有光照不均、有重叠叶片、有复杂背景直接用 PlantVillage 训练的模型预测田间图片召回率会显著下降。解决方向是数据增强和域适应对训练图片做随机旋转、平移、缩放、色彩扰动以及模拟光照变化。更进阶的做法是收集少量真实田间数据哪怕是几十张加入训练集做“小样本域适应”。我试过最有效的组合是PlantVillage 数据 10%-20% 的田间实拍数据混合训练。由于 PlantVillage 数据的类别标注准确、背景干净它能提供稳定的特征基础而田间数据能帮模型适应真实场景的亮度、纹理和背景干扰。混合训练时建议把田间数据放在验证集中观察农田真实场景的 mAP而不是只在 PlantVillage 自己的验证集上自嗨。6.2 从单叶片检测到多叶片计数如果你想在真实田间统计病害叶片数量只做“检测出叶片并分类”是不够的还需要处理叶片重叠问题。YOLO 检测天然会为每片叶子生成一个矩形框但重叠叶片会被矩形框框住多个目标或漏检。这种情况我会在 YOLO 后处理阶段加一个跟踪计数逻辑对相邻帧的检测框用 IoU 进行匹配或者配合 ByteTrack 等跟踪算法实现叶片级计数。6.3 标注生产化半自动标注流程如果你需要制作自己的植物叶片检测数据集纯手工标注的效率太低。推荐一条半自动流程先用 PlantVillage-YOLO 训练一个初始模型然后用这个模型去推理未标注的田间图片生成“高置信度”的预标注框再人工修正低置信度区域。这样可以在一两天内完成原本需要一两周的标注工作。这个流程里预标注结果的质量取决于初始模型的精度建议初始模型先在 PlantVillage 的 5-8 个核心类别上训练扎实再做预标注。总的来说PlantVillage 配合 YOLO 训练出来的模型绝不是只能停留在实验室演示。它可以作为一个强力的“预训练基底”帮你快速启动植物叶片检测项目。根据我的实测经验用 YOLOv8s 在 PlantVillage 约 8000 张训练图上训练 100 轮验证集 mAP50 普遍能到 0.95 以上这个成绩已经具备相当好的参考价值。但真正决定项目成败的还是你在数据清洗、标注修正、阈值调整和场景适配这些“不起眼”环节投入的精力。搞懂这条链路你就有能力把任何一套公开数据集快速嫁接到自己的检测项目里。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进