简介这份资源是面向计算机视觉与深度学习方向的烟雾明火目标检测数据集适合从事火灾预警、烟火识别等课题的研究人员、学生及算法工程师使用可解决烟火检测任务中样本不足、标注不规范的问题。数据集共3007张jpg图片每张均配有对应的VOC格式xml标注文件与YOLO格式txt标注文件压缩包内文件总数约2000个以xml标注文件为主另含一份说明文档整体大小约299.85MB。标注类别共两类分别为fire与smoke其中fire框数5198个、smoke框数1651个总框数达6849个均使用labelImg工具以矩形框方式完成标注标注准确合理。目前已有656人学习下载读者可直接获得一套格式完整、类别清晰的烟火检测数据用于模型训练、算法验证与效果对比省去自行采集与标注的成本。1. 烟雾明火检测数据集3007 张 VOCYOLO 双格式拿到手就能开训做烟火检测的兄弟大概率都经历过这个阶段算法框架搭好了模型结构也调通了结果卡在数据上。网上能找到的公开烟火数据集要么只有几百张、类别不均衡要么只给图片不给标注要么标注格式跟手头的训练脚本对不上。我最近拆了一份 ESE 系列的烟火数据集3007 张 jpg 图片每张都配了 Pascal VOC 的 xml 和 YOLO 的 txt 两套标注类别就两个——fire 和 smoke总框数 6849。这个量级放在目标检测任务里不算大但胜在格式齐全、标注干净拿来跑 YOLOv5/v8 的入门训练或者做烟雾明火场景的 baseline 验证省掉了自己从零标数据的时间。适合谁用一是刚接触目标检测、想拿一个真实场景数据集练手的新手二是需要快速验证烟火检测方案可行性的工程师三是做安防、森林防火、工业巡检方向、需要一个能直接转成训练格式的数据底包的人。下面我从数据本身、格式转换、训练配置到踩坑排查把这份资源拆开讲一遍。2. 数据集结构与 VOC/YOLO 双格式解析先搞清楚手里有什么2.1 文件组织方式与命名规律拿到压缩包解压之后目录结构很朴素没有嵌套多层文件夹。根目录下是一个说明.txt然后是若干.xml文件和对应的.jpg、.txt。从项目正文给出的文件列表可以看到xml 文件的命名格式是ESE_fire_数字.xml比如ESE_fire_1498.xml、ESE_fire_557.xml、ESE_fire_2007.xml这样。这个命名规律说明数据集来自某个 ESE 前缀的采集或标注批次数字是图片编号不连续说明中间做过筛选或剔除。jpg 图片数量 3007xml 标注数量 3007txt 标注数量 3007三者一一对应。这意味着每张图都有 VOC 格式和 YOLO 格式两份标注不需要你自己写脚本从 xml 转 txt也不存在某张图只有图片没有标注的情况。对于目标检测训练来说这种「三件套」齐全的数据包是最省事的直接按格式要求分目录就能开跑。有一点要注意摘要里明确写了「不包含分割路径的 txt 文件」意思是这个数据集只做矩形框检测标注没有做实例分割的 polygon 标注。如果你的任务是实例分割这份数据只能用来做检测预训练不能直接拿来做分割训练。另外数据集不对训练精度作任何保证标注只保证「准确且合理」这个态度是诚实的——目标检测的最终精度取决于模型结构、超参、数据增强、训练策略等一大堆因素数据集只负责把标注这一环做扎实。2.2 VOC 格式的字段含义与读取方式Pascal VOC 格式是目标检测领域最经典的标注格式之一每个 xml 文件对应一张图片里面记录了图片尺寸、目标类别和边界框坐标。用 Python 读取一个 xml 文件核心字段就几个import xml.etree.ElementTree as ET def parse_voc_xml(xml_path): tree ET.parse(xml_path) root tree.getroot() # 图片尺寸YOLO 归一化时要用 size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) # 遍历所有目标 objects [] for obj in root.findall(object): cls_name obj.find(name).text # fire 或 smoke bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) objects.append((cls_name, xmin, ymin, xmax, ymax)) return img_w, img_h, objects这段代码的逻辑很直白先拿到图片的宽高因为 VOC 存的是绝对像素坐标而 YOLO 需要归一化到 0~1 之间。然后逐个读取object节点每个节点里name是类别名bndbox里是左上角和右下角坐标。参数上唯一需要留意的是坐标类型有些标注工具会写成浮点数这里用int()转换如果遇到小数坐标会截断但 labelImg 导出的 VOC 默认是整数问题不大。2.3 YOLO 格式的字段含义与类别映射YOLO 格式的 txt 文件每行代表一个目标格式是类别索引 中心x 中心y 宽 高所有值都是相对于图片宽高的归一化值范围 0~1。这个数据集里类别只有两个按照常见约定fire对应索引 0smoke对应索引 1。但这里有个坑不同标注批次可能把类别顺序反过来所以拿到数据后第一件事是确认类别映射关系不能想当然。# 读取 YOLO 格式标注 def parse_yolo_txt(txt_path): with open(txt_path, r) as f: lines f.readlines() boxes [] for line in lines: parts line.strip().split() cls_id int(parts[0]) # 0 或 1 cx, cy, w, h map(float, parts[1:5]) boxes.append((cls_id, cx, cy, w, h)) return boxes参数说明cls_id是类别索引需要和你的data.yaml里的names列表顺序一致cx, cy是框中心点归一化坐标w, h是框的归一化宽高。如果你要把 YOLO 格式转回 VOC 做可视化验证公式是xmin (cx - w/2) * img_w其余同理。2.4 类别分布与框数统计说明了什么摘要里给了明确的统计fire 框数 5198smoke 框数 1651总框数 6849。fire 的框数是 smoke 的三倍多这个不均衡比例在烟火检测里很常见——明火区域通常边界清晰、标注容易烟雾区域边界模糊、标注一致性差所以标注者往往更倾向于标 fire。3007 张图对应 6849 个框平均每张图 2.28 个框说明大部分图片里目标数量不多场景相对干净。这个分布对训练的影响是模型会偏向于预测 firesmoke 的召回率可能偏低。如果你做的是森林防火或者早期烟雾预警smoke 的漏检代价比 fire 更高那就需要在训练时对 smoke 类别做加权或者用 focal loss 这类能缓解类别不均衡的损失函数。常见做法是在data.yaml里不直接改而是在训练脚本里通过cls_weights或者自定义 loss 来调整。3. 从压缩包到可训练VOC 转 YOLO 与目录划分实操3.1 目录结构规划与文件划分YOLO 系列训练脚本对目录结构有固定要求一般是这样的dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml图片放images对应的 txt 标注放labels文件名保持一致只是扩展名不同。训练集和验证集按 8:2 或 9:1 划分。这个数据集已经自带了 YOLO 格式的 txt所以不需要从 xml 转换直接按文件名配对复制就行。但如果你拿到的版本只有 xml 没有 txt那就需要自己转转换脚本如下import os import xml.etree.ElementTree as ET import random # 类别映射务必确认顺序 class_map {fire: 0, smoke: 1} def voc_to_yolo(xml_path, txt_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) # 转成归一化中心点宽高 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / 1.0 / img_w h (ymax - ymin) / 1.0 / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines))逻辑说明先解析 xml 拿到图片宽高和每个框的绝对坐标然后按 YOLO 公式做归一化。class_map是类别名到索引的映射这个必须和你的data.yaml里names的顺序完全一致否则训练出来的模型会把 fire 认成 smoke。参数上坐标保留 6 位小数足够YOLO 训练时内部还会做处理。3.2 data.yaml 配置与类别名对应YOLOv5/v8 的data.yaml是训练入口配置文件内容不复杂但每个字段都不能错path: ./dataset train: images/train val: images/val nc: 2 names: [fire, smoke]nc是类别数这里是 2。names列表的顺序决定了类别索引fire在前就是索引 0smoke在后就是索引 1。如果你在转换脚本里把映射写反了这里又没对齐训练出来的模型精度会莫名其妙地低而且 loss 曲线看起来还挺正常属于典型的「玄学翻车」。我一般会在转换完之后随机抽几张图用脚本把 YOLO 标注画回图片上肉眼确认框的位置和类别都对再开始训练。3.3 训练集验证集划分与随机种子划分脚本很简单但有个细节随机种子要固定否则每次跑出来的划分不一样实验没法复现。import os import random import shutil random.seed(42) # 固定种子保证可复现 img_dir ./dataset/images lbl_dir ./dataset/labels all_imgs [f for f in os.listdir(img_dir) if f.endswith(.jpg)] random.shuffle(all_imgs) split int(len(all_imgs) * 0.8) train_imgs all_imgs[:split] val_imgs all_imgs[split:] for phase, imgs in [(train, train_imgs), (val, val_imgs)]: os.makedirs(f{img_dir}/{phase}, exist_okTrue) os.makedirs(f{lbl_dir}/{phase}, exist_okTrue) for img in imgs: shutil.copy(os.path.join(img_dir, img), f{img_dir}/{phase}/{img}) txt img.replace(.jpg, .txt) shutil.copy(os.path.join(lbl_dir, txt), f{lbl_dir}/{phase}/{txt})参数说明random.seed(42)是固定随机种子42 是习惯用法你也可以用别的数字但一旦定了就别改。split按 0.8 划分3007 张图大约 2405 张训练、602 张验证。如果数据量再小一些可以考虑 5 折交叉验证但 3000 张这个量级单次 8:2 划分够用了。3.4 用 labelImg 复核标注质量数据集是用 labelImg 标的标注规则是画矩形框。labelImg 支持 VOC 和 YOLO 两种导出格式这也是为什么数据集同时有 xml 和 txt。如果你想复核标注质量可以用 labelImg 打开图片目录加载对应的 xml 或 txt逐张检查。重点看几类问题框是否把目标完整包住、有没有漏标、有没有把非目标区域误标成 fire 或 smoke。3007 张图全看一遍不现实但随机抽 50~100 张做抽样检查是必要的尤其是 smoke 类别因为烟雾边界模糊标注一致性最容易出问题。4. 训练配置与参数调优YOLOv5/v8 跑通烟火检测4.1 环境搭建与依赖安装训练环境用 PyTorch YOLOv5 或 YOLOv8 都行。以 YOLOv8 为例安装命令很简洁pip install ultralytics如果你用 YOLOv5需要克隆仓库再装依赖git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt参数上没什么特别的注意 CUDA 版本和 PyTorch 版本匹配就行。如果是在 AGX Orin 这类边缘设备上搭环境PyTorch 的安装包要用 NVIDIA 官方提供的对应版本直接 pip 装默认版本可能跑不起来 GPU 加速。这个数据集 3007 张图输入尺寸 640×640 的话单卡 8G 显存足够跑 YOLOv8s 这个量级的模型。4.2 训练命令与关键超参设置YOLOv8 的训练命令一行搞定yolo detect train data./dataset/data.yaml modelyolov8s.pt epochs100 imgsz640 batch16 lr00.01关键参数逐个说data指向data.yamlmodel选预训练权重yolov8s.pt是 small 版本速度和精度平衡得比较好如果显存紧张可以换yolov8n.ptepochs100是训练轮数3000 张图 100 轮大概能收敛如果 loss 还在降可以加到 150imgsz640是输入分辨率烟火检测里小目标烟雾比较多如果显存允许可以提到 800 甚至 1024batch16是批大小根据显存调lr00.01是初始学习率YOLOv8 默认就是 0.01一般不用改。YOLOv5 的训练命令类似python train.py --data data.yaml --weights yolov5s.pt --epochs 100 --img 640 --batch 164.3 类别不均衡的处理策略前面提到 fire 框数是 smoke 的三倍多这个不均衡在训练时会有影响。YOLOv8 默认的分类损失是 BCE对不均衡不算特别敏感但如果你发现 smoke 的召回率明显低于 fire可以试几种做法。一是在数据增强层面对包含 smoke 的图片做过采样让 smoke 样本在每个 epoch 里出现的频率更高。二是在 loss 层面YOLOv8 支持通过cls参数调整分类损失的权重但更精细的类别加权需要改源码。三是在评估指标上不要只看 mAP要分别看 fire 和 smoke 的 AP如果 smoke 的 AP 明显低说明不均衡确实造成了影响。常见做法是在data.yaml同级目录下加一个hyp.yaml里面调cls和box的权重但 YOLOv8 的超参入口和 v5 不太一样v8 是在训练命令里直接传cls0.5这样的参数。我一般会先跑一轮 baseline看混淆矩阵再决定要不要调。4.4 数据增强参数的取舍YOLO 默认开启 mosaic、mixup、HSV 增强等。烟火检测场景下HSV 增强对烟雾的颜色变化有帮助因为烟雾从白到灰到黑都有色调抖动能让模型更鲁棒。但 mosaic 增强要注意它会把四张图拼成一张如果拼进来的图里有 fire 和 smoke 混在一起小目标烟雾可能被裁掉反而影响训练。我的习惯是前 80 轮开 mosaic后 20 轮关掉让模型在接近真实分布的图片上做微调。YOLOv8 里通过close_mosaic20这个参数控制意思是最后 20 轮关闭 mosaic。翻转增强也要注意水平翻转对烟火检测一般没问题但垂直翻转要谨慎——火焰和烟雾在自然场景里通常向上运动垂直翻转会造出「火往下烧」的不自然样本可能让模型学到错误的空间先验。YOLO 默认不开垂直翻转保持默认就行。5. 避坑与排查标注、格式、训练里最容易翻车的几件事5.1 类别索引对不上导致模型「指鹿为马」现象训练 loss 正常下降mAP 也有数值但推理时把 fire 框成 smoke或者反过来。原因VOC 转 YOLO 时的class_map和data.yaml里的names顺序不一致。比如转换脚本里写的是{smoke: 0, fire: 1}而data.yaml里写的是[fire, smoke]索引 0 对应 fire但标注里索引 0 实际是 smoke。解决转换前先确认类别顺序转换后随机抽几张图可视化验证确认框的类别标签和图片内容一致再开训。5.2 图片和标注文件名不匹配导致漏读现象训练时日志显示No labels found或者ignoring corrupted image实际图片和标注都在。原因图片是.jpg标注是.txt但文件名除了扩展名之外还有细微差异比如图片叫ESE_fire_1498.jpg标注叫ESE_fire_1498 .txt多了空格或者大小写不一致。解决写个脚本批量检查图片和标注的文件名是否一一对应把不匹配的列出来手动修。YOLO 对文件名匹配是大小写敏感的.JPG和.jpg会被当成两个文件。5.3 坐标越界导致训练报错或框画到图外现象训练时偶尔报RuntimeError: invalid bbox或者可视化时框跑到图片外面。原因VOC 标注里 xmax 超过了图片宽度或者 xmin 小于 0这种情况在标注工具里手动拖框时可能发生。解决转换脚本里加一步裁剪把坐标限制在[0, img_w]和[0, img_h]范围内同时过滤掉宽高小于 1 像素的无效框。YOLO 对归一化坐标要求严格超出 0~1 范围会直接报错。5.4 验证集里出现训练集图片导致指标虚高现象验证集 mAP 高得离谱但实际推理效果很差。原因划分训练集和验证集时没有固定随机种子或者复制文件时把同一张图同时放进了两个目录。解决划分脚本里固定random.seed()复制完成后用集合运算检查两个目录的文件名是否有交集有交集就重新划分。另外如果数据集本身有大量连续帧比如视频抽帧要按视频来源划分不能随机分否则同一段视频的相邻帧会同时出现在训练集和验证集里造成数据泄露。5.5 smoke 标注框过大或过小影响召回现象模型对烟雾的检测效果明显差于火焰漏检多。原因烟雾本身边界模糊标注者可能把整片烟雾区域都框进去导致框很大、中心点偏移也可能只框了烟雾最浓的一小块导致框太小、特征不明显。解决抽样检查 smoke 标注把明显不合理的框修正。如果修正成本太高可以在训练时对 smoke 类别做更强的数据增强比如随机缩放和裁剪让模型适应不同大小的烟雾目标。6. 进阶技巧用这份数据集做迁移学习和模型验证这份数据集 3007 张的体量从零训练一个烟火检测模型是够的但如果你想在特定场景比如森林、工厂、隧道里达到更好的效果迁移学习是更务实的路径。我的习惯是先用这份数据训练一个 base 模型然后把 backbone 冻结用目标场景的少量数据做微调。YOLOv8 里冻结 backbone 的命令是freeze10意思是冻结前 10 层只训练检测头。这样在小样本场景下收敛更快也不容易过拟合。另一个用法是拿这份数据做模型验证。你手头可能已经有一个在别的数据集上训好的烟火检测模型想看看它在不同分布上的表现。把这份数据的验证集跑一遍看 fire 和 smoke 的 AP 分别是多少混淆矩阵里有没有把 smoke 误判成背景的情况。如果 smoke 的 AP 明显低于 fire说明模型对烟雾特征的学习不够可能需要补充烟雾样本或者调整损失函数。验证的时候有个细节YOLO 默认的conf阈值是 0.25iou阈值是 0.45。烟火检测里烟雾的置信度通常比火焰低如果conf设太高烟雾会被大量过滤掉。我一般会把conf降到 0.1 先看召回再根据误报情况往上调。下面这段代码可以批量跑验证集并输出每个类别的 APfrom ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) metrics model.val(data./dataset/data.yaml, conf0.1, iou0.45) print(metrics.box.ap50) # 每个类别的 AP0.5 print(metrics.box.maps) # 每个类别的 mAP0.5:0.95 print(metrics.confusion_matrix)参数说明conf0.1是降低置信度阈值让更多预测框参与评估iou0.45是 NMS 的 IoU 阈值烟火检测里如果两个框重叠度高可能是同一个目标被重复检测NMS 会抑制掉。metrics.box.ap50返回一个列表顺序和data.yaml里的names一致所以你能直接看到 fire 和 smoke 各自的 AP。最后说一个我踩过的坑有一次我用这份数据训完模型在验证集上 mAP 到了 0.85觉得挺满意结果拿到实际监控视频上一跑漏检严重。后来发现是验证集里的图片和训练集分布太接近都是白天、清晰、目标大的场景而实际视频里有夜间、模糊、小目标的情况。从那以后我每次训完模型都会额外找一批跟训练集分布不同的图片做测试哪怕只有几十张也能提前暴露问题。希望这份数据在你手里能跑出靠谱的烟火检测模型帮到你。本文还有配套的精品资源点击获取