ARTICLE DETAIL

资讯详情

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

基于YOLOv5的烟叶病害识别:从数据标注到模型部署全流程实践

基于YOLOv5的烟叶病害识别:从数据标注到模型部署全流程实践 简介这套基于YOLOv5的烟叶病害识别项目面向深度学习初学者及高校学生可支撑课程设计、期末大作业与毕业设计等教学场景。内容覆盖数据预处理、模型训练、病害预测与结果后处理完整流程同时包含可供训练的多类烟叶病害图像及对应标注并提供演示视频与安装教程便于快速复现和二次开发。压缩包共378个文件以jpg烟叶病害样本、txt标注文件、py源码与yaml配置为主辅以mp4演示、pt权重、Dockerfile及部署脚本整体约782.55MB目录结构清晰适配多种实验环境。已有147人浏览学习。附带的环境部署文档与操作视频能帮助学生避开配置弯路直观理解数据增强、特征提取、损失函数与梯度下降等核心概念从数据构建到模型部署全流程动手实践实现理论与实操的紧密结合。1. 基于 YOLOv5 的烟叶病害识别源码从数据集到演示视频一次跑通烟草病害搞不定整片烟田的收成就悬了。毕设选题想往深度学习上靠很多学生最后都会落在目标检测上而基于 YOLOv5 的烟叶病害识别源码恰好把最耗时间的几件事打包好了标注后的数据集、可训练可推理的完整代码、演示视频和安装教程一次给齐。它能解决的核心问题就一个——你不用再东拼西凑病害图片也不用从零调通训练流程照着教程走完就能得到一份能跑、能出检测框、能答辩演示的成品。适合三类人赶毕业设计的学生、想快速入门 YOLOv5 的开发者、以及需要给烟叶病害做识别验证的农业相关从业者。下面我按自己的复现顺序把环境、数据集、训练和排错拆开讲。2. 环境配置与源码结构先把 YOLOv5 跑起来再谈识别这套源码拿到手的第一感觉是“文件比想象的多”。因为是毕设项目一般不会直接躺在官方 YOLOv5 仓库上而是多出数据目录、训练好的权重、演示视频和一份安装教程。别急着训练先把环境锁死再顺着源码结构搞清楚 train.py 和 detect.py 在哪跑通一次推理再碰训练后面会省很多事。2.1 环境准备先用 conda 把 Python 和 PyTorch 锁死环境这块是整条链路里最容易翻车的torch 版本和 CUDA 对不上训练一开始就报奇怪的符号错误或者干脆检测不到显卡。我一般会新建一个独立的 conda 环境避免把实验室或自己电脑上的 Python 环境搞乱。conda create -n smoke python3.8 -y conda activate smoke pip install torch1.13.1cu117 torchvision0.14.1cu117 --extra-index-url https://download.pytorch.org/whl/cu117 pip install -r requirements.txt这段命令里python3.8 是 YOLOv5 比较稳的版本3.10 以上有时会遇到某些依赖包编译报错。torch 和 torchvision 后面的 cu117 表示对应 CUDA 11.7装之前先用 nvidia-smi 看一眼自己显卡驱动支持的 CUDA 版本如果驱动支持到 11.3就把 cu117 改成 cu113。没有 NVIDIA 显卡的机器装 CPU 版就行训练会慢几倍但做验证和演示完全能跑。requirements.txt 里主要是 numpy、opencv-python、PyYAML、matplotlib、tqdm 这类常规库一条命令装完。环境装完先做一个最小检查python -c import torch; print(torch.cuda.is_available())。打印 True 说明 CUDA 版本没配错打印 False 也不一定就是坏的可能只是没装 GPU 版后续训练命令会自动落到 CPU 上。我一般还会顺手跑一次python detect.py --help如果能正常打印参数说明依赖就算齐了。注意conda 环境名和数据集路径都不要用中文YOLOv5 对中文路径的处理很脆弱后面避坑章会展开讲。2.2 源码目录train.py 和 detect.py 是两根主线解压源码后先不急着跑在根目录列一下结构。常见结构大致是这样smoke-yolov5/ ├── train.py ├── detect.py ├── requirements.txt ├── data/ │ ├── smoke.yaml │ └── images/ ├── models/ │ ├── yolov5s.yaml │ └── common.py ├── utils/ │ ├── datasets.py │ ├── loss.py │ └── torch_utils.py ├── weights/ │ └── yolov5s.pt └── runs/ ├── train/ └── detect/train.py 是训练入口所有训练参数都从这里传进去detect.py 是推理入口训练完用它跑图片、视频或者摄像头。data/ 里放数据集配置和图片样本smoke.yaml 里写着类别数量和类别名这是整个项目的说明书。models/ 里的 yolov5s.yaml 定义网络结构不是训练超参数训练超参数在 data/hyps/hyp.scratch-low.yaml。utils/ 是数据集加载、损失函数、模型工具这些底层逻辑一般不用动。weights/ 放预训练权重runs/ 是训练和推理结果的默认输出目录。这套毕设源码和官方仓库最大的差别在 data/ 和顶层多出来的几个文件夹。比如 dataset/ 可能直接放标注好的烟叶图片和 txt 标签教程文档里会写清数据集是什么病害、标签格式怎么定义。如果你拿到的包里还有 demo.mp4那就是给演示用的视频样本训练完成之后可以直接用 detect.py 跑它出结果。结构搞清楚之后我的习惯是先在 data/smoke.yaml 里确认两件事第一train 和 val 的路径是否跟自己数据集实际位置一致第二nc 和 names 的数量是否跟自己标签里的类别编号对得上。这两处不一致后面会有一堆莫名其妙的报错。2.3 首次推理用预训练权重当 hello world环境弄完先别碰自己的数据集拿官方预训练权重跑一次推理。这步的目的是验证安装没问题也顺便把 detect.py 的输入输出方式熟悉一下。python detect.py --weights weights/yolov5s.pt --source data/images/leaf.jpg --conf-thres 0.35如果包里没有 leaf.jpg直接用官方仓库自带的 data/images/bus.jpg 也行。跑完后终端会打印每条检测结果比如 class、confidence、box 坐标并在 runs/detect/exp 下生成一张画了框的图。看到框画出来环境就算验完了。--weights 指定权重文件--source 可以是图片、视频文件、文件夹或者摄像头设备的编号比如 0 表示笔记本前置摄像头。--conf-thres 是置信度阈值0.35 意思是模型只有把握超过 35% 才画框演示视频里我一般设 0.25~0.4太高会漏掉病害小斑块。第一次跑容易踩的坑是库版本冲突如果之前装过其他版本的 torch 或 opencv可能报AttributeError: module numpy has no attribute bool。这是 numpy 版本太新把 np.bool 删了把 numpy 降到 1.24 以下就行。另一个坑是 detect.py 会把结果写进 runs/detect/exp、exp2、exp3 这样递增的目录里要看最新结果找目录名数字最大的那个。3. 烟叶病害数据集标签格式、划分脚本与类别不均衡跑通预训练推理后接下来是把烟叶病害数据集喂给模型。很多毕设在这步翻车不是模型的问题而是标签文件的问题。YOLOv5 的数据集不是给整张图打一个标而是给图里每个病斑画框并写成一个 txt理解了这个格式后面 90% 的报错都能自己解决。3.1 标签格式一行五个数字坐标全是相对值数据集的 labels 目录里每一张图片对应一个同名的 txt 文件。里面每一行表示一个目标格式是五个数字类别编号、归一化中心点 x、归一化中心点 y、归一化宽度、归一化高度。归一化的意思是这些数都除以了图片本身的宽和高值在 0 到 1 之间。烟叶病害在数据里通常会分好几类比如烟草花叶病、黑胫病、赤星病、野火病具体类别以包里的 data.yaml 为准。类别编号从 0 开始不是从 1 开始这一点最容易弄错。我习惯写个小脚本把标签坐标还原成像素坐标看看框是否落在病斑上img_w, img_h 640, 640 # 换成图片实际尺寸 with open(data/smoke/labels/train/000001.txt) as f: for line in f: cls, cx, cy, w, h map(float, line.split()) x1 (cx - w / 2) * img_w y1 (cy - h / 2) * img_h x2 (cx w / 2) * img_w y2 (cy h / 2) * img_h print(fclass {int(cls)}: ({x1:.1f}, {y1:.1f}) - ({x2:.1f}, {y2:.1f}))这段脚本的逻辑是把 YOLO 格式的中心点和宽高先转换成左上角、右下角再乘回图片宽高得到像素坐标。检查时随便找几张图和对应标签用画框工具确认框是否贴合病斑。如果出现 cx、cy 大于 1或者 w、h 为 0 甚至负数这张图的标签就是坏的训练时会直接报错或被跳过。注意 txt 文件名必须和图片名完全一致图片叫 000001.jpg标签就必须叫 000001.txt大小写也别差。3.2 data.yaml 与数据集划分别让验证集里有训练图数据准备好了还要让 YOLOv5 知道去哪读。data/smoke.yaml 是训练用的数据配置一个标准的烟叶病害配置长这样train: data/smoke/train/images val: data/smoke/val/images nc: 4 names: [tobacco_mosaic, black_shank, brown_spot, wildfire]train 和 val 指向的路径相对源码根目录写也行绝对路径也行。nc 写类别数量names 写类别名顺序必须和标签里的编号一致编号 0 对应 names[0]编号 1 对应 names[1]以此类推。如果 names 顺序和标注时不一致训练不会报错但 mAP 会错乱画出来的框类别名也是错的。划分数据集时图片和标签要一起搬而且训练集和验证集不能有同一张图。常见问题是有同学把整个目录塞进 trainval 里也复制了一份结果模型在验证集上成绩虚高。给一个简单可靠的划分脚本import os, random, shutil base data/smoke images os.listdir(os.path.join(base, images)) labels os.listdir(os.path.join(base, labels)) random.seed(42) idx list(range(len(images))) random.shuffle(idx) split int(len(images) * 0.85) for i, pos in enumerate(idx): img, lab images[pos], labels[pos] subset train if i split else val shutil.copy(os.path.join(base, images, img), os.path.join(base, subset, images, img)) shutil.copy(os.path.join(base, labels, lab), os.path.join(base, subset, labels, lab))这段脚本按 85% 和 15% 划分随机种子固定为 42保证每次运行划分结果一致。脚本假设 images 和 labels 里的文件名一一对应如果某张图片少了标签Copy 会直接报错恰好暴露数据缺失问题。训练集比例一般取 0.8 到 0.9样本多就 0.9样本少就 0.8验证集留太少mAP 曲线会抖动得很厉害。3.3 标签体检统计类别数量找出漏标图训练之前我建议先给数据集做个体检统计每个类别有多少个框、有多少张图完全没标签这个动作能提前发现大多数噩梦import os from collections import Counter labels_dir data/smoke/labels counter Counter() empty [] for root, _, files in os.walk(labels_dir): for f in files: if not f.endswith(.txt): continue path os.path.join(root, f) lines [l for l in open(path).read().strip().splitlines() if l] if not lines: empty.append(f) for line in lines: counter[int(line.split()[0])] 1 print(类别分布:, dict(counter)) print(空标签文件:, len(empty), empty[:5])统计结果如果发现某个类别只有十几二十个框这个类别的 mAP 大概率会很低。解决办法不是删掉它而是先做数据增强对这类病害图片做水平翻转、小角度旋转、亮度抖动再重新标注。如果只差几张直接手工补标比换模型更快。空标签文件也要注意YOLOv5 遇到空 txt 不会报错但会当负样本处理空文件太多会让模型倾向不输出任何框。提示报错里常见的Label class 5 exceeds nc4就是标签体检漏掉的问题——某个标签出现了类别 5但 yaml 只定义了 4 类。4. 训练烟叶病害模型命令、超参数与怎么看 mAP数据集就位后训练命令本身不复杂真正影响毕业设计成绩的是三个选择用哪个模型骨架、超参数怎么设置、训练完怎么判断好坏。下面按这个顺序说。4.1 模型选型yolov5s 起步yolov5m 兜底YOLOv5 按深度和宽度分成 s、m、l、x 几档。烟叶病害目标不算太小病斑一般有几十到几百像素yolov5s 的 640 输入完全够用。做毕设我推荐用 s 起步显存占用小、训练速度快先跑通流程再考虑升级。模型参数量640 输入显存占用参考适合场景yolov5s约 7.2M8~12G 可训练毕设起步、快速出结果yolov5m约 21.2M12~16G 可训练想要更高 mAP、显卡不紧张yolov5l约 46.5M16~24G 可训练追求精度、对推理速度不敏感表中的显存占用是 batch-size 16 时的粗略估计实际跟图片分辨率、mosaic 是否开启有关。实验室单卡 8G 的机器用 s 配 batch-size 8 比较稳16G 显存s 可以开到 16m 也能跑。l 和 x 对烟叶病害这种目标形态比较固定的场景有点浪费训练时间翻倍mAP 提升却有限。4.2 训练命令与超参数改 yaml 比改代码安全模型结构文件 models/yolov5s.yaml 一般不用动训练参数通过命令行传。最基础的训练命令python train.py \ --data data/smoke.yaml \ --cfg models/yolov5s.yaml \ --weights weights/yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --imgsz 640 \ --device 0--cfg 指定网络结构--weights 指定预训练权重。用官方预训练权重做迁移学习收敛速度和最终精度都比随机初始化好得多如果 --weights 传空字符串就是从头训练对烟叶这种中等规模数据集一般不推荐。--epochs 100 是毕设常见设置60 个 epoch 能有明显效果100 个足够收敛。--batch-size 受显存限制报 OOM 就降。--imgsz 必须是 32 的倍数640 是默认值想加速可以试 416但小病斑会被缩小精度会掉。超参数文件在 data/hyps/hyp.scratch-low.yaml训练时用 --hyp 指定。里面有几个值得手动改的lr0 是初始学习率默认 0.01mosaic 是马赛克增强开关数据量小的时候建议开着label_smoothing 是标签平滑默认 0.0烟叶病害类间差异大开到 0.05~0.1 能缓解个别误标样本的影响。改超参数改 yaml 文件不要去改 train.py 源码因为很多默认值会被命令行覆盖改 yaml 更容易记录每次实验做了什么。4.3 训练日志与结果loss 曲线、混淆矩阵、best.pt训练结束后runs/train/exp 目录里最重要的三样东西results.png、confusion_matrix.png 和 weights 下的 best.pt。results.png 里有 box_loss、obj_loss、cls_loss 三条 loss 曲线和 mAP 曲线。正常情况三条 loss 整体下行尾部允许振荡如果 mAP0.5 一直趴在地上先回数据集查标签不建议盲目加 epoch。confusion_matrix.png 是混淆矩阵横纵轴都是类别对角线越亮越好。烟叶病害里像赤星病和野火病初期都是褐色小点如果混淆矩阵里它们互相串得厉害说明标注边界不够清晰需要回标签里修框而不是换模型。weights/best.pt 是验证集上 mAP 最高的权重最后部署跑视频用它不用 last.pt。训练过程中想实时看曲线可以开 tensorboardpython -m tensorboard.main --logdir runs/train浏览器打开对应端口就能看到。如果嫌小项目开 tensorboard 麻烦直接等训练完看 results.png 也完全够用。5. 避坑与排查烟叶数据训练翻车的五个常见现场这套资源我前前后后复现了两回第一回几乎把该踩的坑都踩遍了。下面这五个问题是毕设群里问得最多的场景每一条按现象、原因、解决三步讲清楚。5.1 中文路径报错标签读不出来不是玄学现象训练启动时报错常见的有AssertionError: Label class 5 exceeds nc4 in data/smoke.yaml或者图片加载时找不到文件路径里明明有对应文件。更糟的是在自己电脑上能跑拷到实验室电脑上一跑就崩因为两个人的用户名不一样。原因YOLOv5 的数据加载模块对中文路径支持不好Windows 下中文路径加上文件名的编码问题会导致标签文件读不到或图片路径对不上。另一层是标注时的类别编号和 yaml 里定义的对不上比如标签里出现了类别 5但 nc 只定义了 4 类。解决把整个项目放到纯英文路径下数据集也一起比如 D:\yolov5-smoke。用户名是中文就放 D 盘根目录不要放进“C:\用户\张三”下面。图片名和标签名用英文或数字不要用“病斑1.jpg”这种中文名。然后打开标签文件检查里面最大的类别编号是否小于 nc。5.2 CUDA out of memory先降 batch-size 再考虑换卡现象训练命令一敲下去屏幕直接刷红最后一行写着RuntimeError: CUDA out of memory.。原因显存被 batch-size、imgsz 和 mosaic 数据增强一起吃光。YOLOv5 的 mosaic 增强会把 4 张图拼成一张训练显存峰值比正常单图训练高不少。解决把 batch-size 从 16 降到 8 或 4再不行把 --imgsz 从 640 降到 416。对烟叶病害检测416 输入在 8G 显卡上能比较舒服地训练。如果还 OOM检查是不是有其他程序占着显存Windows 下关掉浏览器再试。千万别为了省显存去改代码砍 mosaic那是把数据增强玩残得不偿失。5.3 mAP 低但 loss 正常先查类名编号和标签坐标现象训练 100 个 epochloss 曲线下降很漂亮最后 mAP0.5 只有 20%~30%怎么看都不正常。原因这类情况十有八九是标签编号和 yaml 对不上。比如标注工具用的编号是 1、2、3、4但 yaml 里 nc4、names 从 0 开始于是第一个类别在训练时被整个忽略。另一种是坐标范围越界归一化坐标算出了 1.2 这种值模型学了个寂寞。解决用 3.3 节的统计脚本把每个标签文件里的编号分布和坐标范围打出来。编号如果从 1 开始写个脚本全部减 1再检查坐标是不是都在 0~1 之间。调整完重新划分数据集再训练一次。这个坑最坑的地方在于它不报错只能靠标签体检发现。5.4 全图一个大框通常是锚框或标签文件出了问题现象推理时每张图都被画了一个铺满整图的大框或者一个框反复出现在画面中心置信度还不低。原因两个来源。第一标签文件被误改成了 cx0.5、cy0.5、w1、h1 这种整图标注模型学到的就是“整张图都是目标”。第二训练时关闭了自动锚框计算默认 COCO 数据的锚框不适合烟叶病斑这种更小更密集的目标。解决先排除标签问题随机打开几个 txt 确认坐标分布。确认标签没问题后训练时不要加 --noautoanchor 参数让 YOLOv5 在训练前自动从数据集里算锚框如果已经训练完删除 runs 里的旧结果重新训练一次并观察训练日志里有没有打印 AutoAnchor 相关的输出。5.5 断电后续训--resume 才是后悔药现象训练到第 70 个 epoch 时断电或者手滑关了终端再启动时直接用了python train.py --weights runs/train/exp/weights/last.pt ...结果 loss 从头涨前面 70 个 epoch 白费了。原因这样传 --weights 只是把 last.pt 当作预训练权重重新初始化训练优化器、学习率计划、epoch 计数全部重来等于重新训。解决用 YOLOv5 自带的断点续训命令python train.py --resume runs/train/exp/weights/last.pttrain.py 会从 last.pt 里恢复 optimizer 状态和 epoch 计数继续原来的 exp 目录往下训。从那以后我每次训长任务前都会确认一下 exp 目录还在不在中断后第一时间用 --resume而不是 --weights。6. 用训练好的模型跑演示视频推理参数与部署技巧6.1 视频推理命令与参数conf-thres 别设太高训练完拿到 best.pt最后一步是让它在家演示视频上出结果。命令不复杂python detect.py \ --weights runs/train/exp/weights/best.pt \ --source demo.mp4 \ --conf-thres 0.35 \ --iou-thres 0.45 \ --save-txt \ --project runs/detect--source 支持单张图片、视频文件、整个文件夹甚至摄像头编号。--conf-thres 0.35 表示置信度超过 35% 才画框烟叶病斑小、和背景对比不明显阈值设到 0.5 以上容易漏检0.25~0.4 是稳妥区间。--iou-thres 是 NMS 的 IoU 阈值默认 0.45 够用两个病斑靠得近时可以调低到 0.4减少框被合并。--save-txt 会在输出目录里留下与检测框对应的文本结果格式和训练标签一致方便写数据分析报告。演示视频跑完输出目录下是逐帧标注的图片序列。如果想合成一个视频用于答辩演示用 ffmpeg 就行ffmpeg -framerate 25 -i runs/detect/exp/exp_frame_%05d.jpg -c:v libx264 -pix_fmt yuv420p result.mp4-framerate 25 要和原视频帧率一致否则画面会快进或放慢。这里演示的是通用做法先出帧序列再合成视频比直接在 detect.py 里配视频编码省心。6.2 导出手检模型ONNX 与后续优化方向如果后续想部署到手机上做实时检测可以把 best.pt 转成 ONNX再用 ONNX Runtime 推理。导出命令python export.py --weights runs/train/exp/weights/best.pt --include onnx导出后可以用 onnxruntime 在 CPU 上跑速度比 PyTorch 部署快不少。不过对绝大多数毕设场景到 best.pt 跑通演示视频这步已经完成了闭环ONNX 只是加分项。这套流程复现下来最大的体会是烟叶病害识别在 YOLOv5 这条链路上决定结果上限的是数据集质量不是网络结构。最初拿到这份源码时我也急着省事直接跑预训练结果在中文路径和类别编号上各自栽了一次跟头。从那以后只要拿到新数据集我都会先强制走一遍标签体检和类别编号核对再扔进 train.py。这套习惯应该能帮你省下不少排查时间希望帮到你。本文还有配套的精品资源点击获取
返回列表