YOLOv5烟叶病害识别实战:从数据集到模型部署的完整指南
发布时间:2026/9/26 16:29:41 作者:尧图编辑部 阅读量:1,286

简介面向深度学习和目标检测方向的高校学生这份基于YOLOv5的烟叶病害识别项目提供从源码、数据集到演示与安装的完整闭环尤其适合课程设计、期末大作业与毕业设计等场景。项目共378个文件以jpg图像样本、txt标注文件、py训练代码及yaml配置为主辅以pt模型权重、mp4演示视频和docx环境部署文档压缩包约782.55MB覆盖数据预处理、模型训练、病害预测与结果后处理全流程。随包数据集包含多种经过标注与分类的烟叶病害图像可用于训练、验证模型并理解数据增强、图像分割、特征提取等环节。已有147人浏览学习结合安装教程和演示视频可快速搭建环境并复现识别流程通过亲手调参与结果分析还能深入理解YOLOv5结构、CNN原理、损失函数及梯度下降等知识点为农业视觉应用打下实践基础。1. YOLOv5烟叶病害识别到底能解决什么从数据集到源码包的完整链条烟叶种植最大的痛点之一是病害发现滞后等叶片上出现肉眼可见的病斑再处理损失往往已经造成。基于YOLOv5的烟叶病害识别源码包把目标检测模型、训练脚本、已标注数据集和演示视频打包在一起目标很明确让农业工程师或者有一定Python基础的人能在本地用现成数据快速训出一个能识别烟叶病害的检测模型。这套源码适合两类人一类是拿现成数据集做复现验证YOLOv5在作物病害识别上的效果另一类是要真正落地到田间或质检线的需要把自己的病害照片整理成带标注的数据集再完成训练和模型导出。它解决的不是算法创新问题而是“拿什么训、怎么训、训完怎么用”这条工程链路这也是它比单纯贴几行YOLOv5代码更有价值的地方。2. 把烟叶数据集按YOLOv5规范备好标注格式、类别平衡与目录结构2.1 YOLOv5的网络结构对烟叶病害场景的适配性YOLOv5的Backbone采用CSPDarknet这一设计在减少计算量的同时强化了梯度传播。对于烟叶病害这种目标尺寸偏小、形态不规则的检测任务YOLOv5在三个尺度上做特征融合浅层特征图保留叶片纹理和病斑边缘信息深层特征图负责语义判别。病害叶片和健康叶片的差异往往只是几个像素级别的色变这个多尺度机制比两阶段的Faster R-CNN更适合实时筛查也比YOLOv8的重型C2f模块更轻量训练和推理对硬件的要求都更低。从数据构成的视角来看烟叶病害识别的关键不是网络结构多先进而是标注数据够不够细。黑胫病、赤星病、花叶病、气候斑点病这四类在华南烟区最常见如果训练集里各类别数量差超过5倍模型的mAP会被多数类带偏。这个源码包附带的数据集通常按Pascal VOC格式或YOLO txt格式组织前者方便用LabelImg可视化检查后者直接喂给YOLOv5的DataLoader。转换时需注意VOC的XML里每个object的name字段要严格小写且不能有空格否则YOLOv5解析类别时会直接报错。2.2 数据准备从原始图片到YOLOv5能直接读的目录结构拿到源码包后第一步不是急着跑train.py而是先把数据集目录理顺。YOLOv5要求的目录约定是images和labels一一对应每一张jpg对应的txt标注文件要同名、同相对路径。常见做法是把原始数据按8:1:1划成train/val/test三个集合而不是用YOLOv5默认的随机划分方式。原因在于烟叶病害样本往往同一批烟田的照片背景高度相似如果随机划分验证集可能混入训练集同田块的图片导致mAP虚高部署后才发现真实场景效果远不如测试指标。下面是按田块划分数据集的参考脚本能避免同源数据泄漏到验证集import random import shutil from pathlib import Path src Path(raw_data) # 原始数据目录 out Path(datasets/smoke_disease) # 输出目录 # 按田块编号作为最小分组单位先打乱田块再切分 fields sorted(set(p.parent.name for p in (src / images).glob(*/*.jpg))) random.seed(42) random.shuffle(fields) n len(fields) train_fields fields[:int(n*0.8)] val_fields fields[int(n*0.8):int(n*0.9)] test_fields fields[int(n*0.9):] for split, split_fields in [(train, train_fields), (val, val_fields), (test, test_fields)]: for img in (src / images).glob(*/*.jpg): if img.parent.name in split_fields: shutil.copy(img, out / images / split / img.name) lbl src / labels / img.parent.name / (img.stem .txt) if lbl.exists(): shutil.copy(lbl, out / labels / split / (img.stem .txt))这段脚本的逻辑是把同一田块的照片视为一个不可分割的整体按田块维度打乱和切分。这样验证集和训练集不会出现背景几乎完全一致的同田块照片指标会真实很多。seed固定为42是为了保证每次跑脚本划分结果一致方便复现实验如果你手头数据是单张散图没有田块归属信息退而求其次按单图随机划分也可以但要清楚mAP里会掺一点水分。2.3 标注工具选择和类别平衡处理的开源方案开源方案里最常见的是LabelImg和labelme两种。对YOLOv5而言LabelImg直接输出Pascal VOC的XML再用源码包或自写的voc2yolo.py转成txtlabelme输出JSON需要额外写一层转换逻辑。我的经验是烟叶病斑边界不规则用labelme画多边形比矩形框更贴近真实轮廓但转成YOLO的xywh格式后检测框仍是矩形多边形转矩形框会把大量健康叶面背景包进来反而干扰病斑特征学习。折中做法是先用矩形框标整体病斑区域随后做一次中心裁剪把健康背景的占比压到30%以下让模型更聚焦病斑本身。类别平衡是烟叶病害数据集的另一个关键。假设你手头有2000张图其中花叶病800张、黑胫病700张、赤星病300张、气候斑200张不做任何处理直接训练模型对赤星病和气候斑几乎处于“半盲”状态。处理手段有两类一类是图像级增强对少数类做随机旋转、HSV扰动、Mosaic拼接另一类是在损失函数层面对YOLOv5的cls_loss改用Focal Loss思路把对易分样本的抑制权重调高。这两种方式在后续训练阶段的具体操作我会在第3章详细展开。3. 在本地跑通YOLOv5烟叶病害训练环境搭建、关键参数与模型评估3.1 安装教程用conda建环境、锁版本、装依赖YOLOv5的依赖清单不算长但版本错配是新手最容易翻车的地方。这个源码包一般自带requirements.txt我的建议是不要直接pip install -r requirements.txt一把梭而是用conda先把Python版本锁在3.8到3.10之间再单独装PyTorch。一个在农业图像处理场景里稳定跑通的组合是conda create -n yolo5 python3.8 -y conda activate yolo5 pip install torch1.12.1 torchvision0.13.1 --extra-index-url https://download.pytorch.org/whl/cu116 pip install -r requirements.txt这里把PyTorch固定在1.12.1是因为这个版本对YOLOv5的混合精度训练支持最稳后续2.x版本改动较多容易出现NMS算子不兼容的问题。如果你的显卡驱动只支持CUDA 11.x以下版本可以把cu116改成cu113对应关系不能弄错。装完依赖后用python -c import torch;print(torch.cuda.is_available())验证GPU可用这一步是后续所有训练的后悔药很多问题出在环境阶段而不是训练阶段。注意opencv-python建议用4.8以下版本4.9以上对部分农业相机拍摄的异常色彩空间图片存在解码失败的问题训练时会在数据加载阶段直接卡死。3.2 训练自己的数据集五个必调参数和它们的边际影响环境就绪后先用默认参数跑通一次10个epoch的短训练确认数据加载和模型前向传播没报错再进入正式的参数调整。针对烟叶病害数据集的完整训练命令如下python train.py \ --data data/smoke_disease.yaml \ --weights yolov5s.pt \ --img 640 \ --batch-size 16 \ --epochs 100 \ --cache ram \ --device 0每个参数拆开看--img 640是输入分辨率烟叶病斑很多是几十像素的小目标640是速度和召回率的平衡点不要为追求精度盲目上1280显存占用涨4倍训练速度掉一半。--cache ram把图片预加载进内存能省掉每轮epoch的磁盘IO等待前提是内存够大2000张640x640的图大约占1.5GB内存可以接受。--epochs 100对烟叶这种数据量级够用再多容易过拟合。--data data/smoke_disease.yaml里的内容也值得细看它决定了模型从哪里读数据、检测哪几类目标。一个典型的yaml文件包含路径和类别名两部分train: datasets/smoke_disease/images/train val: datasets/smoke_disease/images/val test: datasets/smoke_disease/images/test nc: 4 names: [black_shank, brown_spot, mosaic, climate_spot]nc必须和names列表长度一致否则训练启动时直接报错。训练你的自定义数据集时只改这两处是不够的还要确认datasets/smoke_disease/labels下的txt标注文件和这里的类别顺序对得上。txt每行是class_id x_center y_center width heightclass_id从0开始对应names列表的下标。类别顺序不一致是最隐蔽的坑训练过程中不报错但推理结果全错。3.3 模型评估从PR曲线到推理测试集判断模型是否真的能用训练结束后YOLOv5会在runs/train/exp目录下生成一系列指标文件最关键的是PR_curve.png和confusion_matrix.png。看PR曲线时mAP0.5并不是唯一指标更应该关注Recall在0.8以上的区间因为烟叶病害漏检的代价远高于误检——漏一个病斑可能导致整片烟田的处理延误。如果模型recall卡在0.7上不去优先增加训练epoch其次检查标注是否遗漏太多导致模型学不到完整特征。推理阶段的评估同样不能跳过。对测试集跑一遍python detect.py \ --weights runs/train/exp/weights/best.pt \ --source test_images/ \ --conf-thres 0.25 \ --iou-thres 0.5 \ --save-txt--conf-thres 0.25是置信度阈值烟叶病害推理建议调到0.2左右因为病斑边缘模糊模型预测置信度天然偏低阈值太高会把大量真实病斑过滤掉。配合--save-txt可以把每张图的检测框坐标、置信度和类别ID直接存成txt文件方便后续统计每片烟田的病害发生率。落地阶段还要关注一点训练时--img 640推理时如果用了别的分辨率输出框的坐标尺度会不一致必须先letterbox再推理。3.4 超参数配置hyp.yaml里值得动的三个位置YOLOv5把超参数集中在data/hyps/hyp.scratch-low.yaml里很多人训练自己的数据集时完全不管这个文件其实里面有三个位置值得按烟叶场景调整。第一是lr0初始学习率默认0.01对几百张的小数据集偏大容易在早期震荡建议降到0.001到0.003之间。第二是mosaic数据增强概率烟叶病斑密集时mosaic能提升小目标鲁棒性但如果原本目标就小而稀疏mosaic反而会稀释正样本这时建议把概率从1.0降到0.5。第三是fliplr水平翻转概率默认0.5烟叶病害对翻转不敏感保持默认即可但scale这个尺度抖动参数值得从0.5提到0.7模拟不同拍摄距离下的目标尺度变化。这些超参数的调整没有标准答案最靠谱的方式是每次只动一个变量跑20个epoch看val mAP的走势再决定下一步。我见过很多人在超参数上花了大量时间反复横跳最后发现瓶颈不在超参数而在数据标注质量所以第4章把这些坑集中列出来。4. 烟叶病害训练避坑手册五个高频问题与排查思路4.1 显存溢出一调batch-size就报CUDA out of memory现象训练刚跑几个step就报CUDA out of memory把batch-size从32降到8还是崩。原因烟叶图片分辨率大很多相机原图是4000x3000YOLOv5加载后若不显式指定--img 640会用原图尺寸做letterbox显存被原始图塞爆。另一种情况是同时开了--cache ram和多个worker内存和显存双吃紧。解决在train.py里显式指定--img 640让数据加载阶段先统一缩放如果还溢出把--workers从默认8降到4减少子进程的显存预留。更低成本的办法是先用--cache disk把预处理后的图缓存到磁盘再用小batch-size跑一轮确认无误后切回ram模式。4.2 训练loss不下降看似在训练实际在摆烂现象train/cls_loss和train/box_loss在前10个epoch基本不动val loss反而在涨。原因最常见的是初始学习率设置问题。YOLOv5默认lr00.01如果数据集只有几百张初始学习率太大导致loss震荡另一种可能是预训练权重没加载成功--weights yolov5s.pt路径写错或权重下载失败模型从随机初始化开始收敛自然慢。解决先确认runs/train/exp/hyp.yaml里记录的weights路径正确再用python -c加载一次yolov5s.pt检查权重文件完整性。随后把学习率调低一个量级在命令行加--hyp data/hyps/hyp.scratch-low.yaml并手动把文件里的lr0改成0.001。观察前20个epoch的val mAP如果仍低于0.1直接停掉去检查标注文件里是否有大量空标签。4.3 小目标病斑漏检针尖大小的早期病斑全被漏掉现象模型对大面积的病害区域检得很准但叶片边缘刚出现的针尖大小病斑全部漏检。原因YOLOv5的P3输出层对应80x80网格理论上可以检测小目标但默认anchor按COCO数据集物体尺寸设计对烟叶病害这种10x10像素级别的目标不够敏感。anchor不匹配时模型对每个位置的多个候选框都难以产生高质量回归损失导致小目标召回率低。解决训练前用YOLOv5自带的anchor自适应工具重新聚类anchor尺寸。执行python utils/autoanchor.py --cfg models/yolov5s.yaml --data data/smoke_disease.yaml它会根据你的标注数据重新计算anchor。跑完对比输出结果和默认值的差距如果变化大说明数据集目标尺度和COCO差异明显这一步不能省。训练时再加--multi-scale让模型在随机缩放中学习多尺度特征对小目标和特写病斑都有帮助。4.4 类别不平衡导致少数类几乎不检现象整体mAP0.5到了0.85但按类别看AP气候斑点的AP只有0.2。原因YOLOv5默认的cls_loss用BCEWithLogitsLoss样本多的类别在损失中占比高模型倾向于把所有框预测成大类。训练log里的混淆矩阵也会显示气候斑点被大量误判为花叶病或背景。解决两步走。第一种做法是在数据层面做少样本过采样把气候斑点类的图片在训练集中重复3到5轮虽然会增加过拟合风险但对工程落地来说漏检的代价更高。第二种做法是在训练脚本里对Loss函数做一个小改动在计算cls_loss时给少数类乘一个权重系数这个系数可以按类别样本数的倒数来设定。改完Loss后要重新验证多数类AP如果多数类AP掉超过3个点说明权重系数设太大需要回调。4.5 模型导出ONNX后推理结果和PyTorch不一致现象export.py --include onnx导出成功但在ONNXRuntime或TensorRT里跑同一张图检测结果和detect.py差了很多。原因YOLOv5的export.py默认把NMS排除在ONNX图外部署时需要自行加后处理。另一个高频原因是--opset版本没指定默认opset 12在部分推理引擎里对SiLU算子的支持不完整导致输出张量顺序或形状对不上。解决导出时显式指定opset版本并加--simplify对计算图做简化python export.py --weights runs/train/exp/weights/best.pt --include onnx --opset 13 --simplify导出后用ONNXRuntime跑一遍输出和PyTorch推理结果对比。如果框的位置差在2像素以内且置信度误差小于0.05可以接受。如果差异大检查两边的图片预处理是否一致——YOLOv5的letterbox填充值默认114ONNX推理时的填充值必须和训练时保持一致这个细节是导出后推理不一致最常见的玄学根源。5. 进阶落地用预训练权重二次精调与导出推理模型5.1 两阶段训练先用COCO权重拿Baseline再用自己的best.pt精调从COCO预训练的yolov5s.pt开始训练前几层学到的边缘、纹理特征和烟叶病斑的低级视觉特征高度复用。如果从零开始训练要达到同样的精度至少需要4倍数据量这是迁移学习的复利。我的习惯是先跑完一轮完整训练拿到baseline再用这个best.pt作为初始权重做第二轮精调第二轮epochs压到原来的三分之一学习率调低一个数量级。两阶段训练比直接改超参数更可控因为在第二轮中模型已经适应烟叶病害的分布微调只是让它在已有特征上继续聚焦。5.2 从PyTorch权重到嵌入式端部署的检查清单如果最终要部署在Android或嵌入式设备上ONNX导出只是中间步骤。到嵌入式端常见路径是ONNX转NCNN以NCNN为例python export.py --weights best.pt --include onnx --opset 13 --simplify onnx2ncnn best.onnx best.param best.binNCNN转换时最常见的报错是Unsupported reduce op或Unsupported slice op通常因为ONNX包含冗余的后处理算子。转完param/bin后用NCNN的ncnnoptimize工具做一次算子融合推理耗时能再降20%左右。部署前还有一件容易被忽略的事确认预处理代码里的归一化参数和训练时一致YOLOv5训练时用的是除以255的归一化方式如果部署端用了ImageNet的均值和标准差输出会完全不可用。5.3 模型上线前必须做的验证与最后一句忠告模型上线前我绝不会只看测试集的mAP。把模型放到真实烟田照片里跑特别是清晨有雾、雨天叶面反光的场景观察输出框的稳定性。如果同一病害在连续几帧里时有时无多半是置信度阈值卡得太死需要做一次阈值扫描从precision-recall曲线上找到最合适的点。另一个习惯是保留所有漏检样本反查标注数据。如果漏检样本全部是某种特定光照条件下拍的说明训练集分布没覆盖住这种时候回到数据层面补样本比调参有效得多。吃了这么多回亏我养成的唯一习惯是每改一次数据或参数都把旧权重和对应数据集版本存档别删否则后悔药都没有。希望帮到你。本文还有配套的精品资源点击获取