ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

YOLOv5火灾图像识别实战:从数据集训练到边缘部署全流程

2026/10/5 5:44:32 拓冰建站 浏览量
YOLOv5火灾图像识别实战:从数据集训练到边缘部署全流程 简介这份资源面向具备一定Python基础、希望入门目标检测与火灾识别方向的开发者与学习者提供从数据准备、模型训练到推理应用的完整实践素材。包内共19个文件以png、jpg图像与md说明文档为主另含yaml配置文件、pt权重文件、ipynb训练笔记、mp4与gif演示素材及license压缩包约30.45MB覆盖训练脚本、预训练模型、数据加载与结果可视化等环节。数据集包含火灾与非火灾两类图像及标注信息可用于模型训练与验证。已有239人学习下载读者可据此掌握yolov5的网格预测与边界框回归思路理解数据集多样性、代表性对模型性能的影响并借助曲线图与预测结果图分析训练效果完成从环境配置到新图像火灾判定的全流程实践适合作为课程设计或入门项目的参考。1. 火灾图像识别为什么值得用 YOLOv5 从头跑一遍火灾图像识别这件事真正动手做过的人都知道难点从来不在「有没有模型」而在「模型能不能在你自己的场景里稳定出框」。烟雾刚起时目标边界模糊、火焰在白天强光下和晚霞高度相似、监控画面里火点可能只占几十个像素——这些都不是拿一个现成权重就能糊弄过去的。YOLOv5 之所以在火灾检测这个方向被反复使用是因为它把「训练自己的数据集」这条路径压得足够短标注、改配置、跑 train.py、导出权重、写推理脚本一个 Python 环境就能闭环。这套「源代码 模型文件 数据集」的组合本质上是给你一个能立刻跑起来、又能按自己场景重训的基线而不是一个只能看 demo 的黑匣子。适合谁适合手上有监控截图或视频、想验证火灾识别可行性、又不打算从论文公式啃起的工程师和在校做项目的同学。下面我按自己复现时的顺序把这条链路拆开讲清楚。2. 环境与数据把 YOLOv5 火灾数据集跑通前要定的事2.1 为什么优先选 YOLOv5 而不是别的检测框架在火灾图像识别这个具体任务上选型其实没那么多玄学。YOLOv5 的工程成熟度是它最大的优势数据加载、增强、训练、验证、导出 ONNX 全在一个仓库里配置文件是 YAML改类别数就是改一行。相比之下两阶段检测器在小目标火焰上精度未必差但推理速度和部署复杂度对边缘设备不友好而更新的版本虽然结构上有改进但社区里针对火灾数据集的现成配置和踩坑记录远不如 v5 密集。我一般会这样判断如果你的目标是「两周内出一个能演示、能继续迭代的火灾识别基线」YOLOv5 是性价比最高的起点如果你要发论文比 SOTA那另说。这里要强调的是火灾识别属于典型的单类或少类检测nc 通常设为 1fire或 2fire、smoke类别少意味着模型容量不用太大yolov5s 往往就够盲目上 yolov5x 只会让训练变慢、过拟合风险上升。2.2 数据集目录结构与标注格式的硬性要求拿到数据集后第一件事不是急着训练而是确认它的组织方式符合 YOLOv5 的约定。YOLOv5 不直接读 VOC 的 XML也不读 COCO 的 json它要的是每张图对应一个同名 txt每行是class x_center y_center width height且坐标全部归一化到 0~1。目录上推荐这样放fire_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── fire_data.yamlfire_data.yaml是数据集描述文件内容大致如下# 数据集根路径建议写绝对路径避免相对路径踩坑 path: /home/user/fire_dataset train: images/train val: images/val # 类别数火灾检测通常 1 或 2 nc: 2 names: [fire, smoke]这里有个血泪经验path用相对路径时训练脚本的工作目录一变就找不到图报错还特别隐晦直接写绝对路径最省心。另外 images 和 labels 下的文件名必须严格对应abc.jpg对应abc.txt少一个就会在训练时被当成背景图悄悄拉低召回。2.3 用脚本检查标注并统计类别分布在正式训练前我习惯先跑一段脚本把标注框画回图上、统计每类数量确认没有越界坐标和空标签。这一步能省掉后面几小时的无效训练。import os import cv2 # 数据集路径按自己实际情况改 img_dir fire_dataset/images/train lbl_dir fire_dataset/labels/train names [fire, smoke] counts {i: 0 for i in range(len(names))} for name in os.listdir(img_dir): if not name.lower().endswith((.jpg, .png, .jpeg)): continue img_path os.path.join(img_dir, name) lbl_path os.path.join(lbl_dir, os.path.splitext(name)[0] .txt) img cv2.imread(img_path) h, w img.shape[:2] if not os.path.exists(lbl_path): print(缺标签:, name) continue with open(lbl_path) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(格式异常:, name, line) continue c, x, y, bw, bh int(parts[0]), *map(float, parts[1:]) counts[c] 1 # 还原到像素坐标并画框肉眼确认 x1 int((x - bw / 2) * w) y1 int((y - bh / 2) * h) x2 int((x bw / 2) * w) y2 int((y bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(check_ name, img) print(类别统计:, {names[k]: v for k, v in counts.items()})这段脚本做了三件事检查标签文件是否存在、校验每行是否为 5 个字段、把归一化坐标还原成像素框画出来。参数上names要和 yaml 里的顺序完全一致否则统计会错位。跑完看check_开头的图如果框明显偏移或大小离谱多半是标注时用了未归一化的坐标需要重新转换。类别统计如果某一类只有几十个框那训练时就要考虑过采样或加增强不然模型会偏向多数类。3. 训练与调参让火灾识别模型真正收敛的关键动作3.1 从预训练权重起步的最小训练命令环境装好后Python 3.8 以上、PyTorch、以及pip install -r requirements.txt最省事的做法是拿官方预训练权重做迁移学习。火灾数据集通常不大从零训练几乎必然过拟合用--weights yolov5s.pt起步能明显加快收敛。# 单卡训练batch 根据显存调显存小就降到 8 或 4 python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data fire_dataset/fire_data.yaml \ --weights yolov5s.pt \ --cfg models/yolov5s.yaml \ --name fire_exp1 \ --cache逐项说下参数--img 640是输入分辨率火灾小目标多的话可以提到 960但显存和速度要权衡--batch 16是常见起点显存不够就往下调别硬撑导致 OOM--epochs 100对几百到几千张图的数据集通常够看验证集 mAP 不再涨就可以早停--cache把图片缓存进内存小数据集能显著提速但数据集大且内存小时别加。训练日志里重点盯三个指标box_loss是否稳定下降、mAP0.5是否在涨、val/obj_loss有没有反弹。如果 loss 震荡剧烈先把学习率降一档或把 batch 调小。3.2 火灾场景下最该调的三个超参数YOLOv5 的超参数在data/hyp.scratch.yaml里火灾识别有几个参数值得单独动。第一是mosaic默认 1.0它把四张图拼一起增强小目标对火焰这种尺度变化大的目标很有用但如果你的数据集里火焰都很大很集中可以降到 0.5 避免引入过多噪声。第二是hsv_v亮度扰动火灾在夜间和白天差异极大适当调高到 0.5 左右能提升光照鲁棒性。第三是fl_gammafocal loss 的 gamma当背景非火区域远多于火点时设成 1.5 左右能缓解正负样本失衡。改完在训练命令里加--hyp data/hyp.fire.yaml指向你的自定义文件即可。这里没有万能值我的习惯是先按默认跑一轮看混淆矩阵里误检主要来自哪类背景再针对性调。3.3 训练过程怎么判断有没有翻车训练不是跑完就完事中途要看懂输出。YOLOv5 每个 epoch 会打印类别损失、框损失、目标损失和 mAP。常见翻车信号有三个一是mAP0.5一直卡在 0.1 以下多半是标签格式错了或类别数对不上二是val/box_loss持续上升而train/box_loss下降典型过拟合该加数据或加增强三是所有预测框都堆在图像中心说明锚框和你的目标尺度不匹配需要用python utils/autanchor.py重新聚类锚框。另外runs/train/fire_exp1/下会生成results.png和confusion_matrix.png前者看曲线趋势后者看哪类容易被误判成背景这两个图比数字更直观。4. 推理与部署把训练好的火灾模型用起来4.1 用 detect.py 快速验证模型效果训练完权重在runs/train/fire_exp1/weights/best.pt先用官方推理脚本确认效果别急着写自己的服务。# 对单张图或整个目录推理--conf 控制置信度阈值 python detect.py \ --weights runs/train/fire_exp1/weights/best.pt \ --source test_images/ \ --img 640 \ --conf 0.4 \ --save-txt--conf 0.4是火灾场景我常用的起点太低会满屏误检太高会漏掉初期小火点实际要按你的误报容忍度调。--save-txt会把检测框坐标存下来方便后续做报警逻辑。推理结果默认在runs/detect/exp/先肉眼过一遍重点看有没有把灯光、夕阳误判成火。4.2 写一个可复用的火灾检测函数实际项目里不会每次敲命令行通常封装成一个函数供服务调用。下面这段用 PyTorch Hub 加载本地权重返回框和类别。import torch # 加载本地训练好的权重避免联网下载 model torch.hub.load(./yolov5, custom, pathruns/train/fire_exp1/weights/best.pt, sourcelocal) model.conf 0.4 # 置信度阈值 model.iou 0.45 # NMS 的 IoU 阈值 def detect_fire(img_path): results model(img_path) # pandas 格式每行 xmin ymin xmax ymax confidence class name df results.pandas().xyxy[0] fires df[df[name].isin([fire, smoke])] return fires[[xmin, ymin, xmax, ymax, confidence, name]].to_dict(records) if __name__ __main__: print(detect_fire(test_images/fire_01.jpg))sourcelocal很关键它让 torch.hub 用本地仓库而不是去拉网络。model.conf和model.iou是实例级参数改了立即生效。返回的 DataFrame 里name列就是类别名直接按名字过滤即可。如果要做视频流把img_path换成帧数组也能跑但要注意每帧都调用会有开销实时场景建议批量或跳帧。4.3 导出 ONNX 给边缘设备用如果最终要部署到树莓派或带 NPU 的板子上PyTorch 权重不是终点通常要转 ONNX 再量化。# 导出 ONNXopset 12 兼容性较好 python export.py \ --weights runs/train/fire_exp1/weights/best.pt \ --include onnx \ --img 640 \ --opset 12导出后得到一个.onnx文件可以用 onnxruntime 验证输出是否和 PyTorch 一致。参数上--opset 12是稳妥选择太低不支持某些算子太高部分推理引擎不认。--img要和训练时一致否则输入尺寸对不上。这一步的坑在于动态轴设置如果部署端需要变尺寸输入导出时要加--dynamic但有些 NPU 工具链对动态轴支持差固定尺寸反而更省事。5. 避坑与排查火灾识别项目里最容易栽的五个地方5.1 训练 loss 正常但 mAP 始终为 0现象训练日志里 box_loss 在降但 mAP0.5 一直是 0 或接近 0。原因九成是标签路径或格式问题——labels 目录名写成了 label、txt 里坐标没归一化、或者类别索引从 1 开始YOLOv5 要求从 0 开始。解决用第 2.3 节的脚本重新检查重点确认坐标是否都在 0~1 之间类别号是否从 0 起。改完清空runs/重训。5.2 模型把夕阳和暖色灯光误判成火现象推理时大量非火区域被框出置信度还不低。原因训练集里缺乏这类负样本模型没学会区分「暖色」和「火焰纹理」。解决收集误检图作为背景样本加入训练集标签文件留空即可同时把hsv_v和hsv_h扰动调大让模型对颜色不那么敏感。这一步比调阈值有效得多。5.3 显存不够导致训练中断现象跑几个 batch 后报 CUDA out of memory。原因--img或--batch设太大或者--cache把大图全塞进内存。解决优先降 batch再考虑降 img--cache换成--cache ram或直接去掉。如果还不行用--device 0明确指定单卡避免多卡默认分配。5.4 推理速度在边缘设备上慢到不可用现象PC 上跑得好好的部署到树莓派上每帧要好几秒。原因PyTorch 权重没转 ONNX或者转了但没量化CPU 推理开销大。解决先导 ONNX再用 onnxruntime 的量化工具做 INT8 量化输入尺寸从 640 降到 416 也能提速代价是小目标召回下降要按场景权衡。5.5 换了自己的数据集后类别名对不上现象推理结果里类别名显示成class0、class1而不是fire。原因fire_data.yaml里的names和训练时不一致或者推理时加载的权重对应的类别数和你现在 yaml 不符。解决确保训练和推理用的是同一份 yaml类别顺序不能变。如果只是显示问题可以在推理函数里手动映射但根本办法是统一配置。6. 把火灾识别做扎实的一个进阶习惯模型能跑通只是起点真正决定这个方案值不值得投入的是你能不能持续用数据把它喂强。我自己的习惯是给推理服务加一个「可疑样本回捞」机制把置信度在 0.2 到 0.4 之间的检测结果单独存下来定期人工过一遍确认是误检就丢进负样本集确认是漏检就补标注。这个区间是模型最犹豫的地方也是提升最快的来源。配合这个机制每积累一两百张新样本就重训一次用--weights接着上次的 best.pt 继续训比从零开始收敛快得多。验证模型有没有真的变好别只看 mAP 一个数。我一般会固定一个包含白天、夜间、强光、烟雾的测试集每次重训后都跑一遍记录每类的召回和误报数做成一张简单的表场景样本数召回率误报数白天明火500.942夜间火光500.885初期烟雾500.763这张表比任何单一指标都能说明问题——如果夜间误报一直高就针对性补夜间负样本如果烟雾召回上不去就检查标注时烟雾边界是不是画得太紧。这套流程跑下来你会发现火灾识别这个方向的投入产出比其实很高因为数据闭环一旦建立模型是越用越准的。希望帮到你。本文还有配套的精品资源点击获取