简介面向 YOLO 烟雾检测任务的数据集标注包适合正在训练烟雾识别模型的研究者、算法工程师及计算机视觉学习者。压缩包内共 2000 个 XML 标注文件压缩后约 268.9MB文件命名与原始图像一一对应可直接作为目标检测训练集的标签输入资源包同样适配 YOLOv5、YOLOv8 等常见训练流程可减少数据准备成本。标题信息显示完整数据规模为 21578 张带标签图像该压缩包是这批数据的标注子集可用于森林防火、工厂安全、智慧安防等烟雾预警场景。已有 482 人在 CSDN 学习下载。通过这套标注文件读者可以快速搭建或扩充 YOLO 训练数据管道省去自行标注图像的时间同时便于对照图像理解 XML 标签结构中边界框与类别信息的记录方式为后续数据清洗、增强或格式转换打下基础文件前缀规则一致适合批量处理与训练集/验证集划分。1. 烟雾检测数据集怎么用21578张带标签图像YOLO训练前的真实起点做目标检测的同行拿到“yolo算法-烟雾数据集-21578张图像带标签-烟smoke100-uwe4t.zip”这串压缩包名第一反应通常是三件事图像量够不够训、标签格式是不是YOLO能直接读的、训练出来在真实场景顶不顶用。烟雾和行人、车辆这类刚性目标不一样它是半透明、无固定形状、边缘模糊的非刚性目标标注边界的主观性很强——同一团烟两个人画出的框可能差出两倍面积。所以这份数据集的价值不只看21578这个数字更要看标签质量和场景覆盖。这篇文章站在一线实操角度把拿到这份数据集后的检查步骤、格式转换、训练参数和踩坑记录一次讲透新手能照着跑熟手能直接对参数。2. 拆开这份数据集目录结构、标签命名与YOLO格式转换前的检查清单2.1 先摸清目录结构解压后第一步别急着训练拿到压缩包先解压到一个统一工作目录解压时注意包名里的中文和连字符在部分Linux发行版下会变成乱码建议解压后立刻改名为纯英文路径后面所有训练脚本都基于英文路径操作避免编码问题在训练中途冒出来。unzip -q yolo算法-烟雾数据集-21578张图像带标签-烟smoke100-uwe4t.zip -d smoke100 cd smoke100 find . -maxdepth 2 -type d | sort find . -type f | sed s/.*\.// | sort | uniq -c第一行解压到smoke100目录-q静默模式减少输出第二行列两层目录结构一眼看清是“images/labels”平铺还是“scene/images”分场景第三行统计所有文件扩展名分布能快速判断图像是jpg还是png、标签是txt还是xml还是json。如果统计结果里出现__MACOSX或者.DS_Store说明压缩包在macOS下打包需要连同嵌套的隐藏目录一起清理掉否则训练时遍历文件会读到一堆垃圾。建议顺手执行一次find . -name .DS_Store -delete和rm -rf __MACOSX。文件名匹配规则是YOLO体系的惯例图像frame_00001.jpg对应标签frame_00001.txt。用下面这行命令统计“有图无标签”和“有标签无图”的数量两个数都应该接近0for img in $(find images -name *.jpg); do base${img%.jpg} [ ! -f labels/${base##*/}.txt ] echo 缺标签: $img done如果缺标签的图像占比超过1%说明这份数据集在打包时有过一次不完整的筛选后续训练前必须把缺标签图像单独挪出去否则YOLO训练报错或者直接跳过这些样本浪费图像量。2.2 标签格式检查YOLO的txt标签与类别编号要从0开始YOLO格式的标签文件每一行代表一个目标框共5个字段类别编号、中心点x坐标、中心点y坐标、框宽、框高。后面四个值全部是相对于图像宽高的归一化比例取值范围在0到1之间。很多新手拿到标注第一件事就是打开txt看数字看到大几百的像素坐标就以为标签坏了其实那是VOC格式的遗留印象YOLO里出现大于1的坐标才是真的坏了。from pathlib import Path label_dir Path(labels/train) for txt_file in label_dir.glob(*.txt): for line_idx, line in enumerate(txt_file.read_text().strip().splitlines(), 1): parts line.split() if len(parts) ! 5: print(f字段数异常: {txt_file} 第{line_idx}行 - {line}) continue cls_id int(parts[0]) x, y, w, h map(float, parts[1:]) if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): print(f坐标越界: {txt_file} 第{line_idx}行 - {line})这段脚本遍历训练标签目录检查每个标签文件的字段数和坐标范围。字段数不等于5的行直接打印出来坐标值超出[0,1]区间也打印出来这两类脏数据是后续loss不降、mAP归零的头号元凶。类别编号必须从0开始连续编号这份数据集如果只有一个类别“smoke”那么所有标签首列都应该是0如果出现首列为1或者5说明标注时类别定义发生过变化训练前需要统一重映射。2.3 训练前必检图像损坏、空标签、类别不平衡神经网络训练最怕的不是bad case而是训练到一半程序crash。图像文件在传输、打包过程中可能截断PIL打开时抛异常但file命令不一定会报错所以要用逐张加载的方式检查。from PIL import Image from pathlib import Path img_dir Path(images/train) broken [] for img_path in img_dir.glob(*.jpg): try: with Image.open(img_path) as im: im.load() if im.size[0] 32 or im.size[1] 32: print(f尺寸过小: {img_path} - {im.size}) except Exception: broken.append(str(img_path)) print(f损坏图像数: {len(broken)})这段脚本把所有打不开的图像路径收集到broken列表同时打印尺寸小于32x32的异常图。烟雾目标通常占据图像中心区域如果大量图像只有几十像素宽说明这批数据在采集时被压缩过后续训练要降低imgsz或者干脆剔除。空标签同样要处理。标签文件存在但内容为空表示这张图没有任何目标YOLO训练时这类图像会被跳过本身不报错但如果空标签数量超过10%说明标注遗漏严重整个数据集的标签质量要打问号。统计方式很简单find labels -name *.txt -size 0 | wc -l。类别不平衡方面这份数据如果单类smoke就不用担心如果标签里出现两类比如烟和火一定要统计每个类别的框数量比例。比例超过10:1时训练权重会被大类别主导小类别学不出来。常见做法是给少样本类别提高loss权重或者用复制粘贴的方式做类别层面的过采样。检查项正常范围异常信号有图无标签 1%训练时图像被静默跳过有标签无图 1%标签文件找不到对应图空标签文件 5%标注遗漏严重坐标越界0训练loss不降类别编号非0起始0模型无法收敛3. 把这份烟雾数据集喂给YOLO标注转换、目录划分与模型选型3.1 从VOC XML或COCO JSON转换到YOLO TXT的脚本标签格式检查做完可能发现这份数据集实际上带的是VOC XML标注——尤其是标注工具LabelImg默认导出XML格式转YOLO格式是逃不掉的一步。转换脚本的核心逻辑是读XML里的bndbox像素坐标除以图像的宽高得到归一化值。import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_file, out_dir, classes): tree ET.parse(xml_file) 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): name obj.find(name).text if name not in classes: continue cls_id classes[name] box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) if x2 x1 or y2 y1: print(f非法框: {xml_file} - {name}, {x1},{y1},{x2},{y2}) continue cx (x1 x2) / 2 / img_w cy (y1 y2) / 2 / img_h bw (x2 - x1) / img_w bh (y2 - y1) / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) out_path out_dir / (xml_file.stem .txt) out_path.write_text(\n.join(lines) \n if lines else ) classes {smoke: 0} xml_dir Path(Annotations) out_dir Path(labels_yolo) out_dir.mkdir(exist_okTrue) for xml_file in xml_dir.glob(*.xml): voc_to_yolo(xml_file, out_dir, classes)转换脚本中classes字典定义了类别名到编号的映射关系smoke对应0。两个细节值得注意一是x2 x1或y2 y1的非法框直接跳过而不是报错这类数据在手工标注时经常出现纠正成本高但影响面小二是img_w和img_h取的是XML里的size字段不是程序猜的默认值。如果打包时有人批量resize过图像而没同步更新XML这里转换出的坐标就全部错位最常见的就是图是1920x1080但XML里写的是1280x720。转完抽查10张图用OpenCV把标注框画回图上这一步不能省。import cv2 img cv2.imread(images/train/frame_00001.jpg) h, w img.shape[:2] with open(labels_yolo/frame_00001.txt) as f: for line in f: cls, cx, cy, bw, bh line.split() cx, cy, bw, bh float(cx) * w, float(cy) * h, float(bw) * w, float(bh) * h x1, y1 int(cx - bw / 2), int(cy - bh / 2) x2, y2 int(cx bw / 2), int(cy bh / 2) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imwrite(check.jpg, img)如果这份数据集给的本来就是YOLO txt标签跳过转换一步直接跑第2.2节的检查脚本。3.2 目录划分按场景不按随机防止数据泄漏YOLO训练要求划分train和val两个目录常见比例是8:2。很多初学者用random.shuffle把全部图像打乱后按比例分配这在目标检测里是典型的低级错误——如果数据是按视频帧采集的相邻帧高度相似同一段视频的帧被同时分到train和val模型在训练时已经“见过”验证集的内容指标虚高部署后立刻原形毕露。对于烟雾数据这种典型视频监控场景必须按场景或视频片段分组保证同一个场景的所有帧要么全在train要么全在val。import shutil import random from pathlib import Path src_img Path(images) src_lbl Path(labels) train_img Path(yolo/images/train) val_img Path(yolo/images/val) train_lbl Path(yolo/labels/train) val_lbl Path(yolo/labels/val) for d in [train_img, val_img, train_lbl, val_lbl]: d.mkdir(parentsTrue, exist_okTrue) scenes [p for p in src_img.iterdir() if p.is_dir()] random.seed(42) random.shuffle(scenes) val_scenes set(scenes[: int(len(scenes) * 0.2)]) for scene in scenes: for img in scene.glob(*.jpg): label_file src_lbl / (img.stem .txt) if not label_file.exists(): continue is_val scene in val_scenes shutil.copy(img, val_img / img.name if is_val else train_img / img.name) shutil.copy(label_file, val_lbl / label_file.name if is_val else train_lbl / label_file.name)这段脚本假设数据在images目录下按场景分子目录存放符合烟雾数据集的常规采集方式。val_scenes取前20%的场景目录作为验证集random.seed(42)固定随机种子保证每次运行划分结果一致。如果数据没有场景子目录文件名带视频编号前缀也可以按前缀分组核心思路是让验证集和训练集在时间上完全分开。3.3 模型选型YOLOv5s还是YOLOv8n烟雾场景的参数量权衡模型参数量级别推理速度小目标表现内存占用YOLOv5s小快一般低YOLOv8n最小最快偏弱最低YOLOv8s小快中等中YOLOv8m中中较好中高烟雾检测有两个鲜明特点一是目标多为远距离小烟柱在画面里占比往往不到1%二是部署环境通常是摄像头边缘端或低配服务器模型不能太大。因此我一般建议先跑YOLOv8n或YOLOv5s建基线用这份21578张的数据集完成一次完整训练流程确认数据质量和指标量级再根据漏检情况决定是否升级到YOLOv8s。直接上YOLOv8m或x会带来两个问题训练时间长batch尺寸被迫减小导致BN统计不稳定。不要迷信大模型烟雾检测里imgsz和推理策略对小目标的收益经常比模型尺寸提升更明显。4. 用这份数据集训练烟雾检测模型配置、命令与指标监控4.1 数据配置文件data.yaml怎么写给YOLOv8YOLOv8训练的数据配置是一个YAML文件指定数据路径、训练集目录、验证集目录和类别名。写法如下path: /data/smoke100 # 数据集根目录必须是绝对路径或相对当前工作目录的稳定路径 train: images/train # 相对path的训练图像目录 val: images/val # 相对path的验证图像目录 names: 0: smoke # 类别编号0对应烟雾保持和标签文件首列一致把文件保存为smoke100.yaml。path字段是YOLOv8特有的训练时所有相对路径都基于它解析写错就报Dataset not found。如果数据集只有smoke一个类别names只写0这一行就够了nc参数可以省略框架会根据names的长度自动推断类别数。但如果在YOLOv5上训练建议显式加一行nc: 1YOLOv5不写nc也能跑但有警告显式声明更稳妥。如果数据集中还包含fire类别names改为0: smoke和1: fire两行顺序必须和标签首列严格对应。一个隐藏问题是如果标签里某个类别编号在names里不存在YOLO训练时会直接忽略该类别标签而不报错导致mAP掉几个点——用第2.2节的类别统计脚本先打印一遍真实编号再回填names。4.2 训练命令与关键超参数从跑通到收敛数据配置就绪后训练命令在命令行一条执行yolo detect train \ datasmoke100.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ optimizerAdamW \ patience15modelyolov8n.pt表示加载COCO预训练权重做迁移学习不要从随机初始化开始训21578张的烟雾数据从零训需要更长epoch且效果更差。epochs100对这份数据量足够配合patience15的早停机制如果验证集指标连续15个epoch不提升就自动停止省时间。batch16是显存安全值在12GB显卡上能跑显存不够降到8或4。imgsz640是输入分辨率烟雾这类小目标场景建议训练阶段直接拉到960代价是训练时间增加约一倍收益是远距离小烟柱的检出率明显提高。lr00.01是初始学习率YOLOv8默认对AdamW有内部学习率调整策略一般不需要手动改。optimizerAdamW比SGD收敛更快数据量中等时更稳。4.3 训练过程看什么loss曲线和PR曲线不能只看mAP训练启动后终端输出每个epoch的box_loss、cls_loss、dfl_loss以及验证集的mAP50、mAP50-95。很多新手只盯mAP50实际上训练日志里最有价值的是val/box_loss的变化趋势。train loss稳定下降但val loss在某个epoch后反弹上升就是过拟合的典型信号patience机制会帮忙提前截断如果train和val loss都从头到尾纹丝不动优先怀疑数据格式而不是模型结构。训练结束后runs/detect/train/weights/下会生成best.pt和last.ptbest.pt是验证集指标最优的权重。用它对测试图片做一次可视化预测yolo predict modelruns/detect/train/weights/best.pt sourcetest_images/ saveTrue打开保存的预测图重点看漏检和误检。烟雾检测场景里漏检代价远高于误检——消防响应中一次漏报可能造成严重后果。看PR曲线时烟雾检测的决策点建议设在Recall一侧让模型倾向多报再由后续逻辑过滤。mAP是黑匣子综合指标白天的mAP和夜间场景的mAP可能有天壤之别看不到分布就会误判模型能力。把测试集按场景切片分别算mAP才能真正评估这份数据集训出的模型是否可用。5. 烟雾数据集的5个常见坑与排查方法5.1 训练loss不降mAP接近0现象训练跑到第20个epochtrain/box_loss停在0.6以上不往下走val/mAP50始终是0。原因绝大多数情况是标签类别编号错位。数据集标注时smoke从1开始编号而data.yaml里names的0对应smoke模型训练时把所有标注当作未知类别忽略相当于没有监督信号。解决用第2.2节的类别统计脚本打印标签首列的真实编号对照names重新映射把标签里所有首列减1或者改names定义重跑训练。排查时打开一张训练图像检查标签框是否画在烟雾区域附近。5.2 mAP高但漏检严重尤其远处小烟柱检测不到现象验证集mAP50达到0.9但在实际视频里距离摄像头50米外的烟柱全部漏检。原因烟雾目标在整张图里占比太小经过YOLO的backbone下采样32倍后小目标在特征图上可能只剩1个像素特征丢失。imgsz640在模型输入端就已经把远处烟雾压缩没了。解决把训练和推理的imgsz同时提升到960或1280显存不够就保持640训练、推理时采用切片推理——把大图切块后分别预测再合并结果。切片推理能实打实提升小目标召回率典型烟雾项目在imgsz640基础上切片后小目标AP能提升3到5个点。5.3 白天效果好夜间误报爆炸现象白天测试图基本准确夜晚场景里把灯光晕、水蒸气、车尾气全部识别成smoke。原因数据本身绝大部分是白天清晰场景图像。夜间烟雾在光照不足时颜色偏灰蓝边界更模糊模型学到的是“半透明白色团块”灯光晕和蒸汽恰好符合这个特征。解决先明确这份数据集的场景边界训练集里补一些夜间和清晨样本再微调。图像算法层面的颜色增强和白平衡调整帮不上实质忙语义混淆需要靠数据重采样解决。如果项目要求全天候部署收集夜间真实烟雾样本是绕不开的投入。5.4 训练到一半卡死或报CUDA error现象训练正常跑了个多小时突然程序中断报错指向图像解码或CUDA OOM重启后又在上次中断附近的位置复现。原因数据集里有损坏图像PIL能打开但OpenCV打不开或者图像尺寸异常导致数据加载器在某个batch崩掉。另外一个隐蔽原因是压缩包解压后带有一堆跨平台垃圾文件数据加载器遍历时把非图像文件也当作样本喂了进去。解决训练前先跑第2.3节的图像完整性脚本把损坏图像直接移出目录。同时清理__MACOSX、.DS_Store、Thumbs.db等隐藏文件并把文件名全部改为纯英文小写。这类问题在远程服务器上训练时特别坑训练到一半崩掉很打击信心提前检查能省一整天。5.5 验证集mAP虚高部署后掉一半现象训练时mAP50显示0.85模型部署到新场景后实测AP只有0.4差距大得让人怀疑模型被换过。原因数据划分方式出错。视频序列的相邻帧几乎相同随机按图像划分会把同一段烟雾序列同时分进train和val模型在训练时见过的信息直接出现在验证集里测得的分不具备泛化意义。解决按场景目录或视频片段ID划分划分脚本参考第3.2节。如果数据集是单张图片没有序列关系也建议按拍摄地点分组保证同一地点不在训练和验证集里同时出现。这个数据泄漏问题在遥感图像标注和视频监控数据集里尤其普遍。6. 用这份数据集提升真实烟雾检测效果的3个技巧先说最立竿见影的技巧切片推理。这份数据集如果包含大量远距离小目标直接整图推理时小烟柱的特征在下采样后基本损失殆尽。实际部署时把画面按50%重叠切成若干patch每个patch独立送入模型推理再对重叠区域的检测框做NMS合并。YOLOv8配合SAHI库的实现是现成的只需要把sahi包安装后传入模型路径和切片尺寸。一般情况下patch尺寸设为960、重叠率0.2效果最好计算量增加约2倍换来的是小目标召回率从0.6提升到0.85以上的收益。第二个技巧是类别设计上别只留smoke一个类。真实火灾场景中烟雾和火焰几乎同时出现如果模型只负责检测烟火苗区域通常会因为“看起来奇怪”而被误分为烟。工业摄像头画面里蒸汽、灰尘、灯光都是烟的强干扰项。如果手头有公开火焰数据集和这份烟雾数据合并训练类别设为0: smoke, 1: fire模型学到的是“烟与火的伴生关系”判别边界会更清晰。合并时注意第2.2节的类别统计两个类别的框数量尽量控制在5:1以内数量差距大时给fire类别提高loss权重。第三个技巧是迁移学习的分阶段策略。直接用yolov8n.pt从头训练到底不是最优解。我一般分两步先用50个epoch微调整个模型然后用早停选出的最优权重冻结backbone只训练head部分跑20个epoch最后解冻全部层再跑10个epoch收尾。这个节奏能避免烟雾这种弱纹理目标在小数据集上把backbone的特征带偏三个阶段的验证集指标逐步爬升。我自己做烟雾检测项目的习惯是先定验收指标再碰数据——把“漏检率低于多少、误报每小时不超过几次”写清楚再回头检查这21578张图像的标签是否支撑这个目标。数据检查花30分钟最小训练跑通花1小时后面才是真正的调参。这份数据集值得投入的方向是有的但前提是你按第2章的清单把标签质量确认清楚否则再多图像也只是让模型在错误标注上过拟合。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?