news 2026/10/14 3:42:25

YOLO格式火灾检测数据集实战:从标注解析到训练调优

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLO格式火灾检测数据集实战:从标注解析到训练调优

简介:一套面向火灾目标检测的YOLO格式数据集,训练集含174张真实场景火灾图像,覆盖近景火焰、烟雾扩散及复杂背景等多种形态,适用于智能安防监控、无人机火灾巡查、消防研究与模拟训练、智慧城市安全平台等场景,帮助开发者构建和验证火灾识别模型。数据包共350个文件,以174个jpg原图和174个txt标注文件为主体,另含1个yaml配置文件和1个docx数据说明文档,压缩包仅8.78MB。每个txt文件对应一张jpg图像,标注信息为归一化中心点坐标(x,y)与宽高(w,h),所有边界框均严格标注火焰核心区域,可直接用于YOLOv5/v8、Faster R-CNN等主流框架,支持迁移学习与模型微调。已有173人学习下载,适合智能安防、智慧城市等领域的算法工程师和研究人员快速上手。

1. 火灾检测数据集:YOLO格式的火焰与烟雾标注,先搞懂它解决哪个问题

火灾目标检测数据集的稀缺性,做过安防或工业巡检的人体会最深。标注火焰和烟雾的样本往往需要从真实监控视频里逐帧提取,还要躲开阳光、车灯、焊接火花这类干扰,一份能直接落地的YOLO格式标注数据,省掉的不只是采集时间,还有反复核对的精力。这份资源把火焰与烟雾目标整理成了标准的目标检测格式,类别定义清晰,文件组织整齐,适合正在做行业视觉方案、需要快速验证检测效果的开发者。新手拿到手能直接训练并跑通流程,有经验的人也能用它作为迁移学习的底料。第一章先不展开技术细节,只说结论:这份数据集解决的是「从零攒数据」的问题,下面几章讲清楚数据结构、训练方法和踩坑点。

2. 目录结构与标注格式:把火焰和烟雾从图片里“读”出来

2.1 目录结构:images 与 labels 的对应逻辑

一份合格的目标检测数据集,目录组织往往决定了你会不会在训练前浪费半天时间。拿到压缩包解压后,典型的YOLO风格目录长这样:

fire_dataset/ ├── images/ │ ├── train/ │ │ ├── fire_001.jpg │ │ ├── fire_002.jpg │ │ └── ... │ ├── val/ │ │ └── ... │ └── test/ │ └── ... ├── labels/ │ ├── train/ │ │ ├── fire_001.txt │ │ ├── fire_002.txt │ │ └── ... │ ├── val/ │ │ └── ... │ └── test/ │ └── ... └── fire_config.yaml

images 和 labels 两个主目录各自带上 train、val、test 子目录,这是最常见的划分方式。训练时需要重点确认:图片和标注文件是否同名。这里有个容易翻车的细节——同名指的是主文件名一致,扩展名不同,比如fire_001.jpg对应fire_001.txt,没有任何额外前缀或后缀。自己写过数据划分脚本的人都知道,文件名对不上是最隐蔽的错误,程序不报错,但模型学到的东西是错的。

查看完整目录树用一条命令:

# 在 fire_dataset 上级目录执行 find fire_dataset -type f | head -50 # 预期输出:images/train/fire_001.jpg、labels/train/fire_001.txt 等

find命令列出所有文件,head -50只取前 50 行,目的是快速确认目录骨架和文件命名规律。如果发现某些 jpg 没有对应的 txt,或者 txt 是空文件,说明标注时有漏标或跳帧,这一步提前发现,比训练到一半再排查省事得多。

2.2 标注文件解析:txt 里每一行代表什么

YOLO 格式的标注文件不需要 JSON 那种嵌套结构,每行描述一个目标框,格式固定为:

class_id x_center y_center width height

四个坐标值全部是相对图片尺寸的归一化小数。举个例子:一张 1920×1080 的图片里有一个火焰框,框左上角在像素坐标 (100, 50),右下角在 (300, 250),换算过程是:

x_center = (100 + 300) / 2 / 1920 = 0.1042 y_center = (50 + 250) / 2 / 1080 = 0.1389 width = (300 - 100) / 1920 = 0.1042 height = (250 - 50) / 1080 = 0.1852

实际标注文件里的内容长这样:

0 0.1042 0.1389 0.1042 0.1852 1 0.6200 0.4800 0.1500 0.2200

第一列是类别 ID,第二、三列是中心点坐标,第四、五列是宽高。注意宽度和高度也可能是归一化后的比例值,不可能是像素绝对值,因为训练时模型会把图片缩放到固定尺寸,归一化坐标才能保持一致。

写个脚本快速解析标注文件,确认类别分布和坐标范围是否正常:

# parse_labels.py import os label_dir = "fire_dataset/labels/train" class_counter = {} coord_errors = 0 for filename in os.listdir(label_dir): if not filename.endswith(".txt"): continue with open(os.path.join(label_dir, filename), "r") as f: for line in f: parts = line.strip().split() if len(parts) != 5: print(f"[格式异常] {filename} 行内容: {line.strip()}") continue cls = int(parts[0]) x, y, w, h = map(float, parts[1:]) class_counter[cls] = class_counter.get(cls, 0) + 1 # 坐标越界检查 if not (0 <= x <= 1 and 0 <= y <= 1 and 0 <= w <= 1 and 0 <= h <= 1): coord_errors += 1 print(f"[越界] {filename} 坐标: {line.strip()}") print("类别统计:", class_counter) print("坐标越界行数:", coord_errors)

脚本先按行拆分标注文件,类别 ID 存入计数器,坐标全部检查是否在 0 到 1 区间内。越界的原因通常是标注工具导出时换算出错,或者手工改过 txt。这个检查是训练前必走的一步,越界框在 Mosaic 增强时会被放大成整张图的色块,害模型学出幻觉。

3. 训练前处理:数据划分、YOLO 配置与首次训练

3.1 数据划分:train/val/test 的生成脚本

拿到手的数据集如果已经分好目录,这一步可以跳过。但很多情况下,资源包只给了全部图片和全部标注,需要自己做划分。常见比例是训练 80%、验证 10%、测试 10%。划分的原则是随机抽样时要保证各类别比例均衡,不能出现火焰全在训练集、烟雾全在测试集的情况。

# split_dataset.py import os import random import shutil random.seed(42) src_images = "fire_dataset/images" src_labels = "fire_dataset/labels" dst_base = "fire_dataset_split" # 先收集所有图片和对应标注 image_files = [f for f in os.listdir(src_images) if f.endswith(".jpg")] label_files = [f for f in os.listdir(src_labels) if f.endswith(".txt")] # 确保图片和标注文件名一致 valid_pairs = [] for img in image_files: base = img.replace(".jpg", "") lbl = base + ".txt" if lbl in label_files: valid_pairs.append((img, lbl)) print(f"有效样本对: {len(valid_pairs)}") random.shuffle(valid_pairs) # 按比例划分 train_n = int(len(valid_pairs) * 0.8) val_n = int(len(valid_pairs) * 0.1) splits = { "train": valid_pairs[:train_n], "val": valid_pairs[train_n:train_n + val_n], "test": valid_pairs[train_n + val_n:], } for split_name, pairs in splits.items(): img_dir = os.path.join(dst_base, "images", split_name) lbl_dir = os.path.join(dst_base, "labels", split_name) os.makedirs(img_dir, exist_ok=True) os.makedirs(lbl_dir, exist_ok=True) for img, lbl in pairs: shutil.copy(os.path.join(src_images, img), img_dir) shutil.copy(os.path.join(src_labels, lbl), lbl_dir) print("划分完成")

random.seed(42)固定随机种子,保证每次运行生成同样的划分结果,这是可复现实验的底线。valid_pairs里只保留成对的图片和标注,防止后面训练时出现空标注。最后的拷贝而不是移动,是因为原始数据最好保留一份,划分失误时还有后悔药。

3.2 训练配置:yaml 文件与关键参数

YOLO 系列训练前需要准备一个数据集描述文件,内容很直接:

# fire_config.yaml path: /absolute/path/to/fire_dataset_split train: images/train val: images/val test: images/test nc: 2 names: 0: fire 1: smoke

path写成绝对路径最稳妥,有些版本对相对路径的解析有坑。nc是类别总数,必须和标注文件里出现的最大类别 ID 匹配。这里只列了 2 个类别,具体以这套数据集的标签规范为准。如果nc写大了,模型输出维度变宽,训练速度变慢且容易过拟合;写小了,训练直接报索引越界的错。

训练命令按你用的框架来,开源目标检测框架这块已经非常统一:

# 以常见 YOLO 训练入口为例 python train.py \ --yaml fire_config.yaml \ --weights yolov8s.pt \ --imgsz 640 \ --epochs 100 \ --batch-size 16 \ --device 0

参数说明:--yaml指定数据集配置文件,--weights是预训练权重,yolov8s.pt这种模型体量兼顾速度和精度,适合第一次跑通流程。--imgsz 640是训练时的输入分辨率,火焰和烟雾这类目标尺寸浮动很大,640 是合理起点,先保证流程通顺再调参。--epochs 100对工业级数据集不算多,但如果只有几百张图,100 轮已经足够过拟合测试了。

3.3 首次训练后的验证:先看哪些指标

训练结束会得到一堆指标,重点看三样:验证集上的 mAP@0.5、mAP@0.5:0.95、PR 曲线。mAP@0.5 是 IoU 阈值设 0.5 时的平均精度,数值高代表框得准;mAP@0.5:0.95 把阈值从 0.5 到 0.95 按步长计算平均,数值比前者低是正常的,它更苛刻,小目标在这项上掉分最明显。

第一次训练后的正确操作不是马上调参,而是打开验证集的预测图片,逐张看火焰有没有框住、烟雾有没有被漏掉。指标是黑匣子,图片是透明的,一眼能看出模型学到的是火焰本身的颜色纹理,还是把夕阳误判成火灾。

4. 避坑与常见问题:标注错位、类别失衡与漏检排查

数据集训练过程中翻车的地方,多数不在模型结构,而在数据本身的隐藏问题。以下四条是从实操里提炼的高频踩坑记录,照着排查能省下不少时间。

4.1 现象:训练时 loss 正常下降,但验证集 mAP 极低

原因:标注坐标与图片内容错位。常见触发场景是有人批量处理图片后改了分辨率,但标注文件还是按旧尺寸归一化的,或者标注时选了错误类别 ID。这个时候模型的损失函数在收敛,学的是混乱的映射关系。

解决:写脚本随机抽查 20 组图片与标注,把框画到图上人工查看:

# draw_boxes.py import cv2 import os img_dir = "fire_dataset/images/val" label_dir = "fire_dataset/labels/val" names = ["fire", "smoke"] for fname in sorted(os.listdir(img_dir))[:10]: img = cv2.imread(os.path.join(img_dir, fname)) if img is None: continue h, w = img.shape[:2] base = fname.replace(".jpg", "") txt_path = os.path.join(label_dir, base + ".txt") if not os.path.exists(txt_path): continue with open(txt_path) as f: for line in f: parts = line.strip().split() cls = int(parts[0]) x, y, bw, bh = map(float, parts[1:]) x1 = int((x - bw / 2) * w) y1 = int((y - bh / 2) * h) x2 = int((x + bw / 2) * w) y2 = int((y + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, names[cls], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) save_path = f"check_{base}.jpg" cv2.imwrite(save_path, img) print(f"已保存 {save_path}")

这段脚本把归一化坐标还原成像素坐标并画框,保存到当前目录。人工扫一眼就能判断标注是否准确。如果发现框大面积偏移或类别明显标错,最有效的解决方式是回到标注源头修正,不要靠训练时的数据增强硬拉回来。

4.2 现象:训练时直接报 IndexError 或者类别维度不一致

原因:标注文件里出现了配置文件中的nc未包含的类别 ID,比如nc: 2但标注里有class_id = 2。这种情况多半是数据来自多个来源拼接,某个来源的类别起始编号不是 0。

解决:用解析脚本统计所有 txt 里出现的类别 ID,看是否有跳号或超范围:

# 利用前面的 parse_labels.py 输出类别统计 python parse_labels.py # 看到 class_counter = {0: 1200, 1: 300, 2: 150} 时, # 就知道 nc 至少要写成 3,或者要把类别 2 重新映射

如果确认只有两类,但第三类出现次数很少,可以直接将其合并到最近语义的类别里。注意合并时要同步修改fire_config.yaml里的names描述。

4.3 现象:小目标火焰漏检,特别是远处或视频低分辨率下的火焰

原因:半个屏幕都是大面积火焰的样本占了绝大部分,小目标样本占比太低。模型在特征提取阶段对大目标响应强,小目标的特征图已经缩到几乎没有像素可用了。

解决:有两个方向。一是训练时提高输入分辨率,--imgsz 1280看模型显存能不能承受;二是数据层面做小目标复制粘贴增强,把标注框缩放到小尺寸后随机贴到背景图上,同时生成对应标注行:

# paste_small_objects.py 核心逻辑 import random import shutil import cv2 import os def paste_small_objects(src_img, src_label, dst_img, dst_label): img = cv2.imread(src_img) h, w = img.shape[:2] with open(src_label) as f: boxes = [] for line in f: parts = line.strip().split() cls = int(parts[0]) x, y, bw, bh = map(float, parts[1:]) boxes.append((cls, x, y, bw, bh)) new_boxes = [] for cls, x, y, bw, bh in boxes: # 只缩小不放大,让目标更小 scale = random.uniform(0.2, 0.6) new_w = bw * scale new_h = bh * scale new_cx = random.uniform(0, 1) new_cy = random.uniform(0, 1) new_boxes.append((cls, new_cx, new_cy, new_w, new_h)) # 将原标注和增强标注合并写回 with open(dst_label, "w") as f: for cls, x, y, bw, bh in boxes: f.write(f"{cls} {x:.4f} {y:.4f} {bw:.4f} {bh:.4f}\n") for cls, x, y, bw, bh in new_boxes: f.write(f"{cls} {x:.4f} {y:.4f} {bw:.4f} {bh:.4f}\n") # 图片层面不需要改动,框是虚拟粘贴 shutil.copy(src_img, dst_img)

代码只调整标注框,不实际修改图片像素,等于告诉模型某些小位置也有目标,逼它学习更细粒度的特征。实际工程中这种做法能有效缓解小目标漏检,注意缩放系数别太小,否则框只有几个像素,超出网络下采样后的感受野覆盖范围。

4.4 现象:烟雾类别 mAP 低,火焰类别表现好

原因:类别样本量极度不均衡,火焰样本可能是烟雾的几十倍。烟雾本身边界模糊、透明度高,标注不一致的问题也比火焰严重。

解决:先统计两个类别的框数量,若烟雾明显少,通用手段是给烟雾样本更高的损失权重。YOLO 系列框架通常在配置文件里不直接支持类别权重,但可以通过重复采样烟雾图片来等价实现:

# 把烟雾相关的图片多复制几份到 train 目录 # 注意同时复制同名 txt,并重命名避免覆盖 # 比如 smoke_train.txt 复制为 smoke_train_extra1.txt 等

简单说,把样本量小的类别复制到训练集里,模型过拟合风险会增加,但总比类别被压制住强。这种做法治标不治本,真正有效的还是补充更多真实烟雾场景的标注数据。

5. 数据质量体检:用脚本验证标注的可用性与边界情况

5.1 统计每个类别的样本量与框数

训练前不体检,训练中翻车是大概率事件。最基础的体检是统计每张图的类别分布、总框数、每类框数,把数据集的构成摸清楚。下面的脚本汇总这些指标:

# inspect_dataset.py import os from collections import defaultdict label_dirs = ["fire_dataset/labels/train"] total_images = 0 image_with_boxes = 0 class_box_count = defaultdict(int) box_per_image = [] for ld in label_dirs: for fname in os.listdir(ld): if not fname.endswith(".txt"): continue total_images += 1 count = 0 with open(os.path.join(ld, fname)) as f: for line in f: parts = line.strip().split() if len(parts) == 5: cls = int(parts[0]) class_box_count[cls] += 1 count += 1 if count > 0: image_with_boxes += 1 box_per_image.append(count) print(f"标注文件总数(图片数): {total_images}") print(f"含目标的图片数: {image_with_boxes}") print(f"空标注文件数: {total_images - image_with_boxes}") print(f"每类框数: {dict(class_box_count)}") avg_boxes = sum(box_per_image) / len(box_per_image) if box_per_image else 0 print(f"平均每张图框数: {avg_boxes:.2f}")

两个指标特别值得关注:空标注文件数和平均每张图框数。空文件多说明采集时有很多背景帧被保留,这些帧作为负样本在目标检测里用处有限,还可能降低精度;平均每张图框数小于 1,说明大多数图片没有目标,训练时负样本占比过高。

5.2 边界框质量检查:越界、宽高比、极端小目标

很多数据集的问题不在目标数量,而在标注质量。常见标识是:坐标越界(前面解析脚本已查)、宽高比极端、框过小。宽高比极端的情况,比如火焰框宽高比超过 10,通常是标注时拖框失误;框过小则是目标真的小,或者远处火焰只占几个像素。检查脚本不需要复杂逻辑,直接在统计层面筛出潜在问题:

# quality_check.py import os from collections import defaultdict label_dirs = ["fire_dataset/labels/train"] ratio_outliers = 0 tiny_boxes = 0 box_area_sum = 0 box_area_count = 0 for ld in label_dirs: for fname in os.listdir(ld): if not fname.endswith(".txt"): continue with open(os.path.join(ld, fname)) as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue x, y, w, h = map(float, parts[1:]) area = w * h box_area_sum += area box_area_count += 1 if area < 0.001: # 面积占整图千分之一以下 tiny_boxes += 1 if w / h > 10 or h / w > 10: ratio_outliers += 1 print(f"框总面积均值: {box_area_sum / box_area_count:.5f}") print(f"极小目标框数量: {tiny_boxes}") print(f"极端宽高比框数量: {ratio_outliers}")

面积阈值0.001是我常用的经验值,对应 640×640 输入下大约 4096 像素,低于这个值目标已经很难被有效检测。极值编号采集后人工抽查一下,如果数量多,建议删除这批样本。保留极端宽高比会让模型对锚框尺寸的适配产生干扰。

5.3 从体检结果决定是否清洗数据集

体检完成之后,处理策略不是统一的。常见决策流程是:空标注文件占比超过 20%,建议重新检视拍摄流程;极小目标框占比超过 10%,先做小目标增强而不是直接清洗;极端宽高比框数量多,优先人工核验再决定是否删除。数据清洗本身没有标准答案,但一个可遵循的原则是:先看异常样本是否可解释,不可解释的就删,可解释但要保留的,至少要在训练日志里记录下来,方便回头排查。

这块的产出是把数据集从一个“可以跑”的状态升级成“可信赖”的状态,后续训练和调参都建立在可信数据上。

6. 进阶用法:小目标优化与迁移训练的两个技巧

6.1 切图训练:让模型看见更小的火焰

对监控这类高分辨率大画幅场景,一个常见技巧是把原图切成 640×640 的小块再训练。切图时注意切出来的小块要保持标注框的形状信息,同时要处理好被切到边缘的目标框。

# 借助 imgsz 参数配合切图工具,把每张大图切为 4 张子图 # 子图包含原目标的全部或部分,大部分框架自带 slice 参数, # 或用 python 脚本按 stride 切块后重新生成对应 yolo 标注

切图训练的代价是训练时间变长、样本总量膨胀,但小火焰在缩小的 feature map 上可辨识度明显提高。如果你的场景是高空摄像头、大空间厂房,这个方法优先级很高。

6.2 迁移训练:从预训练权重出发,别从零开始

哪怕数据集只有几百张图,训练也可以不从头开始。加载通用目标检测预训练权重,火焰和烟雾的底层特征(纹理、边缘、色彩)和预训练任务有一定的共性。这种做法可以显著缩短收敛时间,尤其在数据量不足时能避免训练发散。

# 指定预训练权重路径,并冻结前几层 python train.py \ --yaml fire_config.yaml \ --weights pretrained.pt \ --freeze 10 \ --epochs 80

--freeze 10表示冻结前 10 层参数,保留预训练的低层通用特征,只更新高层语义特征。数据多时可减少冻结层数,数据少时可以多冻结几层。迁移训练效果的验证不只看 mAP 上升多少,还要看验证集预测图片上误检是否减少,特别是把阳光反射、红色车灯误检成火焰的情况。

我把迁移训练作为每次换场景时的默认起点。经历过的教训是:有一回在夜间监控场景下从零训练,跑到 200 轮 mAP 还在 0.3 徘徊,后来加载预训练权重重训,60 轮就突破到 0.75。从那以后,每次拿到新的火灾检测数据集,我第一件事就是用parse_labels.py过一遍标注,再看一遍类别统计,最后才决定训练策略。这份数据集本身够规整,但数据质量这事不能只看文件大小,每一步核查都值得,希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 3:42:16

MapReduce初级编程实践:从WordCount到shuffle机制与避坑指南

简介&#xff1a;《大数据技术原理与应用》实验报告四围绕MapReduce初级编程实践&#xff0c;是一份面向计算机专业学生、大数据初学者及相关开发者的完整技术报告。资源为单个docx文档&#xff0c;压缩包体积为10.48MB&#xff0c;基于VMWare虚拟机、Ubuntu、JDK1.8、Hadoop与…

作者头像 李华
网站建设 2026/10/14 3:42:08

栈与数制转换:C语言数据结构经典组合实战

简介&#xff1a;面向C语言初学者的数制转换实例代码讲解&#xff0c;完整演示如何借助顺序栈实现十进制到八进制等进制的转换。资源以严蔚敏《数据结构》中的数制转换算法为蓝本&#xff0c;将伪代码转化为可运行、可调试的C程序&#xff0c;覆盖顺序栈的初始化、压栈、出栈、…

作者头像 李华
网站建设 2026/10/14 3:41:54

2025智能驾驶白皮书解读:从技术分级到端到端与数据闭环的落地判断

简介&#xff1a;《汽车智能驾驶技术及产业发展白皮书》PDF电子版由中国汽车技术研究中心、清华大学与华为联合编写&#xff0c;面向智能网联汽车产业研究者、车企工程师与政策制定者&#xff0c;旨在系统梳理智能驾驶技术演进、产业生态与安全落地路径。资源为单个PDF文件&…

作者头像 李华
网站建设 2026/10/14 3:40:44

上海浦东张江壁挂炉维修|博世壁挂炉维修预约|附近持证师傅上门检修|欧米到家报修热线

&#x1f525; 壁挂炉是家庭中冬季24小时不间断供暖与供热水的核心设备&#xff0c;一旦突发不点火、不加热、漏水异响或显示屏报错&#xff0c;全家取暖和热水往往立刻受影响。上海家庭使用的壁挂炉品牌繁多&#xff0c;电控逻辑和燃烧结构差异较大。本文系统梳理上海地区壁挂…

作者头像 李华
网站建设 2026/10/14 3:40:44

PyTorch U-Net城市遥感水体识别实战:从假彩色影像到二值掩膜全流程

简介&#xff1a;这是一套面向城市区域水体提取的开箱即用实战资源&#xff0c;适合遥感、计算机视觉方向的学生与开发者&#xff0c;可用于本科毕业设计、课程大作业或轻量级水体监测原型开发。资源以高分辨率城市遥感影像为对象&#xff0c;集成U-Net与AttU-Net两种主流分割网…

作者头像 李华
网站建设 2026/10/14 3:40:44

VS2022安装与插件指南:工作负载选型、静默安装与避坑实践

简介&#xff1a;这份资源面向C/C初学者及希望快速上手Visual Studio 2022的开发者&#xff0c;围绕集成开发环境的安装配置与插件扩展展开&#xff0c;帮助解决从下载安装到日常编码调试中的常见问题。压缩包共3个文件&#xff0c;约6KB&#xff0c;以html页面为主体承载指南内…

作者头像 李华