
简介这份资源面向计算机视觉方向的目标检测学习者与开发者提供烟雾与明火两类目标的标注数据集可用于火灾预警、烟火识别等场景的模型训练与算法验证。压缩包共约2000个文件以1999个xml标注文件和1个说明txt为主整体约299.85MB图片与标注一一对应方便直接接入训练流程。数据集实际包含3007张jpg图片每张均配有对应的VOC格式xml与YOLO格式txt标注标注类别为fire与smoke两类其中fire框数5198、smoke框数1651总框数达6849均使用labelImg以矩形框方式完成标注。目前已有656人学习下载适合需要现成烟火数据做检测实验、课程设计或模型对比的读者可省去自行采集与标注的成本快速搭建训练与验证环境。1. 烟雾明火烟火火灾目标检测数据集3000 张 VOCYOLO 双格式到底能干什么如果你正在做烟雾、明火、烟火、火灾四类目标的检测大概率绕不开一个现实问题公开数据要么只有火焰没有烟雾要么标注格式只给 VOC 不给 YOLO要么场景单一到模型一换摄像头就翻车。这个 3000 张规模、同时提供 VOC 和 YOLO 两种标注格式的数据集解决的正是「拿来就能训、训完能验证」这件事。它适合三类人刚入门 yolo 目标检测、想跑通第一个自定义数据集的新手需要快速验证烟雾与明火区分能力的算法工程师以及做智慧消防、园区监控、森林防火预警这类落地项目的从业者。核心价值不在图片数量而在双格式省掉了格式转换的踩坑环节以及烟雾和明火被拆成独立类别让模型能学到「有烟无火」这种早期预警信号。2. 先搞懂 VOC 与 YOLO 两种标注格式的差异和转换逻辑拿到一个数据集第一件事不是急着训练而是搞清楚它的标注长什么样。VOC 和 YOLO 是目标检测里最常见的两种标注格式很多人在这上面翻过车——用 VOC 的坐标直接喂给 YOLO模型 loss 不降反升排查半天才发现是坐标系没转。2.1 VOC 格式的 XML 结构与字段含义VOC 格式每张图对应一个 XML 文件核心信息在object节点里。一个典型的标注长这样annotation foldersmoke_fire/folder filename0001.jpg/filename size width640/width height480/height depth3/depth /size object namesmoke/name !-- 类别名smoke / fire / smoke_fire / flame -- poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin112/xmin !-- 左上角 x绝对像素坐标 -- ymin86/ymin !-- 左上角 y -- xmax430/xmax !-- 右下角 x -- ymax355/ymax !-- 右下角 y -- /bndbox /object /annotation关键点xmin/ymin/xmax/ymax是绝对像素坐标原点在左上角。name字段就是类别标签这个数据集里通常包含 smoke烟雾、fire明火、smoke_fire烟火混合、flame火焰这几类具体以实际 XML 为准。difficult标记为 1 的目标在评估时一般会被忽略训练时是否保留要看你的策略。2.2 YOLO 格式的 txt 结构与归一化规则YOLO 格式每张图对应一个 txt 文件每行一个目标格式是class_id x_center y_center width height五个值全部是归一化到 0~1 的浮点数。class_id从 0 开始对应一个classes.txt或data.yaml里的类别列表。举个例子一张 640×480 的图里有个 smoke 目标VOC 坐标是 (112, 86, 430, 355)转成 YOLO 就是0 0.4234 0.4594 0.4969 0.5604计算过程中心 x (112430)/2/640 0.4234中心 y (86355)/2/480 0.4594宽 (430-112)/640 0.4969高 (355-86)/480 0.5604。2.3 用脚本把 VOC 批量转成 YOLO 并校验虽然这个数据集已经给了双格式但实际项目里你经常需要自己转或者需要校验两边的标注是否一致。下面这个脚本可以直接抄import xml.etree.ElementTree as ET import os # 类别映射顺序决定 class_id必须和 data.yaml 一致 CLASSES [smoke, fire, smoke_fire, flame] def voc_to_yolo(xml_path, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASSES: continue # 跳过未定义类别避免 class_id 越界 cls_id CLASSES.index(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) # 边界裁剪防止标注越界导致归一化后超出 0~1 xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) xc (xmin xmax) / 2.0 / img_w yc (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}) return lines # 批量转换 xml_dir annotations_xml out_dir labels_yolo os.makedirs(out_dir, exist_okTrue) for f in os.listdir(xml_dir): if not f.endswith(.xml): continue # 图片尺寸从 XML 的 size 节点读也可以从对应图片读 tree ET.parse(os.path.join(xml_dir, f)) size tree.getroot().find(size) w int(size.find(width).text) h int(size.find(height).text) lines voc_to_yolo(os.path.join(xml_dir, f), w, h) with open(os.path.join(out_dir, f.replace(.xml, .txt)), w) as fp: fp.write(\n.join(lines))逻辑说明先建立类别到 id 的映射遍历每个 object 节点做边界裁剪后再归一化。参数上CLASSES的顺序必须和训练时data.yaml里的names完全一致否则模型学到的类别会错位。边界裁剪这步很多人省掉结果遇到标注框超出图片边界的脏数据归一化后坐标大于 1训练时虽然不报错但会引入噪声。提示转换完一定要抽查几张用可视化脚本把 YOLO 框画回原图确认框的位置和类别都对。我一般会随机抽 20 张肉眼过一遍。3. 用 YOLOv8 在本地跑通烟雾明火检测的最小流程格式搞清楚了接下来就是训练。这里以 YOLOv8 为例因为它的生态最成熟、文档最全新手跟着走不容易卡住。整个流程分四步组织目录、写配置文件、启动训练、看结果。3.1 目录结构与 data.yaml 的正确写法YOLO 训练对目录结构有约定推荐这样组织fire_smoke_dataset/ ├── images/ │ ├── train/ # 训练集图片 │ ├── val/ # 验证集图片 │ └── test/ # 测试集图片可选 ├── labels/ │ ├── train/ # 训练集标签 txt │ ├── val/ │ └── test/ └── data.yamldata.yaml是训练的入口配置写错一个字段训练就起不来path: /home/user/fire_smoke_dataset # 数据集根目录绝对路径最稳 train: images/train # 相对 path 的路径 val: images/val test: images/test nc: 4 # 类别数必须和 names 长度一致 names: 0: smoke 1: fire 2: smoke_fire 3: flame参数说明path用绝对路径能避免相对路径带来的玄学问题nc是 number of classes写错会导致训练时类别索引越界报错names的键必须从 0 连续不能跳号。如果你的数据集只有 smoke 和 fire 两类就把 nc 改成 2names 只留前两行。3.2 训练命令与关键超参设置环境装好后pip install ultralytics一行命令启动训练yolo detect train \ data/home/user/fire_smoke_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/fire_smoke \ nameexp1逐个说参数modelyolov8n.pt用 nano 版本先跑通显存占用小、速度快验证流程没问题再换 s/m/lepochs100是上限配合patience20做早停20 轮验证指标不涨就停省时间imgsz640是输入分辨率烟雾和明火目标通常占图比例较大640 够用如果小目标多可以提到 1280 但显存翻倍batch16根据显存调8G 显存跑 640 分辨率大概能到 16爆显存就降到 8lr00.01是初始学习率YOLOv8 默认用 SGD 时这个值比较稳换 AdamW 的话要降到 0.001 量级。训练过程中重点看三个指标box_loss是否稳定下降、mAP50是否上升、mAP50-95是否跟着涨。如果 box_loss 震荡不降先检查学习率是不是太大如果 mAP50 涨但 mAP50-95 不涨说明框的位置不够准可能是标注质量或 anchor 匹配的问题。3.3 推理验证与结果解读训练完在验证集上跑推理确认模型真的学到了东西yolo detect predict \ modelruns/fire_smoke/exp1/weights/best.pt \ source/home/user/fire_smoke_dataset/images/val \ conf0.25 \ iou0.45 \ saveTrueconf0.25是置信度阈值低于这个值的框不输出烟雾检测场景建议先设 0.25 看召回漏检多就降到 0.15iou0.45是 NMS 的 IoU 阈值重叠框超过这个值会被抑制烟雾和明火经常挨在一起这个值可以适当调高到 0.5 避免误抑制。结果图存在runs/detect/predict下重点看两类错误把烟雾误判成明火类别混淆以及该检的没检出来漏检。前者通常是两类样本不均衡导致后者可能是小目标或遮挡问题。注意验证集和训练集的场景分布要尽量一致。如果训练集全是白天场景验证集塞一堆夜间图mAP 会难看但这不代表模型不行而是分布偏移。4. 烟雾明火检测的避坑与排查5 个血泪教训这一章是我自己在烟雾明火项目里踩过的坑每条都按「现象 → 原因 → 解决」写你对号入座。4.1 训练 loss 正常但 mAP 极低现象训练时 box_loss 和 cls_loss 都在降但验证集 mAP50 一直在 0.1 以下。原因最常见的是data.yaml里names的顺序和标注文件里的class_id对不上。比如标注里 0 是 fire但 yaml 里 0 写成了 smoke模型学到的类别全错位loss 能降是因为它在拟合错误的映射。解决写个脚本统计所有 txt 里出现的 class_id 分布和data.yaml的 names 逐一核对。另外检查验证集的 labels 路径是否写对路径错了会读到空标签mAP 自然为 0。4.2 烟雾检测召回率低明火正常现象明火检测 mAP 能到 0.8烟雾只有 0.4 左右大量烟雾漏检。原因烟雾本身是半透明、边界模糊的目标标注时框的松紧差异大模型学到的特征不稳定。另外烟雾和背景的对比度低尤其在灰暗场景下。解决一是检查烟雾标注是否过松框太大引入大量背景二是训练时开 Mosaic 和 MixUp 增强提升模型对模糊边界的鲁棒性三是把imgsz提到 960 或 1280给烟雾更多像素。如果数据集中烟雾样本远少于明火用copy_paste增强或对烟雾类做过采样。4.3 显存溢出导致训练中断现象训练跑了几十轮突然报 CUDA out of memory。原因YOLOv8 默认开启 AMP 混合精度但某些显卡或驱动组合下 AMP 会异常占用显存另外 dataloader 的workers设太大也会吃内存。解决先把batch减半试还不行就加ampFalse关掉混合精度或者把workers从默认 8 降到 4。如果用的是小显存卡6G 以下imgsz降到 416 先跑通。4.4 模型在测试集上表现好但实际部署翻车现象测试集 mAP 0.85接到摄像头实时流上误报一堆。原因测试集和实际场景的域差异。测试集可能是网上爬的清晰图实际摄像头有运动模糊、逆光、雨雾干扰。另外训练时的预处理resize 方式、归一化参数和部署时不一致也会导致性能下降。解决从实际摄像头采集一批图人工标注后加入训练集做微调。部署时严格对齐预处理流程YOLOv8 导出 ONNX 后推理的 letterbox 方式和训练时保持一致。实时流上把conf阈值调高到 0.4~0.5 压误报宁可漏检也别频繁误报。4.5 类别不均衡导致小类别被忽略现象smoke_fire 这类混合样本很少模型几乎不预测这个类别。原因类别样本数差距过大损失函数被多数类主导。解决训练时给稀有类加权YOLOv8 可以通过自定义损失或对数据集做重采样。简单做法是把 smoke_fire 样本复制多份或者用focal_loss替代默认的 BCE。另外评估时分开看每个类别的 mAP别只看总体。5. 从能跑到好用提升烟雾明火检测精度的几个实战技巧跑通训练只是起点真正决定项目能不能落地的是精度和稳定性。这一章讲几个我反复验证过的技巧都是能直接加到现有流程里的。第一个技巧是分阶段训练。先用全部数据训一个基线模型然后用基线模型在验证集上跑推理把置信度在 0.3~0.6 之间的「模糊样本」挑出来人工复核。这些样本往往是模型最不确定的修正它们的标注后加入训练集做第二轮微调mAP 通常能涨 3~5 个点。这个思路本质是主动学习比盲目加数据高效得多。第二个技巧是合理使用测试时增强TTA。推理时对同一张图做水平翻转、多尺度缩放把多次预测结果融合。YOLOv8 推理时加augmentTrue就能开启yolo detect predict \ modelruns/fire_smoke/exp1/weights/best.pt \ sourcetest_images \ augmentTrue \ conf0.25TTA 能提升 1~2 个点 mAP代价是推理速度慢 2~3 倍。实时场景慎用离线批量检测可以用。第三个技巧是导出 ONNX 做部署前的精度对齐验证。很多人训练完直接导 ONNX 上线结果发现精度掉了原因是导出时的动态轴设置或算子版本不匹配。导出命令yolo export modelbest.pt formatonnx opset12 simplifyTrue dynamicFalseopset12兼容性最好simplifyTrue会做图优化dynamicFalse固定输入尺寸推理更快。导出后一定要用同一批图分别跑 PyTorch 和 ONNX 推理逐张对比框的坐标和置信度差异超过 1% 就要查原因。第四个技巧是关注数据本身的质量而非数量。3000 张如果标注质量高、场景覆盖全比 10000 张脏数据训出来的模型强得多。我一般会花时间做三件事统计每个类别的样本数和框的尺寸分布看有没有长尾抽查标注框是否贴合目标检查是否有重复图或近似图造成数据泄漏。最后一个习惯每次训练都记录完整的配置和结果。我习惯在runs目录下留一个train_config.md写清楚这次用的数据版本、超参、mAP 结果和遇到的问题。下次调参时翻记录能省掉大量重复试错。烟雾明火检测这个方向数据集的场景覆盖度和标注一致性比模型选型更影响最终效果。希望帮到你。本文还有配套的精品资源点击获取