YOLOv5火灾烟雾检测实战:从权重推理到边缘部署
简介这份资源面向准备毕业设计的学生提供一套基于YOLOv5的火灾与烟雾检测模型方案帮助解决目标检测类课题中数据标注、模型训练与推理部署等实际问题。包内共4个文件包含2张jpg示例图片、1个py推理脚本和1个pt训练权重压缩包约4.86MB体积轻便便于快速上手与二次开发。资源覆盖从数据准备、模型训练、超参数优化到模型评估、预测应用与结果可视化的完整流程读者可借助训练权重直接运行推理脚本观察火灾与烟雾的检测框及类别输出并参考示例图片核对预测效果。已有221人学习下载适合作为毕业设计中的算法验证与实验对比素材也可用于课程项目或自学目标检测的实践参考。1. 火灾烟雾检测为什么总在关键时刻掉链子从一套 YOLOv5 权重说起烟雾刚起时是半透明的絮状物火焰在白天几乎和夕阳同色这种目标在常规检测器眼里约等于背景。我见过太多实验室里 mAP 0.85 的模型搬到真实走廊摄像头画面里连明火都框不出来。问题不在网络不够深而在训练数据里根本没有“早期火灾”这个概念——公开数据集大多是火焰已经烧穿屋顶的壮观场面模型学到的其实是“大面积橙色区域”。这套 YOLOv5 火灾、烟雾检测方案要解决的正是这个断层它提供训练好的权重、推理代码、示例图片和预测结果让你不用从零标注几千张图就能跑通一条完整的检测链路。适合谁准备毕业设计、需要快速出可视化结果、又不想在环境配置上耗掉两周的同学。但我要先把丑话说在前面权重能帮你跳过训练跳不过对场景的理解。你拿到的是一把已经开过刃的刀砍什么、怎么砍仍然取决于你对火灾烟雾成像特性的判断。接下来的内容按“先跑通再调优”的顺序展开先让推理代码在你机器上出第一张预测图再拆解权重背后的训练逻辑然后处理误报和漏报最后给出把模型推到边缘设备的具体路径。每一步都有可复现的命令和参数说明不玩虚的。2. 把权重跑起来从 conda 环境到第一张预测结果图2.1 环境配置的版本陷阱与最小依赖清单YOLOv5 对环境版本极其敏感尤其是 PyTorch 和 torchvision 的匹配关系。我一般用 conda 建一个干净环境Python 锁在 3.8 到 3.9 之间再高会碰到某些依赖包没有预编译轮子的问题。下面这套命令是我在 Ubuntu 20.04 和 Windows 11 上都验证过的conda create -n fire_yolov5 python3.9 -y conda activate fire_yolov5 pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117 pip install opencv-python numpy pandas matplotlib pyyaml tqdm seaborn逻辑说明PyTorch 1.13.1 搭配 torchvision 0.14.1 是经过大量项目验证的稳定组合cu117 表示 CUDA 11.7 版本如果你只有 CPU 就把 index-url 整段去掉。opencv-python 用于图像读写和画框pyyaml 负责解析模型配置文件tqdm 在批量推理时显示进度条。参数说明python3.9不要随意改成 3.10 或 3.11YOLOv5 的某些自定义算子在这些版本上编译会报错。如果你用 GPU 推理装完后执行python -c import torch; print(torch.cuda.is_available())输出 True 才算成功。显存低于 4GB 的话推理时把 batch size 设为 1否则会 OOM。2.2 推理代码逐段拆解预处理、前向传播、NMS 后处理拿到权重文件后核心推理流程其实只有四步读图并做 letterbox 缩放、归一化、送入模型前向传播、对输出做非极大值抑制。下面是我常用的推理脚本骨架import cv2 import torch import numpy as np # 加载模型weights 替换为你的 .pt 文件路径 model torch.hub.load(./yolov5, custom, path./weights/best.pt, sourcelocal) model.conf 0.35 # 置信度阈值烟雾建议调低到 0.25 model.iou 0.45 # NMS 的 IoU 阈值火焰重叠多时可降到 0.4 img cv2.imread(./samples/fire_01.jpg) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) results model(img_rgb, size640) # size 控制推理分辨率 results.print() # 打印检测到的类别和置信度 results.save(save_dir./runs/detect/exp) # 保存带框结果图 # 提取结构化数据方便后续统计 df results.pandas().xyxy[0] print(df[[xmin, ymin, xmax, ymax, confidence, name]])逻辑说明torch.hub.load的sourcelocal表示从本地 yolov5 仓库加载模型定义不走网络下载。model.conf和model.iou是推理时最常调的两个参数前者决定多低的置信度才保留框后者决定重叠框怎么合并。results.pandas().xyxy[0]把检测结果转成 DataFrame方便你按置信度排序或统计某类目标数量。参数说明size640是推理分辨率烟雾检测建议保持 640降到 320 会丢失远处小烟雾。conf0.35是火焰的常用值烟雾因为特征弥散我一般单独设 0.25。iou0.45适合大多数场景如果画面里火焰区域大面积重叠降到 0.4 能减少框的冗余。2.3 用示例图片验证预测结果是否正常跑通代码后先别急着换自己的图。用方案里自带的示例图片做一次基准测试确认三件事火焰框是否贴合、烟雾框是否覆盖主要区域、有没有把灯光或夕阳误判成火。我通常会把预测结果图和原图并排放在一起看重点检查边缘区域。如果示例图上的框明显偏移先检查 letterbox 缩放是否和训练时一致。YOLOv5 默认在推理时做 letterbox 填充到 640x640如果你的图片长宽比极端填充区域过大目标会被压缩得很小。解决办法是把size改成 1280或者对图片先做裁剪再推理。如果烟雾检测置信度普遍偏低不要急着改模型先把conf降到 0.2 看看有没有框出来。烟雾在早期阶段颜色和背景接近模型给出的置信度天然偏低这是数据分布决定的不是代码 bug。3. 权重背后的训练逻辑数据集、超参数与迁移策略3.1 火灾烟雾数据集怎么选公开数据与自标注的取舍训练权重的好坏七成取决于数据。公开的火灾烟雾数据集常见的有几个来源一类是实验室可控燃烧实验拍摄的背景干净、火焰形态标准但场景单一另一类是网络爬取的新闻图片场景丰富但标注质量参差不齐。我一般建议毕业设计阶段用公开数据集打底再补拍 200 到 300 张自己场景的图做微调。自标注时有个血泪经验烟雾的边界极其模糊不同人标注的框大小能差出 30%。解决办法是制定标注规范——烟雾框只框“肉眼可辨的烟雾主体”不框稀薄到几乎透明的边缘。火焰框则要包含所有明火区域包括火星飞溅的部分。标注工具用 labelImg 或 CVAT 都行导出 YOLO 格式的 txt 文件。数据划分比例按 8:1:1 走训练集、验证集、测试集。注意验证集和测试集要从不同场景里抽不能全是一个视频里截的帧否则评估结果会虚高。3.2 超参数怎么设从 yolov5s 到火灾场景的适配YOLOv5 的默认超参数是针对 COCO 数据集调的搬到火灾烟雾场景需要改几个关键值。下面是我在多次训练中总结的配置# hyp_fire.yaml 关键参数 lr0: 0.01 # 初始学习率默认 0.01小数据集降到 0.005 lrf: 0.2 # 最终学习率系数余弦退火到 lr0 * lrf momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3.0 box: 0.05 # 框回归损失权重 cls: 0.5 # 分类损失权重火灾两类可保持默认 obj: 1.0 # 目标置信度损失权重 anchor_t: 4.0 # 锚框匹配阈值逻辑说明lr0是初始学习率如果你用预训练权重微调0.01 足够如果从零训练可以提到 0.02 但需要更长的 warmup。lrf控制学习率衰减终点0.2 表示最终学习率是初始值的 20%。warmup_epochs设 3 表示前 3 个 epoch 学习率从 0 线性升到 lr0避免一开始就大梯度破坏预训练权重。参数说明box和cls的权重比影响模型更关注定位还是分类。火灾检测里定位准确性更重要所以box可以适当调高到 0.08。anchor_t是锚框匹配阈值调高会让更多锚框参与训练小目标多的时候可以设 5.0。训练命令用python train.py --data fire.yaml --weights yolov5s.pt --hyp hyp_fire.yaml --epochs 100 --batch-size 16 --img 640。--weights yolov5s.pt表示从 COCO 预训练权重开始迁移这比从零训练收敛快至少 3 倍。3.3 迁移学习策略冻结层数与学习率分组的实操迁移学习的核心是决定冻结哪些层。YOLOv5 的 backbone 前 10 层学的是通用特征火灾烟雾和 COCO 里的物体在底层特征上有共性所以可以冻结。但 neck 和 head 必须解冻因为检测头的输出维度变了。我一般用两阶段策略第一阶段冻结 backbone只训练 head学习率设 0.01跑 20 个 epoch第二阶段解冻全部学习率降到 0.001再跑 80 个 epoch。这样做的原因是随机初始化的 head 如果和大学习率的 backbone 一起训练梯度会互相干扰导致前期震荡。代码里通过--freeze 10参数冻结前 10 层第二阶段去掉这个参数即可。学习率分组在 YOLOv5 里默认开启backbone 的学习率是 head 的 0.1 倍这个比例在火灾场景下表现稳定不建议改。4. 误报与漏报的排查从数据分布到后处理阈值4.1 火焰被夕阳误判颜色特征的干扰与缓解夕阳、暖色灯光、橙色衣物是火焰检测的三大误报源。模型在训练时如果没见过这些负样本就会把任何大面积橙红色区域当成火焰。我处理这个问题的办法是在训练集里加入 300 到 500 张负样本——不含火焰但包含夕阳、灯光、橙色物体的图片标注为空。如果已经训练完了不想重训可以在推理后处理阶段加一个颜色校验对检测为火焰的框计算框内像素在 HSV 空间的色调分布如果色调集中在 0 到 25 之外就降低置信度。这个逻辑用 OpenCV 十几行就能实现hsv cv2.cvtColor(img[y1:y2, x1:x2], cv2.COLOR_BGR2HSV) hue hsv[:, :, 0] fire_ratio np.sum((hue 25) | (hue 160)) / hue.size if fire_ratio 0.3: confidence * 0.5 # 色调不符置信度打折逻辑说明火焰的色调在 HSV 空间里集中在 0 到 25 和 160 到 180 两个区间夕阳的色调偏 10 到 20 但饱和度低灯光的色调可能偏黄。fire_ratio低于 0.3 说明框内大部分像素不是火焰色置信度打五折。参数说明fire_ratio的阈值 0.3 是经验值烟雾场景不适用这个逻辑只对火焰类生效。饱和度阈值可以再加一层过滤火焰的饱和度通常高于 150。4.2 烟雾漏报小目标与低对比度的处理方案烟雾漏报比误报更危险。早期烟雾在画面里可能只占几十个像素YOLOv5 的 P3 特征图负责小目标检测但如果训练时小烟雾样本太少P3 分支学不到有效特征。解决办法有两个一是在数据增强里开启 mosaic 和 copy-paste人为制造小目标二是推理时把size提到 1280让烟雾在特征图上占更多像素。另一个原因是烟雾对比度低。我试过在推理前对图像做 CLAHE 自适应直方图均衡化提升局部对比度烟雾召回率能涨 5 到 8 个百分点。代码很简单clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) lab cv2.cvtColor(img, cv2.COLOR_BGR2LAB) lab[:, :, 0] clahe.apply(lab[:, :, 0]) img_enhanced cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)逻辑说明CLAHE 在 LAB 空间的 L 通道上做均衡化只增强亮度对比度不改变颜色分布。clipLimit2.0控制对比度增强上限太高会放大噪声。tileGridSize(8,8)表示把图像分成 8x8 的块分别做均衡化。参数说明clipLimit在烟雾场景建议 2.0 到 3.0火焰场景可以降到 1.5 避免过曝。这个预处理只用于推理训练时不需要加否则模型会学到增强后的分布部署时反而退化。4.3 NMS 后处理参数对密集火焰框的影响火灾现场往往有多处火焰同时燃烧NMS 的 IoU 阈值设不好会出现两种情况阈值太高同一个火焰被框多次阈值太低相邻火焰被合并成一个框。我一般先用 0.45 跑一遍看结果图里有没有重复框或漏框再微调。如果火焰区域密集且重叠把iou降到 0.35 到 0.4让 NMS 更激进地合并重叠框。如果火焰之间距离近但不相连保持 0.45 到 0.5避免误合并。YOLOv5 还支持agnostic_nms参数设为 True 时不同类别的框也会互相抑制火灾烟雾两类场景下不建议开因为火焰和烟雾经常共存互相抑制会导致漏检。5. 避坑与排查训练和部署中最容易翻车的五个点5.1 现象训练 loss 震荡不收敛mAP 卡在 0.3 上不去原因学习率设太大或者 batch size 太小导致梯度噪声大。火灾烟雾数据集通常只有几千张图batch size 设 32 以上容易过拟合设 4 以下梯度方向不稳定。解决把lr0降到 0.005batch size 设 8 或 16开启--cos-lr余弦退火。如果还震荡检查标注文件里有没有空 txt 或坐标越界的框用python utils/general.py --check-labels扫一遍。5.2 现象推理时 GPU 显存溢出报 CUDA out of memory原因推理分辨率设太高或者 batch size 没设对。YOLOv5 推理时默认 batch size 是 1但如果你用 DataLoader 批量读图显存会随 batch 线性增长。解决把size从 1280 降到 640或者用--half半精度推理显存占用直接减半。显存小于 4GB 的卡推理时加torch.cuda.empty_cache()在每个 batch 后清理缓存。5.3 现象自己标注的数据训练后模型只框大火焰不框小火焰原因小目标样本在数据集里占比太低YOLOv5 的 P3 分支没有足够梯度。另外锚框尺寸如果和你的目标尺寸不匹配小目标会匹配不到合适的锚框。解决用python utils/autoanchor.py重新聚类锚框把--img设成 640 跑一遍。数据增强里开启--mosaic 1.0和--copy-paste 0.3人为增加小目标出现频率。5.4 现象部署到树莓派 5 上推理速度只有 2 FPS原因树莓派 5 的 GPU 不支持 CUDA只能用 CPU 推理YOLOv5s 在 ARM CPU 上单张 640 分辨率推理大约 300 到 500ms。如果你用的是 YOLOv5m 或 l速度会更慢。解决导出 ONNX 模型并用 onnxruntime 推理比 PyTorch 原生推理快 30% 左右。或者把模型换成 YOLOv5n精度掉 3 到 5 个点但速度翻倍。树莓派 5 上建议用size320推理帧率能到 8 到 10 FPS对烟雾检测来说够用。5.5 现象预测结果图里框的位置整体偏移和原图对不上原因推理时的 letterbox 缩放和训练时不一致或者画框时没有把坐标映射回原图尺寸。YOLOv5 的results.save()会自动处理映射但如果你手动用xyxy坐标画框需要先除以缩放比例再加上填充偏移。解决直接用results.pandas().xyxy[0]拿到的坐标就是原图坐标系下的不要自己再做变换。如果手动处理记住公式x_orig (x_letterbox - pad_x) / scale。6. 把模型推到边缘设备ONNX 导出与树莓派 5 部署的实操细节训练和验证都跑通之后下一步是把模型从开发机搬到实际设备上。树莓派 5 是毕业设计里最常见的边缘平台但它没有 CUDAPyTorch 原生推理慢得让人想砸键盘。我一般走 ONNX 路线先在开发机上把.pt导出成.onnx再在树莓派上用 onnxruntime 加载。导出命令如下python export.py --weights ./weights/best.pt --include onnx --img 640 --batch 1 --simplify--simplify会调用 onnx-simplifier 优化计算图去掉冗余算子推理速度能再快 10% 到 15%。导出后在树莓派上安装 onnxruntimepip install onnxruntime推理代码需要自己写预处理和后处理因为 onnxruntime 不包含 YOLOv5 的 letterbox 和 NMS。预处理部分和训练时保持一致BGR 转 RGB、归一化到 0 到 1、HWC 转 CHW、加 batch 维度。后处理部分对输出张量做置信度过滤和 NMS可以用 numpy 实现也可以调cv2.dnn.NMSBoxes。我实测的数据树莓派 5 上用 onnxruntime 跑 YOLOv5s输入 320x320单帧推理约 120ms加上预处理和后处理总共 180ms 左右帧率 5 到 6 FPS。输入 640x640 时单帧 380ms帧率不到 3 FPS。烟雾检测对帧率要求不高5 FPS 足够捕捉烟雾扩散趋势。有一个坑要注意树莓派 5 的散热必须做好连续推理 10 分钟以上 CPU 会降频帧率掉 30%。加一个主动散热风扇或者把推理间隔设成每 3 帧处理 1 帧降低热积累。最后说一个我自己的习惯每次换场景部署前先用手机拍 20 张该场景的图在开发机上跑一遍推理看误报和漏报情况。如果误报超过 3 张先调conf和iou不要急着重新训练。大部分场景下后处理参数微调就能解决 80% 的问题。希望帮到你。本文还有配套的精品资源点击获取