☰
火焰检测实战:YOLOv5数据集标注、训练调参与部署全攻略
2026/10/17 2:58:03 网站建设 项目流程

简介:火焰数据集是一套面向目标检测模型训练的专用标注图像集,包含火焰场景的jpg图片以及对应的txt、xml标签文件,能够直接用于YOLOv5等深度学习框架的训练与验证。该数据集针对火灾预警、视频监控等应用场景设计,覆盖不同形态与光照条件下的火焰,适合计算机视觉开发者和相关方向研究人员使用。压缩包共5260个文件,其中jpg为火焰图像,txt与xml为标注信息,整体大小约194.03MB,目录结构清晰便于加载。训练参考方面,基于该数据集的YOLOv5模型在IoU=0.5时平均精度达到95.3%,在0.5:0.95区间为67.9%,数据质量较高。资源同时包含数据预处理、数据增强、超参调优、防过拟合等实践提示,有助于快速搭建并优化火焰检测模型。目前已有4901人学习下载,适合需要在实际项目中实现实时火焰识别的开发者参考使用。

1. 火焰数据集+YOLOv5:模型结构谁都能跑通,真正卡住进度的是标注数据

去年做一个火灾预警Demo时,我在火焰检测上翻了车。模型代码从仓库里拉下来就能跑,但训练数据是怎么都凑不齐——网上的火焰图片不少,可要的是带YOLO格式标注框的,一张张自己用LabelImg框太痛苦,框了三天手腕都快废了。后来拿到一份火焰数据集(含标注好的标签),目录整理得规整,标签直接是yolov5能读的txt格式,省下的时间全用来调参了。如果你是做安防监控、森林防火预警、工业厂区火焰识别这类项目的,且正卡在数据和标注上,这份资源能直接缩短你两周左右的准备期,把精力留给真正需要人工介入的误检调优环节。

2. 数据集解剖:从目录结构到标签内容的完整样张

2.1 目录结构与文件命名

这份数据集拿到的第一眼是清爽。解压后根目录直接分成images和labels两大块,每一块底下又按train、val、test三个子目录组织。这种结构对应YOLOv5默认的期望布局,不需要额外写脚本去搬文件。

flame_dataset/ ├── images/ │ ├── train/ # 训练图像 │ ├── val/ # 验证图像 │ └── test/ # 测试图像 ├── labels/ │ ├── train/ # 训练标签 │ ├── val/ # 验证标签 │ └── test/ # 测试标签 ├── data.yaml # 数据配置文件 └── README.md # 标注说明

洗数据的时候要重点核对一个地方:images和labels下面的train、val、test三个目录里的文件数量是否一一对应。比如images/train里有1200张jpg,labels/train里就应该有1200个txt,每张图一个标签文件。空标注的图片,有些数据集会直接不生成txt,有些会放一个空文件,这份数据集我核对下来是后者,也就是说每张图都有对应的txt,哪怕里面没有目标,这可以在训练时通过rect参数减少无效计算,但需要注意空txt的比例,如果超过总样本量的10%,建议先把空样本筛掉,否则训练出来的模型会倾向输出低置信度背景框。

文件命名上,图像和标签是同一个文件名,后缀不同——IMG_20241101_001.jpg配IMG_20241101_001.txt。这种命名方式的好处是,你后续要增补自己的图片时,只要保持前后缀一致,任何标注工具都能直接生成匹配的标签。注意别用中文文件名,YOLOv5的Dataloader在Windows下读取中文路径偶尔会踩编码坑,Linux下没问题,但为了跨平台省心,一律改成拼音或英文。

2.2 标签文件内容:xywh坐标与类别ID

打开任意一个标签文件,里面每行代表一个目标实例,格式是class x_center y_center width height。这五个值全部是归一化后的相对坐标,除以了图片宽高,取值范围在0到1之间。下面是一个实际标注内容:

0 0.525391 0.520833 0.262695 0.523148 0 0.218750 0.365741 0.189453 0.429630 1 0.612305 0.817130 0.125977 0.159722 2 0.904785 0.709491 0.150391 0.361111

第一列是类别ID,0代表火焰主体,1代表烟雾,2代表疑似火点(小面积火焰)。后四列是归一化后的中心点x、中心点y、宽度w、高度h。我习惯拿到数据集先写个小脚本扫描一遍标签,检查有没有超过[0,1]区间的异常值——有些标注工具会在裁剪图片时把坐标算超边界,训练时YOLOv5虽然会自动clip,但如果标签里本身就错位严重,模型学到的边界框就不稳定,后面推理时框会抖。

import os label_dir = "flame_dataset/labels/train" for name in os.listdir(label_dir): if not name.endswith(".txt"): continue with open(os.path.join(label_dir, name), "r", encoding="utf-8") as f: lines = f.readlines() for line in lines: parts = line.strip().split() if len(parts) != 5: print(f"格式异常: {name} -> {line.strip()}") continue cls, x, y, w, h = parts vals = [float(x), float(y), float(w), float(h)] if any(v < 0 or v > 1 for v in vals): print(f"坐标越界: {name} -> {line.strip()}")

这段脚本扫描标签目录里每个txt,逐行拆分五个字段,检查坐标是否落在合理的归一化区间内。如果出现越界或字段数量不对,说明这个文件在标注或转换过程中出了问题,需要单独修复或剔除。数据质量检查这件事虽然琐碎,但在火焰检测里特别值得做——因为火焰边界天然是模糊的、非刚性的,标注本身就有主观偏差,如果坐标格式再出问题,你后续调模型完全分不清是模型能力不行还是数据在撒谎。

关于类别ID,使用前务必对照数据集的README确认哪些ID对应什么。有的火焰数据集只有一类fire,有的会把smoke也标进去,这份分了三类,训练前你要想清楚自己的应用场景需不需要单独区分烟雾。如果实际部署只需要火焰告警,可以把烟雾这类合并进火焰,或者干脆忽略烟雾的预测结果,在推理阶段过滤类别ID即可,不必为此重新训练。

2.3 train/valid/test划分与数量配比

数据集的划分是train 70%、val 20%、test 10%,这是目标检测里比较常规的配比。训练时要保证val集的分布和train不会差太远,否则验证损失参考价值会失真。

# 统计各目录下的文件数量 echo "train images: $(ls flame_dataset/images/train | wc -l)" echo "train labels: $(ls flame_dataset/labels/train | wc -l)" echo "val images: $(ls flame_dataset/images/val | wc -l)" echo "val labels: $(ls flame_dataset/labels/val | wc -l)" echo "test images: $(ls flame_dataset/images/test | wc -l)" echo "test labels: $(ls flame_dataset/labels/test | wc -l)"

跑完这个统计,你会看到train大概一千多张、val几百张。数量不算海量,但火焰检测有个特征——火焰形态相对固定,不像行人检测那样需要几十万级别的数据才能覆盖姿态多样性。火焰主要是颜色、纹理、形状的组合变化,一两千张标注图足够YOLOv5s收敛到能用的程度。如果你的场景是特定的,比如只需要检测室外林火,建议从这份数据集里筛掉室内的火焰图,只保留背景接近的样本再训练,这比直接拿全量数据训练效果更稳。

3. YOLOv5训练:从数据配置到权重落地的完整流程

3.1 data.yaml与模型选择

拿到数据集后的第一步不是直接敲训练命令,而是先配好data.yaml。这个文件告诉YOLOv5三件事:训练和验证图片的路径、类别数量、类别名称。写错一个字段,训练就会在数据加载阶段直接报错。

# data.yaml train: /path/to/flame_dataset/images/train val: /path/to/flame_dataset/images/val test: /path/to/flame_dataset/images/test nc: 3 names: ['fire', 'smoke', 'small_fire']

train和val的路径建议写成绝对路径,特别是跨机器训练时。nc必须和标签文件里的最大类别ID对齐,这里类别ID是0、1、2,所以nc是3。names的顺序和ID一一对应,第一项对应ID 0。路径末尾不要多写斜杠,YOLOv5拼接路径时偶尔会因此出重复斜杠问题,虽然一般不影响,但看着难受且排查起来费时间。

模型选择上,我一般先用yolov5s作为baseline。s版本参数量小、训练快,适合先跑通流程、验证数据质量。如果精确率不够,再切换yolov5m或yolov5l。火焰检测这种单场景目标,s和m之间的差距不会像通用目标检测那样显著,因为目标本身纹理简单、尺度变化有限,更关键的往往是数据和后处理。先s后m是我一直在用的策略,能快速识别出训练配置问题,而不至于在大型模型上等半天才发现是层率设置错了。

训练前如果显卡显存不大(6GB以下),把--batch调低到8或4,同时把--imgsz从默认的640降到512。火焰这类目标通常面积占比不小,降分辨率不会造成灾难性掉点,但显存占用能少一半。

3.2 训练命令与关键超参数

配置好data.yaml之后,训练命令本身不复杂。YOLOv5仓库克隆下来后,直接调用train.py即可:

cd yolov5 python train.py \ --data /path/to/flame_dataset/data.yaml \ --weights yolov5s.pt \ --epochs 200 \ --batch-size 16 \ --img 640 \ --device 0 \ --cache ram \ --project runs/flame_det \ --name exp1 \ --exist-ok

参数拆开解释一下:--weights yolov5s.pt是预训练权重的路径,YOLOv5会下载COCO上预训练的s模型作为初始权重,迁移学习可以加速收敛;--cache ram把图片一次性加载进内存,省去每次迭代从磁盘读图的时间,注意如果你的内存只有16GB且数据集超过2000张,建议改成--cache disk别硬撑,不然会直接内存溢出;--epochs 200表示迭代200轮,火焰数据集不算大,200轮足够收敛,实际我观察到120轮左右验证损失就已经走平了,早停耐心值可以设在30轮。

--project和--name是控制训练日志输出路径的。养成一个好习惯:每次实验用不同的--name区分,比如exp1_640_batch16,后面看result曲线时才能对得上号。不加--exist-ok的话,重复使用同一个name会报错,加上它可以在重跑时覆盖旧目录,但注意只是覆盖输出目录,不是覆盖权重文件的暂存版本。

关于学习率,YOLOv5默认用--lr0 0.01,在火焰检测这种中等规模数据集上不用特意改动。但如果用--cos-lr余弦退火策略,训练后期学习率会降得更平滑,对最终精度的提升有一点帮助。数据增强方面,YOLOv5默认开了mosaic、mixup、hsv增强,这些对火焰检测基本友好,不需要关掉。需要警惕的是--fliplr左右翻转增强,火焰的形状虽然不对称,但翻转后仍是合理的火焰形态,所以开着也没问题。

3.3 训练产物解读:weights与result曲线

训练结束后,YOLOv5会在输出目录生成一组文件:best.pt、last.pt、results.png、confusion_matrix.png等。

runs/flame_det/exp1/ ├── weights/ │ ├── best.pt # 验证集上mAP最高的权重 │ └── last.pt # 最后一轮权重 ├── results.png # 训练/验证损失曲线 ├── confusion_matrix.png └── hyp.yaml # 本次训练的超参数快照

best.pt和last.pt的区别要清楚:best.pt在训练过程中验证集上表现最好的那一轮保存下来的,last.pt是训练结束那轮的。实际部署基本都用best.pt,但如果你的训练曲线在最后几十轮还在下降,last.pt反而可能比best.pt更优,可以两个都做一次验证对比再选。hyp.yaml是超参数快照,记录本次训练用到的所有增强和优化器参数。

results.png里最值得看的是val/box_loss和val/obj_loss两条曲线。如果它们在前30轮快速下降然后缓慢振荡,说明模型在正常学习;如果它们一路下降但val损失突然反弹,说明过拟合,要加大--wh或--mixup的数据增强强度。另外一个容易忽略的点是results.png默认显示的是验证集上的损失,和训练损失对应起来看才能判断是欠拟合还是过拟合——只盯着训练损失看的人,经常会误判模型状态。

4. 评估与调参:看懂指标背后的火焰细节

4.1 mAP、PR曲线与置信度阈值

训练完最常问的问题是“模型到底行不行”。YOLOv5的val.py脚本会对指定的权重在验证集上跑一遍,输出带表格的评估结果:

python val.py \ --data /path/to/flame_dataset/data.yaml \ --weights runs/flame_det/exp1/weights/best.pt \ --conf-thres 0.25 \ --iou-thres 0.5

输出表格里的mAP@0.5和mAP@0.5:0.95是两个核心数字。前者是IoU阈值0.5下的平均精度,比较宽松,适合评估火焰目标这种边界模糊的场景;后者是多个IoU阈值下的综合指标,严苛且偏向边界框定位精准度。火焰框本身带有主观标注偏差,mAP@0.5达到0.9以上就算可用的模型,mAP@0.5:0.95能到0.6左右已经表现不错。

--conf-thres参数只影响验证时的置信度阈值,不会改变模型权重。你在验证时用0.25,部署推理时可以改成0.4甚至0.5,这会直接改变精确率和召回率的平衡。火焰检测的安全导向场景里,宁可多报几个误检也不要漏掉真火,所以阈值可以放宽,但这取决于你告警机制有没有二次确认。

4.2 漏检与误检的权衡:NMS参数

NMS(非极大值抑制)在推理阶段负责合并重叠框。YOLOv5中由--iou-thres控制,通常默认0.45。在火焰检测里可能存在一个问题:火焰边缘的框相互重叠,NMS把两个相邻的火苗合并成一个框,这看起来没问题;但如果一个场景中有两团距离很近的火焰,NMS的IoU阈值过小会把两个独立目标合并成一个,导致漏检。

# 推理时手动调整NMS参数 model.conf = 0.30 # 置信度阈值 model.iou = 0.35 # NMS IoU阈值,比默认更严格

我在推理脚本里会把iou从默认的0.45调到0.35,这样相邻的火焰框不容易被合并掉。但代价是同一目标可能出现多个重叠框,需要在后处理时再对框进行聚类。这个调整没有标准值,取决于你场景里火焰是否经常密集出现。如果火焰都是单个的大目标,默认0.45就好;如果是木材堆垛、森林里多处起火点,调低NMS阈值值得一试。

4.3 小目标火焰的锚框调整

火焰检测里容易出现一个痛点:远处的小火苗或初期火灾的烟头,目标像素面积很小。YOLOv5默认锚框是为COCO数据集设计的,对火焰数据集不一定是最优。你可以在训练命令里加--noautoanchor参数禁用自动锚框计算,但这个参数多数情况下不建议禁用——YOLOv5在训练前会自动用k-means重新计算锚框,适配你当前数据集的框大小分布。

# 自动计算锚框,并保存到数据集目录下 python train.py --data data.yaml --weights yolov5s.pt --epochs 200 --noautoanchor

加了--noautoanchor后,模型会使用默认的COCO锚框。我测试下来,如果数据集中以小目标为主(目标面积小于32x32像素),自动锚框通常能提升2到4个点的mAP;如果目标普遍是大面积火焰,两者差别很小。建议做法是:先用默认方式跑一版,然后强制开启--noautoanchor再跑一版,对比两版在验证集上的指标,选高的用。这个对比不费多少时间,值得做。

5. 避坑手册:标注、训练、推理三端的常见翻车

5.1 标注坐标越界:训练正常但框严重偏移

现象:训练损失收敛正常,但推理时部分框明显偏离火焰位置,歪在图片边缘。原因:部分标签在转换时没有按缩放后的图片尺寸重新归一化,导致坐标超出有效范围。解决:用2.2节里的扫描脚本全量检查一遍标签,把越界的txt找出来重新标注或剔除。

我拆过不少数据集,越界问题不是个例。很多标注工具导出的坐标是基于原始大图的,但有人把图片resize之后再导出标签,坐标没有同步更新。代码扫描加人工抽检,能提前排除掉这个坑。这里再补一个坑,见到训练时loss像心电图一样无限振荡,时不时冒一个尖锐峰值,大概率是部分标签文件里混入了空行或非数字字符,扫描脚本里加上空行跳过判断。

5.2 类别不平衡:烟雾远多于火焰,模型全学烟雾去了

现象:验证集上烟雾类目mAP 0.85,火焰类目只有0.6。原因:数据集里烟雾标注数量是火焰的3倍,模型为了降低总体损失,把更多容量分配给了烟雾。解决:在训练时用--cls参数提高稀有类别的损失权重,比如火焰类别的损失权重设成1.5,或者干脆丢弃一部分烟雾样本,让两者比例接近。

# 提高类别损失权重的示例 python train.py --data data.yaml --weights yolov5s.pt --cls 1.5 1.0 1.2 --epochs 200

--cls后面跟的是每个类别的损失权重,顺序和names里定义的一致。这里给火焰1.5、烟雾1.0、小火点1.2,本质上是告诉损失函数“火焰分错了更严重”。这个调整要看数据分布来定。更稳的做法还是先统计一下数据集里每类目标的数量,再决定是调权重还是抽样调整。

5.3 过拟合在白天场景:训练loss下降但验证loss甩尾

现象:训练超过100轮后训练损失还在降,验证损失掉头向上,模型在夜间火焰图上表现差。原因:数据增强强度不足,模型记住了训练图里的背景和光照分布,没有学到火焰的本质特征。解决:在YOLOv5的hyp.yaml里把hsv_h、hsv_s、hsv_v三个参数调大,增强色彩扰动,同时把degrees旋转角度从0增加到5度,让模型对图像姿态更鲁棒。

火焰检测对光照变化特别敏感,尤其是室内火焰和室外阳光下的火焰,颜色分布差异很大。如果训练集里室外场景偏多,模型对室内火焰的适应能力会差。在增强参数上多做扰动,让模型见过更广的颜色分布,是最直接的补足手段。注意增强参数不要一次调太大,否则模型会把火焰和橘色物体混淆,见过一个项目把hsv_s调到1.5后,模型把橙色的救生衣全检测成了火。

5.4 推理时显存暴涨:多路视频流同时跑YOLOv5撑爆显卡

现象:单路视频帧率还行,加到四路之后显存溢出。原因:每一路视频流的预处理和推理都独立占用了显存,没有做批次合并。解决:把多路视频帧收集到一个batch里统一推理,YOLOv5的detect.py本就是batch推理,你只需要在代码里把多个视频帧的预处理结果堆叠成一个tensor。

import torch import cv2 frames = [cv2.imread(f) for f in frame_paths] imgs = [letterbox(f, new_shape=640)[0] for f in frames] imgs = torch.stack([torch.from_numpy(i.transpose(2, 0, 1)) for i in imgs], dim=0) imgs = imgs.float() / 255.0 results = model(imgs, augment=False)

这个stack操作把多个单帧合并成一个batch tensor,模型一次前向推理处理多帧,显存利用率大幅提高。代价是batch推理的响应时间会略有增加,因为需要等所有帧都处理完成才开始推理,但吞吐量的提升远超这点延迟。多路视频场景下,这是最直接的省显存方案。

6. 部署前的最后一步:让火焰检测模型在视频流上稳定跑起来

6.1 帧率与延迟:先保检测频率,再谈精度

模型从训练到部署,很多人只关心mAP,忽略了实际运行时的帧率约束。火焰检测往往要接监控摄像头,告警的及时性直接取决于推理帧率。我在实际搭建中会做一个取舍:在保证单帧处理时间不超过150毫秒的前提下,再追求更高的模型精度。否则320x240的摄像头画面,你跑一个yolov5l每帧要400毫秒,火焰烧起来两秒后才报警,精度再高也没意义。

from models.experimental import attempt_load model = attempt_load("best.pt", device="cuda") model.eval()

推理前必须显式调用model.eval(),这是新手很容易漏掉的一步。PyTorch模型默认在训练模式,dropout和bn层的状态不一致,没有切到eval模式时,同一张图每次推理结果都会有小幅随机波动,多路视频下看起来就像框在抖动。切到eval模式后,bn层使用全局统计量,结果完全确定。

6.2 帧间去抖:单帧误检的后悔药

火焰在视频里是动态变化的,单帧的检测结果可能会因为噪声、光照变化而出现偶发误检。直接拿单帧结果去触发告警,会产生大量无效警报。我一般会做一个简单的帧间确认机制:连续3帧检测到火焰且置信度都超过阈值,才触发告警;超过3帧没检测到火焰,则解除告警状态。

class FlameDetector: def __init__(self, conf_thres=0.35, required_frames=3): self.conf_thres = conf_thres self.required_frames = required_frames self.detect_streak = 0 def update(self, frame): det = detect(frame, self.conf_thres) if len(det) > 0: self.detect_streak += 1 else: self.detect_streak = max(0, self.detect_streak - 1) return self.detect_streak >= self.required_frames

这个类维护一个累加器,检测到火焰时加1,没检测到减1,累加到3就触发告警。相比连续3帧必须都检测到的“硬确认”逻辑,这种积分式设计能容忍偶尔漏检的帧,又不会因为一帧误检就报警。参数required_frames可以根据摄像头帧率调整,帧率30FPS时设3约等于100毫秒的确认窗口,正常火焰蔓延速度不会错过。

6.3 导出ONNX:摆脱PyTorch依赖与显存占用

部署阶段把模型导出成ONNX格式,是一个值得做的操作。ONNX模型可以脱离PyTorch环境,在一个十几MB的文件里封装好网络结构,推理时通过ONNX Runtime实现,显存占用比PyTorch推理低30%左右,推理速度也有小幅提升。

python export.py \ --weights runs/flame_det/exp1/weights/best.pt \ --include onnx \ --imgsz 640

导出的best.onnx可以直接用onnxruntime加载:

import onnxruntime as ort sess = ort.InferenceSession("best.onnx") out = sess.run(None, {sess.get_inputs()[0].name: blob})

ONNX在边缘设备上(Jetson、RK3588等)的兼容性更好,还支持TensorRT的二次优化。我第一次导出时栽过跟头,export.py要求PyTorch版本和ONNX opset版本匹配,版本不匹配会导出成功但推理结果全错。建议使用Python 3.8以上版本,安装onnxruntime和onnx时注意看YOLOv5仓库requirements里锁定的版本号,版本差太多宁可upgrade到一致再导出。

从那以后,我每次部署火焰检测模型都会强制走一遍eval模式验证、帧间确认、ONNX导出这三步,这三步走完模型才算真正能用。火焰检测这东西,很多时候差的不是算法原理,而是数据准备和后处理里的细节。希望这份数据集能帮你跳过最耗时的标注阶段,把时间花在真正影响效果的调优上,少走我踩过的那些弯路。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询