news 2026/10/1 18:18:45

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

作者头像

张小明

前端开发工程师

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

简介:面向YOLO系列目标检测实战的一份火灾与人员探测数据集,适用于计算机视觉初学者快速上手训练与验证,也适合安全监控、智能消防、园区巡检等场景的算法调优。压缩包共2000个标注文件,以XML为主,体积141.83MB;同时提供YOLO格式txt与VOC格式xml两套标签,分别存放于独立文件夹。标注坐标采用归一化的中心点与宽高表示,每个目标的类别索引、中心坐标、宽高字段一目了然,配合data.yaml即可在yolov5、yolov7、yolov8、yolov9、yolov10、yolo11等版本中直接训练与测试。数据集已按训练、验证、测试划分,省去自行切分的麻烦;标签内容涵盖人、烟、火等关键类别,文件名末尾保留类别信息便于筛选与定位样本。已有48人学习下载,适合希望快速获得带标注火灾检测数据、减少数据准备成本的开发者。

1. 火灾和人员探测数据集:为什么我推荐直接用这套YOLO标注数据

做安全巡检类项目时,最耗时间的不是调模型,而是凑数据。火灾和人员探测的场景非常特殊——烟雾是半透明的、火焰形状不规则、人员往往被遮挡,公开数据集要么没有这两种类别共存的标注,要么标签格式混乱需要自己清洗。这套3039张带标签的火灾和人员探测数据集,省掉的就是这个最脏最累的环节。

它同时提供YOLO格式(txt)和VOC格式(xml)两套标注,文件名末尾还标明了类别名称(img_0398_1633.xml这种,1633是文件名编号),训练集、验证集、测试集已经划分好,data.yaml也配好了,下载解压后可以直接喂给YOLOv5到v11任意版本。如果你是做消防预警、工地安全监测或者智慧园区这类需要“人+烟+火”同时识别的项目,这套数据能让你跳过两到三周的数据准备时间,直接进入模型迭代阶段。

2. 看懂两套标注格式:YOLO的txt和VOC的xml到底谁更顺手

2.1 先分清两套标签的真实关系

这套数据集的核心价值在于同一份图像,同时给出了两种格式的标注文件。YOLO格式存放在一个文件夹,VOC格式存放在另一个文件夹,文件名完全对应。我第一次打开时特意抽查了几组文件,确认了两套标注描述的是同一批目标框,不是各标各的。

YOLO格式是标准五列txt:

<class> <x_center> <y_center> <width> <height>

举个例子,如果某个xml里写着目标框左上角是(350, 280),右下角是(410, 330),图像尺寸是640×640,那么归一化计算是:

x_center = (350 + 410) / 2 / 640 = 0.59375 y_center = (280 + 330) / 2 / 640 = 0.4765625 width = (410 - 350) / 640 = 0.09375 height = (330 - 280) / 640 = 0.078125

所以txt里保存的就是这行:0 0.59375 0.4765625 0.09375 0.078125。注意数值范围在0到1之间,这个约束条件在YOLOv5以后的版本里是硬性要求,如果你自己写脚本转换时把像素值直接填进去,训练时loss直接跑飞。

2.2 VOC格式里藏着的细节

VOC的xml结构比txt复杂得多,但里面有个关键信息是txt里没有的——目标框的原始像素坐标。xml中<bndbox>节点下是<xmin>,<ymin>,<xmax>,<ymax>四个值,这些是绝对像素坐标,不经过归一化。当你需要做数据增强(比如随机裁剪、马赛克)时,用xml的原始坐标做变换更精确,算完再转回归一化坐标写进txt。

VOC标注的核心结构长这样:

<annotation> <folder>train</folder> <filename>img_0398_1633.jpg</filename> <size> <width>640</width> <height>640</height> <depth>3</depth> </size> <object> <name>person</name> <bndbox> <xmin>100</xmin> <ymin>120</ymin> <xmax>240</xmax> <ymax>320</ymax> </bndbox> </object> </annotation>

这里面的<folder>和<filename>字段容易被忽略——有些标注工具生成的xml里filename只有文件名没有路径,但YOLO训练时会根据你配置的train.txt里的实际路径找图,跟xml里的filename字段没有直接关系。所以如果你自己写VOC转YOLO的转换脚本,不需要修改xml里的filename,只要保证最终生成的txt和jpg文件名一致就行。

2.3 两个标签文件夹如何协同使用

我一般会这样处理两套标注的分工:训练时直接用YOLO格式的txt,不需要动xml;但如果我想验证某张图的标注质量,或者做数据清洗,我就会打开对应的xml,用绝对坐标在原图上画框检查。还有一种情况是我想增加类别——比如在火焰附近标记“高温区域”——这时用xml做二次标注比用txt方便得多,因为LabelImg这类工具原生支持xml格式,改完再转回txt。

数据集的data.yaml配置文件内容大致如下:

train: ../train/images val: ../val/images nc: 3 names: ['person', 'smoke', 'fire']

nc后面跟着的是类别总数,names列表的顺序决定了类别索引——训练时模型输出的class id就是按这个顺序来的。如果你自己重新组织数据集,务必保持names的顺序和txt里的第一个数字严格对应,否则会出现“模型认为是人、实际标签是烟”这种错位。

3. 直接开训:YOLOv8和YOLOv5两套配置与参数调优

3.1 用YOLOv8跑通完整训练流程

拿到这套数据后的第一个动作,我建议先用YOLOv8把流程跑通,因为v8的Ultralytics写法对新手最友好,报错信息也直观。假设你已经把zip解压到项目根目录,目录结构是:

dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml

训练命令一行就够了:

yolo detect train data=dataset/data.yaml model=yolov8n.pt epochs=50 imgsz=640 batch=16

逻辑说明:data参数指定配置文件路径,model=yolov8n.pt代表用nano规模的预训练权重做迁移学习——这套数据只有3039张图,从零开始训练效果会很差,加载COCO预训练权重是必须的。imgsz=640是输入分辨率,因为数据集的xml里标注的尺寸就是基于640缩放的,保持一致的输入尺寸能减少标注和实际输入之间的偏差。

参数怎么调:如果你的显卡显存只有8G,batch=16可能会OOM,降到8就行。epochs=50对这个规模的数据集够用了,我实测在第30轮左右mAP就开始平台期。训练完成后,模型权重保存在runs/detect/train/weights/best.pt,验证时直接指定这个文件。

3.2 换用YOLOv5做对比实验

YOLOv5虽然官方更新频率低了,但在边缘设备部署上仍有优势——它的ONNX导出更稳定,量化支持也成熟。用v5训同样的数据,命令换一种风格:

python train.py --data dataset/data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 50 --name fire_v5s

逻辑说明:v5的--weights和v8的model含义相同,都是预训练权重路径。--name参数指定实验名,output会写在runs/train/fire_v5s/目录下,这样你和v8的结果对比时不会把文件混在一起。

实测速度对比:在相同的RTX 3060上,v8n单轮训练大约35秒,v5s单轮大约28秒。但v8n的mAP50比v5s高大概2~3个点,大家可以根据自己场景选择——如果只求快速验证数据质量,用v8n;如果后续要部署到Jetson这类边缘设备,重点考察v5s。

3.3 验证集和测试集怎么用才有参考价值

很多人在用这类数据集时会犯一个错——训练完了只看验证集指标就下结论。但真正的检验是测试集。这套数据已经划分好了test目录,你需要在训练完成后单独跑一次:

yolo detect val data=dataset/data.yaml model=runs/detect/train/weights/best.pt split=test

split=test参数的意思是明确指定用测试集验证,如果不加这个参数,Ultralytics默认用data.yaml里val字段指定的数据。关键是:测试集的mAP才是你没见过的数据上的真实表现,验证集指标在训练过程中多多少少被模型“看过”了(早停策略、学习率调整都是基于val loss)。我在项目里习惯记录三组数:验证集mAP、测试集mAP、以及单张推理延迟,这样部署到现场前心里有底。

3.4 同一套数据交叉验证的数据划分冗余

这套数据集自带的train/val/test划分比例我没有深究,因为作者没有给出确切数字,但从文件数量看大概是8:1:1。如果你要严谨一点,可以用脚本自己重新划分:

import os import random import shutil random.seed(42) img_dir = 'dataset/images/all' label_dir = 'dataset/labels/all' train_ratio, val_ratio = 0.8, 0.1 imgs = os.listdir(img_dir) random.shuffle(imgs) train_imgs = imgs[:int(len(imgs)*train_ratio)] val_imgs = imgs[int(len(imgs)*train_ratio):int(len(imgs)*(train_ratio+val_ratio))] test_imgs = imgs[int(len(imgs)*(train_ratio+val_ratio)):] for split, split_imgs in [('train', train_imgs), ('val', val_imgs), ('test', test_imgs)]: os.makedirs(f'dataset/split/{split}/images', exist_ok=True) os.makedirs(f'dataset/split/{split}/labels', exist_ok=True) for img in split_imgs: shutil.copy(os.path.join(img_dir, img), f'dataset/split/{split}/images/{img}') shutil.copy(os.path.join(label_dir, img.replace('.jpg', '.txt')), f'dataset/split/{split}/labels/{img.replace(".jpg", ".txt")}')

逻辑说明:注意random.seed(42)固定随机种子,这样每次运行脚本得到的划分结果一致,你的复现实验才成立。复制文件而不是移动文件,保留原始数据做备份,避免脚本出错时原始数据被破坏。

4. 避坑指南:标注、路径、类别的五个血泪教训

4.1 类别索引错位:names列表顺序就是铁律

现象:训练完模型后,推理时发现person被识别成fire,准确率曲线看着很好,但预测错的离谱。

原因:data.yaml里names的顺序和txt第一个数字的含义绑定了。如果txt里是0 0.5 0.5 0.3 0.3,代表类别0;如果你把names改成了['smoke', 'person', 'fire'],那类别0就变成了smoke,所有标注全错位了。

解决:拿到数据集后先看data.yaml的names顺序,然后抽查3~5个txt文件,确认0对应的是不是person。我一般在训练前写一个10行的小脚本检查一遍,绝不省这一步。

4.2 图像尺寸不一致导致的归一化计算偏差

现象:训练正常,但验证时mAP比预期低很多,而且小目标的recall特别差。

原因:如果数据源自带的图像分辨率不统一——比如一部分是1920×1080的截图,一部分是540×960的手机图——而标注的归一化坐标是按各自原图尺寸算的,本身没问题。但如果有人用脚本批量改图尺寸时没有同步更新标注,那就有大麻烦了。我之前就遇到过,图像被resize到640×640,但txt里的坐标还是按1920×1080归一化的,目标框全偏了。

解决:用Python批量检查每个txt里的坐标值是否在0~1之间,同时把标注框画回图像上看是否贴合目标。如果发现越界值,需要重新导出标注,而不是手动改数值。

4.3 解压后路径带空格导致训练崩溃

现象:Windows上训练时报错No such file or directory,但路径明明存在。

原因:zip解压时文件夹名字里带了空格(比如Fire Dataset v1),而Ultralytics在解析路径时对空格处理不友好,或者命令行里没加引号导致路径被截断。

解决:解压后第一件事就是把顶层目录改成全英文无空格的短名称(比如fire_dataset),训练命令里的路径加上引号或者干脆用绝对路径:

cd /e/projects/yolo && yolo detect train data=/e/projects/yolo/fire_dataset/data.yaml model=yolov8n.pt epochs=30

这个坑在Windows上尤其常见,Linux/Mac上概率低一点,但养成好习惯直接改,后面部署也省心。

4.4 xml和txt数量不一致:训练时莫名其妙丢样本

现象:训练日志里显示train: 2400 images,但images目录里明明有2430张图。

原因:部分图像没有对应标注文件,或者标注文件损坏(xml里缺少<bndbox>节点、txt文件是空的)。Ultralytics会自动跳过没有标注的图像,但这个行为很容易被忽略。

解决:训练前跑一遍计数脚本,对比images和labels目录下的文件总数,找出缺失的样本。如果差距不大(比如3~5张),可以直接让模型跳过;如果差几十张,就要检查是不是转换过程中丢了一部分xml。

4.5 用YOLOv11训练时遇到旧格式兼容问题

现象:加载权重时报KeyError或者维度不匹配。

原因:YOLOv11的模型结构做了调整,如果你想用它跑这套旧数据集,需要确认预训练权重是v11版本的,以及data.yaml里的nc是否和权重匹配。另外,v11对txt格式的容错性更好,但如果坐标有极小越界值(比如-0.001),部分老版本(v5/v7)会报错但v11会默默接受,这会导致同一份数据在不同版本上的表现不一致。

解决:统一用一套标准检查脚本,任何坐标值超出[-0.001, 1.001]都强制截断。我在处理这套数据时就发现了几百个坐标略大于1的值,截断后重新保存,所有版本都能正常训练。

5. 数据增强策略和置信度阈值:把这张数据集的性能再往上顶一截

5.1 针对烟雾和火焰的增强参数设置

这套数据里最难检测的目标是烟雾——轮廓模糊、边缘透明、形状高度多变。如果直接用默认增强参数,模型对烟雾的召回率往往不理想。我一般会在训练配置里额外开启mosaic=1.0和mixup=0.2,同时对烟雾类别的目标做针对性增强。

YOLOv8的增强参数可以直接写在训练命令里:

yolo detect train data=fire_dataset/data.yaml model=yolov8s.pt epochs=80 imgsz=640 batch=16 mosaic=1.0 mixup=0.2 hsv_h=0.015 hsv_s=0.7 hsv_v=0.4

参数说明:mosaic=1.0表示每次迭代都用马赛克增强(4张图拼成一张),这对小目标(远处的火焰、被遮挡的人)提升明显。mixup=0.2意味着20%的概率对两张图做融合,增加背景多样性。hsv_*三个参数控制颜色扰动幅度——烟雾的灰度范围广、火焰的色温变化大,适度增加色域扰动能提升模型对光照变化的鲁棒性。我自己试过,增大这些值之后mAP50能提升大约1.5个点,但注意不要超过上述值,否则模型会“学”到错误颜色模式。

注意mosaic默认就是开的,但如果你数据量只有3000张,建议维持开启状态。另外,如果验证集包含大量密集人群场景,mosaic对这类数据效果一般,反而可能破坏原始空间关系。

5.2 类别不平衡的应对策略

火灾数据有个典型特点——smoke目标往往占大面积、但数量少;person目标数量多、但尺寸小。训练时模型会被person主导,导致smoke类别的loss权重被稀释。

我一般在训练后检查每个类别单独的AP值:

yolo detect val data=fire_dataset/data.yaml model=runs/detect/train/weights/best.pt

然后看输出里的Class列,如果fire类的AP明显低于其他类(比如差了10个点以上),就做两件事:一是把fire和smoke类别的图像做离线复制增强(旋转、翻转、加噪声),二是在损失函数里为少数类增加权重。YOLOv8没有直接的类别权重参数,但你可以用--loss_weights或者修改配置文件的方式来做,实操中最常见的做法是复制图像。

复制增强的脚本参考:

import cv2 import os def augment_fire_images(img_path, label_path, out_img_dir, out_label_dir, copies=3): img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path) as f: lines = f.readlines() for i in range(copies): aug_img = img.copy() if i == 0: aug_img = cv2.flip(img, 1) elif i == 1: matrix = cv2.getRotationMatrix2D((w//2, h//2), 15, 1.0) aug_img = cv2.warpAffine(img, matrix, (w, h)) # 保存增强图像和原标注(注意旋转后需要对框坐标做几何变换,示例略) base = os.path.basename(img_path).split('.')[0] cv2.imwrite(f'{out_img_dir}/{base}_aug{i}.jpg', aug_img) new_lines = [] for line in lines: parts = line.split() cls = parts[0] xc, yc, bw, bh = map(float, parts[1:]) if i == 0: # 水平翻转 xc = 1.0 - xc new_lines.append(f'{cls} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}\n') with open(f'{out_label_dir}/{base}_aug{i}.txt', 'w') as f: f.writelines(new_lines)

参数说明:copies=3表示每张火灾图像生成3份增强副本,提高fire样本占比。翻转和旋转后的坐标变换必须同步进行,否则框就飘了——特别是水平翻转时x_center变成1.0 - xc,这一点很容易漏掉。增加副本后记得重新划分train/val/test,避免增强副本同时出现在训练集和验证集导致数据泄露。

5.3 推理端置信度阈值的验证建议

训练完成后,实际部署时的置信度阈值选择有玄学成分。这套数据里,person的目标通常框得很实在,阈值设0.35就够;但fire的目标因为火焰形状不规则,置信度往往在0.2~0.3之间波动。如果你用默认0.25阈值,会漏掉相当一部分真实火焰。

我在现场部署时一般是双阈值策略:人员检测用0.4(宁可漏检不可误报),烟雾和火焰用0.15(宁可误报不可漏报)。这个策略能否用同一套权重实现,取决于你的后处理逻辑——可以在推理代码里对类别做差异化阈值判断:

from ultralytics import YOLO model = YOLO('best.pt') result = model('test_imgs/fire_day_001.jpg', conf=0.15) for box in result[0].boxes: cls = int(box.cls[0]) conf = float(box.conf[0]) if cls == 0 and conf < 0.4: continue # 人员检测,低置信度直接放弃 elif cls in [1, 2] and conf >= 0.15: print(f'Fire/Smoke detected: {box.xyxy[0].tolist()}')

实际部署时,烟雾的误报率会很高,因为雾天、水蒸气都有可能被模型当成烟。这种问题不能靠调阈值解决,需要加时序滤波——多帧确认。我在做火灾预警项目时的习惯是:单帧检出fire类别的置信度超过0.3就报警,低于0.2且连续3帧检出才报警,这样能抑制大部分误报。从那以后我每次部署这类模型前,都会先跑一遍不同阈值下的精准率和召回率曲线,再根据业务容忍度选阈值,模型本身训得再好,部署策略不对照样会被现场环境击穿。希望帮到你。

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

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

std::thread 入门:启动、join、detach 与生命周期

std::thread 是 C11 给并发编程开的第一道门&#xff0c;也是最容易在第一个小时就撞墙的一道门。撞的方式还很吓人&#xff1a;不是编译错误&#xff0c;不是抛异常&#xff0c;而是整个进程被 std::terminate 直接干掉&#xff0c;运行库只留下几行 terminate called without…

作者头像 李华
网站建设 2026/10/1 18:15:38

考场信号屏蔽器在标准化考场建设中的技术选型与合规配置指南

标准化考场建设是教育考试公平性的基础设施保障。信号屏蔽器作为考场的核心安防设备&#xff0c;其技术选型与配置方案直接关系到作弊防控的有效性与周边环境的兼容性。以下从技术维度梳理选型与配置的关键要点。频段覆盖&#xff1a;全频段屏蔽的技术底线考场信号屏蔽的首要原…

作者头像 李华
网站建设 2026/10/1 18:15:33

AMD ROCm上Gemma4情绪分析LoRA微调实战指南

1. 这不是“跑个demo”——它是一次在AMD生态里把大模型微调链路彻底打通的实操验证我在 AMD ROCm 云上真跑通了 Gemma4 情绪 LoRA 微调&#xff1a;准确率 0.594 → 0.734&#xff0c;附 4 个坑和全套截图。这句话里每一个词都不是虚的——AMD ROCm是硬件底座的硬约束&#xf…

作者头像 李华
网站建设 2026/10/1 18:15:23

ComfyUI v0.37跑通Qwen-Image-2.1:从模型部署到稳定出图全攻略

昨天把 ComfyUI 更新到了 v0.37&#xff0c;顺手把 Qwen-Image-2.1 跑通了。整个过程比我预想的顺利&#xff0c;但中间也踩了几个坑——比如模型路径不对、采样器选错导致画面发灰、爆内存等等。这篇就好好记录一下&#xff0c;从下载模型到稳定出图的完整流程&#xff0c;顺带…

作者头像 李华
网站建设 2026/10/1 18:15:22

数据集成平台选型实战:核心能力验证与演示场景设计

最近因为业务系统越来越多&#xff0c;数据分散在好几套数据库和接口里&#xff0c;我决定不再靠临时脚本打补丁&#xff0c;而是认真评估一套数据集成平台来统一处理同步和转换问题。前后花了大概三周&#xff0c;完成了选型、环境搭建、能力演示和复盘&#xff0c;亲测下来确…

作者头像 李华
网站建设 2026/10/1 18:15:10

红黑树原理详解:自平衡二叉搜索树的插入删除与工程应用

1. 红黑树到底是什么——从二叉搜索树的退化说开去红黑树&#xff08;RBTree&#xff09;估计劝退过不少人&#xff0c;很多人一听到“红黑树插入删除等原理”就头皮发麻。但在实际的工程世界里&#xff0c;它频繁出现在你根本看不见的地方&#xff1a;Java 的TreeMap、TreeSet…

作者头像 李华