做图像火灾检测这几年,我自己攒得最顺手的家底,是一套8495张的火灾图像数据集。这个数字听起来不算大,但其中每一张几乎都是现实监控环境下真正会遇到的画面:白天厂房里的木垛火、夜晚低照度下的油盘火、远处山腰飘起来的烟羽,还有大量看起来像火但又不是火的干扰场景。这套数据集不是为了凑数量好看,而是从一开始就奔着同一个目标去的——让检测模型在园区监控、室外堆场、森林卡口这些真实摄像头画面里,能分得清“火、烟、干扰”,并且尽量少报错。
这篇内容想把整个数据集从方案设计、样本构成、标注规则,到增广策略、训练参数、踩坑实录,全部拆开来说一说。不管你是准备从零攒一套自己的检测数据,还是手里有数据但模型怎么调都不过关,都可以拿这篇文章的思路做参照。我没有讲太多玄乎的理论,重点全在实操,凡是能用表格、参数、阈值讲清楚的,就不含糊其辞。
1. 为什么非要自建火灾数据集:项目背景与核心思路
1.1 火灾检测落地的真实场景,离不了自有数据
火灾检测跟一般的目标检测还不太一样。常规的物体检测,比如人、车、猫、狗,公开数据集里可谓海量,随便拿一套来预训练都够用。但火灾这个目标本身就是个低频事件,真正着火时没人有心思架着相机慢慢拍,公开数据集里能找到的,多半是实验室环境下的高分辨率火焰特写,或者是救灾新闻里的远视角大火。这两类素材放到真实监控画面上,往往都不好用。
我实际接过的项目里,监控摄像头要么装在十几米高的立杆上,要么装在厂区围墙拐角,画面里最常出现的“像火”的东西反而是一堆干扰:傍晚的夕阳、红色的横幅、工地电焊的弧光、大货车的尾灯、甚至红色外墙在强光下的反射。你拿一个只在火焰特写上训练过的模型去跑这类画面,第一天就会被打爆误报。所以说到底,火灾检测的核心壁垒压根不在网络结构,而在数据能不能覆盖目标设备和真实场景的长尾分布。
同一套公开数据在不同的摄像头角度、不同的光照条件下,效果能差出一大截。想要一个能真正落地的模型,就必须针对自己项目里的监控点位、设备型号、安装高度、视野范围,去采集和整理一套贴合业务的数据。这套8495张的数据集,就是我在这类项目里逐步沉淀下来的。
1.2 8495张规模,到底能干什么
不少人一听到自建数据集,第一反应是“太少了吧,别人动辄几十万张”。这里我要泼盆冷水:火灾检测这个细分领域,完全没必要一上来就追求数据量,尤其是在早期验证阶段。8495张这个规模,对一个五人以下的算法团队来说,是刚好可以在一两周内完成标注、并且能快速迭代出第一版可用模型的体量。
数据再多,如果种类单一、标注不统一,模型学到的也只是某个特定场景的纹理记忆,换个机位就失效。反之,哪怕只有八千多张,只要把场景层次铺开、把负样本做足、把标注规则定严,训练出来的模型在真实项目里已经能扛住大部分情况。更关键的是,这个体量也决定了从采集、清洗、标注到训练评估的整个闭环是可控的。
这套数据集的构成大致如下:
| 类别 | 样本数量 | 说明 |
|---|---|---|
| 明火 | 4562张 | 包括油盘火、木垛火、垃圾火、车辆起火等多种火源 |
| 烟雾 | 1744张 | 白天和夜间两种环境下的烟气,覆盖不同扩散阶段 |
| 干扰负样本 | 2189张 | 夕阳、灯光、电焊火花、红色物体、残留烟尘等易误报场景 |
| 合计 | 8495张 | 当前版本V1.2 |
我特意把负样本比例压到接近四分之一。别看这些负样本训练时不会提供火和烟的正梯度,它们才是真正决定模型误报率高不高的关键。火灾报警系统最尴尬的状态不是漏报,因为漏报往往发生在极端场景下,用户还勉强能理解;真正让客户直接弃用系统的,是二十四小时不停地误报。负样本的分量,就是用来压制这种问题的。
1.3 方案选型的几个取舍
在定方案时我做过三件事:第一,明确目标检测为主,不做单纯的图像分类。真实监控画面里往往同时存在多个火源和烟羽,分类模型只能告诉你画面里“有火”,却没法告诉平台“当前火源在什么位置、需要联动哪台设备”,所以检测框是不可少的。第二,优先采用单阶段检测器作为主力模型,因为后续要部署到边缘端的嵌入式设备上,算力有限,速度和显存占用都是硬约束。第三,评估指标在一开始就固定下来,不只盯着mAP,还要记录误报率、漏报率,因为这些才是客户每天能感知到的关键词。
这套数据从一开始就不是拍脑袋堆素材,而是先明确了目标场景,再反推需要什么样本,所以后面的每一步都走得不绕路。
2. 数据构成、类别体系与标注规范
2.1 数据来源与场景搭建
数据的来源我做了组合式收集,而不是依赖单一渠道。第一类是可控实验场景的实拍:在安全合规的前提下,组织过油盘火、木垛火和热烟实验,用火盆和烟气发生装置模拟早期火灾阶段,使用不同机位、不同高度的相机进行拍摄。这类素材的好处是干净、可控、贴近真实火灾的燃烧特征,火苗的形状、烟气的颜色和浓度都可以根据需要调整。
第二类是项目现场的联合测试记录:比如消防演练、设备联动测试时留下的录像帧,这些画面里的烟和火虽然不是真实事故,但视角和光线条件与最终上线部署的监控点位非常接近,对模型泛化能力的提升帮助很大。第三类是公开可用的共享素材,主要用来补充特殊场景,比如森林火、车辆起火、高层建筑火灾等,这些场景组织实拍成本太高,但模型又不能完全没见过。
现实点说,这不是一个能靠周末两天拍完的数据集,整套素材的积累前后跨度大约一个季度。中间不断有新项目加进来,我就把墙面反光、夜间车灯、LED广告屏这类新发现的干扰场景也顺手归到negative类别里。数据集的版本号也从V1.0慢慢迭代到了V1.2。
2.2 类别体系与目标定义
很多第一次做火灾数据的人,拿到图就画框,画着画着就乱套了。原因是火焰本身是非刚性目标,边缘模糊、半透明、还有颜色过曝的问题,画框的标准稍微不一致,模型学到的特征就会漂移。我在项目里对三类目标分别定了非常具体的标注口径。
对明火,要求边界框必须包含从火源底部到外焰尖端的可见高温燃烧区域,但不包括外围肉眼可见的红色光晕,更不包括光线照亮的墙体。比如一张油盘火的照片,火焰跳起来半米高,外围还有一道很大的红光晕,此时框只需要紧紧包住火焰本体,不用把光晕扩进来。这样做的理由是:检测器的核心任务是确认“燃烧正在发生”,火焰本体的纹理和形态比环境光晕稳定得多,如果把光晕算进去,等到光晕被风吹散或者火被扑灭,模型反而容易犹豫。
对烟雾,要求框住烟羽的主体部分,也就是“肉眼能明确判断出浓淡和轮廓”的区域,边缘特别淡、将散未散的半透明层不强行全包。烟气扩散得快,一个画面里的烟可能从几个小团变成一大片,标注时宁可框小一点,也要保证框内确实是“烟”而不是“雾”。
对干扰负样本,不需要手动画框,只需要整图打上negative标签即可。因为负样本的意义是让模型学到“这些跟火长得很像的东西不是火”,不需要告诉模型具体哪里像。
2.3 标注流程与质检机制
标注工作我采用的是“初标-检查-抽检”三层流程。初标人员只负责正常画框,标注工具用常见的LabelImg,输出成COCO JSON格式。检查环节由另一个有模型训练经验的人来做,重点看三类问题:类别是否标错,比如把电焊火花误标成明火;框是否明显偏移,尤其是火焰被风吹歪后,框还在原来的位置;是否存在漏标,比如画面里明明有两团火只标了一团。
抽检环节我会随机抽取10%的图像,计算同一样本在不同标注结果之间的一致性。实际操作中,火灾框的一致率能做到85%以上就算合格,不需要追求完全一致,因为火焰的边界天然存在模糊地带。但一旦发现某个初标人员的边框普遍比其他人偏大15%以上,我会直接要求他重新过一遍,因为边框误差会直接稀释模型在做定位回归时的有效性,比多标几个框的影响更大。
注意:火灾数据的标注规则一定要白纸黑字写下来,让每个参与标注的人都能看到。口头交代的规则,三天后就会被新进来的人破坏掉。
3. 数据预处理与样本增强
3.1 离线清洗:先把脏数据拒之门外
火灾数据集里最容易被忽略但影响最大的问题,就是混入低质量、重复性太高的图片。我见过有人把视频按帧随机抽,一个两分钟的视频抽出一百多张,里面光是静止画面就占了七成,这种数据喂给模型,除了让训练时间变长,没有任何帮助。
我的离线清洗流程分三步。第一步是分辨率筛查,删除分辨率低于720p的图,因为火焰和烟雾的目标尺寸普遍不大,分辨率再低就没法看了。第二步是质量筛查,把过度压缩导致色块明显、过曝到整片发白、或者运动模糊严重的图挑出来,人工判断是修复还是删除。第三步是去重,用感知哈希算法算出一组数据的相似度,相似度阈值低于8的图片只保留一张。这一轮下来,原始素材大概能压缩掉10%到15%,看上去损失了一些数量,但留下的每一张都是有效样本。
还有一个细节,就是检查图像的时间戳。同一个场景的连续帧之间不要选择太多,尽量把帧间距拉开,比如每隔十帧才抽一帧。这样做保证了训练集里的多样性,模型不会因为见了同一个背景一百次,就对没见过的背景失去判断力。
3.2 在线增强策略:别把火烧成了蓝火
数据增强这一步,我做了一个让很多人意外的决定:对图像的色相扰动开到非常小。常规目标检测里的HSV增强,常常把色相范围设置在正负30度,作用就是让模型对颜色变化不那么敏感。但火灾识别恰恰依赖颜色线索,如果你把色相范围设置得太大,训练过程中就很容易出现蓝色火焰、紫色烟雾这种在物理上不存在的样本,模型被迫学会了“不要完全相信红色”,结果就是真实火焰的召回率被拉低。
具体增强配置可以参照下面这套:
| 增强方式 | 参数范围 | 操作目的 |
|---|---|---|
| 随机翻转 | 水平/垂直各50%概率 | 适应不同安装角度 |
| 随机旋转 | 正负15度 | 模拟鱼眼、斜装等机位 |
| 亮度扰动 | 正负25% | 覆盖白天夜晚光线差异 |
| 饱和度扰动 | 正负30% | 适应不同品牌摄像头色彩差异 |
| 色相扰动 | 正负6% | 只做微调,不破坏火的颜色特征 |
| 随机尺度缩放 | 0.6到1.4倍 | 模拟远近机位差异 |
| Mosaic拼接 | 50%概率 | 让模型看到更丰富的上下文 |
亮度一定要给足。同一个火源在白天阳光直射下和夜晚纯黑背景下,亮度差可以达到几十倍。模型如果只见过中等亮度的火,夜里一进画面大概率漏报。
3.3 类别平衡与困难样本挖掘
数据集里明火样本明显多于烟雾样本,因为烟雾出现的早期阶段往往伴随明火,单独出现初期烟羽的机会不多。但实际业务里,烟常常是火灾最早的信号,很多监控场景下火苗还没起来,烟已经先冒出来了。所以烟雾类别绝对不能少,否则模型只能识别“已经烧起来”的火,无法在火势可控阶段做预警。
我的做法是对烟雾样本做三倍的过采样,也就是让烟雾样本在每轮训练中出现的次数提高到明火的3倍,配合复制粘贴类的增强方式,比如把一块烟羽剪切出来贴到背景图上,补偿原本缺失的多样场景。明火样本则不做过度过采样,保持自然分布。
真正有价值的操作是困难负样本挖掘。第一版模型在测试集里反复把路灯光晕、晚霞、焊花当成火之后,我就专门从旧监控视频里截了几百张包含这些场景的图片,持续补充到negative类别里。这比调模型阈值有效得多,因为模型找错样本的本质原因是没见过这些干扰,现在让它见够了,误报自然就下去了。
4. 模型训练实战:从数据到可用检测器
4.1 数据划分:别让评测分数骗了你
数据集整理好之后,第一件事不是急着开训练,而是先做数据划分。我用的是70%训练、15%验证、15%测试的比例,但这里面有个非常重要的坑:必须按“场景分组”划分。
什么叫场景分组?同一个视频序列、同一个监控点位拍摄出来的连续帧,应该全部归入训练集、验证集或测试集中的某一侧,绝对不能打散后混进多个集合。原因很简单,同一个场景的背景、光照、视角高度相似,前后几帧之间的差异甚至小于不同时间段的差异,一旦同时出现在训练集和测试集里,测试结果就相当于开卷考试,mAP虚高得没有任何参考价值。
我踩过这个坑。某个版本的评测指标看起来高到离谱,模型部署后一测才发现,换了机位它的性能直接掉了一截。后来排查发现,就是因为当时把同一个演练视频的连续帧既放进了训练集又放进了验证集。从那以后,划分脚本里出了一个硬性约束:按拍摄场景ID做分组,一组数据只能完整地落在某一个集合里。
4.2 训练参数与关键配置
模型方面,我用的是目前比较成熟的YOLO系列检测框架,输入分辨率设为640x640。这个尺寸是精度和速度的平衡点,再往上加到1280确实能提升小目标的检测效果,但边缘端设备跑起来会明显吃力,所以我只在最后的优化阶段才考虑高分辨率微调。
训练参数参考如下:
- 优化器:AdamW,初始学习率1e-3,余弦退火衰减
- 批次大小:16,单卡显存12GB左右可跑
- 训练轮数:300轮,配合早停策略
- 置信度阈值:推理时明火设0.25,烟雾设0.35
- 类别权重:烟雾类别权重乘1.5
之所以明火的置信度阈值设得比烟雾低,是因为在消防场景里,宁愿把一些可疑的红色区域上报给值班人员复核,也不能错过真正的火苗。烟雾误报的容忍度稍高一点,因为烟的特征干扰项比较多,阈值太高容易漏,但阈值太低又会带来大量误报。这个数值不是拍脑袋定的,是基于验证集上漏报率和误报率的交叉点选的。
训练轮数300轮看起来偏多,但火灾数据的复杂度并不低,尤其是火焰形态变化剧烈,模型需要更多轮次去收敛边界特征。配合早停策略,如果验证集mAP连续30轮没有提升就提前终止,实际大约在220轮左右就能停。
4.3 模型评估:别只盯着mAP
模型训练完后的评估维度,我会拆成三个看:检测精度、误报率、漏报率。mAP50和mAP50-95负责衡量检测框画得准不准,这个指标只代表算法表现;误报率和漏报率才是业务方真正感知到的指标。
我在测试集上单独统计了一个指标:平均每路摄像头每天误报次数。这个指标不是模型直接输出的,而是把单帧检测结果加上了简单的时间序列判断逻辑后统计出来的。比如连续三帧里至少有两次检出火焰,才触发一次报警,这种简单策略能把偶发的单帧误检大幅过滤掉。单纯追求mAP高分没有意义,模型检测出了火但报警体验太差,最后客户一样会退货。
5. 常见问题与排查技巧实录
5.1 红色物体和反光引发误报
这是所有火灾检测项目里出现频率最高的问题。红色车漆、红色衣服、红色砖墙、傍晚夕阳、工地警示灯,这些都能让模型产生“疑似火焰”的高置信度输出。排查下来,最有效的不是改模型结构,而是按下面两条腿走路。
一条腿是扩充负样本。发现哪类误报,就去找哪类图,单独建一个子目录塞进训练集。另一条腿是时序投票。单帧检测结果本来就不稳定,模型可能这帧把夕阳当火,下一帧背景暗了又当成正常。利用连续多帧联合判断,能过滤掉大量非持续的误报。
实测下来,加了时序投票之后,误报率下降了一个数量级。而负样本扩充解决的是“模型对某个固定干扰异常敏感”的根因问题,两者配合使用效果最好。
5.2 夜间小目标漏报
夜里发生的火灾漏报比误报更危险。低照度环境下火苗目标小、亮度层次少,模型很容易把远处的一堆小火判定为背景噪声。针对这个问题,我做了两个调整。
第一,把夜间样本在训练集里的比例提到三成以上,并且配套做暗光增强,模拟真实监控在夜间自动切换红外模式后的黑白画面。第二,推理阶段对全图做分块检测后再合并结果,把输入分辨率从640提升到1280横向分两块跑,相当于把小目标变大之后再识别。这个操作会提高计算量,但通常只部署在边缘设备里重点路线的分析任务上,还是可以接受的。
5.3 标注框偏差影响评估
有些新手做完一轮训练发现mAP一直上不去,怀疑是模型能力不行,结果检查发现是标注一致性出了大问题。同一团火焰,一个人框得很紧,另一个人把整个光晕都框进去了,模型回归时就出现了“到底学哪个框”的困惑。
解决办法是在训练前对每一帧做边界框统计。如果同一个物体的框面积在不同标注人员手里浮动超过30%,就把这类框单独挑出来重新回标。这个操作看起来繁琐,但对mAP的影响立竿见影,尤其是在火焰这种边界模糊的目标上,边框抖动往往占了定位误差的大头。
5.4 评测虚高而部署失灵
前面提过的场景分组问题,这里再单独强调一次。一个监控点位的连续帧,如果同时出现在训练和测试集中,评测结果会高到让人误以为模型已经可以上线。但真实部署到全新的场景时,背景、光照、视角全部变化,模型表现立刻回到真实水平。
排查这类问题最直接的方法,是在评测时只使用独立场景的测试集,并且保证测试集里的画面在训练阶段一次也没有出现过。如果团队数据量特别紧张,宁可缩减训练集,也要保持测试集的独立性。这个原则,比多两百张训练图重要得多。
6. 数据集的后续演进与扩展方向
6.1 合成数据与真实数据结合
8495张这个规模,跑通第一版已经够了,但要想继续提升上限,就必须考虑合成数据的引入。用三维渲染软件搭建火焰和烟雾的物理模型,渲染成不同视角、不同光照下的图像序列,再与真实监控背景做合成,可以有效弥补极端场景样本不足的问题。
合成数据的质量关键在于真实感。我实验过直接把三维渲染图贴到监控截图里,效果很假,模型的泛化能力反而下降。后来改成用cutMix方式,把合成出来的火焰区域混合到真实监控背景上,并保留光源对环境亮度的影响,模型的表现才能持续提升。建议在扩展数据时,合成样本比例控制在总样本量的两成以内。
6.2 向边缘端部署与轻量化迭代
数据集到模型之后,最后一公里是部署。边缘端的算力有限,模型需要做int8量化或者通道剪枝。但在量化这件事上火灾检测有自己的特殊性:明火在画面中往往是少数像素,属于典型的小目标稀疏分布,int8量化容易把这类微弱特征的精度损失掉。如果你想做量化,建议先用测试集实测召回率,如果recall下降超过一个百分点,就退回FP16推理,保精度比省算力更重要。
另外,模型部署后的日志也是一个数据来源。真实运行中产生的误报和漏报截图,定期回流到数据集里做增量训练,能让模型越用越准。这套基于8495张打底、加上运行日志持续反馈的数据闭环,才是火灾检测项目后期真正的护城河。
6.3 版本管理与数据安全
数据集的版本管理同样不能马虎。每次新增样本、修改标注规则,都应该记录变更日志,并且保留上一个版本的副本。我习惯用版本号加备注的方式管理,比如“V1.2:新增电焊干扰样本300张,调整烟雾标注口径”。这样做的好处是,当模型出现回归时,可以快速回溯到是数据变化引起的,还是训练参数变化引起的。
如果有多个标注人员协作,也建议明确数据文件的权限边界,避免误删误改。火灾图像数据本身不带敏感信息,但若是来自真实的监控场地,在整理和使用时仍然要符合数据安全和隐私的规范要求,这一点在任何项目里都要放在最前面。
如果让我重新做一次这套数据,我会把负样本收集计划再提前两周开始,而不是等项目测试阶段被误报逼到墙角才回头补数据。很多时候模型效果不好,问题确实不在模型上,而在数据层面还欠着账。这套火灾数据集的整理和训练经验,希望能给正在做同类项目的你一点参考,少走一些我走过的弯路。