简介这份资源面向准备毕业设计的学生提供一套基于YOLOv5的火灾与烟雾检测完整方案帮助解决从数据准备到结果可视化全流程的实现问题。包内共4个文件包含2张jpg示例图片、1个py推理脚本和1个pt训练权重压缩包约4.86MB体积轻便便于快速部署与验证。资源覆盖数据标注、模型训练、超参数调优、指标评估及预测应用等关键环节读者可借助训练权重直接运行推理代码在示例图片上复现火灾与烟雾的边界框检测效果并参考预测结果图分析模型表现。已有221人学习下载适合作为毕业设计中的算法实现与实验对比素材也可用于课程项目或原型验证帮助节省环境搭建与调参时间聚焦论文撰写与结果分析。1. 从一张烟雾图说起yolov5火灾烟雾检测模型到底交付了什么实验室楼道里那台摄像头拍到过一张图画面右下角刚冒出一缕灰白烟三秒后火苗窜起来。人眼能判断但传统阈值报警器要等烟雾浓度到设定值才响。这就是 yolov5 火灾、烟雾检测模型要解决的问题——把「看得见的异常」直接变成检测框和置信度。这个标题背后其实是一套完整交付物示例图片、推理代码、预测结果、训练权重四样东西凑齐才叫「能跑起来」。适合谁准备毕业设计的同学最典型导师要的是能演示、能写进论文、能答辩的系统而不是一个跑不通的仓库。我见过太多人卡在环境配置和权重加载上最后连一张图都推理不出来。所以这篇不聊虚的从模型选型、数据组织、推理复现、训练微调一路讲到部署边界让你拿到这套东西后知道每一步在干什么、参数怎么改、哪里会翻车。2. 为什么火灾烟雾检测选 yolov5 而不是别的检测器2.1 火焰与烟雾的视觉特征决定了检测器选型火焰和烟雾在图像里有两个麻烦特性。第一是形态不固定火焰可能是烛火大小的点也可能是整面墙的蔓延烟雾更是没有边界从一缕到一片连续变化。第二是颜色和纹理受光照、背景干扰极大白天白烟和白云、晚上火光和路灯都容易混淆。这就要求检测器同时具备多尺度特征提取能力和较强的语义区分能力。yolov5 的 PANet 结构加上 FPN正好在浅层保留小目标细节、深层保留语义信息对「小火点」和「大片烟」都能覆盖。相比 Faster R-CNN 这类两阶段检测器yolov5 单阶段推理速度快部署到边缘设备更现实。相比 yolov8yolov5 的生态更成熟网上可参考的训练脚本、超参数配置、部署教程数量多对毕业设计这种时间紧、要快速出结果的任务更友好。这不是说 yolov8 不好而是 yolov5 的「踩坑资料密度」更高遇到问题更容易搜到答案。另一个现实原因是权重兼容性。标题里明确给了训练权重说明这套方案已经完成了从数据到模型的闭环。你拿到权重后最关心的是能不能直接推理、能不能继续微调。yolov5 的权重格式.pt在 torch 生态里加载简单改类别数、冻结层、继续训练都有成熟写法。如果换成一些冷门框架光权重转换就能耗掉一周。2.2 从交付物反推技术栈示例图片、推理代码、预测结果、训练权重这四样交付物其实对应四个技术环节。示例图片是输入验证用来确认你的环境能读图、能预处理推理代码是执行链路包含模型加载、图像缩放、前向传播、NMS 后处理预测结果是输出验证让你对比自己的运行结果和作者给的是否一致训练权重是模型本体决定检测精度和类别。我一般建议按这个顺序验收先跑通推理代码用示例图片得到预测结果确认和作者给的结果图一致再去碰训练。很多人一上来就改代码、换数据集结果推理都没跑通后面全是玄学问题。验收推理时重点看三个东西检测框位置是否合理、类别标签是否正确、置信度是否在正常范围通常 0.25 以上才可信。如果框乱飞或者置信度普遍低于 0.1大概率是权重没加载对或者输入尺寸不匹配。2.3 环境配置conda 隔离与依赖版本锁定yolov5 对环境版本敏感尤其是 torch 和 torchvision 的匹配。我习惯用 conda 建独立环境避免和系统里其他项目冲突。下面是一套经过验证的配置流程Python 用 3.8 或 3.9 都行torch 选 1.13 附近版本比较稳。# 创建独立环境Python 3.8 兼容性最好 conda create -n fire_yolov5 python3.8 -y conda activate fire_yolov5 # 安装 pytorch根据你的 CUDA 版本选对应命令 # 如果没有 GPU用 CPU 版本也能推理只是慢 pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117 # 安装 yolov5 依赖注意 requirements 里有些包版本要锁 pip install -r requirements.txt这段命令的逻辑是先隔离环境再装深度学习框架最后装项目依赖。参数说明python3.8是因为部分旧版 numpy 和 opencv 对 3.10 支持不好cu117对应 CUDA 11.7你要根据自己显卡驱动改没有 GPU 就装 CPU 版。装完用python -c import torch; print(torch.cuda.is_available())验证输出 True 说明 GPU 可用。提示requirements.txt 里如果出现opencv-python和opencv-python-headless同时存在卸载前者保留后者否则在服务器无显示环境下会报错。3. 推理代码逐行拆解从读图到画出检测框3.1 加载训练权重与模型结构对齐推理第一步是加载权重。yolov5 的权重文件里保存了模型结构和参数但加载方式有两种一种是用torch.load直接读另一种是通过attempt_load函数。推荐后者因为它会自动处理模型融合和半精度。import torch from models.experimental import attempt_load # 加载训练权重map_location 确保 CPU 也能加载 GPU 保存的权重 weights_path weights/best.pt device torch.device(cuda if torch.cuda.is_available() else cpu) model attempt_load(weights_path, map_locationdevice) model.eval() # 切换到推理模式关闭 dropout 和 batchnorm 更新 # 打印模型类别数和类别名确认和你的任务一致 print(类别数:, model.yaml[nc]) print(类别名:, model.names)逻辑说明attempt_load会读取权重里的模型配置自动构建网络结构。map_location是关键参数如果你在 GPU 上训练、在 CPU 上推理不加这个会报错。model.eval()必须调用否则推理结果会不稳定。打印类别数和类别名是为了确认权重对应的类别和你预期一致火灾烟雾检测通常是两类fire 和 smoke。参数说明weights_path指向你的 .pt 文件device自动选择 GPU 或 CPU。如果类别数不是 2说明权重不是这个任务的需要重新找。3.2 图像预处理letterbox 缩放与归一化yolov5 推理前要把输入图像缩放到模型要求的尺寸默认是 640x640。但直接 resize 会变形所以用 letterbox 保持长宽比不足的地方补灰边。import cv2 import numpy as np def letterbox(img, new_shape640, color(114, 114, 114)): # 计算缩放比例取长边对齐 shape img.shape[:2] r min(new_shape / shape[0], new_shape / shape[1]) new_unpad int(round(shape[1] * r)), int(round(shape[0] * r)) dw, dh new_shape - new_unpad[0], new_shape - new_unpad[1] dw, dh dw // 2, dh // 2 # 两边均匀填充 img cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) top, bottom dh, dh left, right dw, dw img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, valuecolor) return img, r, (dw, dh) # 读取示例图片并预处理 img0 cv2.imread(sample_fire.jpg) img, ratio, pad letterbox(img0, new_shape640) img img[:, :, ::-1].transpose(2, 0, 1) # BGR 转 RGBHWC 转 CHW img np.ascontiguousarray(img) img torch.from_numpy(img).float() / 255.0 # 归一化到 0-1 img img.unsqueeze(0).to(device) # 增加 batch 维度逻辑说明letterbox 先算缩放比再补边保证图像不变形。img[:, :, ::-1]是 BGR 转 RGB因为 opencv 读进来是 BGR而模型训练时用的是 RGB。transpose(2, 0, 1)把通道维度换到前面。归一化除以 255 是标准操作。最后unsqueeze(0)增加 batch 维度因为模型输入要求是 NCHW。参数说明new_shape640要和训练时一致改大了精度可能提升但速度下降color(114,114,114)是填充灰度值和训练时保持一致。3.3 NMS 后处理与置信度阈值调节模型输出是一堆候选框需要经过非极大值抑制NMS去掉重叠框再按置信度过滤。from utils.general import non_max_suppression # 前向传播 pred model(img)[0] # NMS 后处理conf_thres 置信度阈值iou_thres 重叠度阈值 pred non_max_suppression(pred, conf_thres0.25, iou_thres0.45, classesNone, agnosticFalse) # 解析结果 for det in pred: if det is not None and len(det): # 把框坐标从 640 尺度还原到原图尺度 det[:, :4] scale_coords(img.shape[2:], det[:, :4], img0.shape).round() for *xyxy, conf, cls in det: label f{model.names[int(cls)]} {conf:.2f} print(f检测到: {label}, 坐标: {xyxy})逻辑说明model(img)[0]取第一个输出因为 yolov5 推理时只返回一个张量。non_max_suppression做两件事先按conf_thres过滤低置信度框再按iou_thres去掉重叠框。scale_coords把框坐标映射回原图尺寸否则画出来的框位置不对。参数说明conf_thres0.25是常用起点漏检多就降到 0.15误检多就升到 0.4iou_thres0.45控制重叠框合并程度烟雾重叠多可以调到 0.5。classesNone表示检测所有类别也可以指定只检测 fire 或 smoke。注意如果推理结果里出现大量置信度 0.3 左右的框但位置明显不对先检查 letterbox 的 pad 参数有没有在 scale_coords 里正确传入这是最常见的坐标还原翻车点。4. 用示例图片验证推理结果三个必查项4.1 检测框位置与类别标签核对拿到预测结果后第一件事是肉眼核对。打开示例图片看检测框是否框住了火焰或烟雾区域。如果框偏了可能是坐标还原有问题如果框住了但类别标反了火标成烟说明权重训练时类别定义和你的理解不一致。我一般会把结果画到图上保存方便对比。import cv2 # 在图上画框 for *xyxy, conf, cls in det: x1, y1, x2, y2 map(int, xyxy) label f{model.names[int(cls)]} {conf:.2f} cv2.rectangle(img0, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img0, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2) cv2.imwrite(result.jpg, img0)逻辑说明遍历检测结果用cv2.rectangle画框cv2.putText写标签。保存成 result.jpg 后和作者给的预测结果对比。如果框的位置和标签都一致说明推理链路没问题。4.2 置信度分布判断模型是否过拟合置信度不是越高越好。如果所有框的置信度都在 0.9 以上可能模型过拟合了训练集换一张新图就崩。正常情况应该有高有低火焰明显的框置信度高烟雾边缘的框置信度低。我习惯统计一下置信度分布confs [float(conf) for *_, conf, _ in det] print(f检测框数量: {len(confs)}) print(f平均置信度: {sum(confs)/len(confs):.3f}) print(f最高置信度: {max(confs):.3f}) print(f最低置信度: {min(confs):.3f})如果平均置信度低于 0.3说明模型对这个场景不自信可能需要微调如果全是 0.95 以上反而要警惕过拟合。参数说明这里没有需要调的参数纯粹是观察指标。4.3 推理速度与硬件匹配推理速度决定能不能实时检测。在 GPU 上yolov5s 跑 640x640 大概 10-20ms 一帧在 CPU 上可能 200-500ms。用下面代码测一下import time # 预热 for _ in range(5): _ model(img) # 计时 start time.time() for _ in range(20): _ model(img) end time.time() print(f平均推理时间: {(end-start)/20*1000:.1f} ms)逻辑说明先预热 5 次避免首次加载开销再跑 20 次取平均。参数说明如果平均时间超过 100ms实时检测就吃力考虑换 yolov5n 或降低输入尺寸到 416。5. 训练权重微调与数据集组织毕业设计常见需求5.1 数据集目录结构与标注格式转换毕业设计通常要求自己标注一部分数据。yolov5 要求的数据格式是 YOLO txt每行类别 x_center y_center width height坐标归一化到 0-1。目录结构如下dataset/ images/ train/ val/ labels/ train/ val/ data.yamldata.yaml 内容train: dataset/images/train val: dataset/images/val nc: 2 names: [fire, smoke]如果你用 labelImg 标注导出的是 VOC xml需要转成 YOLO txt。转换脚本核心逻辑import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, classes): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): cls obj.find(name).text if cls not in classes: continue cls_id classes.index(cls) bbox obj.find(bndbox) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # 归一化并转中心点格式 x_center (x1 x2) / 2 / w y_center (y1 y2) / 2 / h bw (x2 - x1) / w bh (y2 - y1) / h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) return lines逻辑说明解析 xml 拿到宽高和框坐标归一化后转成中心点加宽高格式。参数说明classes是类别列表顺序要和 data.yaml 里一致否则类别会错位。5.2 冻结层训练与学习率设置微调时如果数据量小建议冻结 backbone 前几层只训练检测头。yolov5 训练命令python train.py --data data.yaml --weights best.pt --epochs 50 --batch-size 8 --freeze 10 --lr0 0.001参数说明--weights best.pt加载预训练权重--freeze 10冻结前 10 层--lr0 0.001初始学习率微调时比从头训练小一个数量级--batch-size 8根据显存调显存小就降到 4。如果 loss 震荡把 lr0 再降到 0.0005。5.3 训练过程监控与早停策略训练时看三个指标box_loss、obj_loss、cls_loss。正常情况三个都下降。如果 box_loss 下降但 obj_loss 上升说明模型在乱框需要检查标注。yolov5 自带早停--patience 10表示 10 轮没提升就停。我一般还会看 mAP0.5到 0.8 以上基本可用。6. 避坑与排查火灾烟雾检测落地时的五个血泪教训6.1 现象推理结果全是背景没有任何检测框原因权重加载失败或者类别数不匹配。常见情况是用了 yolov5 官方权重而不是训练好的火灾权重官方权重是 80 类 COCO没有 fire/smoke。解决打印model.yaml[nc]确认类别数如果是 80 就换权重。6.2 现象检测框位置整体偏移原因letterbox 的 pad 参数没有正确传给 scale_coords。很多人自己写预处理忘了记录 pad 值。解决用官方datasets里的 letterbox 函数或者手动记录 dw、dh 并传入 scale_coords。6.3 现象烟雾检测漏检严重火焰正常原因烟雾特征弥散训练数据里烟雾样本少或者标注框太大。解决增加烟雾样本标注时框紧贴烟雾区域不要框太大推理时把 conf_thres 降到 0.15 试试。6.4 现象训练 loss 不下降原因学习率太大或者数据标注格式错误。先检查 labels 里有没有空文件、坐标是否超出 0-1。解决用python utils/general.py --check验证标注把 lr0 降到 0.0005 重跑。6.5 现象GPU 显存不足报错原因batch-size 太大或者输入尺寸太大。解决降 batch-size 到 4或者用--img-size 416训练推理时也保持一致。7. 把模型塞进树莓派边缘部署的取舍与验证树莓派 5 上部署自己训练的 yolov5 模型是很多毕业设计想加的亮点。但树莓派没有 CUDA只能跑 CPU 推理yolov5s 在 640 尺寸下大概 1-2 秒一帧做实时检测不现实。我的做法是导出 ONNX 模型用 onnxruntime 推理再把输入尺寸降到 320速度能到 300-500ms 一帧勉强能接受。导出 ONNXpython export.py --weights best.pt --include onnx --img-size 320然后在树莓派上装 onnxruntimepip install onnxruntime推理代码和 pytorch 版类似只是把模型换成 onnxruntime 的 InferenceSession。关键参数是providers[CPUExecutionProvider]树莓派上没有其他 provider。验证方法拿同一张示例图片对比 PC 端 pytorch 推理和树莓派 onnx 推理的检测框IoU 大于 0.9 说明精度损失可接受。如果框差太多检查导出时的 img-size 和推理时是否一致。我自己的习惯是边缘部署先跑通再优化不要一上来就追求实时。先确认能出结果再调尺寸和线程数。树莓派上把intra_op_num_threads设成 4能榨出一点性能。这套方案值不值得做如果你毕业设计需要演示硬件联动值得如果只是算法验证PC 端就够了。希望帮到你。本文还有配套的精品资源点击获取