简介:面向目标检测与消防预警场景的 YOLOv5 火灾检测模型包,适合计算机视觉初学者、算法工程师及安防监控开发者直接上手。压缩包内含已训练好的火焰与烟雾识别模型,无需重新训练即可对图片或视频进行推理,并输出边界框与置信度,衔接监控系统即可形成预警能力。包体共135个文件,主要由 Python 源码、YAML 配置文件、训练权重(.pt)、示例图片与视频、Jupyter Notebook 脚本及 Dockerfile 等组成,合计约68.51MB,既可用于快速验证效果,也可参考其中的训练与调参思路。目前已有3265人学习下载。对于想避开繁琐训练流程、专注应用落地的用户,可直接获得可复用的模型权重、完整项目结构和说明文档,帮助理解 YOLOv5 在火灾检测中的实际部署流程,也可作为进一步微调模型或开发实时报警系统的基础。
1. 火灾检测不是通用目标检测:YOLOv5为什么能扛住这一场景
把 YOLOv5 用在火灾检测上,很多人第一反应是「无非是换个数据集训练」。真做起来你会发现,火焰和烟雾的形态、颜色、边缘都在变,误报来源又多——灯光、晚霞、蒸汽都能骗过模型。我做过几轮实际落地的火灾检测方案,最终还是选 YOLOv5 作为基线:它训练生态成熟、部署链路短,从源码到自定义数据集训练再到树莓派上推理,整个路径有大量现成经验可抄。这篇文章把从环境配置、数据整理、超参数设置到后处理部署的完整过程写出来,重点放在参数怎么调、哪些地方容易翻车,适合正准备拿 YOLOv5 做火灾检测的从业者。
2. 搭建 YOLOv5 训练环境:conda、依赖与数据集组织的完整路径
2.1 conda 建环境:一套最稳的安装顺序
YOLOv5 的环境配置本身不复杂,但很多人卡在第一步——PyTorch、CUDA、torchvision 三者版本不匹配,装完之后import torch报错或者 GPU 根本不可用。我一般会在 conda 里单独建一个环境,避免污染其他项目。
常见做法是先用 conda 创建 Python 3.8 的环境,然后通过 pip 安装 PyTorch 全家桶。这里的关键是先确认本机 NVIDIA 驱动的 CUDA 版本,再选择对应的 PyTorch 版本,顺序不能反。
# 创建独立环境,Python 版本选 3.8 最稳 conda create -n fire_yolov5 python=3.8 -y conda activate fire_yolov5 # 查看本机 CUDA 驱动支持的版本,以 nvidia-smi 为准 nvidia-smi # 安装 PyTorch,这里假设你的 CUDA 是 11.8 pip install torch==1.13.1 torchvision==0.14.1 --extra-index-url https://download.pytorch.org/whl/cu118 # 安装 YOLOv5 其余依赖(在项目根目录执行) cd yolov5 # 你 clone 下来的源码目录 pip install -r requirements.txt这段命令的逻辑是:先创建隔离的 conda 环境,避免依赖冲突,这是 Python 项目最朴素也最有效的管理方式。nvidia-smi查到的 CUDA 版本是驱动支持的版本,它决定了你能装哪个 PyTorch 编译版本。装完 PyTorch 之后再装requirements.txt里的其余依赖——numpy、opencv、matplotlib 这些是训练和推理的公共底座。
这里有个参数很容易被忽略:--extra-index-url指向 PyTorch 官方源时,pip 会从该源拉取对应 CUDA 版本的 wheel 包。如果你直接pip install torch,默认从 PyPI 拉的是 CPU 版本,GPU 根本用不上。装完之后用下面命令验证:
python -c "import torch; print(torch.cuda.is_available(), torch.__version__)"输出True 1.13.1+cu118才算环境就绪。我之前见过有人torch.cuda.is_available()返回False,查了半天发现是 conda 默认装了 CPU 版 torch,重装之后才解决。这套环境配置路径是 YOLOv5 训练前的标配,也是系列热搜词里「conda yolov5」「yolov5环境配置」被反复搜索的原因——问题大多出在版本匹配,而不是命令本身。
2.2 火灾数据集从哪来、怎么整理成 YOLO 格式
火灾检测的数据集比通用目标检测难凑,公开的火灾数据集规模都不大,而且场景单一。常见做法是拿公开火灾图像数据集作为基础,再自己补充一部分场景图。这里要特别注意:火焰样本和烟雾样本要分开处理,因为它们的视觉特征差异很大——火焰边缘锐利、颜色集中在红黄区间,烟雾则是半透明的、形状不规则的弥散区域。
拿到图片之后,要标注成 YOLO 格式。YOLO 格式的标注是每张图片对应一个 txt 文件,每行代表一个目标框:类别编号 cx cy w h,其中cx cy是框中心点坐标(归一化到 0~1),w h是框的宽高(也是归一化)。标注工具我常用 LabelImg,导出时直接选 YOLO 格式即可。
标注完成后,数据集目录结构必须严格按 YOLOv5 的要求组织:
fire_dataset/ ├── images/ │ ├── train/ # 训练集图片 │ └── val/ # 验证集图片 └── labels/ ├── train/ # 训练集标注 txt └── val/ # 验证集标注 txt目录结构对了还不够,图片和标注文件的文件名必须一一对应——同名的.jpg和.txt放在对应的images和labels目录下。YOLOv5 训练时通过图片路径推断标注路径,名字对不上就会导致训练时「有图片没标注」,模型等于在学空气。
对于火灾检测,类别建议按实际场景压缩成0: fire(火焰)和1: smoke(烟雾)两个类,而不是把火焰细分成多种类型。分类过细会稀释训练样本,导致每个类别的正样本数量不足,模型收敛变慢甚至欠拟合。我自己第一次做时把火焰按「明火」「暗火」分了两类,结果暗火类样本太少,模型基本学不出来,后来合并成单类效果立刻提升。
3. 训练自己的火灾检测模型:超参数、训练命令与收敛判断
3.1 数据配置与模型配置:yaml 文件到底在管什么
YOLOv5 的训练入口是train.py,但它本身不直接读取各层超参数——所有配置都写在 yaml 文件里,这也是让很多人困惑的地方。数据配置和模型配置是两套 yaml,职责不同,不能混用。
数据 yaml 定义的是「你的数据长什么样」:
# fire_data.yaml train: fire_dataset/images/train val: fire_dataset/images/val nc: 2 # 类别数量:火焰 + 烟雾 names: ['fire', 'smoke']这个 yaml 里train和val指向图片目录,nc必须和names一一对应。nc填错是新手最容易犯的错——类别数写成 1,但标注文件里有类别编号 0 和 1,训练会直接报错或者静默地把类别 1 当背景。模型 yaml 定义的是网络结构,比如最常用的yolov5s.yaml:
# yolov5s.yaml(部分) nc: 2 # 必须改成和数据 yaml 一致 depth_multiple: 0.33 width_multiple: 0.50depth_multiple和width_multiple是 YOLOv5 模型缩放系数,控制网络的深度和宽度。yolov5s的0.33 / 0.50是轻量配置,yolov5m是0.67 / 0.75,yolov5l是1.0 / 1.0。火灾检测这种实时性要求高的场景,我一般从yolov5s起步,验证集精度不够再往yolov5m升,避免一上来就上大模型导致训练慢、部署难。
这两处nc必须同步修改,数据 yaml 改了但模型 yaml 忘改,训练会报维度不匹配的错误,错误信息还不直观,需要仔细看 stack trace 才能发现是类别数问题。
3.2 训练命令参数逐项拆解:batch、epoch、imgsz 怎么设
训练命令是整套流程里最值得逐项说明的部分。YOLOv5 的train.py参数很多,但决定训练效果的其实就那么几个:
python train.py \ --data fire_data.yaml \ --cfg yolov5s.yaml \ --weights yolov5s.pt \ --batch-size 16 \ --epochs 100 \ --imgsz 640 \ --device 0 \ --name fire_run--weights yolov5s.pt是预训练权重,用 COCO 上训好的权重做初始化,能大幅缩短收敛时间。火灾检测的火焰和烟雾虽然在 COCO 类别里没有直接对应,但 COCO 预训练模型学到的底层特征——边缘、纹理、颜色分布——对火灾检测同样有效。不用预训练权重从零开始训,100 epoch 往往不够,模型很难收敛到可用水平。
--batch-size受显存限制,默认 16,显存不够就降到 8,但不要低于 4,否则 BN 层的统计量不稳定,训练震荡。--imgsz是输入分辨率,默认 640。火灾检测有个特殊点:火焰小目标多——远处的起火点可能只占整张图的 1%,640 分辨率下可能只有十几个像素。如果小目标漏检严重,可以把--imgsz提到 768 或 896,代价是训练时间和推理时间都显著增加。
--epochs一般从 100 起步。火灾数据集通常只有几千张图,100 epoch 足够模型收敛;如果发现验证集指标还在缓慢上升,可以加训。加训时最好在--weights里填上次训练的best.pt路径,用--resume而不是从头再跑。
3.3 训练收敛怎么看:loss 曲线三件套与验证指标
训练过程中控制台会实时打印 loss 和指标,同时runs/train/fire_run/目录下会生成results.png。很多人只看train_loss下降就觉得完事了,这是理解偏差。results.png里有三条曲线最重要——train/box_loss、train/cls_loss、train/obj_loss,外加验证集的val/box_loss和val/cls_loss。
判断收敛的标准不是 loss 降到了多低,而是「训练集和验证集的 loss 差距」。如果train/cls_loss降到 0.01 但val/cls_loss还在 0.1 以上,说明模型在过拟合训练集,对火灾场景的泛化能力不足。
验证集指标里重点看mAP@0.5和mAP@0.5:0.95。火灾检测我从来看mAP@0.5——对火灾报警场景,IOU 阈值 0.5 已经足够,不需要追求高精度定位。mAP@0.5:0.95是更严格的指标,在所有 IOU 阈值上求平均,对框的位置精度要求高,火灾检测的框稍微偏一点不影响报警决策,这个指标参考即可。
如果 100 个 epoch 结束时mAP@0.5还低于 0.5,不要急着调网络结构——先去看数据集。最常见的坑是训练集和验证集的场景分布不均衡,比如训练集里大量室内火焰、验证集里大量室外烟雾,模型学到的特征不能覆盖验证场景。这时候优先补数据,而不是调超参数。YOLOv5 的超参数调优(比如--hyp指向的进化算法)对数据充分的场景才有意义,数据本身有问题,调参只是玄学。
4. 把模型搬到真实场景:后处理调优、导出与树莓派部署
4.1 后处理的阈值怎么设:置信度、NMS 与误报抑制
训练完的模型输出的是原始预测——成千上万个候选框,每个框带置信度和类别概率。后处理的职责是从这些候选框里筛出真正要报警的目标。YOLOv5 的detect.py里有两个关键参数:--conf-thres和--iou-thres。
火灾检测的阈值设置和通用目标检测有明显区别。普通检测场景--conf-thres设 0.25 是常见做法,但火灾检测我会提高到 0.4 以上。原因是火灾场景的误报代价高——半夜误报一次,消防资源白跑一趟。置信度阈值设低,火焰的召回率是上去了,但晚霞、红色灯光、蒸汽都会被当成火,报警系统基本没法用。从 0.3 到 0.5 之间扫描验证集,选择一个「误报可接受 + 召回达标」的平衡点,这是做火灾检测后处理必做的一件事。
NMS 的--iou-thres控制的是重合框的合并力度,默认 0.45。火灾场景有个特殊性:烟雾目标的框往往很大且边缘不规则,同一个烟雾目标可能产生多个高置信度预测框,IOU 阈值设太高会导致一个烟雾目标报多个框,设太低又可能把一个大烟雾拦腰切掉。我用 0.5 作为起点,实际效果在验证集上确认。
置信度阈值到底怎么扫?我一般用一段小脚本遍历阈值,输出每个阈值下的精确率和召回率,而不是盲目瞎调。
import torch from pathlib import Path # 加载验证集预测结果,假设已经用 detect.py 跑过并保存了 txt 结果 results = load_validation_predictions("runs/detect/fire_run/labels") # 自定义加载函数 gt_labels = load_ground_truth("fire_dataset/labels/val") # 扫描置信度阈值 for conf in [0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6]: tp, fp, fn = evaluate_at_threshold(results, gt_labels, conf_thres=conf) precision = tp / (tp + fp + 1e-6) recall = tp / (tp + fn + 1e-6) print(f"conf={conf}, precision={precision:.3f}, recall={recall:.3f}")这段脚本的逻辑是:在验证集上逐一改变置信度阈值,分别计算精确率和召回率。火灾报警场景希望精确率和召回率都尽量高,但两者本质是矛盾的。如果 0.45 时精确率 0.85、召回率 0.82,而 0.55 时精确率 0.93、召回率 0.68,我宁可选 0.45——火灾漏报的后果比误报更严重,召回率不能牺牲太多。
4.2 导出 ONNX 并部署:在树莓派 5 上跑自己的火灾检测模型
训练完的权重是 PyTorch 格式,直接部署到边缘设备效率很低。常见做法是导出成 ONNX 格式,再用 ONNX Runtime 做推理。树莓派 5 这类 ARM 设备上,ONNX Runtime 比直接跑 PyTorch 快得多,且更容易做量化。
导出命令很简单,但有两个参数要盯紧:
python export.py \ --weights runs/train/fire_run/weights/best.pt \ --include onnx \ --imgsz 640 \ --opset 12--include onnx指定导出格式,--opset 12是 ONNX 算子集版本。树莓派 5 上跑 ONNX Runtime,opset 版本太高会导致部分算子不受支持,报错信息也不直观。我一般用 12 或 13,太低不行——YOLOv5 的一些新算子需要高版本才支持。
导出完成后,写一个精简的推理脚本。这里有个 YOLOv5 后处理不能省——ONNX 模型的输出是原始的检测头输出,要做解码、NMS、阈值过滤,直接用model(input)拿到的是张量而不是检测结果。
import onnxruntime as ort import cv2 import numpy as np # 创建推理会话,树莓派 5 上优先用 CPUExecutionProvider sess = ort.InferenceSession("best.onnx", providers=["CPUExecutionProvider"]) # 读取并预处理图片 img = cv2.imread("test_fire.jpg") img_resized = cv2.resize(img, (640, 640)) input_data = img_resized[:, :, ::-1].transpose(2, 0, 1) # BGR 转 RGB、HWC 转 CHW input_data = np.ascontiguousarray(input_data).astype(np.float32) / 255.0 input_data = np.expand_dims(input_data, axis=0) # 推理拿到原始输出张量 outputs = sess.run(None, {sess.get_inputs()[0].name: input_data})[0] # 此处需要补 YOLOv5 的 decode + NMS + conf_thres 过滤逻辑这段代码的正确逻辑是:图片读进来后先缩放再归一化,通道顺序从 BGR 换成 RGB,维度从 HWC 换成 CHW,最后扩展 batch 维度。sess.run的输出是形状如[1, 25200, 7]的张量,其中 25200 是三个检测头累加的锚框数量,7 是xc, yc, w, h, obj_conf, cls_conf, cls_id的排列。之后要做 sigmoid 解码、坐标缩放回原图尺寸、NMS 合并。这部分后处理逻辑 YOLOv5 源码里有现成的,但移植到 ONNX 推理时容易出错,我建议直接参考 YOLOv5 的models/yolo.py里 Detect 层的实现思路,逐行核对每个维度的含义。
树莓派 5 上实际跑,模型用yolov5s配置的话,640 分辨率下大概可以到 8~12 FPS,勉强够用,但不够流畅。想提速走量化——把 ONNX 模型用onnxruntime的 INT8 量化转一遍,精度会掉几个点,火焰检测对精度不是极度敏感(关注有效报警),量化后的速度提升明显。
5. 火灾检测避坑指南:数据、训练、部署的 6 条血泪经验
5.1 火焰小目标漏检严重:不是因为模型不行
现象:验证集 mAP 不低,但实际视频里远处的起火点完全不报警,甚至近处的小火苗也检测不到。
原因:YOLOv5 的主检测头下采样倍率是 8/16/32 三档,小目标主要靠 8 倍下采样的检测头负责。如果你直接用默认的 640 分辨率训练,远处火焰在 32 倍下采样层上只有几个像素,特征已经完全丢失。
解决:把--imgsz提升到 768 或 896,让模型在更大分辨率下看到目标。如果提升分辨率后提速跟不上,就改用yolov5s版本并在数据增强里增加马赛克增强的比例。火灾场景里宁愿牺牲一点速度也要保住小目标召回率——小火苗不报,等烧大了才报,这个系统就没有意义。
5.2 烟雾目标边界模糊导致框抖动
现象:同一个烟雾目标在不同帧里检测框忽大忽小,视频里看着像是模型在跳变,误报率倒不高,但报警框不稳定。
原因:烟雾是半透明弥散区域,边缘没有清晰轮廓,模型在相邻帧里学到的特征支点不同——前一帧用颜色特征,后一帧可能用纹理特征,导致框的位置浮动。
解决:在后处理里加帧间平滑。常见做法是维护一个目标框的滑动平均:当前帧的新框和前一帧的框做加权平均,权重给当前帧 0.7、历史帧 0.3,框的漂移就明显缓解。这个方法不会提升单帧精度,但视频监控场景下观感变化很大,也便于下游报警逻辑稳定。
5.3 夜晚场景模型集体翻车
现象:训练时白天场景测试精度不错,一到夜晚视频里灯的亮光、车灯、路灯被大面积误检为火焰。
原因:火焰在 RGB 颜色空间里集中在红色到黄色区间,夜间的暖色灯光在颜色分布上和火焰高度重合,模型很容易把「颜色像火」当成「是火」。
解决:训练数据必须加入夜晚负样本。在数据增强里把亮度、对比度、色彩饱和度的扰动幅度加大,模拟夜间环境。同时后处理时对检测到的目标做面积和位置过滤——固定位置的常亮光源(路灯、车灯)和火焰的显著区别是面积稳定且不扩散,用帧间变化率可以筛掉一大批误报。
5.4 训练中途进程被杀,几天的训练白费
现象:训练到第 80 个 epoch,进程被系统 OOM 杀掉或者手动 Ctrl+C,重新执行训练命令发现从头开始,之前的时间全部浪费。
原因:YOLOv5 默认情况下每次启动都是新的训练,runs/train/下生成新目录,不会自动从断点恢复。
解决:训练时加--resume参数,它会自动读取最近的last.pt权重和训练状态。
python train.py --resume runs/train/fire_run/weights/last.pt这个命令会恢复 optimizer 状态、epoch 计数和学习率调度器,几乎无缝衔接。训练中途手动中断后再续跑,是长训练任务的后悔药,不要等到丢进度了才想起来。
5.5 数据 yaml 改了但没生效
现象:修改了fire_data.yaml里的nc或者names,重新训练发现报错或者类别名还是旧的。
原因:YOLOv5 的train.py启动时会检查runs/train/下是否有同名的历史运行记录,如果--name相同,它会继续读取旧的缓存而不是新的配置。这是我见过最隐蔽的坑。
解决:改数据配置后换一个新的--name,或者手动删除同名目录。我习惯在每次改配置后把实验名加上日期后缀,既避免缓存冲突又方便对比实验。
python train.py --data fire_data_v2.yaml --name fire_run_v2_10125.6 树莓派部署后推理速度远低于预期
现象:在 PC 上导出 ONNX 后测试推理 30ms 每帧,部署到树莓派 5 上变成 300ms 每帧,速度掉了 10 倍。
原因:树莓派 5 的 CPU 是 ARM Cortex-A76,浮点计算能力和 x86 桌面 CPU 差距极大;另外 ONNX Runtime 默认线程数设置可能没有充分利用四核性能。
解决:推理会话创建时显式指定线程数,并开启内存优化。
sess_options = ort.SessionOptions() sess_options.intra_op_num_threads = 4 # 四核全开 sess_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL sess = ort.InferenceSession("best.onnx", sess_options, providers=["CPUExecutionProvider"])6. 让模型更可靠:难例挖掘与帧间融合的进阶用法
阈值调完、部署上线之后,模型还有一层提升空间。我常用的做法是难例挖掘——把验证集里所有误检和漏检的图片单独收集起来,人工标注后混合进训练集,重新训练一轮。这比增加随机数据的效率更高,因为模型正在被那些它学不会的样本卡住。
具体操作不难。跑一轮detect.py输出所有验证集的检测结果,把置信度低于阈值但实际有火焰的图片、置信度高于阈值但实际是背景的图片分别挑出来,前者补齐标注,后者整理成负样本。负样本在火灾检测里的价值被严重低估——夜晚路灯、红色霓虹灯、清晨的朝霞,这些「疑似火焰但不是火」的图像越多,模型越不容易误报。
另一个实用技巧是帧间融合检测。树莓派 5 上推理帧率不高的场景下,不需要每一帧都跑模型——每 3 帧检测一次,中间 2 帧沿用上一帧的目标框,同时用一个简单的跟踪逻辑判断目标是否移动。火焰的物理特征决定了它不会瞬间消失也不会瞬间位移,所以这种降频策略对报警准确率几乎没有影响,但能把设备的功耗和发热降下来。帧间融合的后处理逻辑还可以顺带解决第 5 章提到的框抖动问题:检测到目标后记录连续 N 帧的置信度,只有连续 N 帧都超过阈值才触发报警,这个简单的「多帧确认」机制能过滤掉大量单帧随机误报。
我自己在真实项目里的习惯是:模型训练到收敛后,先用一周的现场视频做影子测试——模型只做记录不参与实际报警,攒一批真实场景的误检和漏检,再回头补训练数据。两轮迭代之后,误报率能压到可接受的水平,这个过程是在实验室永远模拟不出来的。
这套基于 YOLOv5 的火灾检测流程,从环境配置、数据整理、训练调参到后处理部署,每一步都有明确的落地路径和坑位提示。你照着做一遍就能跑通最小系统,再结合自己的场景数据做迭代。希望帮到你。
本文还有配套的精品资源,点击获取