新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于YOLOV5的火灾火焰烟雾检测:从数据集到推理的完整实战指南

发布时间:2026/9/28 16:19:46来源:尧图网络
基于YOLOV5的火灾火焰烟雾检测:从数据集到推理的完整实战指南
简介这份资源面向计算机相关专业的本科毕业生及需要完成目标检测课题的开发者提供一套基于YOLOv5的火灾火焰与烟雾检测完整方案可用于毕业设计、课程项目或算法入门实践。压缩包共74个文件以yaml配置文件、Python源码、shell脚本为主辅以png与jpg示例图片及说明文档整体约718KB体积轻量便于快速部署与二次开发。内容涵盖标注好的数据集、训练好的模型权重、PyQt可视化界面以及完整源码并实现了基于TensorRT的推理加速流程涉及串口通信、OpenCV绘图、CUDA显存分配与执行上下文构建等关键环节同时提供CBAM、SE等注意力机制的改进配置与训练脚本方便对比实验与性能调优。目前已有118人学习下载适合希望掌握从数据标注、模型训练到界面集成与推理加速全流程的读者参考借鉴。1. 火灾火焰烟雾检测从数据集到 YOLOV5 推理一套能跑通的毕设方案长什么样每年到了毕设季问得最多的一类问题就是手头有一个标注好的火灾火焰烟雾检测数据集想用 YOLOV5 跑起来但环境装完就卡在训练脚本报错或者训完模型发现漏检严重。这个方向本身不复杂核心链路就四步环境配置、数据集组织、模型训练、推理部署。真正让人翻车的地方在于网上教程大多只给命令不给上下文数据集格式对不上、超参数照抄不适用、推理时置信度阈值一刀切结果就是「能跑但没用」。这篇内容面向正在做 Python 毕业设计、方向是火灾火焰烟雾检测的读者也适合想快速验证 YOLOV5 在自建数据集上效果的从业者。我会按一条完整落地路径来讲先讲清楚这个任务的技术边界和选型理由再给可直接复现的环境配置、数据集转换、训练命令和参数说明最后把常见报错和调参经验摊开。读完你应该能自己把数据集喂进去、把模型训出来、把推理跑通并且知道每一步为什么这么做。2. 环境配置与 YOLOV5 源码拉取把依赖装对就赢了一半2.1 为什么优先用 conda 而不是裸 pipYOLOV5 的依赖里最麻烦的是 PyTorch 和 torchvision 的版本匹配以及 OpenCV 在部分系统上的编译问题。裸 pip 装出来的环境经常出现 torch 和 torchvision 版本错位训练时直接报RuntimeError: expected scalar type Half but found Float或者 CUDA 算子找不到。用 conda 建独立环境能把 Python 版本、CUDA 运行时和 PyTorch 三者锁在一起出问题也好回滚。我一般会固定 Python 3.8 或 3.9这两个版本和 YOLOV5 各版本兼容性最好。CUDA 版本看显卡驱动30 系卡用 CUDA 11.3 以上20 系卡 CUDA 10.2 到 11.3 都能跑。下面这套命令是我在 Ubuntu 和 Windows WSL 下都验证过的# 创建独立环境Python 版本锁 3.8 conda create -n fire_yolo python3.8 -y conda activate fire_yolo # 安装 PyTorch这里以 CUDA 11.3 为例其他版本去官网查对应命令 pip install torch1.12.1cu113 torchvision0.13.1cu113 \ --extra-index-url https://download.pytorch.org/whl/cu113 # 拉取 YOLOV5 源码建议用 v7.0 分支稳定且文档全 git clone -b v7.0 https://github.com/ultralytics/yolov5.git cd yolov5 # 安装项目依赖 pip install -r requirements.txt装完之后必须做一次自检确认 CUDA 可用、torch 能调用显卡import torch print(torch.__version__) # 应输出 1.12.1cu113 print(torch.cuda.is_available()) # 应输出 True print(torch.cuda.get_device_name(0)) # 输出显卡型号如果cuda.is_available()返回 False先别急着改代码九成是 PyTorch 装成了 CPU 版。用pip list | grep torch看版本号后面有没有cu后缀没有就重装。另一个高频问题是 conda 环境里 pip 和 conda 混用导致包路径冲突解决办法是全程只用 pip 装 Python 包conda 只负责建环境和装 CUDA 工具链。2.2 源码目录里哪些文件必须认识YOLOV5 源码拉下来之后目录结构不算复杂但有几个文件在后续训练和推理里一定会改到提前认清楚能省很多时间文件/目录作用什么时候会改data/存放数据集配置 yaml 和超参数 yaml每次换数据集都要改models/网络结构定义yolov5s.yaml 等换模型规模时选不同文件train.py训练入口脚本调参时通过命令行传一般不直接改detect.py推理入口脚本推理时传参一般不直接改runs/训练和推理输出目录自动生成看日志和权重在这data/下面会放一个类似fire_smoke.yaml的数据集配置文件里面写训练集、验证集路径和类别名。models/下面yolov5s.yaml、yolov5m.yaml、yolov5l.yaml分别对应小、中、大三种规模火焰烟雾检测一般用 s 或 m 就够l 在数据量不足时反而容易过拟合。提示requirements.txt 里的包版本会随分支变化如果装完跑训练报某个包版本不兼容优先按报错信息单独降级那个包不要整体重装环境。3. 火灾火焰烟雾数据集组织格式转换与划分的四个关键动作3.1 数据集该长什么样YOLO 格式的硬性要求YOLOV5 只认一种标注格式每张图片对应一个同名 txt 文件txt 里每行是一个目标格式为类别索引 中心x 中心y 宽 高后四个值都是相对图片宽高的归一化数值范围 0 到 1。很多公开的火灾数据集给的是 VOC 的 xml 或者 COCO 的 json必须转成这个格式才能训。假设你的原始数据是 VOC 格式目录结构是Annotations/放 xmlJPEGImages/放图片转换脚本核心逻辑如下import os import xml.etree.ElementTree as ET from PIL import Image # 类别映射火焰和烟雾两类顺序要和训练配置一致 classes [fire, smoke] def convert_voc_to_yolo(xml_path, img_path, out_txt_path): tree ET.parse(xml_path) root tree.getroot() # 读图片真实宽高用于归一化 img Image.open(img_path) w, h img.size lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 转成中心点加宽高再归一化 cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines))这段脚本里有两个容易忽略的点一是归一化必须用图片真实宽高不能用 xml 里可能存在的size字段因为部分标注工具写进去的 size 和实际图片不一致二是坐标要保留 6 位小数精度不够会导致小目标框偏移。转换完之后每张图旁边应该有一个同名 txt没有目标的图可以留空 txt但不能没有。3.2 训练集验证集划分别用随机划分糊弄数据集划分看起来简单但火灾场景有个特殊性同一段视频抽出来的帧高度相似如果随机划分训练集和验证集里会出现几乎一样的图验证指标虚高实际部署就翻车。正确做法是按视频源或拍摄场景划分同一场景的图只进训练集或只进验证集。常见做法是 8:1:1 或 8:2 划分火焰烟雾检测数据量通常不大验证集至少留 10% 且要覆盖不同光照和距离。划分脚本可以这样写import os import random import shutil random.seed(42) # 固定种子保证可复现 img_dir images txt_dir labels out_dir dataset # 按文件名前缀分组同前缀视为同一场景 groups {} for name in os.listdir(img_dir): if not name.endswith((.jpg, .png)): continue prefix name.split(_)[0] groups.setdefault(prefix, []).append(name) group_list list(groups.values()) random.shuffle(group_list) # 按组划分8:2 split int(len(group_list) * 0.8) train_groups group_list[:split] val_groups group_list[split:] for subset, gs in [(train, train_groups), (val, val_groups)]: os.makedirs(f{out_dir}/images/{subset}, exist_okTrue) os.makedirs(f{out_dir}/labels/{subset}, exist_okTrue) for g in gs: for name in g: shutil.copy(f{img_dir}/{name}, f{out_dir}/images/{subset}/{name}) txt_name os.path.splitext(name)[0] .txt shutil.copy(f{txt_dir}/{txt_name}, f{out_dir}/labels/{subset}/{txt_name})按前缀分组是关键如果你的数据集文件名没有统一前缀就按视频编号或拍摄日期手动分。这一步多花十分钟验证指标的可信度能提升一大截。3.3 数据集配置文件怎么写划分完之后在data/下建一个fire_smoke.yaml内容如下# 训练集和验证集路径相对路径以 yolov5 根目录为基准 train: dataset/images/train val: dataset/images/val # 类别数 nc: 2 # 类别名顺序必须和标注时的类别索引一致 names: [fire, smoke]nc和names必须和标注文件里的类别索引严格对应如果标注时 fire 是 0、smoke 是 1这里就不能反。路径写错是新手最高频的报错来源训练一启动就报FileNotFoundError先检查这个 yaml 里的路径能不能在文件管理器里点进去。注意如果数据集里只有火焰没有烟雾nc改成 1names只留[fire]不要保留不存在的类别否则训练时该类别的损失会一直异常。4. YOLOV5 训练火焰烟雾模型超参数怎么设、日志怎么看4.1 启动训练的最小命令与参数含义环境、数据、配置都就绪后训练命令本身不复杂但每个参数都影响结果。下面这条是我在 8GB 显存上跑 yolov5s 的常用命令python train.py \ --data data/fire_smoke.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0 \ --workers 4 \ --project runs/train \ --name fire_smoke_v1逐项说明--data指向数据集配置--weights用官方预训练权重做迁移学习火焰烟雾数据量通常几千张从头训很难收敛用预训练权重是标配--img 640是输入分辨率火焰和烟雾目标通常占画面比例不小640 够用如果小目标多可以上 1280 但显存翻倍--batch 16在 8GB 显存下比较稳显存不够就降到 8--epochs 100是上限实际看验证指标早停--workers是数据加载线程数设成 CPU 核数的 1/4 到 1/2。训练启动后终端会打印每个 epoch 的 box_loss、obj_loss、cls_loss 和 mAP。重点看三个信号box_loss 持续下降说明框回归在学mAP0.5 在 30 个 epoch 后应该明显上升如果 cls_loss 不降反升多半是类别标注有错或者类别不平衡。4.2 超参数微调火灾场景最该动的三个值YOLOV5 的超参数在data/hyp.scratch.yaml里训练时可以通过--hyp指定自定义文件。火灾场景有三个值值得单独调第一个是lr0初始学习率默认 0.01。如果训练前 10 个 epoch loss 震荡剧烈降到 0.001如果 loss 几乎不动升到 0.02 试。火焰烟雾数据集通常不大学习率偏小更稳。第二个是mosaic马赛克增强概率默认 1.0。这个增强对小目标检测帮助很大但火灾场景里火焰和烟雾的形态和背景关联强过度马赛克会让模型学到不真实的组合。我一般降到 0.5保留一半样本用原始图训练。第三个是fl_gammafocal loss 的 gamma 值默认 0。如果数据里小目标烟雾多、大目标火焰少类别不平衡明显把fl_gamma设到 1.5 到 2.0能让模型更关注难样本。改完存成data/hyp_fire.yaml训练时加--hyp data/hyp_fire.yaml。# hyp_fire.yaml 关键片段 lr0: 0.005 # 初始学习率降低 lrf: 0.01 # 最终学习率余弦退火到 lr0*lrf mosaic: 0.5 # 马赛克增强减半 fl_gamma: 1.5 # 开启 focal loss4.3 训练日志里必须盯住的四个指标训练过程中runs/train/fire_smoke_v1/下会生成results.csv和若干曲线图。results.csv每行是一个 epoch列包括train/box_loss、metrics/mAP_0.5、metrics/mAP_0.5:0.95等。判断训练是否健康看四个点mAP0.5 在 50 个 epoch 内应该达到 0.7 以上火焰烟雾这种对比度高的目标正常数据质量下 0.85 以上不罕见。如果卡在 0.5 以下先查标注再查类别配置。验证集 loss 和训练集 loss 的差距。如果训练 loss 一直降但验证 loss 从某个 epoch 开始升就是过拟合减少 epoch 或加数据增强。metrics/precision和metrics/recall的平衡。火灾检测里漏检recall 低比误检precision 低后果更严重如果 recall 明显低于 precision把推理时的置信度阈值调低或者训练时提高正样本权重。最后看runs/train/fire_smoke_v1/weights/下的best.pt和last.ptbest.pt是验证指标最好的权重推理优先用它不要用last.pt。5. 推理部署与效果验证从单张图到视频流的落地细节5.1 用 detect.py 跑通单张图和视频训练完拿到best.pt推理命令如下# 单张图片推理 python detect.py \ --weights runs/train/fire_smoke_v1/weights/best.pt \ --source test_fire.jpg \ --img 640 \ --conf 0.25 \ --iou 0.45 \ --device 0 # 视频推理结果存到 runs/detect/exp python detect.py \ --weights runs/train/fire_smoke_v1/weights/best.pt \ --source fire_video.mp4 \ --conf 0.25 \ --iou 0.45--conf是置信度阈值低于这个值的框不输出。火灾场景建议从 0.25 起步漏检多就降到 0.15误检多就升到 0.4。--iou是 NMS 的 IoU 阈值火焰和烟雾经常重叠这个值设太高会把相邻目标合并0.45 是比较稳的默认值。推理结果默认存在runs/detect/exp下图片会画好框和类别。5.2 用 Python 脚本批量验证并统计指标detect.py适合看效果但要量化指标得自己写脚本调模型。下面这段用 YOLOV5 的 API 对验证集批量推理统计每类的检出数量import torch from pathlib import Path from PIL import Image # 加载模型指定设备 model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/fire_smoke_v1/weights/best.pt) model.conf 0.25 model.iou 0.45 val_dir Path(dataset/images/val) count {fire: 0, smoke: 0} for img_path in val_dir.glob(*.jpg): results model(Image.open(img_path)) # pandas 格式每行一个检测框 df results.pandas().xyxy[0] for _, row in df.iterrows(): count[row[name]] 1 print(count)这段脚本的价值在于快速看类别分布。如果验证集里火焰图占多数但检出全是 smoke说明类别映射或者标注有问题。批量推理还能帮你找出漏检的图单独拿出来看是标注漏了还是模型确实没学到。5.3 推理速度与部署形态的选择YOLOV5s 在 1080Ti 上单张 640 推理大约 10 到 15 毫秒换成 CPU 会到 200 毫秒以上。如果毕设要求实时视频流必须用 GPU如果只是离线检测图片CPU 也能接受。部署形态上常见三种直接跑detect.py最简单用 Flask 或 FastAPI 包一层 HTTP 接口适合做演示系统用 TensorRT 或 ONNX Runtime 加速适合对延迟敏感的场景。毕设演示用第二种就够把推理脚本包成接口前端传图返回框坐标和类别。提示导出 ONNX 用python export.py --weights best.pt --include onnx导出后可以用 Netron 看网络结构确认输入输出维度再集成到其他框架。6. 避坑与排查火焰烟雾检测里最容易翻车的五个地方6.1 训练 loss 正常但 mAP 一直是 0现象训练跑了几十个 epochbox_loss 在降但metrics/mAP_0.5始终是 0 或者极低。原因九成是标注文件的类别索引和 yaml 里的names顺序不一致或者标注坐标没有归一化。YOLOV5 在计算 mAP 时按类别匹配索引对不上就全部算错。解决随便挑一张训练图用labelImg或直接打开对应 txt确认第一列数字和fire_smoke.yaml里names的顺序一致。再检查坐标是否都在 0 到 1 之间有大于 1 的值说明没归一化。6.2 显存溢出报 CUDA out of memory现象训练启动几秒后报RuntimeError: CUDA out of memory。原因--batch或--img设太大或者--workers太多导致数据加载占用显存。解决先把--batch减半还不行就把--img从 640 降到 416。--workers设成 2 或 4不要设成 CPU 核数。如果显卡本身小于 6GB直接用 yolov5n 或 yolov5s别上 m 和 l。6.3 验证集指标虚高但实际推理漏检严重现象训练日志里 mAP0.5 有 0.9但拿新视频推理火焰漏检一半。原因数据集划分时同一场景的图同时进了训练集和验证集验证集本质上是训练集的近似复制。另外可能是验证集和实际场景的光照、距离差异大。解决按视频源或场景重新划分数据集确保验证集里的场景训练时没见过。如果实际场景和训练数据差异大补拍或找同场景数据加入训练集别指望模型泛化到完全没见过的环境。6.4 推理结果框重叠严重或同一目标多个框现象一张图里同一个火焰被画了三四个框。原因NMS 的--iou阈值设太高或者模型对同一目标输出了多个高置信度框。解决把--iou从默认 0.45 降到 0.3 到 0.4让 NMS 更激进地合并重叠框。如果还不行检查训练时hyp里的box损失权重适当提高能让框回归更准。6.5 训练到一半突然报 nan 损失现象前几十个 epoch 正常突然 loss 变成 nan训练崩溃。原因学习率太大导致梯度爆炸或者数据里有标注框宽高为 0 的脏数据。解决先把lr0降到 0.001 重跑。同时写个脚本扫一遍所有标注 txt把宽或高为 0 的行删掉。如果数据里有个别图标注框超出图片边界也要裁剪到边界内。7. 把模型推到能用的程度一个验证技巧和我的调参习惯训练跑通只是起点真正决定这套方案能不能用在毕设答辩或者实际场景里的是验证环节做得够不够细。我一般会在训练结束后做一件事把验证集里 mAP 最低的 20 张图单独拎出来逐张看推理结果和标注的差异。这个动作比看整体 mAP 有用得多因为整体指标会被大量简单样本拉高而漏检和误检往往集中在少数困难样本上。具体做法是改一下验证脚本让它输出每张图的指标而不是整体平均import torch from pathlib import Path from PIL import Image model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/fire_smoke_v1/weights/best.pt) model.conf 0.25 val_img_dir Path(dataset/images/val) val_lbl_dir Path(dataset/labels/val) def load_gt(label_path, w, h): boxes [] if not label_path.exists(): return boxes for line in label_path.read_text().strip().split(\n): if not line: continue cls, cx, cy, bw, bh map(float, line.split()) # 转成 xyxy 像素坐标 x1 (cx - bw / 2) * w y1 (cy - bh / 2) * h x2 (cx bw / 2) * w y2 (cy bh / 2) * h boxes.append((int(cls), x1, y1, x2, y2)) return boxes def iou(box1, box2): x1 max(box1[0], box2[0]) y1 max(box1[1], box2[1]) x2 min(box1[2], box2[2]) y2 min(box1[3], box2[3]) inter max(0, x2 - x1) * max(0, y2 - y1) area1 (box1[2] - box1[0]) * (box1[3] - box1[1]) area2 (box2[2] - box2[0]) * (box2[3] - box2[1]) return inter / (area1 area2 - inter 1e-6) results [] for img_path in val_img_dir.glob(*.jpg): img Image.open(img_path) w, h img.size pred model(img).xyxy[0].cpu().numpy() gt load_gt(val_lbl_dir / (img_path.stem .txt), w, h) # 统计匹配上的 gt 数量 matched 0 for g in gt: for p in pred: if iou(g[1:], p[:4]) 0.5: matched 1 break recall matched / len(gt) if gt else 1.0 results.append((img_path.name, recall, len(gt), len(pred))) # 按 recall 升序看最差的 20 张 results.sort(keylambda x: x[1]) for r in results[:20]: print(f{r[0]} recall{r[1]:.2f} gt{r[2]} pred{r[3]})这段脚本输出每张图的 recall按从低到高排序。recall 低且 gt 数量大于 0 的图就是漏检重灾区。打开这些图看如果是火焰太小考虑提高输入分辨率或者加小目标增强如果是烟雾和背景颜色接近考虑在训练集里补类似场景如果是标注本身漏了修标注重新训。调参这件事上我的习惯是一次只动一个参数改完记录在runs/train/下的opt.yaml里对比两次训练的results.csv。同时动多个参数最后涨了也不知道是哪个起的作用。另外火焰烟雾检测里 recall 比 precision 重要调参时优先保 recall误检可以通过后处理再过滤漏检没法补救。这套流程走下来从数据集到能演示的模型快的话两三天慢的话一周主要时间花在数据清洗和验证上训练本身反而很快。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

JDK 8/17双版本切换与IDEA、Maven配置实战指南 2026/9/29 1:12:01

JDK 8/17双版本切换与IDEA、Maven配置实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
ZED + YOLO 双目测距:从原理到落地链路实战 2026/9/29 1:12:01

ZED + YOLO 双目测距:从原理到落地链路实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
升压电路设计避坑指南:电感、二极管与PCB布局关键细节 2026/9/29 1:12:01

升压电路设计避坑指南:电感、二极管与PCB布局关键细节

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
OpenStack企业私有云部署与排障实战:从架构设计到运维 2026/9/29 1:12:01

OpenStack企业私有云部署与排障实战:从架构设计到运维

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
C++期末作业飞翔的小鸟:源代码与文档说明全解析 2026/9/29 1:12:01

C++期末作业飞翔的小鸟:源代码与文档说明全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
初级通信工程师备考:把一份模拟题做成体检仪,用错题清单定输赢 2026/9/29 1:11:49

初级通信工程师备考:把一份模拟题做成体检仪,用错题清单定输赢

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉