
简介这份资源面向计算机相关专业的本科毕业生及需要完成目标检测课题的开发者提供一套基于YOLOv5的火灾火焰与烟雾检测完整方案可用于毕业设计、课程项目或算法入门实践。压缩包共74个文件约718KB以yaml配置文件、py源码、sh脚本及png、jpg图像为主涵盖模型结构定义、训练与推理脚本、数据配置、界面与串口通信模块等并附带已标注数据集与训练好的权重。资源重点实现了TensorRT加速下的预处理、推理与后处理流程涉及Runtime、deserialize_cached_engine、create_execution_context等引擎构建接口以及CUDA显存分配、Stream流操作与串口通信、OpenCV矩形绘制等实用功能还包含CBAM、SE等注意力机制改进示例。已有118人学习适合希望快速跑通火焰烟雾检测、理解加速部署与界面集成的读者参考借鉴。1. 从一份 YOLOv5 火灾火焰烟雾检测方案说起数据集、模型、源码到底怎么串起来火灾火焰烟雾检测这个方向每年毕业季都会被大量同学翻出来做。原因很直接场景直观、效果可视化强、数据集相对好找而且用 YOLOv5 这种成熟框架从标注到推理能跑通一条完整链路。但真正动手时问题往往不在模型本身而在三个环节的衔接上——数据集怎么组织、模型怎么配、源码怎么改才能跑出自己的结果。很多人卡在第一步下载了一堆图片却不知道 YOLOv5 要的目录结构长什么样或者训练跑起来了mAP 却低得离谱回头一看是标注格式错了。这套「Python毕业设计-YOLOV5火灾火焰烟雾检测数据集模型源码」的组合本质上解决的就是这条链路的完整性问题。它适合两类人一类是毕业设计需要快速搭出可演示系统的同学另一类是刚接触目标检测、想用一个真实场景把 YOLOv5 全流程走一遍的入门者。火焰和烟雾这两个类别有个特点——火焰边界清晰但形态多变烟雾边界模糊且半透明这对检测模型来说是个不小的挑战也正好能体现数据增强和 anchor 调整的价值。我一般会把这个方案拆成四步来看数据集准备与格式转换、YOLOv5 环境配置与训练、模型评估与调参、源码集成与推理部署。下面按这个顺序把每一步里真正会卡人的地方讲清楚。2. 数据集准备从原始图片到 YOLOv5 可训练的目录结构2.1 火焰烟雾数据集的类别定义与标注要点火焰烟雾检测的数据集核心就两个类别fire 和 smoke。听起来简单但标注时的边界判定直接决定模型上限。火焰的标注相对明确把可见的火焰区域框住即可但要注意火焰边缘的过渡区域——如果框得太紧模型学到的特征会偏保守遇到远距离小火苗容易漏检框得太松又会把背景里的暖色物体误纳入。烟雾的问题更大。烟雾没有硬边界标注时容易出现过框或欠框。我的经验是以烟雾浓度较高、肉眼能明确辨认的区域为准边缘稀薄部分不强行框入。如果一张图里烟雾和火焰同时存在且区域重叠建议分别标注两个框不要合并成一个大框否则模型学到的特征会混淆。标注工具用 LabelImg 就够了输出格式选 YOLO 格式每张图对应一个 .txt 文件每行是class_id x_center y_center width height坐标全部归一化到 0-1。这里有个高频翻车点LabelImg 默认可能输出 PascalVOC 的 XML 格式需要在切换格式时确认一下否则后面转换脚本会报错。2.2 目录结构搭建与数据划分脚本YOLOv5 对目录结构有固定要求不按这个来训练脚本直接找不到图片。标准结构如下fire_smoke_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamlimages 和 labels 下的子目录必须一一对应图片和同名 txt 文件放在对应目录里。划分比例常见做法是 train:val:test 7:2:1 或 8:1:1火焰烟雾这种场景建议验证集留足因为烟雾的类内差异大验证集太小会导致评估波动明显。下面这个脚本用来做随机划分同时把图片和标签同步搬过去import os import random import shutil # 原始数据目录图片和标签混在一起 src_img_dir ./raw_images src_label_dir ./raw_labels # 目标目录 dst_root ./fire_smoke_dataset split_ratio {train: 0.7, val: 0.2, test: 0.1} # 收集所有图片文件名不含扩展名 names [os.path.splitext(f)[0] for f in os.listdir(src_img_dir) if f.lower().endswith((.jpg, .png, .jpeg))] random.seed(42) # 固定随机种子保证可复现 random.shuffle(names) total len(names) n_train int(total * split_ratio[train]) n_val int(total * split_ratio[val]) splits { train: names[:n_train], val: names[n_train:n_train n_val], test: names[n_train n_val:] } for split, file_list in splits.items(): img_out os.path.join(dst_root, images, split) lbl_out os.path.join(dst_root, labels, split) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for name in file_list: # 图片可能有不同扩展名逐个尝试 for ext in (.jpg, .png, .jpeg): src_img os.path.join(src_img_dir, name ext) if os.path.exists(src_img): shutil.copy(src_img, os.path.join(img_out, name ext)) break src_lbl os.path.join(src_label_dir, name .txt) if os.path.exists(src_lbl): shutil.copy(src_lbl, os.path.join(lbl_out, name .txt)) print(f划分完成: train{len(splits[train])}, val{len(splits[val])}, test{len(splits[test])})这段脚本的关键参数是split_ratio和random.seed。固定种子是为了让每次划分结果一致方便复现实验。如果数据集本身有视频帧连续采样的情况随机划分会导致同一段视频的帧同时出现在训练集和验证集里造成验证指标虚高。遇到这种情况要按视频来源分组划分而不是按帧随机划分。2.3 data.yaml 配置与路径校验data.yaml 是 YOLOv5 训练时读取数据集信息的入口文件内容如下path: ./fire_smoke_dataset train: images/train val: images/val test: images/test nc: 2 names: [fire, smoke]path是数据集根目录train/val/test是相对路径。nc是类别数names按 class_id 顺序排列。这里最常见的错误是路径层级搞混——比如把path写成绝对路径后换机器跑就失效或者train写成了images/train/末尾多斜杠在某些版本会出问题。配置完后建议先用一个小脚本检查图片和标签是否一一对应import os img_dir ./fire_smoke_dataset/images/train lbl_dir ./fire_smoke_dataset/labels/train imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir)} lbls {os.path.splitext(f)[0] for f in os.listdir(lbl_dir)} missing_label imgs - lbls missing_img lbls - imgs print(f有图无标签: {len(missing_label)}) print(f有标签无图: {len(missing_img)})如果这两个数字不为零训练时 YOLOv5 会跳过对应样本或直接报错。有图无标签的情况要么补标注要么把图删掉有标签无图的情况直接删标签文件。3. YOLOv5 环境配置与训练从 conda 到第一个 baseline3.1 环境配置的版本选择与依赖安装YOLOv5 对环境的要求不算苛刻但版本不匹配会出各种玄学问题。我一般用 conda 建一个独立环境Python 选 3.8 或 3.9这两个版本和 PyTorch 的兼容性最稳。PyTorch 版本根据显卡驱动来定CUDA 11.3 以上配 PyTorch 1.10 基本没问题。conda create -n fire_yolov5 python3.9 -y conda activate fire_yolov5 # 安装 PyTorch根据自己 CUDA 版本调整 pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117 # 克隆 YOLOv5 仓库并安装依赖 git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt安装完后用python -c import torch; print(torch.cuda.is_available())验证 GPU 是否可用。如果返回 False先检查显卡驱动和 CUDA 版本不要急着改代码。另一个高频问题是requirements.txt里某些包版本冲突比如 numpy 版本过高导致和 torch 不兼容遇到报错就按提示降级不要强行忽略。3.2 训练命令与关键超参数设置YOLOv5 的训练入口是train.py最简命令如下python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data ./fire_smoke_dataset/data.yaml \ --weights yolov5s.pt \ --cfg models/yolov5s.yaml \ --name fire_smoke_baseline几个参数需要根据实际情况调参数含义调整建议--img输入图像尺寸火焰烟雾建议 640远距离小目标可试 1280--batch批大小根据显存调8G 显存用 164G 用 8--weights预训练权重用 yolov5s.pt 做迁移学习不要从零训--cfg模型结构yolov5s 最快yolov5m/l 精度更高但更慢--hyp超参数文件默认 data/hyp.scratch.yaml可自定义火焰烟雾检测有个特殊点烟雾目标通常比火焰大而且形态更分散。如果数据集里烟雾占比高建议把 anchor 重新聚类一遍。YOLOv5 自带utils/autoanchor.py训练时加--noautoanchor可以关闭自动 anchor但一般让它自动跑就行。训练过程中重点看三个指标box_loss、obj_loss、mAP0.5。box_loss 下降说明定位在收敛obj_loss 下降说明置信度在学mAP 是最终效果。如果 box_loss 一直震荡不降大概率是学习率太大或标注框有问题如果 mAP 卡在低位不动检查类别是否标错或数据量太少。3.3 训练日志解读与中断恢复YOLOv5 训练时会在runs/train/下生成实验目录里面有results.csv、weights/、hyp.yaml等。results.csv每行是一个 epoch 的指标可以用 pandas 快速画图import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/train/fire_smoke_baseline/results.csv) df.columns df.columns.str.strip() # 列名可能带空格 fig, ax plt.subplots(1, 2, figsize(12, 4)) ax[0].plot(df[epoch], df[train/box_loss], labelbox_loss) ax[0].plot(df[epoch], df[train/obj_loss], labelobj_loss) ax[0].legend() ax[1].plot(df[epoch], df[metrics/mAP_0.5], labelmAP0.5) ax[1].legend() plt.savefig(training_curve.png)如果训练中途断了用--resume参数可以从最后一个 checkpoint 继续python train.py --resume runs/train/fire_smoke_baseline/weights/last.pt注意--resume会读取原实验的配置不要额外加其他参数否则可能覆盖原设置。另外last.pt是最后一个 epoch 的权重best.pt是验证集指标最好的权重部署时用best.pt。4. 模型评估与调参让火焰烟雾检测的 mAP 真正可用4.1 验证集评估与混淆矩阵分析训练完后用val.py做评估python val.py \ --data ./fire_smoke_dataset/data.yaml \ --weights runs/train/fire_smoke_baseline/weights/best.pt \ --img 640 \ --conf 0.25 \ --iou 0.5--conf是置信度阈值--iou是 NMS 的 IoU 阈值。评估结果里除了 mAP还会输出每个类别的 precision 和 recall。火焰烟雾场景下火焰的 recall 通常高于烟雾因为烟雾边界模糊导致漏检更多。混淆矩阵在runs/val/下会生成confusion_matrix.png。重点看两个地方一是 fire 被误判为 smoke 的比例二是背景被误判为目标的比例。如果背景误判高说明模型对背景里的暖色物体或雾气过度敏感需要增加负样本如果 fire 和 smoke 互相误判多说明两个类别的特征区分度不够可以考虑在标注时更严格地区分。4.2 针对烟雾漏检的数据增强策略烟雾漏检是这类项目最头疼的问题。除了增加烟雾样本量数据增强是最直接的手段。YOLOv5 默认的 hyp 文件里已经包含 mosaic、mixup、HSV 增强等但针对烟雾可以额外调整# data/hyp.fire_smoke.yaml lr0: 0.01 lrf: 0.2 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3.0 warmup_momentum: 0.8 # 数据增强 hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4 degrees: 0.0 translate: 0.1 scale: 0.5 shear: 0.0 perspective: 0.0 flipud: 0.0 fliplr: 0.5 mosaic: 1.0 mixup: 0.1 copy_paste: 0.0关键调整hsv_s和hsv_v调高让模型对烟雾的灰白和半透明变化更鲁棒scale设 0.5 让目标尺度变化更大覆盖远近距离的烟雾mixup设 0.1 做少量混合太多会让烟雾边界更模糊。训练时用--hyp data/hyp.fire_smoke.yaml指定。4.3 推理测试与阈值调优训练完后用detect.py做推理python detect.py \ --weights runs/train/fire_smoke_baseline/weights/best.pt \ --source ./test_images \ --img 640 \ --conf 0.3 \ --iou 0.45 \ --save-txt--conf和--iou需要根据实际场景调。火焰检测可以适当降低 conf 到 0.25宁可多报不可漏报烟雾检测建议 conf 设 0.35 以上因为烟雾误报的代价更高。--save-txt会输出检测框坐标方便后续集成到自己的系统里。如果发现某些图片漏检严重可以单独拿出来看是不是标注问题或者用--augment开启 TTA测试时增强但会拖慢推理速度。5. 避坑与排查火焰烟雾检测项目里最容易翻车的 5 个地方5.1 现象训练 loss 正常下降但 mAP 始终为 0原因标签文件里的 class_id 超出了data.yaml里nc定义的范围或者标签坐标没有归一化。YOLOv5 在读取标签时如果发现坐标大于 1会直接跳过该样本导致模型学不到任何东西。解决用脚本检查所有标签文件确认每行的第一个数字在[0, nc-1]范围内后四个数字在[0, 1]之间。发现异常就修正或删除对应标签。5.2 现象训练时显存溢出batch 降到 1 还是 OOM原因--img设得太大或者模型选了 yolov5l/x。另外如果数据集里有个别图片分辨率极高YOLOv5 在 dataloader 阶段就会占大量显存。解决先把--img降到 416 跑通再逐步升到 640。检查数据集里是否有超大图统一 resize 到合理尺寸。如果显存实在小用--batch 4 --accumulate 4做梯度累积等效 batch 还是 16。5.3 现象推理时火焰检测正常烟雾完全检不出原因训练集里烟雾样本太少或者烟雾标注框过大导致模型学不到局部特征。另一个可能是--conf设太高烟雾的置信度普遍偏低。解决先统计训练集里 fire 和 smoke 的标注框数量如果比例超过 3:1需要补充烟雾样本。推理时把--conf降到 0.2 试试如果还是不行检查烟雾标注框是否把整张图都框进去了。5.4 现象换一台机器跑源码报错找不到模块或版本不兼容原因YOLOv5 的依赖版本在不同机器上不一致尤其是 torch、torchvision、numpy 这三个。另外如果源码里用了绝对路径换机器后路径失效。解决用pip freeze requirements.txt导出当前环境依赖在新机器上按这个文件安装。源码里的路径全部改成相对路径或者用os.path.dirname(__file__)动态获取。5.5 现象验证集 mAP 很高但实际视频推理效果很差原因验证集和训练集来自同一批图片分布太接近模型过拟合了。视频推理时帧间变化、光照变化、运动模糊都是训练集里没有的。解决从视频里抽帧做验证集确保验证集和训练集来源不同。训练时加--rect做矩形推理减少 padding 带来的分布差异。如果条件允许用视频帧做一轮微调。6. 从跑通到能用把检测模型接进自己的 Python 系统6.1 用 Python 调用模型做实时推理训练出的best.pt可以直接用torch.hub加载不依赖 YOLOv5 的 detect.pyimport torch import cv2 import numpy as np # 加载模型 model torch.hub.load(./yolov5, custom, pathruns/train/fire_smoke_baseline/weights/best.pt, sourcelocal) model.conf 0.3 model.iou 0.45 cap cv2.VideoCapture(0) # 摄像头也可以换成视频文件路径 while cap.isOpened(): ret, frame cap.read() if not ret: break # YOLOv5 接受 RGB 输入 img_rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results model(img_rgb) # 渲染检测框 annotated np.squeeze(results.render()) cv2.imshow(Fire Smoke Detection, cv2.cvtColor(annotated, cv2.COLOR_RGB2BGR)) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这段代码的关键是sourcelocal它让 torch.hub 从本地 YOLOv5 目录加载而不是从网络拉取。model.conf和model.iou可以在运行时动态调整方便根据场景切换灵敏度。6.2 检测结果的结构化输出与报警逻辑实际系统里检测框坐标需要转成结构化数据再叠加业务逻辑。比如火焰面积超过画面一定比例就触发报警results model(img_rgb) detections results.pandas().xyxy[0] # DataFrame: xmin, ymin, xmax, ymax, confidence, class, name h, w img_rgb.shape[:2] frame_area h * w for _, det in detections.iterrows(): if det[name] fire and det[confidence] 0.5: box_area (det[xmax] - det[xmin]) * (det[ymax] - det[ymin]) ratio box_area / frame_area if ratio 0.05: # 火焰面积超过 5% 触发报警 print(f火焰报警: 置信度{det[confidence]:.2f}, 面积占比{ratio:.2%})results.pandas().xyxy[0]返回的是 pandas DataFrame列名固定方便做条件筛选。报警阈值0.05需要根据实际监控距离和画面分辨率调整没有通用值。6.3 模型导出与推理加速如果部署环境没有 GPU或者需要更快的推理速度可以把模型导出成 ONNX 或 TensorRT# 导出 ONNX python export.py --weights runs/train/fire_smoke_baseline/weights/best.pt --include onnx --img 640 # 导出 TensorRT需要 GPU 和 tensorrt 环境 python export.py --weights runs/train/fire_smoke_baseline/weights/best.pt --include engine --img 640 --device 0ONNX 适合跨平台部署TensorRT 在 NVIDIA 显卡上能提速 2-3 倍。导出后可以用onnxruntime或tensorrt加载推理不再依赖 PyTorch。注意导出时的--img要和训练时一致否则精度会掉。6.4 一个我踩过的坑别在验证集上反复调参最后说一个血泪经验。我刚开始做这个项目时看到验证集 mAP 不理想就反复调 conf、iou、数据增强参数每次都在同一个验证集上看结果。调了十几轮后 mAP 确实上去了但换一批新图片测试效果反而更差。后来才意识到验证集被我用成了测试集模型间接过拟合了验证集。正确的做法是训练集训练验证集只用来选 best.pt测试集留到最后只跑一次。如果测试集效果不行回头检查数据分布和标注质量而不是继续调参。这个习惯我后来一直保持希望帮到你。本文还有配套的精品资源点击获取