火灾烟雾检测数据集2059张+YOLOv5标签转换与训练避坑指南

发布时间:2026/10/10 15:30:51
火灾烟雾检测数据集2059张+YOLOv5标签转换与训练避坑指南 简介这套火灾烟火烟雾检测数据集面向目标检测、安防监控与火灾预警方向的开发者提供2059张覆盖大火小火、建筑/草原/森林/车辆起火、白天/黑夜、室内/室外等多样场景的带标签图像按Pascal VOC格式组织Annotations中为XML标注JPEGImages为原始图像ImageSets包含训练验证划分。随包附带基于YOLOv5的火灾烟雾检测模型、使用说明以及voc_label.py等格式转换脚本可快速完成VOC转YOLO并开展微调与部署验证。资源共332个文件整体约200MB除了JPEG图像与XML标注外还包含77个o目标文件、70个c源文件、61个h头文件、31个py脚本、16个yaml配置、11个cu文件以及pt、weights、cfg等模型相关文件覆盖darknet框架的编译、训练、推理与转换全流程。目前已有839人学习下载是火灾检测项目可直接使用的数据与基线模型方案适合需要系统训练和快速实验的工程师与学生。1. 火灾烟火烟雾检测数据集2059张图像标签能帮你绕开哪些坑火灾烟雾检测最头疼的不是模型结构而是数据。监控摄像头要想识别远处若有若无的烟和刚起势的火苗需要几千张带标签的现场图光靠人工标注很容易标到崩溃。这套“火灾烟火烟雾检测数据集2059张图像含标签yolov5烟雾火灾检测模型使用说明”给的就是一条完整落地路径2059张已标注图像、一个能直接用的YOLOv5烟雾火灾检测模型和说明文档。它适合做消防告警、安防监控和森林防火的开发者你既可以用它训练出自己的模型也能借它理解自己的数据该怎么整理。下文按处理这类项目的经验展开讲数据怎么拆、标签怎么转、模型怎么训、现场哪些地方最容易翻车。新手能照着走熟手直接看参数边界。2. 拆解2059张标注图像目录结构、标签格式与VOC转YOLO脚本2.1 先摸清家底统计文件分布和类别数量拿到一个带图像的检测数据集第一件事不是急着训练而是先把目录和标签普查一遍。常见做法是压缩包里有 images或 JPEGImages、labels或 Annotations、一个 class_names.txt 和一份使用说明。先跑几个命令把文件数和类别分布确认下来。# 统计图像数量jpg/png 都算 find images -name *.jpg -o -name *.png | wc -l # 统计标签文件数量YOLO 格式是 txtVOC 格式是 xml find labels -name *.txt | wc -l # 查看所有标签里出现过的类别编号txt 首列 cat labels/*.txt | awk {print $1} | sort | uniq -c第一条命令确认是不是恰好 2059 张第二条确认标签文件是否完整我见过有些包里的 xml 齐全、txt 缺了一半的情况这类问题不查会直接导致训练时大量空标注第三条非常关键它把每个 txt 的首列 class id 拉出来排序。如果预期的 smoke、fire 两类分别对应 0、1结果却冒出 2、3说明标注文件里混了别的类别或者类别顺序被改过后面训练会非常难受。这个统计在 Windows 上也能做用 PowerShell 的 Get-ChildItem 同样能数但我建议你直接把项目环境切到 Linux 或 WSL 下再操作。后面所有训练命令都是 Linux 习惯路径分隔符统一坑少很多。我一般还会顺手统计图片尺寸分布因为烟雾和火灾经常是远距离小目标如果多数图是 1080p 而标注框很小训练时就要考虑提升输入分辨率而不是无脑 640。2.2 标签格式选型VOC的XML和YOLO的txt为什么训练前要统一这份数据集里的标注对象通常是两类fire 和 smoke。标注格式不外乎两种LabelImg 导出的 VOC XML或者标注时直接存成 YOLO 的 txt。VOC 的 XML 适合人工检查和二次编辑字段里有 object 的 name还有 bndbox 的 xmin、ymin、xmax、ymaxYOLO 的 txt 则是一行一个目标五个数字依次是 class id、归一化中心 x、归一化中心 y、归一化宽、归一化高。YOLOv5 原生吃 txt所以如果拿到手的是 XML第一步就是转换。!-- VOC XML 示例一个 fire 目标 -- annotation filenamesmoke_001.jpg/filename sizewidth1920/widthheight1080/height/size object namefire/name bndbox xmin812/xminymin433/ymin xmax978/xmaxymax610/ymax /bndbox /object /annotation转换后对应的 YOLO txt 行如下。注意 YOLO 的坐标是中心点加宽高的归一化值而 VOC 给的是左上角和右下角绝对坐标。转换时要用图片真实宽高做除法不能只依赖 XML 里的 size 字段。# 格式class_id, x_center, y_center, width, height均归一化 0 0.4661 0.4830 0.0865 0.1640很多包里的 XML 和 JPG 是分开整理的图片被重压缩后宽高没变时倒还好一旦有过缩放XML 里的 size 就可能失真。这也是为什么我的转换脚本在运行时重新用 OpenCV 读一遍图片尺寸而不是信任 XML 里的 size 标签。YOLOv5 的类别顺序以 data.yaml 的 names 为准常见做法是names: [fire, smoke]那 fire 就是 0、smoke 就是 1。如果你原来 XML 里的 name 顺序是 smoke 在前转换脚本里的 classes 列表就必须严格保持这个顺序否则训练完推理时会把 smoke 当 fire 输出现场告警直接错乱。这里就是标签格式选型最容易埋雷的地方。2.3 写一个VOC转YOLO的转换脚本坐标归一化与防越界直接给一份我常用在火灾数据集上的转换脚本。它做四件事读 XML、按 class_names 映射类别、写 YOLO 格式 txt、顺手处理越界框。import os import cv2 import xml.etree.ElementTree as ET # 和 data.yaml 里的 names 顺序保持一致 CLASSES [fire, smoke] def convert_voc_to_yolo(voc_dir, img_dir, out_dir): os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(voc_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(voc_dir, xml_file)) root tree.getroot() # 运行时读取真实宽高避免依赖 XML 里的 size img_path os.path.join(img_dir, root.find(filename).text) img cv2.imread(img_path) if img is None: print(fskip missing image: {img_path}) continue h, w img.shape[:2] lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASSES: continue cls_id CLASSES.index(name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 归一化中心坐标和宽高 x_center ((xmin xmax) / 2) / w y_center ((ymin ymax) / 2) / h box_w (xmax - xmin) / w box_h (ymax - ymin) / h # 裁剪到 [0,1]防止标注线画到图外 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) box_w min(box_w, 1.0) box_h min(box_h, 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) if lines: txt_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines)) else: print(fempty after convert: {xml_file}) convert_voc_to_yolo(annotations, images, labels)说明几个参数CLASSES的顺序必须和最终 data.yaml 里的 names 完全一致这是整个转换的核心排错时必须盯住。w和h用cv2.imread实时读取防止图片被预处理后尺寸变化。坐标做min(max())裁剪能挡住标注手滑把 bndbox 画到图像边缘外的越界框。末尾的空标签直接跳过避免 YOLOv5 训练遇到空 txt 时报 negative sample 相关的难懂报错。还有一个坑如果一张图里有多个目标YOLO 格式要求每行一个目标不能像 VOC 那样并列在多个 object 里如果某个目标类别不在 CLASSES 里脚本会静默跳过可能让某张图的真值数量变少。建议转换完后再跑一次统计比对 XML 里的 object 总数和 txt 行数是否一致。2.4 划分 train/val2059张图怎么切不容易让模型过拟合转换之后要划分训练集和验证集。很多人图省事直接随机切 9:1但对视频抽帧来的火灾数据这个做法很危险。同一段烟雾视频的连续帧之间外观几乎一样随机切会让同一场景同时出现在训练集和验证集里验证分数虚高现场换一个镜头就崩。正确做法是按视频片段或拍摄时间划分。import os, random, shutil random.seed(42) images sorted(os.listdir(images)) random.shuffle(images) split int(len(images) * 0.9) train_files images[:split] val_files images[split:] # 建立目录结构 for split_name, files in [(train, train_files), (val, val_files)]: os.makedirs(fimages/{split_name}, exist_okTrue) os.makedirs(flabels/{split_name}, exist_okTrue) for f in files: shutil.copy(fimages/{f}, fimages/{split_name}/{f}) txt f.replace(.jpg, .txt).replace(.png, .txt) src_txt flabels/{txt} if os.path.exists(src_txt): shutil.copy(src_txt, flabels/{split_name}/{txt})参数说明random.seed(42)固定随机种子保证每次重跑结果一致这对可复现很重要。random.shuffle是列表原地操作后面紧跟的split是对全体图像按比例切分。如果发现按文件名随机切的效果仍然虚高就改成按目录名分组切比如 src_01、src_02 这样的源摄像头目录整个目录进训练或验证不做跨目录取样。2059 张图像不算多划分后训练集通常不到 1900 张。这种体量下我更建议用 90% 训练、10% 验证而不是 80/20因为烟雾形态本身变化大验证集留多了会让训练数据不够。如果后面你觉得现场泛化差再把验证集比例往上调但不要动划分方式本身。3. 用YOLOv5跑通烟雾火灾训练环境、命令与超参数怎么调3.1 搭环境依赖版本与GPU/CPU选择YOLOv5 官方仓库拉下来后requirements.txt 会带一批依赖用虚拟环境装避免污染系统 Python。常用做法是 conda 建 Python 3.9 环境然后先装与 CUDA 匹配的 PyTorch再装其余依赖。git clone https://github.com/ultralytics/yolov5 cd yolov5 conda create -n smoke_fire python3.9 -y conda activate smoke_fire # 以 cu117 为例实际按你的 CUDA 版本选 pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117 pip install -r requirements.txt依赖版本别乱升。YOLOv5 对 torch 版本有隐式依赖太新的 torch 会导致某些算子编译报错太旧则不支持新卡。装完先用官方权重跑一次python detect.py --weights yolov5s.pt --source data/images/bus.jpg确认环境通。如果没有 NVIDIA GPUCPU 跑 100 轮会很痛苦可以把 imgsz 降到 448、epochs 降到 50 做冒烟测试或者用云 GPU 训练、本地 CPU 推理。我不建议在树莓派 4B 上训练那台机器更适合部署推理。显存占用要提前算8G 显存跑 yolov5s、batch16、imgsz640 基本是上限16G 显存可以尝试 yolov5m 或者把 imgsz 提到 960。对于 2059 张图的数据量yolov5s 已经足够yolov5m 能提升一点精度但训练时间会翻倍。3.2 准备 data.yaml类别顺序、路径与验证集YOLOv5 训练自己的数据集时data.yaml 是唯一和业务绑定的配置文件。下面是我给烟雾火灾项目常用的模板。# data.yaml train: /absolute/path/to/dataset/images/train val: /absolute/path/to/dataset/images/val nc: 2 names: 0: fire 1: smoke路径建议用绝对路径相对路径在换机器或换工作目录时容易找不着。nc必须和 names 数量一致。顺序必须和标签 txt 里的 class id 对应第 2 章转换脚本的 CLASSES 是[fire, smoke]这里 names 就必须先 fire 后 smoke。验证集不参与训练但训练时会用它每 10 轮算一次验证指标所以 val 路径不能指向训练集否则指标失真。还要注意路径不能有中文字符和空格。我用 YOLOv5 处理过带中文目录的数据集coco 工具链在读取标注路径时对中文支持不稳定训练到一半报文件找不到非常折腾。尽量把所有数据集放到dataset/这种纯英文路径下从根目录开始就不要混入中文。3.3 训练命令与核心参数epochs、batch、imgsz、超参数训练命令本身不复杂参数边界才是决定成败的地方。python train.py \ --data data.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --imgsz 640 \ --cache \ --name smoke_fire_run--weights yolov5s.pt用 COCO 预训练权重做迁移学习收敛速度远快于从零训练--cache把所有图像加载到显存或内存2059 张图总量不大能省掉训练时读盘的等待--imgsz 640是训练输入边长火焰这种稍大目标没问题但烟雾如果是远景小目标我建议直接用 960代价是显存占用变大可配合--batch-size 8。--epochs 100对这份数据量是合理起点如果训练集太小100 轮基本已经能看到过拟合拐点。YOLOv5 的超参数写在data/hyp.scratch-low.yaml里训练时会自动加载。我一般会改两个mosaic1.0对密集小目标有奇效但 2059 张小数据里 mosaic 会产生大量半真半假的图像如果发现早期 loss 震荡可以降到 0.5hsv_h、hsv_s等颜色增强对夜间烟雾很重要烟雾是半透明白灰色颜色增强太强会让模型把白墙当烟建议把饱和度增强从默认 0.7 降到 0.4。改完超参数后存一份新文件再在训练命令里加--hyp data/hyp.scratch_low_custom.yaml。训练过程中要盯三个东西results.png里 train_loss 和 val_loss 的走势每轮结束后的best.pt和last.pt以及confusion_matrix.png是否出现类别混淆。如果 train_loss 一直降、val_loss 在某个 epoch 后回升说明开始过拟合可以用提前停止或者增加验证集比例。最终部署用的是best.pt它按验证集 mAP 自动挑选不是最后一轮的last.pt。4. 训练踩坑与排查标签、小目标和昼夜场景的常见翻车点4.1 类别顺序错乱loss正常但AP全为0现象训练日志显示 loss 在下降但验证集的 mAP 始终接近 0PR 曲线几乎贴底。原因转换脚本的 CLASSES 顺序和 data.yaml 的 names 不一致。比如转换脚本里写的是[smoke, fire]标注时把烟当成 0、火当成 1但 data.yaml 却写names: {0: fire, 1: smoke}那模型学到的类别语义就是反的。由于 loss 仍然能收敛很多人在这一步懵很久。解决训练前先做一次标签抽查打印几张图的 txt 首行和对应 xml 的 object name 对照。# 随机抽 5 个 txt打印每行第一个数字 for f in labels/train/*.txt; do head -1 $f; done | sort | uniq -c # 再抽对应 xml打印 object name grep -r name annotations/ | head -5如果发现 0 对应 smoke、1 对应 fire有两个改法一是改 data.yaml 的 names 顺序二是重新跑转换脚本统一顺序。不要在训练中途去改标签那会让缓存里的数据索引失效产生更隐蔽的错位。这个坑我在用 YOLOv5 训练自己的数据集时踩过一次后来把“先查标签分布”写进了 checklist再没犯过。4.2 小目标烟雾被漏检网络结构里的下采样瓶颈现象近处大火框得很准远处轻烟全漏尤其是刚起火时那种稀薄的白烟。原因YOLOv5 网络结构图里CSPDarknet 的 stride32 分支对 16×16 像素以下的目标响应很弱。摄像头拍到的远距离烟可能只有 10×10 像素经过多次下采样后特征几乎消融检测器自然看不到。解决优先把 imgsz 从 640 提到 960 或 1280。代价是显存占用按平方涨2059 张图的数据量下1280 容易过拟合我一般折中到 960。如果现场是实时视频流还可以用切片推理把一帧切分成多个 640×640 的 patch 分别检测再合并结果。我试过先用图像超分辨率重建放大两倍再检测对夜间远处白烟有一点帮助但单张耗时增加明显只适合低帧率巡检或事后分析不适合报警链路。另外还有一个隐蔽因素训练时 mosaic 增强会把小目标拼到大图上大幅改变目标尺寸分布。如果发现小目标漏检先不要急着换大模型试着把--mosaic 0.5在自定义超参数文件里调低验证集小目标 AP 可能会明显改善。4.3 训练集和验证集同场景相邻帧mAP虚高现场翻车现象验证集 mAP 能到 0.95可一接到实时视频就疯狂误报漏报置信度阈值怎么调都不对。原因划分数据集时用了随机切监控视频抽帧里同一场景的相邻帧几乎一模一样验证时模型等于开了“开卷考试”。这不只是数据量的问题而是评测方式失真。解决按视频片段或时间分组划分。比如从同一段视频里抽了 500 张就让它整体落到训练集或验证集不能拆开。这样做出来的验证指标虽然难看一点但接近真实部署。我在一个消防项目中把随机切改成按日期切后现场漏报率从 12% 降到 3%验证 mAP 反而跌了 0.06但这个 0.06 是诚实的。血泪经验是宁可验证指标难看也要让它代表真实场景。4.4 夜间样本不足与颜色增强过度白墙、灯光变成“烟雾”现象白天模型很准晚上对着白墙、路灯和车灯频繁误报。原因2059 张图里如果夜间图占比很低模型学到的其实是“亮灰色区域像烟”这种伪规律。再加上默认超参里 hsv 颜色增强较强训练图经过色相扰动后把原本偏灰的墙面转成偏白色给了模型错误的特征。解决先把训练集里夜间图数量提上来至少要占三成。如果数据来源有限可以对夜间图做亮度扰动和对比度增强模拟不同路灯下的亮灰变化。同时把超参数文件里的hsv_h、hsv_s调低比如 hsv_h 从 0.015 降到 0.005hsv_s 从 0.7 降到 0.4。夜间烟雾是半透明的颜色饱和度很低增强过度就是在制造噪声。如果还是误报就在输出端加时序置信度连续 3 帧都检测到 smoke 才告警单帧偶发的高置信度直接丢弃。5. 把模型用到现场推理、导出与验证阈值5.1 用best.pt做图片和视频推理最小命令训练完成后推理命令很简单python detect.py \ --weights runs/train/smoke_fire_run/weights/best.pt \ --source test.jpg \ --conf-thres 0.25 \ --iou-thres 0.45--conf-thres 0.25是置信度阈值--iou-thres 0.45是 NMS 的 IoU 阈值。这个组合适合火灾这类宁可误报不可漏报的场景如果误报太多再把阈值往上提。输出会落在runs/detect/exp下直接看标注结果即可。5.2 导出ONNX并在真实场景验收混淆矩阵和阈值选择部署到边缘设备前通常把模型导出为 ONNX方便后续转 RKNN 或 TensorRT。命令如下python export.py \ --weights runs/train/smoke_fire_run/weights/best.pt \ --include onnx \ --dynamic导出后先用onnxruntime跑一遍同一张图确认输出和 PyTorch 推理一致。树莓派 4B 或 RK3568 上部署时ONNX 还只是中间产物需要转成目标平台的格式这一步的关键是让模型输入尺寸和设备实际输入保持一致。我在树莓派 4B 上试过 640 输入的单帧推理速度约 3 FPS够用如果改成 960速度会掉到 1 FPS 以下这种场景建议用--imgsz 640的固定尺寸导出。上线前的验收不要只看 mAP一定要看confusion_matrix.png。这张图会告诉你 smoke 被误判成 fire 的比例以及背景 false positive 集中在哪个类。根据现场可接受的误报率反推置信度阈值。我吃过一次亏某个项目里室内测试 ok拉到楼道就疯狂报警后来发现楼道灯光色温偏暖模型把暖光中心当成 fire。从那以后每次落地前都会先录一段该场景的原始视频跑一遍再决定阈值和告警策略。数据集的这 2059 张图帮你解决了训练起点但现场验证才是决定模型能不能用的最后一公里。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询