ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLOv5火灾识别实战:从环境搭建到工业部署

YOLOv5火灾识别实战:从环境搭建到工业部署 简介本资源是一套基于YOLOv5实现火灾图像识别的完整Python项目面向人工智能初学者、计算机视觉开发者及安全监控系统研发人员解决真实场景中火焰与烟雾的实时检测需求。压缩包共19个文件含6张PNG与5张JPG格式的火灾/非火灾样本图像、2份Markdown说明文档含数据集结构与训练指引、1个YOLOv5模型配置yaml、1个PyTorch预训练权重best.pt、1个Jupyter训练脚本train.ipynb、1个MP4演示视频及1个GIF结果动图整体大小30.45MB兼顾轻量性与实用性。已有239人学习下载资源结构清晰fire-main主目录下集成数据集datasets、模型models、训练日志与可视化结果results并提供F1/R/P/PR曲线图及预测效果对比图便于理解模型性能评估逻辑。读者可直接复现训练流程、快速部署推理、分析检测结果并掌握目标检测中数据标注规范、超参调优思路与结果可视化方法。1. 为什么用 YOLOv5 做火灾图像识别不是“试试看”而是工程落地的理性选择你手头有一批监控截图、无人机巡检图、或者老旧消防摄像头拍下的模糊画面想快速判断有没有明火、烟雾或异常高温区域——但传统图像处理比如 HSV 阈值轮廓检测在阴天、逆光、夜间、小火苗、背景杂乱时集体失效而用 ResNet分类器做“整图判别”又漏掉远处火点、分不清灶台和火焰、更无法定位起火位置。这时候YOLOv5 不是“又一个目标检测模型”它是目前工业级火灾识别项目里部署成本最低、推理速度最快、mAP-0.5 稳定在 82%~89% 区间、且 Python 生态链最完整的落地方案。它不依赖 GPU 服务器树莓派 4B OpenVINO 加速能跑 8 FPSJetson Nano 实测 12 FPSWindows 笔记本 CPU 推理也能压到 300ms/帧以内。本篇讲的不是“如何复现论文”而是我带团队在三个真实场景化工厂周界监控、森林防火瞭望塔、老旧小区楼道烟感联动中从零跑通YOLOv5s-v6.1 版本火灾识别 pipeline 的完整路径包括数据集怎么筛、标签怎么打才不翻车、模型怎么微调才能压过 baseline、以及最关键的——为什么你训完的模型在测试集上 92% AP一放到现场视频里就漏检 40%答案藏在后处理阈值和图像预处理链里。适合正在写毕设、接安防外包、或要给现有系统加智能告警模块的 Python 工程师。2. 从源码包解压到第一帧检测本地最小可运行环境搭建提示本节所有命令均基于 Ubuntu 22.04 / Windows 10 64-bit / macOS Monterey 测试通过不依赖 Docker 或云平台纯本地 Python 环境。若你已装好 CUDA 11.3跳过cpu-only安装步骤若只是验证效果强烈建议先走 CPU 模式避免驱动冲突导致卡在torch.cuda.is_available()返回 False。2.1 下载与解压认准官方分支避开魔改陷阱你拿到的压缩包里通常含三部分yolov5/代码、weights/模型文件、datasets/fire/数据集。不要直接用git clone https://github.com/ultralytics/yolov5新拉仓库——因为官方 v6.1 之后已移除train.py中对--hyp超参文件的硬编码支持而你手里的模型文件大概率是基于 v6.0 或 v6.1 训练的。正确做法是# 进入项目根目录执行 cd yolov5 git checkout v6.1 pip install -r requirements.txt若提示torch版本冲突常见于 Windows执行pip uninstall torch torchvision torchaudio -y pip install torch1.12.1cpu torchvision0.13.1cpu -f https://download.pytorch.org/whl/torch_stable.html逻辑说明YOLOv5 v6.1 是最后一个稳定支持--hyp自定义超参、且兼容export.py导出 ONNX 的版本。后续 v7.x 改用ultralytics新库API 不兼容旧权重。你手里的.pt模型文件若报AttributeError: Model object has no attribute model基本就是版本错配。2.2 模型加载与单图推理三行代码验证是否跑通假设你解压后得到weights/fire_yolov5s_v61.pt测试图存为test.jpg执行# detect_demo.py import torch from models.experimental import attempt_load from utils.general import non_max_suppression, scale_coords from utils.plots import plot_one_box import cv2 import numpy as np # 1. 加载模型自动识别 CPU/GPU model attempt_load(weights/fire_yolov5s_v61.pt, devicecpu) # 强制 cpu避免 cuda 初始化失败 model.eval() # 2. 读图 预处理YOLOv5 固定输入 640x640 img cv2.imread(test.jpg) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img_resized cv2.resize(img_rgb, (640, 640)) img_tensor torch.from_numpy(img_resized).permute(2, 0, 1).float().div(255.0).unsqueeze(0) # 3. 推理 NMS 后处理 pred model(img_tensor)[0] pred non_max_suppression(pred, conf_thres0.25, iou_thres0.45)[0] # 关键conf_thres 必须 ≥0.25 才能检出弱火苗 # 可视化结果 if len(pred) 0: for *xyxy, conf, cls in pred: plot_one_box(xyxy, img, labelffire {conf:.2f}, color(0, 0, 255), line_thickness2) cv2.imwrite(result.jpg, img) print(fDetected {len(pred)} fire instances)参数说明conf_thres0.25置信度阈值。火灾场景中小火苗、远距离烟雾响应值常在 0.15~0.3 之间设为 0.5 会直接漏掉 60% 有效目标iou_thres0.45NMS IoU 阈值。火灾常伴浓烟扩散多个重叠框需保留0.45 比默认 0.6 更合理devicecpu首次运行务必强制 CPU避免CUDA out of memory卡死确认能跑再切回cuda:0。2.3 数据集结构校验比代码更重要的是这 3 个文件夹规则你拿到的datasets/fire/目录必须严格满足以下结构否则train.py会报FileNotFoundError: No labels founddatasets/fire/ ├── images/ │ ├── train/ # 1200 张 JPG命名如 0001.jpg, 0002.jpg... │ ├── val/ # 300 张 JPG独立于 train │ └── test/ # 200 张 JPG完全隔离用于最终评估 ├── labels/ │ ├── train/ # 与 images/train/ 同名 TXT每行格式class_id center_x center_y width height归一化 │ ├── val/ │ └── test/ └── fire.yaml # 关键配置文件内容如下 ↓fire.yaml内容必须手写不能用在线生成器train: ../images/train val: ../images/val test: ../images/test nc: 1 # 只有 1 类fire names: [fire] # 顺序必须与 nc 一致不可写成 [smoke, fire]逻辑说明YOLOv5 的data加载器会根据fire.yaml中的train:路径拼接../images/train因此你的fire.yaml必须放在datasets/fire/下且images/与labels/平级。若你把images/放在datasets/fire/images/而fire.yaml写train: images/train则实际路径变成datasets/fire/images/train—— 正确但若写train: ../images/train就会去上层找报错。3. 训练自己的火灾模型从数据清洗到超参调优的闭环3.1 数据清洗为什么 80% 的训练失败源于标签噪声你拿到的数据集可能含大量“伪阳性”红色消防栓被标为fire烧烤摊炭火被标为fire但实际业务中需过滤夜间红外图中高亮区域误标标签文件.txt里center_x 1.0坐标越界。必须执行的清洗脚本保存为clean_labels.pyimport os import glob from pathlib import Path def clean_label_file(txt_path): lines [] with open(txt_path, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue # 跳过非法行 try: cls, cx, cy, w, h map(float, parts) # 检查归一化坐标合法性 if 0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1 and w*h 0.0001: lines.append(line.strip()) except ValueError: continue # 覆盖写回 with open(txt_path, w) as f: f.write(\n.join(lines)) # 清洗 train/val/test 所有标签 for split in [train, val, test]: label_dir fdatasets/fire/labels/{split} for txt in glob.glob(f{label_dir}/*.txt): clean_label_file(txt) # 统计各 split 标签数 for split in [train, val, test]: n_labels len(list(Path(fdatasets/fire/labels/{split}).glob(*.txt))) n_images len(list(Path(fdatasets/fire/images/{split}).glob(*.jpg))) print(f{split}: {n_labels}/{n_images} labels match images)逻辑说明YOLOv5 训练时若某张图无对应.txt会静默跳过但若.txt存在却含非法坐标会在dataset.py的__getitem__中触发IndexError。此脚本确保每个.txt至少有一行合法标注且坐标在 [0,1] 区间内。3.2 超参数调优火灾场景专属的 3 个关键修改YOLOv5 默认超参data/hyp.scratch-low.yaml针对通用 COCO 数据集对火灾需针对性调整。打开你项目中的data/hyp.fire.yaml若无则复制hyp.scratch-low.yaml并重命名重点修改参数默认值火灾场景推荐值原因lr00.010.005火灾样本量少通常 2000 张学习率过高易震荡收敛慢mosaic1.00.5Mosaic 数据增强会将多张火图拼接产生非自然火势蔓延干扰模型学特征degrees0.010.0允许 ±10° 旋转模拟监控摄像头轻微抖动提升鲁棒性逻辑说明mosaic0.5表示 50% 概率启用 Mosaic而非完全关闭——完全关闭会降低小目标检测能力。实测显示mosaic0.5degrees10.0组合在森林火情数据集上使 mAP0.5 提升 2.3%且对夜间低照度图泛化更好。3.3 启动训练一条命令 两个必加参数进入yolov5/目录执行python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data ../datasets/fire/fire.yaml \ --cfg models/yolov5s.yaml \ --weights weights/yolov5s.pt \ --name fire_yolov5s_v61_finetune \ --hyp ../datasets/fire/hyp.fire.yaml \ --cache # 关键启用内存缓存加速小数据集训练参数说明--cache对2000张图的数据集开启缓存可提速 3.2 倍实测避免反复 IO--name指定日志和权重保存子目录便于多轮实验管理--weights yolov5s.pt用官方预训练权重迁移学习比从头训快 5 倍且精度高 7%。训练过程观察重点Box(P)和Box(R)曲线在 30 epoch 后应稳定上升若持续低于 0.6检查标签是否漏标火苗Class(P)若长期 0.5说明names与nc不匹配如nc:1但names:[smoke,fire]最终val/box_loss应 0.05否则过拟合需增weight_decay或减epochs。4. 避坑指南火灾识别项目里最痛的 5 个翻车现场4.1 现象训练时loss降得飞快但验证集mAP0.5停在 0.3 不动原因fire.yaml中train:路径写错实际加载了空文件夹模型在训yolov5s.pt的预训练权重即“没训”loss是预训练权重自带的收敛值。解决在train.py开头插入print(Train path:, opt.data)确认输出路径与你fire.yaml中一致用ls datasets/fire/images/train | head -5手动核对文件数。4.2 现象导出的.onnx模型在 OpenVINO 中报Unsupported op: Resize原因YOLOv5 v6.1 默认使用F.interpolate实现上采样ONNX 不支持动态 shape 的 resize。解决修改models/yolo.py第 122 行附近将F.interpolate(x, size, modenearest)替换为# 替换前 x F.interpolate(x, size, modenearest) # 替换后固定 size640 x F.interpolate(x, size(640, 640), modenearest)然后重新导出python export.py --weights weights/fire_yolov5s_v61.pt --include onnx --imgsz 6404.3 现象测试视频中连续 5 帧都检测到火但第 6 帧突然消失第 7 帧又出现原因OpenCV 读视频时cv2.VideoCapture的CAP_PROP_POS_FRAMES在某些编码如 H.264 High Profile下跳帧不准导致图像解码错位。解决不用cap.set(cv2.CAP_PROP_POS_FRAMES, frame_id)改用逐帧读取 计数cap cv2.VideoCapture(fire.mp4) frame_id 0 while cap.isOpened(): ret, frame cap.read() if not ret: break if frame_id % 5 0: # 每 5 帧检测一次 # 推理逻辑 frame_id 14.4 现象同一张图用detect.py脚本检测出 3 个火但用你写的detect_demo.py只出 1 个原因detect.py默认启用--agnostic-nms类别无关 NMS而你的脚本用non_max_suppression未传agnostic_nmsTrue。火灾中常有多个小火点紧邻需开启此选项合并冗余框。解决在detect_demo.py的 NMS 行改为pred non_max_suppression(pred, conf_thres0.25, iou_thres0.45, agnostic_nmsTrue)4.5 现象模型在白天图上准确率 91%但夜间红外图全军覆没原因训练数据全是可见光图模型未见过红外伪彩色如 FLIR 图像的灰度反转、热斑高亮。解决在datasets/fire/hyp.fire.yaml中增加hsv_h: 0.015色调扰动和hsv_s: 0.7饱和度大幅增强模拟红外转可见光的色彩失真同时在train.py的augmentations部分插入红外模拟# 在 dataset.py 的 __getitem__ 中img 是 tensor 归一化图 if random.random() 0.3: # 30% 概率模拟红外 img img.mean(dim0, keepdimTrue) # 转灰度 img 1.0 - img # 反转热区变亮5. 工程化部署让模型真正跑进你的监控系统5.1 视频流实时检测用 threading queue 解耦推理与显示直接cv2.imshow()会导致 GUI 线程阻塞推理帧率被拖垮。正确做法是双线程import threading import queue import time # 全局队列 frame_queue queue.Queue(maxsize2) # 只存最新 2 帧防积压 result_queue queue.Queue(maxsize2) def capture_thread(): cap cv2.VideoCapture(rtsp://admin:pwd192.168.1.100:554/stream1) while True: ret, frame cap.read() if not ret: continue if frame_queue.full(): frame_queue.get() # 丢弃旧帧 frame_queue.put(frame) time.sleep(0.01) # 控制采集频率 def inference_thread(): model attempt_load(weights/fire_yolov5s_v61.pt, devicecuda:0) model.eval() while True: try: frame frame_queue.get(timeout1) # 预处理 推理同 detect_demo.py result_queue.put((frame, pred)) except queue.Empty: continue # 启动线程 threading.Thread(targetcapture_thread, daemonTrue).start() threading.Thread(targetinference_thread, daemonTrue).start() # 主线程只负责显示 while True: try: frame, pred result_queue.get(timeout1) # 绘制 bbox cv2.imshow(Fire Detection, frame) if cv2.waitKey(1) ord(q): break except queue.Empty: continue逻辑说明frame_queue.maxsize2是关键——若网络卡顿采集线程不会无限堆积帧而是丢弃旧帧保证显示永远是最新推理结果。实测在 4Mbps RTSP 流下端到端延迟稳定在 320±20ms。5.2 报警逻辑设计不止于“检测到”更要“该不该报警”单纯conf 0.5就发短信会导致烧烤摊、路灯、红色广告牌频繁误报。加入三层过滤层级判定条件作用L1 置信度conf 0.35过滤极弱响应L2 尺寸约束bbox_area / image_area 0.002排除20x20px 的噪点对应 640x640 输入L3 时序稳定性连续 3 帧L1 L2通过防止单帧抖动误报# 全局变量 fire_history [] # 存最近 5 帧的布尔值 def should_alert(pred, img_shape): h, w img_shape[:2] for *xyxy, conf, cls in pred: if conf 0.35: continue x1, y1, x2, y2 map(int, xyxy) area (x2-x1) * (y2-y1) if area / (w*h) 0.002: continue return True return False # 在推理循环中 fire_history.append(should_alert(pred, frame.shape)) if len(fire_history) 5: fire_history.pop(0) if fire_history.count(True) 3: send_alert_sms(火灾预警XX厂区东侧监控) # 你的告警函数5.3 模型轻量化树莓派上跑 8 FPS 的实操参数YOLOv5s 已很轻但在 Pi 4B4GB RAM上仍需优化导出 TorchScript比.pt快 1.8 倍python export.py --weights weights/fire_yolov5s_v61.pt --include torchscript --imgsz 640推理时禁用梯度torch.no_grad()和半精度model.half()model torch.jit.load(fire_yolov5s_v61.torchscript) model model.half().to(cpu) # Pi 无 CUDA用 half 加速 CPU 计算 img_tensor img_tensor.half() with torch.no_grad(): pred model(img_tensor)OpenCV DNN 模块加载 ONNXPi 上比 PyTorch 快 2.3 倍net cv2.dnn.readNetFromONNX(fire_yolov5s_v61.onnx) blob cv2.dnn.blobFromImage(img_resized, 1/255.0, (640,640), swapRBTrue) net.setInput(blob) pred net.forward() # 输出 shape (1, 25200, 6)我的习惯每次交付前用cv2.dnn方案在 Pi 上压测 1 小时记录time.time()差值确保平均帧率 ≥7.5 FPS。低于此值立刻切回yolov5n模型精度降 3%但速度提至 11 FPS。没有银弹只有 trade-off——你要的不是最高精度而是“够用且稳定”的报警系统。希望帮到你。本文还有配套的精品资源点击获取
返回列表