☰
YOLOv5烟叶病害识别:从数据集构建到模型部署全流程
2026/10/9 12:54:00 网站建设 项目流程

简介:面向大学生课程设计、期末作业与毕业设计场景的YOLOv5烟叶病害识别源码项目,提供从数据预处理、模型训练、病害预测到结果后处理的完整工作流,适合希望系统掌握目标检测落地流程的深度学习初学者。压缩包共378个文件,以156个jpg图像样本、90个txt标注文件、36个py源码、28个yaml配置及3个pt权重为主,另含演示视频和安装文档,整体约782.55MB,目录结构清晰,便于按数据、模型与训练流程分别查阅。目前已有147人学习下载。借助这套资源,可学会烟叶病害图像的数据标注、增强与划分,理解YOLOv5的网络搭建与损失函数,并通过附带的数据集完成从训练到推理的完整实验;演示视频能直观展示运行效果,安装教程则降低环境配置门槛,帮助快速在本地复现项目,为农业病害识别类课题提供可扩展的参考基线。

1. 烟叶病害识别:模型只是工具箱,数据集才是上限

烟叶病害识别这个方向,说到底是把 YOLOv5 这样的目标检测模型,训练到能在一张烟叶照片里同时圈出病斑位置、判断病害类别。听起来是个标准的目标检测落地项目,但真正动手做过一轮的人都知道,卡住你的往往不是模型结构,而是数据:烟叶病害没有现成的公开大数据集,病斑边界模糊、叶片纹理复杂、不同生长期表现差异大,同一个病害在不同地块拍出来可能完全不像同一个东西。这个标题给出的源码、数据集、演示视频和安装教程,本质上是一套完整的复现链路——你拿到的不只是训练脚本,而是从数据标注到模型部署的整套打法。这篇文章就按这条链路拆开讲:数据集怎么构建、环境怎么搭不翻车、训练参数怎么设、哪些坑我替你踩过了。适合正在做农业检测项目、或者想把 YOLOv5 用到真实场景的开发者,照着走一遍,你就能在自己机器上跑通一个能用的烟叶病害识别模型。

2. 烟叶病害数据集的构建与标注:这一关过了,后面都是水到渠成

2.1 数据从哪来:不要指望现成数据集,自己拍是常态

烟叶病害识别最大的门槛不是模型,是数据。公开数据集里能找到的烟叶病害图片非常少,而且大多是实验室环境拍的、背景干净、光照均匀,拿到田间地头基本失灵。我自己的习惯是:如果项目对精度要求不高(比如只要区分健康叶和病叶),先从田间自然光照下拍摄开始;如果要细分到具体病害类别,就得在几个不同地块、不同生长期分别采集。拍摄时注意三个点:一是叶片要占画面主体,别让背景抢了注意力;二是同一片叶子的病斑要从不同角度、不同距离多拍几张,增加样本多样性;三是把健康叶片也拍进去,作为负样本,不然模型会倾向于“见到叶子就报病”。

采集到的原始图片先做一轮筛选,把模糊的、过曝的、叶片占比太小的删掉。我一般会控制在每张图 800×600 到 1920×1080 之间,太大训练慢,太小病斑细节丢失。数量上,每个病害类别最少 300 张原图,加上数据增强,勉强够 YOLOv5s 这种小模型起步;想训练到能实际用的水平,每个类别 800 张以上才稳。

2.2 用 LabelImg 标注:框的边界决定了模型的“视力”

标注工具用 LabelImg 就够,安装很简单:

pip install labelimg labelimg # 打开图形界面

打开后按 P 键切换到 PascalVOC 格式(会生成 XML 文件),或者直接默认 YOLO 格式(生成 txt 文件)。我推荐直接存 YOLO 格式,省一步转换。操作上就是画框、选类别、保存,没什么玄学,真正的坑在标注规范上。

烟叶病斑和通用目标检测的标注不太一样。通用场景里框人、框车,目标边界清晰,框稍微大一点小一点影响不大;但烟叶病斑是渐变的,病斑边缘从变色到正常组织是过渡的,标的时候很容易凭感觉画。我的经验是,病斑标注宁紧勿松:框紧贴病斑的明显变色区域,不要把外围的褪绿过渡区框进来。框大了,模型学到的边界就是模糊的,推理时会往外飘。另一个是遮挡问题,两片叶子叠在一起,只标看得见的部分,不要脑补被遮住的病斑范围。

标注完成后,一定做一轮复查。我自己翻车过:标了 600 张图,训练出来 mAP 看起来很高,但拿到新图上一测,框全打在叶片边缘上,后来发现是标注时有大概 50 张图的类别选错了,模型被带偏了。复查方法很简单,用 LabelImg 打开每张图过一遍,重点看两个地方:框有没有明显偏离病斑中心,类别 ID 有没有选错。

2.3 数据集目录组织与划分:按地块分,别按文件随机分

YOLOv5 的训练脚本要求数据集按固定目录结构组织。我一般这样放:

datasets/ └── tobacco_disease/ ├── images/ │ ├── train/ # 训练集图片 │ └── val/ # 验证集图片 ├── labels/ │ ├── train/ # 与图片同名的 txt 标注文件 │ └── val/ └── data.yaml # 数据集配置文件

图片和标注文件必须同名,一个 .jpg 对应一个 .txt。txt 里每行格式是:类别ID 中心点x 中心点y 宽度w 高度h,注意 x、y、w、h 都是相对图片宽高的归一化值,范围 0 到 1。LabelImg 存 YOLO 格式时会自动算好这些值,不需要手写。

划分训练集和验证集时有一个很多人忽略的坑:不要随机打乱文件再按比例切片。烟叶病害的图片往往是在同一时间、同一地块拍的,背景、光照高度相似,随机划分会把同一株烟叶的不同角度照片同时分到训练集和验证集,导致验证集“泄漏”——模型其实见过这些样本了,val mAP 虚高,一到新地块就露馅。我一般按拍摄时间或地块编号来划分,比如 A 地块和 B 地块的照片进训练集,C 地块进验证集,这样才能验证模型真正的泛化能力。

2.4 数据增强:YOLOv5 自带增强够用了,别重复叠加

YOLOv5 训练时默认开启 Mosaic、MixUp、随机仿射变换、HSV 扰动等增强,对小数据集非常友好。我的建议是先用默认增强,不要自己在预处理里再叠加一轮 OpenCV 变换。一个常见的翻车操作是:自己先把图片做了水平翻转和亮度调整存到硬盘里,又开 YOLOv5 自带的增强,结果模型在增强后的重复样本上过拟合,泛化反而更差。YOLOv5 的增强是线内实时做的,每个 epoch 看到的增强结果都不同,比你离线做几百张增强图高效得多。

小数据集上唯一值得手动干预的是类别不平衡。如果某个病害类别样本特别少,我一般会单独对这类图片做离线增强(比如旋转 90 度、加高斯噪声、局部放大),把数量补到其他类别的三分之一以上,再交给 YOLOv5 训练。这样比单纯靠 Mosaic 硬撑要稳。

3. YOLOv5 环境搭建:版本对应关系不弄清楚,装完就是黑匣子

3.1 Python、PyTorch、CUDA 的版本匹配:这是第一个劝退点

YOLOv5 的依赖很敏感,PyTorch 版本和 CUDA 版本不匹配,装完跑起来各种报错,玄学到让人怀疑人生。我用得比较稳的组合是 Python 3.8 + PyTorch 1.8.1 + CUDA 11.1,这个组合也是 YOLOv5 官方早期版本测试最多的环境。如果你拿到的是新版本的 YOLOv5 源码,也要先看 requirements.txt 里锁的 PyTorch 版本,不要直接 pip install torch 装最新版。

创建虚拟环境是必须的,我一般这样操作:

conda create -n yolo python=3.8 conda activate yolo pip install torch==1.8.1 torchvision==0.9.1 --index-url https://download.pytorch.org/whl/cu111

注意--index-url后面指定的 cu111 表示 CUDA 11.1 对应的 PyTorch 版本。如果机器没有 NVIDIA 显卡,可以装 CPU 版(把 cu111 改成 cpu),但训练速度会慢很多,适合验证代码能不能跑通,不适合真正训练。

装完后到 Python 里验证一下:

import torch print(torch.__version__) # 查看 PyTorch 版本 print(torch.cuda.is_available()) # 是否检测到 GPU

如果torch.cuda.is_available()返回 False,大概率是 PyTorch 版本和显卡驱动不匹配,或者装成了 CPU 版。这时候不要慌,先nvidia-smi看一下驱动支持的 CUDA 版本,再回到上一步选对应的 PyTorch 版本重新装。

3.2 requirements.txt 里那些装了必踩的库

YOLOv5 的 requirements.txt 里除了 torch 和 torchvision,还有几个库值得单独说一下。opencv-python必须装,但注意不要和opencv-contrib-python同时装,两个一起装会互相覆盖,导致 cv2 导入报错。matplotlib用于训练过程的可视化,版本不要太老,3.3 以上就行。pandas和seaborn是画混淆矩阵用的,如果只做训练不画图,可以注释掉,少装两个依赖少两个风险。

装依赖时有一个保守做法:

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

用国内镜像源速度快,但要注意镜像源同步可能有延迟,如果某个库版本找不到,就换成默认源。装完以后,跑一下 YOLOv5 自带的检测脚本验证环境:

python detect.py --source data/images/bus.jpg --weights yolov5s.pt

能正常输出检测结果,环境就算通了。这里有个细节:第一次跑会自动下载 yolov5s.pt 权重文件,如果下载不动,可以手动下载后放到项目根目录。权重文件属于官方预训练模型,用的是 COCO 80 类,可以直接拿来做迁移学习的起点。

3.3 训练时的硬件要求:没有 8G 显存就老实改参数

烟叶病害识别不像自动驾驶那么吃显存,但也不能太寒酸。YOLOv5s 是最小的模型,在 640×640 分辨率下,batch size 设为 16 时,显存占用大概 6~8G,这是最常用的配置。如果你的显卡只有 4G 显存,有两条路:一是把--img从 640 降到 416,batch size 降到 8,能跑但精度会掉;二是换 YOLOv5n(nano 版本),模型更小更快,显存占用可以压在 4G 以内,但精度比 s 版本低一截。

说个我的实测感受:同一个烟叶病害数据集,YOLOv5s 训练 100 轮,val mAP 能到 0.82 左右,换成 YOLOv5n,同样的参数只能到 0.74 左右。如果你的目标是跑通流程,YOLOv5n 就够了;如果是做实际项目,还是建议至少用 s 版本。显存不够不是世界末日,但不要指望靠调参把 nano 模型调到 s 的精度,天花板在那。

4. 训练自己的烟叶病害模型:配置文件、命令与三个必调参数

4.1 数据配置 data.yaml:类别名和路径一个都不能错

数据集的 data.yaml 是训练脚本读取的第一个配置文件,写错了全是白忙活。我见过最离谱的报错是在 YAML 文件里中文写路径,导致训练时找不到图片。稳妥的做法是:

# datasets/tobacco_disease/data.yaml train: datasets/tobacco_disease/images/train val: datasets/tobacco_disease/images/val nc: 3 names: ['brown_spot', 'tobacco_mosaic', 'powdery_mildew']

train和val指向图片目录,注意是图片目录不是 labels 目录,YOLOv5 会根据图片目录自动找同名的 labels 目录。nc是类别数量,和 names 列表长度必须一致,不一致会在训练开始时报错。names 里的顺序要和标注时的类别 ID 对应上——标注时 brown_spot 是 0,这里就必须是第一个,不能按字母序重排。

如果训练时提示图片路径找不到,先检查是不是用了相对路径而当前工作目录不在项目根目录。我习惯把 data.yaml 里的路径写绝对路径,一了百了。但绝对路径的问题在于换机器要改,如果用相对路径,就记住:训练命令要在项目根目录下执行,别在 datasets 目录里执行。

4.2 训练命令:最小可复现的那条命令

环境装好、数据准备好,就可以开始训练了。我用的是这条命令:

python train.py \ --data datasets/tobacco_disease/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --name tobacco_run1

拆开解释每个参数。--weights yolov5s.pt是加载 COCO 预训练权重做迁移学习,别小看这个参数,从零训练的话,100 轮可能刚起步,加载预训练权重的话同样 epoch 数能收敛到可用精度。--img 640是把输入图片缩放到 640×640,分辨率越高小病斑越容易检测到,但显存和训练时间也线性涨。--batch 16是每轮迭代的批量大小,显存不够就降到 8 或 4。--epochs 100是训练轮数,小数据集 100 轮够用了,加多了容易过拟合。--name tobacco_run1是给这次训练起个名字,输出会写到 runs/train/tobacco_run1 目录下,方便多个实验对比。

训练开始后,终端会打印每个 epoch 的 loss 值,包含 box_loss、obj_loss、cls_loss 三项。我的经验是看趋势而不是看绝对值:前 20 轮 loss 下降快是正常的,到 60 轮以后趋于平缓。如果 loss 一直震荡不降,先不要加 epoch,而是回去查数据集标注质量或者学习率。

4.3 学习率与超参数:hyp 文件里动这两个就够

YOLOv5 默认的学习率设置(hyp.scratch.yaml)对大多数数据集都适用,不需要大改。如果一定要调,我只动两个:lr0初始学习率和momentum动量。默认 lr0=0.01、momentum=0.937 是官方调过的,如果你换了数据集后发现 loss 震荡特别剧烈,可以把 lr0 调到 0.005 试试,代价是收敛会变慢。反过来,如果 loss 下降非常慢,可以把 lr0 调回 0.01 或者 0.015。

训练时还有个容易忽略的参数是--patience,默认 100,意思是连续 100 轮 val mAP 没有提升就提前停止训练。我第一次跑烟叶数据集时没注意这个参数,训练到第 80 轮停了,结果模型还没收敛完,后来改成--patience 50,让它在 100 轮的范围内多跑一截。小数据集上建议把这个值设小一点,比如 30~50,省时间。

4.4 训练结果怎么看:weights 目录和 result.png 里的门道

训练结束(或被提前停止)后,去runs/train/tobacco_run1/目录下看结果。weights/目录里有两个文件:best.pt是 val mAP 最高的权重,last.pt是最后一轮的权重。默认用 best.pt 做推理就行。results.png里画了 loss 曲线和 mAP 曲线,重点看 mAP 曲线是不是还在上升——如果最后一轮 mAP 还在涨,说明 100 轮不够,可以加--epochs 150续跑;如果 mAP 曲线涨到一半掉头向下,说明过拟合了,应该减少 epoch 或者增强数据多样性。

还有一个只看数字发现不了的问题:如果 val mAP 很高(比如 0.85 以上)但在新图片上效果很差,百分之八九十是数据划分泄漏,也就是验证集和训练集太像了。这时候回头检查第 2 章说的按地块划分方法,重新划分后再训练。

5. 烟叶病害识别常见坑与排查记录:5 条血泪经验

5.1 训练 loss 变成 NaN:先查学习率,再查标注数据

现象:训练跑到第 20 轮,终端打印的 loss 突然变成 nan,之后每轮都是 nan,模型废了。

原因:最常见是学习率太大导致梯度爆炸,其次是标注文件里有空文件或者坐标值超过 0~1 范围。我用 640 分辨率配默认 lr0=0.01 没出过这个问题,但把 img 改成 1280 后出现过一次,原因是分辨率涨了,梯度尺度变了,学习率没跟着降。

解决:优先把 lr0 降到 0.005,batch size 减半。如果还是 nan,就去检查 labels 目录下的 txt 文件,用脚本把所有标注文件的坐标值筛一遍,看有没有大于 1 或者小于 0 的。筛完删掉坏文件重训。

5.2 验证集 mAP 虚高,新图上一测就翻车

现象:训练结束看 val mAP 有 0.85,自我感觉良好,结果拿手机拍一张烟叶照片测,框全偏了,甚至把叶脉当成病斑。

原因:几乎可以断定是训练集和验证集数据划分不规范。同一片叶子、同一个背景,只是换个角度拍,验证集里有一部分样本在训练集里都有“近亲”,模型记住了背景而不是病斑特征。

解决:按地块或按拍摄批次重划数据集,确保验证集图片在拍摄时间、地点上和训练集完全没有重叠。重新划分后 mAP 会掉一些,但那个数字才是真实水平。

5.3 显存不足,OOM 报错

现象:训练一开始就报RuntimeError: CUDA out of memory。

原因:batch size 设置超过了显存容量,或者 img 分辨率太高。4G 显存强行跑 640 分辨率加 batch 16 必炸。

解决:先nvidia-smi看显存总量,按显存大小倒推配置。4G 显卡用--img 416 --batch 8 --weights yolov5n.pt;6G 显卡用--img 640 --batch 8 --weights yolov5s.pt;8G 及以上可以放开跑 640 加 batch 16。还有一个技巧是加--cache参数把图片缓存到内存,显存不变,但能减少磁盘 IO 瓶颈。

5.4 检测框乱飘,框的位置和病斑对不上

现象:推理时模型能标出类别,但框的位置明显偏离病斑,甚至框在叶片外。

原因:训练时正样本数量太少,模型没学够病斑的位置特征。另一个可能性是标注时框画得太松,把病斑周围的叶片正常区域也框进去了,模型学到的是“叶片区域”而不是“病斑区域”。

解决:先检查标注质量,把框和病斑边缘的贴合度提高;再把该类别的图片数量补到 500 张以上;最后考虑用--augment参数开启测试时增强,推理时对同一张图做多种变换再合并结果,能稍微缓解框偏的问题,但治标不治本,根子还在数据。

5.5 训练到一半,mAP 突然掉到 0

现象:训练曲线好好地往上走,到第 70 轮 mAP 突然归零,之后又慢慢恢复。

原因:数据集里有一张图片的标注文件损坏(坐标值是 nan 或者格式错乱),训练时 loss 爆炸但没中断,把权重带崩了,后面几轮又自己恢复。这个比较隐蔽,因为不是每轮都会采样到那张坏图。

解决:训练前写一个脚本遍历 labels 目录,检查所有 txt 文件的格式和数值范围。我习惯把这个检查做成数据预处理的一部分,每次新数据集进来先跑一遍,格式化数据本身就是在给训练兜底。

6. 推理部署与进阶验证:从 detect.py 到移动端的最后一步

6.1 用 best.pt 做单张图和视频推理

训练完成后,常用的是 best.pt。推理命令:

python detect.py \ --source data/smoke_test.jpg \ --weights runs/train/tobacco_run1/weights/best.pt \ --conf-thres 0.25 \ --iou-thres 0.45

--conf-thres 0.25是置信度阈值,低于这个值的检测结果会被过滤掉。烟叶病害场景里如果误报多(把正常叶判成病叶),我一般往上调到 0.35;如果漏报多(病斑没被圈出来),就调到 0.15。--iou-thres 0.45是 NMS 阈值,控制重叠框的合并力度,默认 0.45 够用,不建议乱动。

如果--source传视频文件路径,YOLOv5 会逐帧检测并输出标注后的视频。实际项目里我很少直接用 detect.py 做视频推理,它只是验证工具,真要落地还是要导出模型后自己写推理脚本。

6.2 导出 ONNX 模型:脱离 PyTorch 跑推理的第一步

训练好的模型要部署到生产环境,一般先导出 ONNX:

python export.py \ --weights runs/train/tobacco_run1/weights/best.pt \ --include onnx \ --img 640

导出后的 onnx 文件可以给 ONNX Runtime 或者 TensorRT 调用,不再依赖 PyTorch 环境。我实测过,在 GPU 上 ONNX Runtime 的推理速度比 PyTorch 快 20%~30%,在 CPU 上差距更明显。导出过程一般不会报错,如果报错大多是 torch 版本和 onnx 版本不兼容,升级 onnx 到最新版就好。导出后用onnxruntime跑一眼输出和 PyTorch 差值,确定精度没掉再进部署。

6.3 进阶验证:扩展类别到其他作物病害,一个参数都不用改

烟叶病害的标注和训练流程,换到其他作物上完全通用。我后来把同一套数据流程迁移到茶树病害上,改的只有 data.yaml 里的 nc 和 names,训练命令和参数一点没动。这就是 YOLOv5 这类框架的好处:它把通用目标检测的能力封住了,你聚焦在数据上就行。但有一个边界要承认:YOLOv5 对小目标的检测能力一般,烟叶上的早期病斑如果只有几个像素大,它大概率会漏,这是模型本身的局限,不是你的数据问题。要突破这个局限,得换 YOLOv8 或者检测头带注意力机制的模型,那就是另一个话题了。

做了一轮烟叶病害识别下来,我最大的教训是:不要急着调模型、调参数,先把数据集的划分和标注做干净,模型训练只是水到渠成的事。这个方向值不值得做?如果你手头有农业检测的项目,非常值得——它的链路短、可复现性强、迁移成本低。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询