
简介本资源为面向目标检测初学者与算法工程师的YOLO烟雾检测数据集聚焦真实场景下的烟雾识别任务可用于安防监控、工业巡检、火灾预警等方向的模型训练与课程实践。数据经labelimg精细标注标注框质量高场景覆盖丰富并同步提供voc、coco、yolo三种格式标签分别存放于独立文件夹可直接接入YOLO系列检测框架。压缩包共2000个文件以1000个xml标注、990个txt标签为主另含yaml配置、py划分脚本及html说明文档整体约86.54MB结构清晰便于检索。资源附赠环境搭建、训练案例教程与数据集划分脚本可按需生成训练集、验证集与测试集帮助读者快速跑通从数据准备到模型训练的全流程。目前已有362人学习下载适合希望低成本获取高质量烟雾数据并快速验证检测方案的读者。1. 烟雾检测数据集拿到手先别急着训练1000 张图背后的三个真相烟雾目标检测这个方向我见过太多人栽在第一步。拿到一个标着「1000 张图片 VOC/COCO/YOLO 三格式标签 划分脚本 训练教程」的压缩包第一反应往往是解压、改data.yaml、yolo train三连然后盯着 loss 曲线等奇迹。结果要么 mAP 卡在 0.3 上不去要么模型把白云、雾气、甚至白色墙壁全框成烟雾。问题不在 YOLO 本身而在于烟雾这个目标太特殊——它没有固定形状、边缘模糊、半透明、和背景对比度极低1000 张图的体量在通用检测任务里算小在烟雾任务里更考验数据质量和划分策略。这个数据集真正值钱的地方不是那 1000 张图本身而是它同时给了 VOC、COCO、YOLO 三种格式标签和一套划分脚本。这意味着你可以跳过最耗时的标注环节直接把精力放在格式转换验证、划分合理性检查和训练参数调优上。适合谁适合已经跑通过 YOLO 官方 demo、想切入烟雾/火灾/工业排烟检测场景的工程师也适合拿它做课程设计或毕设的学生——但前提是你得知道下面这些坑在哪。2. 三种标签格式到底怎么选VOC、COCO、YOLO 的转换逻辑与验证方法2.1 为什么同一个数据集要给你三种格式VOC 是 XML 结构一个图对应一个 XML 文件里面存bndbox的xmin/ymin/xmax/ymax绝对坐标。COCO 是单个 JSON 管全量数据annotations数组里存bbox的[x, y, width, height]和category_id。YOLO 是每张图一个.txt每行class_id x_center y_center width height全部归一化到 0~1。三种格式不是随便给的。VOC 适合用labelImg继续补标或人工复核COCO 适合接pycocotools做评估或喂给 MMDetection 系框架YOLO 格式直接进 Ultralytics 训练。很多人只用了 YOLO 格式结果想换评估指标或者做数据增强时发现没有 COCO 的info和licenses字段又得回头转。所以拿到数据集第一件事不是训练是把三种格式都验证一遍确认它们描述的是同一批框。2.2 用脚本验证三格式一致性下面这段代码做一件事读一张图的 VOC XML、COCO JSON 里对应的 annotation、YOLO txt把三种框还原成绝对像素坐标比对是否一致。不一致就说明转换过程有精度损失或类别映射错误。import xml.etree.ElementTree as ET import json import os IMG_W, IMG_H 640, 640 # 按你数据集实际尺寸改 def voc_to_abs(xml_path): tree ET.parse(xml_path) root tree.getroot() boxes [] for obj in root.findall(object): name obj.find(name).text bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) boxes.append((name, xmin, ymin, xmax, ymax)) return boxes def yolo_to_abs(txt_path): boxes [] with open(txt_path) as f: for line in f: cid, xc, yc, w, h map(float, line.strip().split()) xmin (xc - w / 2) * IMG_W ymin (yc - h / 2) * IMG_H xmax (xc w / 2) * IMG_W ymax (yc h / 2) * IMG_H boxes.append((int(cid), xmin, ymin, xmax, ymax)) return boxes def coco_to_abs(json_path, img_id): with open(json_path) as f: data json.load(f) boxes [] for ann in data[annotations]: if ann[image_id] ! img_id: continue x, y, w, h ann[bbox] boxes.append((ann[category_id], x, y, x w, y h)) return boxes # 逐图比对阈值设 1 像素 voc_boxes voc_to_abs(annotations/0001.xml) yolo_boxes yolo_to_abs(labels/0001.txt) coco_boxes coco_to_abs(annotations/instances.json, img_id1) for v, y in zip(voc_boxes, yolo_boxes): diff max(abs(v[1] - y[1]), abs(v[2] - y[2]), abs(v[3] - y[3]), abs(v[4] - y[4])) if diff 1.0: print(f不一致: VOC{v} YOLO{y} 最大偏差{diff:.2f}px)逻辑说明VOC 和 COCO 存的是绝对坐标YOLO 存归一化坐标还原时乘回图像宽高。比对阈值设 1 像素是因为浮点转换和取整会带来亚像素误差超过 1 像素就说明转换脚本有问题。参数上IMG_W/IMG_H必须和标注时用的尺寸一致如果数据集里图片被 resize 过而标签没同步这里会直接暴露。2.3 划分脚本怎么用才不翻车数据集自带的划分脚本通常是按 8:1:1 或 7:2:1 随机切分。但烟雾数据有个特点同一段视频抽帧出来的图高度相似如果随机划分训练集和验证集里会出现几乎一样的图验证 mAP 虚高上线就崩。正确做法是按场景或按视频源分组划分。# 假设图片按场景放在 scenes/ 下每个子目录是一个独立场景 python split.py --data_root ./images --val_ratio 0.15 --test_ratio 0.15 \ --group_by scene --seed 42 --output ./splits参数说明--group_by scene表示同一场景的图只进一个集合避免数据泄漏--seed 42固定随机种子保证可复现--val_ratio和--test_ratio按你的总量调1000 张图建议验证集不少于 150 张否则 mAP 波动会很大。如果脚本不支持分组就自己按文件名前缀或目录手动分别偷懒用纯随机。提示划分完一定要统计三个集合里正样本框的数量和尺寸分布如果验证集里小目标框占比和训练集差很多mAP 会明显偏低这不是模型问题是划分问题。3. 从 1000 张图到可训练 YOLO 数据集目录结构、配置文件与最小训练命令3.1 目录结构定死别自创Ultralytics 系 YOLO 对目录结构有约定自创结构会在data.yaml解析时翻车。标准结构如下smoke_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamlimages/train/0001.jpg对应labels/train/0001.txt文件名必须一致扩展名不同。常见错误是把所有图放一个文件夹然后用 txt 列表指定YOLOv8 之后虽然支持但val阶段的路径推断容易出问题老老实实按目录分。3.2 data.yaml 的三个必调字段path: /abs/path/to/smoke_dataset train: images/train val: images/val test: images/test nc: 1 names: 0: smokepath用绝对路径相对路径在不同工作目录下启动训练会找不到数据。nc是类别数烟雾检测通常就 1 类如果你的数据集把「白烟」「黑烟」分开标了这里要对应改但我不建议分太细1000 张图分多类每类样本更少模型学不动。names的 key 从 0 开始和 YOLO txt 里的class_id对应错一位整个训练全废。3.3 最小训练命令与参数含义yolo detect train \ datasmoke_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/smoke \ nameexp1modelyolov8n.pt用 nano 版起步1000 张图用大模型必过拟合。imgsz640是烟雾检测的常用尺寸烟雾目标通常占图面积不小640 够用再大显存吃不消。batch16在 8G 显存上跑 640 分辨率比较稳显存不够就降到 8 并同步把lr0降到 0.005。patience20表示 20 轮 mAP 不升就早停烟雾数据容易过拟合这个值别设太大。训练启动后重点看三个输出box_loss是否稳定下降、mAP50是否在 30 轮后还在涨、val/box_loss和train/box_loss的差距。如果 train loss 降但 val loss 涨就是过拟合加数据增强或减模型容量。3.4 数据增强参数怎么设烟雾检测的增强策略和通用目标检测不同。mosaic默认 1.0 可以用但mixup建议关掉或设 0.1 以下因为烟雾和背景混合后语义更模糊模型更难学。hsv_h可以调大一点到 0.03模拟不同光照下的烟雾颜色变化。flipud垂直翻转对烟雾合理因为烟往上飘翻转后变成往下沉物理上不自然建议设 0。yolo detect train datasmoke_dataset/data.yaml modelyolov8n.pt \ epochs100 imgsz640 batch16 \ hsv_h0.03 hsv_s0.7 hsv_v0.4 \ degrees10 translate0.1 scale0.5 \ fliplr0.5 flipud0.0 mosaic1.0 mixup0.0这些值不是拍脑袋是我在几个烟雾项目里试出来的。scale0.5让目标缩放范围大模拟远近烟雾degrees10小角度旋转烟雾没有严格方向性但大角度旋转会引入不自然边缘。4. 烟雾检测训练避坑5 个让 mAP 卡住不动的真实原因4.1 现象mAP50 一直在 0.2~0.3 徘徊loss 降不下去原因标签里大量框是「整张图都是烟」的大框YOLO 的 anchor 匹配策略对大框回归不稳定而且大框的 IoU 计算对位置偏移不敏感模型学不到精细边界。解决统计框的宽高分布如果超过 60% 的框面积占比大于 0.5考虑把大框裁成多个小框或者改用分割任务。另一个办法是检查是否有空标签文件——有些图没有烟雾但被放进来了YOLO 会把它当负样本少量可以多了就干扰。4.2 现象验证集 mAP 很高换一批图测试全漏检原因划分时同一场景的图泄漏到了训练集和验证集。烟雾数据很多是从视频抽帧相邻帧差异极小随机划分必然泄漏。解决按视频源或时间段分组划分验证集用完全没在训练集出现过的场景。验证方法很简单用感知哈希算一下训练集和验证集图片的相似度有大量高相似对就说明泄漏了。4.3 现象模型把白云、雾气、白色墙面框成 smoke原因负样本不足。1000 张图里如果全是含烟雾的正样本模型没见过「像烟但不是烟」的干扰项就会过检。解决往训练集里加 10%~20% 的纯负样本图无烟雾但含云、雾、白色物体标签文件留空。YOLO 对空标签文件是支持的但要注意data.yaml里不能把这些图漏掉。加负样本后 mAP 可能略降但误检率会明显改善实际部署更看重这个。4.4 现象训练到 50 轮后 val loss 开始涨mAP 掉原因过拟合。1000 张图对 YOLO 来说数据量偏小模型在 50 轮左右就记住了训练集。解决早停patience设 15~20加weight_decay0.0005把model换成更小的 nano 或加 dropout。如果还不行用冻结 backbone 的方式先训 head 20 轮再解冻全训这是小数据集的常规操作。4.5 现象推理时框的位置对但类别置信度很低原因data.yaml里names的顺序和 YOLO txt 里class_id不一致或者 COCO 转 YOLO 时category_id从 1 开始而 YOLO 要求从 0 开始。解决写个脚本统计所有 txt 里出现的class_id集合和names的 key 比对。COCO 的category_id经常是 1 起步转换时必须减 1这个坑我踩过不止一次。注意每次改完标签或data.yaml先跑yolo detect train epochs1看第一轮能不能正常出 loss别直接开 100 轮浪费卡时。5. 小数据集提点技巧用 COCO 预训练权重和冻结策略把 mAP 再拉 5 个点1000 张图想从零训到高 mAP 不现实必须借预训练权重。但直接用 COCO 预训练权重有个问题COCO 的 80 类里没有 smokebackbone 学到的特征偏通用物体head 完全不对口。我的做法是分两阶段第一阶段冻结 backbone只训 head 30 轮让 head 先适配烟雾的二分类有烟/无烟第二阶段解冻全部用更小的学习率训 50 轮。# 第一阶段冻结 backbone yolo detect train datasmoke_dataset/data.yaml modelyolov8n.pt \ epochs30 imgsz640 batch16 lr00.01 \ freeze10 projectruns/smoke namestage1 # 第二阶段解冻全训学习率降一个量级 yolo detect train datasmoke_dataset/data.yaml \ modelruns/smoke/stage1/weights/best.pt \ epochs50 imgsz640 batch16 lr00.001 \ projectruns/smoke namestage2freeze10表示冻结前 10 层YOLOv8n 的 backbone 大概就是前 10 层。第一阶段学习率可以大一点因为只更新 head第二阶段必须降否则预训练特征被破坏。这个策略在我经手的几个烟雾项目里比直接全量微调平均高 3~5 个 mAP 点。另一个技巧是验证时用TTA测试时增强Ultralytics 推理时加augmentTrue会做多尺度翻转推理再融合mAP 能再提 1~2 个点代价是推理速度慢 2~3 倍。如果部署端算力够这个开关值得开。yolo detect val modelruns/smoke/stage2/weights/best.pt \ datasmoke_dataset/data.yaml augmentTrue最后说个习惯每次训完把results.csv和confusion_matrix.png存下来按日期和参数命名。烟雾检测的调参很依赖对比没有历史记录就是黑匣子下次改参数全靠猜。我一般会在project目录下建个notes.md记下这次改了什么、mAP 变化多少、为什么。这个习惯帮我省了至少几十个小时的重复试错。希望帮到你。本文还有配套的精品资源点击获取