资讯动态

YOLOv5烟叶病害识别实战:目标检测模型训练与部署全攻略

发布时间:2026/9/26 15:52:51 来源:尧图企业网站定制
简介面向高校深度学习课程设计、期末大作业与毕业设计场景这一基于YOLOv5的烟叶病害识别项目提供了从数据处理到模型部署的完整实践路径。资源共378个文件压缩包约782.55MB包含156张jpg病害样本图、90个txt标注文件、36个py脚本、28个yaml配置以及pt权重、mp4演示视频、安装教程文档等能覆盖数据预处理、模型训练、病害预测与结果后处理全流程。已有147人学习适用于希望系统掌握YOLOv5目标检测、CNN原理及农业病害防治应用的学生。除源码外还附带Dockerfile、训练日志events.out.tfevents与results.csv等便于复现环境并分析训练曲线演示视频和教学文档可帮助初学者快速跑通项目深入理解YOLOv5的架构改进与训练优化方法。这是一份将理论讲授与实战操作紧密结合的毕业设计级参考资源。1. 一套能直接跑起来的烟叶病害识别项目能给你省下多少事做农业视觉的人第一次拿到“YOLOv5烟叶病害识别源码完整源码数据集演示视频安装教程”这类包最怕是压缩包里到处都是半个文件、路径写死、数据集和源码对不上。我拆过不少这种项目包负责任地说这套东西的价值不在算法多新而在它把“烟叶病害识别”从零到训练出一条可用权重的最短路径给你铺好了——源码、标注好的数据、训练演示、环境安装说明一次给齐。你不需要去COCO上重新做迁移也不用满网找带标签的烟叶图片解压之后照着装依赖、跑训练即可。适用的人很明确一是做烟草植保或农业AI课题的学生需要一个能快速出结果的基线模型二是刚接触YOLOv5、想拿一个小型数据集跑通全流程的工程师三是想评估“病害检测在自己的烟叶产线上到底能不能用”的决策者。我不会替你把代码抄一遍而是按我实际落地这类项目的顺序把复现、换数据、避坑和参数调优一条线讲清楚。2. 识别什么、靠什么识别烟叶病害数据与模型选型2.1 烟叶病害识别的目标与数据集长什么样烟叶病害识别本质上是一个目标检测Object Detection问题输入一张大田或烤房里的烟叶照片算法输出每个病害区域的位置框Bounding Box和类别。常见类别包括烟草赤星病、野火病、普通花叶病、角斑病等不同产地、不同生长期发病形态差异很大有些病斑只有几毫米这就是为什么很多人拿通用目标检测权重直接跑效果很差。这个项目自带的数据集一般会按YOLO格式组织目录结构无非是这样smoke_disease/ ├── images/ │ ├── train/ │ │ ├── img_0001.jpg │ │ ├── img_0002.jpg │ └── val/ │ ├── img_0100.jpg ├── labels/ │ ├── train/ │ │ ├── img_0001.txt │ └── val/ │ ├── img_0100.txt ├── data.yaml ├── classes.txt每张jpg对应一个同名txttxt里每一行是类别id x_center y_center width height注意这里四个坐标是相对于图片宽高的归一化值不是像素坐标。拿到项目先看labels里有没有空文件、有没有类别id超出classes.txt数量这两类问题能坑掉你半天时间。数据集的图片分辨率一般不会太高常见是640×640或接近这个尺度因为YOLOv5训练时默认会做letterbox缩放。2.2 为什么选YOLOv5而不是Faster R-CNN或YOLOv8选YOLOv5不是因为它最强而是因为它在“落地重复实现”这件事上最省心。核心理由有三条。第一单阶段模型速度优势明显。烟叶病害识别如果要做成田间巡检或无人机巡田实时性很重要YOLOv5s在GTX 1660上做640×640推理大概能跑到30-60 FPSFaster R-CNN很难做到这个帧率除非上更好的显卡。第二YOLOv5的生态最完整。你要找预训练权重、旧版本兼容方法、TensorRT部署案例网上资料量远大于其他框架。对新手来说“报错搜得到答案”本身就是选型理由。YOLOv8的anchor-free设计更新但小目标召回率在作物病斑这类场景上不一定会更好而且很多教程还停留在v5的写法上照着项目包走更顺。第三显存门槛低。一张8GB显存的显卡就能训yolov5s这对很多只有2060或3060 Laptop的实验室来说很关键。Faster R-CNN跑同样的数据显存占用几乎翻倍训练时间也更长。如果你手里的数据只有几百张我的建议是不换模型直接在YOLOv5上做迁移学习并且锁定输入分辨率640别盲目把图拉大后文会说到为什么。2.3 源码包里有哪几块先看哪个文件拿到源码包别急着点train.py。我一般按这个顺序拆包train.py训练入口跑起来之前必须确认参数解析器里的--data和--weights指向的文件是否存在。detect.py推理入口用来拿训练好的权重跑图片或视频。data/目录下放数据集配置文件重点是data.yaml和classes.txt。models/目录放模型结构定义常见是yolov5s.yaml、yolov5m.yaml等签名文件。utils/里面是损失函数、增强策略、指标计算的工具代码一般不用动。runs/目录在第一次训练后自动生成存tensorboard日志、权重和验证结果图。演示视频里一般就是跑detect.py拿训练好的best.pt对着几张烟叶照片画框。你要做的第一件事是先把视频里的命令反向复现一遍确认环境没问题再决定要不要重新训练。不要一上来就训练那样环境炸了你都分不清是依赖问题还是数据问题。3. 本地复现从环境配置到训练跑通一次完整的烟叶病害识别3.1 环境配置Python版本、Anaconda与依赖安装我建议用Anaconda建独立环境别用系统Python直接装YOLOv5的依赖之间版本敏感度很高尤其是torch和torchvision的对应关系。分环境是“后悔药”环境搞坏了直接删掉重建不用动系统里其他项目。# 1. 创建独立虚拟环境Python版本选3.8或3.9 conda create -n yolov5-smoke python3.9 -y conda activate yolov5-smoke # 2. 安装PyTorch先确认自己的CUDA版本 # 有NVIDIA显卡且驱动支持的话装CUDA版 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 3. 进入项目根目录安装requirements.txt里的依赖 cd YOLOv5-SmokeDisease pip install -r requirements.txt参数说明cu118表示PyTorch编译时用的CUDA 11.8如果你的显卡驱动较老可以先跑nvidia-smi看右上角的CUDA Version如果小于11.8就改用cu117或cu121装错版本最常见的报错是AssertionError: Torch not compiled with CUDA enabled。装完依赖先验证GPU能用import torch print(torch.__version__) print(torch.cuda.is_available())这里torch.cuda.is_available()如果输出False多半是PyTorch装成了CPU版已经踩过坑的人会告诉你这个检查比看一百遍教程都好使。没有NVIDIA显卡的机器也能跑但训练时间会多出十几倍建议优先找云GPU或借一台卡。3.2 把数据集整理成YOLO格式一个转换脚本解决有些下载到的烟叶数据集是VOC格式xml标签或者标好的标签是txt但坐标格式不是归一化的后者最容易翻车。我给你一个通用转换脚本能把VOC格式的XML转成YOLO格式的txt前提是你的图片目录和xml目录一一对应。import os import xml.etree.ElementTree as ET from pathlib import Path def voc2yolo(xml_file, out_dir, class_list): tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): cls obj.find(name).text if cls not in class_list: continue cls_id class_list.index(cls) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # YOLO格式需要归一化的中心坐标和宽高 x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) if lines: txt_path Path(out_dir) / (Path(xml_file).stem .txt) txt_path.write_text(\n.join(lines)) class_list [Tobacco_Mosaic, Frog_Eye_Spot, Wild_Fire] # 按你数据集的类别填 xml_dir xml_files/ out_dir labels/ os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): voc2yolo(os.path.join(xml_dir, xml_file), out_dir, class_list) print(转换完成)逻辑说明这个脚本先读XML里的图片宽高再拿到每个目标的bndbox四角坐标换算成中心点和宽高后除以图片宽高完成归一化。关键点是归一化——YOLO训练时如果喂进去的是像素坐标边界框会偏到图片外模型收敛后loss很低但预测框全在角落这个问题能让你怀疑人生。参数说明class_list的顺序决定类别id必须和之后data.yaml里的names保持一致。另外注意txt文件名必须是对应图片名的stem不能多后缀。3.3 修改数据配置文件data.yaml与类别核对YOLOv5训练的第一步读data.yaml里面的路径和类别写错了程序不会直接拒绝但会给出一个非常隐晦的警告然后继续训练最后你得到的是一个永远不出病斑框的模型。# 项目自带或自己新建的data.yaml train: smoke_disease/images/train val: smoke_disease/images/val nc: 3 names: [Tobacco_Mosaic, Frog_Eye_Spot, Wild_Fire]参数说明train和val建议写绝对路径或从项目根目录出发的相对路径不要写C:/Users/你/Desktop/...这种带中文的路径YOLOv5和OpenCV对中文路径支持极差出错了你都看不出原因。nc是类别数量必须等于names的长度这也意味着如果你删除某个类别要把对应的txt文件和class_list一次性同步处理掉三处不配套就会出现类别错位。3.4 启动训练三个必须设好的超参数环境就绪、数据格式确认后正式训练命令如下。python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch-size 16 \ --epochs 100 \ --workers 4 \ --device 0参数说明--weights yolov5s.pt是COCO预训练权重会从官方仓库自动下载到项目根目录。如果你的网络环境不方便下载找一个能上外网的朋友帮你把文件拖回来再放进目录后续断网也能训练。--img 640是训练输入分辨率烟叶病斑普遍偏小我建议不要低于640有条件可以试--img 896但显存占用会涨一倍以上。--batch-size根据显存调整3060 12G能跑168G卡就降到8。--workers在Windows上建议设成0或2设大了会报DataLoader worker崩溃这个坑在农用笔记本上尤其常见。训练过程中重点观察终端里的三列数box_loss、obj_loss和mAP0.5。前两者应该逐步下降mAP逐步上升。不需要等到全部epoch结束如果60轮后mAP0.5已经在0.7以上可以提前停掉用runs/train/exp/weights/best.pt去跑推理。4. 替换成自己的烟叶数据集标注、格式转换与数据集划分4.1 自采图片的标注与导出项目自带的数据集训练出来的模型只能识别那三类病害如果要用到你产地的数据必须替换数据集重训。自采烟叶图片后需要一个标注工具常见做法是labelImg或X-AnyLabeling。前者轻量直接后者支持自动标注但配置稍重新手先用labelImg就行。标注时的三个原则图像分辨率不够就不要标。小于800×600的病斑图放大标注很容易偏导致标签框边缘误差过大。每个类别的样本量尽量均衡。赤星病好找花叶病难拍你最后会得到一个类别不平衡的数据集结果mAP看起来不错但花叶病mAP只有0.3。标注框要紧贴病斑边缘宁小勿大。YOLOv5每个格子只负责预测中心点落在它内部的物体框太大时正负样本分配容易出问题。labelImg导出时选择PascalVOC格式输出一堆xml文件再套用前面那个转换脚本。如果你直接用YOLO格式标注导出的txt已经归一化不需要再转换但要注意目标ID一定从0开始不要用1开头。4.2 按比例划分训练集和验证集并做一致性校验标注完成后用下面脚本划分数据集同时校验文件名和图片数量是否匹配。import os import random import shutil from pathlib import Path images list(Path(raw_images).glob(*.jpg)) random.seed(42) random.shuffle(images) train_ratio 0.8 train_files images[:int(len(images) * train_ratio)] val_files images[int(len(images) * train_ratio):] for split, file_list in [(train, train_files), (val, val_files)]: img_out Path(fdataset/images/{split}) lbl_out Path(fdataset/labels/{split}) img_out.mkdir(parentsTrue, exist_okTrue) lbl_out.mkdir(parentsTrue, exist_okTrue) for img_path in file_list: lbl_path Path(labels) / (img_path.stem .txt) if not lbl_path.exists(): print(f警告{img_path.name} 缺少标签文件已跳过) continue shutil.copy(img_path, img_out / img_path.name) shutil.copy(lbl_path, lbl_out / lbl_path.name) # 校验统计每个类别的bbox数量检查是否有偏 from collections import Counter cls_counter Counter() for split in [train, val]: for txt in Path(fdataset/labels/{split}).glob(*.txt): for line in txt.read_text().strip().split(\n): if line: cls_counter[int(line.split()[0])] 1 print(cls_counter)逻辑说明random.seed(42)保证划分可复现下次再做相同划分不会变。缺失标签的图片直接跳过因为训练时jpg和txt任意一边缺了都会中断或静默丢样本。最后那个Counter统计能告诉你每个类别的样本占比如果某个类别只有个位数需要回去补标。校验之后把dataset目录的名字和路径写进data.yaml注意保持YOLO要求的images/...和labels/...相对关系不要手工拆散。4.3 新数据集上要重点调的三个超参数换成自己的小数据集后假设只有500张图直接跑默认参数容易不收敛。我一般先改三个地方。python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch-size 8 \ --epochs 150 \ --workers 2 \ --cache \ --patience 30参数说明--patience 30表示30轮没改善就早停小数据集训练后期很容易过拟合早停是护身符。--cache把图片一次性加载进内存小数据集下能明显缩短每个epoch的时间但如果机器内存不足16G建议不开。--batch-size 8是8G显存下稳妥值如果你用的是16G以上显存可以提到16。还有两个在代码里调而命令行看不到的参数是数据增强策略。YOLOv5的hyp.scratch.yaml里四个增强参数值得关注hsv_h、hsv_s、hsv_v控制色彩扰动mosaic控制拼接增强概率。烟叶照片在不同光照条件下颜色差异极大我建议把hsv_h从0.015调到0.03hsv_s从0.7调到0.9能明显提升在不同田块光照下的稳定性。如果你的病斑很小可以把mosaic保持1.0但训练最后20轮建议关掉否则小目标会被拼接图里的其他纹理干扰。5. 训练翻车现场烟叶病害识别最常见的5个坑5.1 坑一标签类别编号对不上训练出来全是无差别框现象loss在稳步下降但推理时每个烟叶都只出一个大框把整片叶子框进去跟没训一样。原因标注时的class id和data.yaml里的names顺序不一致网络学到的是“这片区域有病害”但类别分支混乱。解决把训练集里任取三张图的txt文件打印出来对照classes.txt逐行核对id。如果是0、1、2三类确保data.yaml里的names顺序与标注工具导出时一致然后删掉runs/下的旧结果重训。5.2 坑二小病斑漏检严重mAP看着不错但实际用不了现象验证集mAP0.5有0.82但拿手机拍的现场图进来病斑一个都没框出来。原因验证集图片与训练集同源场景、角度、分辨率都接近mAP虚高而真实场景里病斑可能只有十几个像素宽。解决不要只盯mAP0.5看mAP0.5:0.95这个指标对小目标更敏感。如果mAP0.5:0.95低于0.4基本可以断定小目标能力差。处理方法一是把--img从640提高到896或1280二是给数据增强里加scale0.5的随机缩放让模型看到更多不同尺度的目标。5.3 坑三显存不足训练跑到一半直接OOM现象epoch 1跑完一半终端弹出CUDA out of memory之前算的全部白费。原因--img设太高或--batch-size排太大也可能--workers多进程把内存占满。解决先把batch-size降一半重跑如果还爆就降--img。在batch-size等于8、img等于640的情况下8G显存通常能跑yolov5s如果你用的是yolov5l或yolov5x8G卡就不要想了换成yolov5s或yolov5m。还有一个歪招是把训练命令加上--noval跳过每个epoch的验证能省出约20%-30%显存等训练完再单独跑val.py。5.4 坑四验证loss一路走高模型过拟合了现象训练集loss降得很漂亮但val loss在30轮后开始反弹mAP也停滞。原因数据集太小比如只有300张图模型把训练数据的背景纹理背下来了。解决优先加数据增强不给模型背背景的机会然后加大正则把--dropout从0加到0.1或0.2。不要一上来就减模型深度换yolov5n训练虽然慢一点但泛化更好。最后兜底的是早停--patience设15-20val loss连续不降就自动停止保存的还是之前best.pt。5.5 坑五训练完的best.pt在另一台机器上无法推理现象换一台电脑跑detect.py报KeyError: model.24或直接说权重文件损坏。原因两台机器的PyTorch版本差异太大或者训练时用多卡--device 0,1保存的模型带module.前缀。解决训练完记得跑一次python models/export.py --weights best.pt --include torchscript导出的TorchScript模型基本跨版本通用。如果只是多卡前缀问题在推理代码里加一行model torch.nn.DataParallel(model)再加载即可。我自己的血泪经验是凡是给别人复现的pt文件一律导成TorchScript或者ONNX别直接给原版pt。6. 把模型做得更稳数据增强、自动标注与边缘端导出训练收敛只是第一步真正能拿去用的模型还得做三件事增强鲁棒性、减少标注成本、能部署到其他设备。第一件事是在hyp.scratch.yaml里把增强策略调到适应农业场景。烟叶病害识别最大的变量是光照和拍摄角度我把hsv_h设为0.03、hsv_s设为0.8同时开启fliplr: 0.5水平翻转和mosaic: 1.0。对雨雾天气的田间图我习惯额外在预处理里做一次clahe均衡化代码里用cv2.createCLAHE(clipLimit2.0, tileGridSize(8,8))跑一遍再喂给模型。这个改动不增训练时间但对阴天和背光场景的稳定性提升非常明显。第二件事是半自动标注。烟叶病害的标注成本很高病斑边界模糊人标一张图平均要一分钟。常见做法是先用当前模型对未标注图片做预测生成粗略的伪标签然后在labelImg里加载这些框手工修正只改位置和删错框能省一半时间。我每周迭代一次标注100张新图→训练→用新权重预测下一批→再修正。三轮之后模型在你自己地块上的表现会明显超过直接沿用原始数据集训练的结果。第三件事是导出部署格式。我一般在训练最终确定后用下面命令导出ONNX方便后续用OpenCV或ONNX Runtime做推理或者转到边缘设备上跑。python models/export.py \ --weights runs/train/exp/best.pt \ --include onnx \ --img 640导出后用onnxruntime做一个加载测试确认输出张量形状是[1, 25200, 7]640输入、3类目标时再根据置信度阈值筛选和NMS就能得到最终框。这一步能提前暴露出很多原版pt加载时发现不了的算子兼容问题。我自己的习惯是每次训练前把所有关键设置数据路径、批次、图片尺寸、增强参数记在一个txt里和best.pt放同一个目录。这花不了五分钟但两周后再回头复现实验时能救命。农业场景的病害识别不是一锤子买卖不同季节、不同光照拍回来的图差异都很大模型要持续迭代记录比调参更像核心竞争力。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑