☰
从零搭建YOLO26火焰烟雾检测系统:数据集、训练与部署实战
2026/10/17 3:42:11 网站建设 项目流程

一次真实的园区消防演练里,检测系统在两秒内圈出了起火点,比人工发现快了将近四十秒——直到这场演练跑完,我才敢说火焰烟雾检测这套东西是真的能用的。这篇内容要讲的是从零搭建一套YOLO26火焰烟雾检测系统的完整过程,包括数据集构建、模型训练、部署全流程,所有经验都来自我自己的实际项目,不是网上东拼西凑的教程。如果你正在做园区安防、仓库消防、森林防火这类场景,或者单纯想入门深度学习目标检测,这篇可以帮你省掉大量试错时间。文末我还会说明免费模型包的获取方式,训练好的权重和推理脚本都会给到。先交代清楚边界:这套系统解决的核心问题是“在视频画面里快速发现火焰和烟雾,并给出位置坐标”,它定位是视觉预警,不是单纯替代传统感烟探测器。

1. 火焰烟雾检测的本质:先搞清楚要检测什么,再定技术路线

1.1 火焰和烟雾的核心视觉特征

火焰在图像上最显著的特点是颜色从亮黄到橙红的大梯度分布,边缘轮廓不稳定,内部有持续跳动的纹理,中心区域往往过曝成纯白色。烟雾则完全不同,它有半透明的特性,颜色从灰白到深灰不等,边界模糊,但对背景有明显的遮挡作用,形态还受风力影响不断变化。两者在视觉上的差异非常大,但在火灾场景里往往同时出现,交叉遮挡的情况也不罕见,所以类别设定就成了第一个关键决策。

我最终把检测类别定成两个独立类别:fire和smoke。有人建议过直接合并成一个“fire_smoke”类,理由反正是火情,不用分那么细。我的实测结论是不建议这么做。合并之后,模型对“火的亮色”和“烟的灰层”会产生内部特征冲突,收敛速度明显变慢,验证集指标也不如分开训练来得好。目标检测的类别粒度,从来不是越少越好,而是要让每个类别内部的视觉一致性足够强。

1.2 视觉检测与传统感烟探测器的真实差异

传统感烟探测器检测的是烟气粒子浓度、散射光变化这类物理量,优点是探测准确,不受视觉环境影响,缺点是给不出火源位置,也区分不了明火和阴燃。YOLO26这类视觉方案输出的是边界框坐标和类别概率,不仅知道画面里有没有火情,还能告诉联动平台火源在画面哪个位置。需要接消防水炮时,这个空间位置是硬需求,水炮要按坐标调整水平角和俯仰角,没有坐标框就只能靠预置位盲喷。

我自己做方案评估时一直坚持“两者互补”的定位:视觉方案负责广域快速发现和位置引导,传统感烟负责近距离可靠确认,二选一都会留下盲区。比如一个大厂房里只装感烟探头,报警以后你还是不知道是哪个角落出的问题,必须派人到现场确认;上了视觉检测以后,第一时间就能看到现场画面,值班人员远程判断的效率高了不止一个档次。这套理解,也决定了整个系统的架构走向。

1.3 可见光方案和热成像方案的取舍逻辑

有人问过我,热成像直接做高温点检测不是更可靠吗?热成像确实对高温异常区域更敏感,不受可见光干扰,但价格和分辨率是硬伤,低温阴燃、遮挡火焰这些场景也容易看漏。我最终选择可见光方案,最现实的理由是存量监控系统里绝大多数都是可见光摄像头,换热像仪等于把设备层全部推倒重来,预算上基本不可接受。

工程上更稳妥的架构是:可见光YOLO做第一层筛选,检测到可疑目标之后,再联动热成像或人工复核,两个信号叠加确认后才触发告警或喷淋。这一层一层确认的机制,比单纯依赖任何一种信号都更抗误报。做系统的初期就奔着“多信号融合”去设计,后面就不会被单一方案的短板反复折腾。

1.4 分类别设置置信度阈值的理由

训练完成后,模型会输出每个类别的置信度分数。很多人习惯把所有类别共用一个阈值,这个做法在火焰烟雾场景里是吃亏的。火焰漏报的后果可能很严重,所以fire类的置信度阈值我会刻意调低,宁可多出一些候选,也不愿意漏掉真正的火源;烟雾误报的主要危害是值班疲劳和告警骚扰,所以smoke类的阈值反而调高一些,保证报上来的基本都是确有其物。

这个“分类别设阈值”的思路,在部署配置里用一份单独的JSON文件就能实现,运行中调整配置也不会影响模型本体。千万别把阈值写死在代码里,否则每次调参都得改脚本重新发布,运维成本会翻着跟头涨。

2. 数据集构建:这一步决定了检测引擎的天花板

2.1 数据来源三条路:公开集、自采和视频抽帧

时间有限的话,我建议分三层来凑数据集。第一层是公开的火焰图像集和烟雾图像集,量大但质量层次不齐,适合做底料;第二层是自己采集,用普通摄像头对着烟雾饼、蜡烛、纸张在不同背景和距离下录制视频,然后按每30帧抽1帧的方式变成图片;第三层是从视频平台找真实的火灾报道片段,这类画面的火场背景和浓烟形态是合成样本很难替代的。

最终训练集我用了8000张火焰图、7000张烟雾图和3000张纯背景负样本图,验证集和测试集各留下1200张。负样本这一段经常被人忽略,但没有负样本的模型,遇到夕阳霞光、路面反光、昏黄路灯都可能报警,现场测试时会非常尴尬。数据不齐的代价,很多人在训练阶段看不见,在部署阶段会加倍偿还。

2.2 标注规范:边界框怎么打才靠谱

标注质量直接决定模型是“能看”还是“能打”。我的标注规范总结成四句话:火焰边界框包住火焰主体外轮廓,不强行把外部过大的光晕包含进去;烟雾边界框包含整片可见烟雾范围,哪怕透明度很低也要标出来;火和烟重叠时按火优先,只打fire框;同一个目标绝不打两个重叠框,否则模型在学习时会无所适从。

工具方面我用的是常见的开源标注工具,导出YOLO格式的txt,每行依次是类别id、中心点x、中心点y、宽度、高度,坐标全部除以图像宽高后落到0到1区间。归一化的好处是,训练时不管图像被resize成多大,框的相对位置都不变。我强烈建议训练图统一控制在1280x1280以内,既能保留火焰的纹理细节,又不会把显存烧爆。标注环节我不想渲染得太轻松,确实枯燥,但它的优先级比选模型结构还高。

2.3 样本均衡与脏数据清洗

火焰和烟雾的样本天然不平衡,真实火灾画面里烟雾的面积通常远大于火焰。如果不干预,模型容易把大片灰色烟雾直接学成背景。我把烟雾样本比例做到火焰的1.2倍,同时把负样本单独建成一个background类别,让模型明确学习“没有目标”的情况。

清洗阶段我会先做一次快速预训练,用刚训完的模型回头去跑训练集本身,把“置信度极低但存在标注”的图片翻出来逐张检查,问题通常是标注框画歪了、图片过暗、目标太小根本看不清。这类脏数据清掉以后,训练后期的loss曲线会平稳很多,省掉大量反复调参的时间。清洗这步没有捷径,一张一张看,看得越细,后面越省心。

2.4 数据增强:合成烟雾与光照扰动

增强分两块,一块是常规增强,包括随机翻转、随机色域扰动、马赛克拼接、随机仿射变换;另一块是场景增强,包括往干净背景图上随机合成烟雾贴图来生成“伪烟雾样本”,以及对火焰样本做亮度扰动,模拟火光把周围环境照亮的真实效果。

增强有一个很容易踩的坑:它在训练时应该按概率触发,不能每张图都全量叠加。如果每张图都做全套增强,模型会去学增强痕迹本身,换到真实场景反而变差。我踩过一次,测试集指标好看,视频实测一片乱报,后来把增强触发概率调低才恢复正常。很多公开教程里把增强当成“加了就一定变强”的万能药,实际不是这样,增强策略必须贴着目标场景的真实分布来设计。

3. YOLO26训练全流程:环境配置、参数选择与曲线判断

3.1 硬件底线与训练环境调试

训练这套模型的门槛没有想象中高,一张显存8G的中端显卡就能把1280输入尺寸稳定跑起来。环境搭建的难点主要在版本对齐:深度学习框架版本和计算平台版本一旦错位,最常见的是import报错,或者GPU算力跑不满。我的习惯是新建环境后先跑一个最小推理脚本,输入随机图片,确认前向计算没有问题,再进入正式训练。这个习惯替我省掉了好几次“配了半天环境,训练一启动才发现版本不对”的尴尬。

目录结构也值得提前规划好。训练图片放images/train,标签放labels/train,两者文件名一一对应;验证集单独建images/val,不要把训练集和验证集混在一个文件夹里再手动切分。更规范的做法是先按场景分组再随机划分,避免来自同一段视频的连续帧同时出现在训练集和验证集,出现数据泄漏而不自知。

3.2 关键超参数的取值逻辑

配置文件里最影响结果的参数是imgsz、batch、lr和epoch。imgsz我取1280,这是为火焰的纹理细节让步,输入太小会把跳动边缘磨平;batch受显存限制设为8,对应1280输入尺寸已经是比较紧的状态。初始学习率用0.01起步,配合余弦退火计划逐步下降,这个组合在我这个数据规模下最稳。下面是我常用的配置起点,换数据集之后仍然需要重新验证。

参数取值选择理由
imgsz1280保留火焰跳动纹理,显存可接受
batch88G显存下的紧平衡
lr00.01配合余弦退火,中后期自动衰减
epochs150结合早停,收敛即止
置信度阈值fire低、smoke高漏报与误报的代价不同

轮数我没有一味开大。火焰烟雾任务的难点在背景复杂度而不是类别数,大概150轮就已经收敛稳定,继续训练只会看到验证集mAP停滞并出现轻微过拟合。训练中我开了早停:验证集mAP连续20轮不提升就自动暂停,最终采用mAP最高那一轮的权重,而不是最后一次迭代的权重。这个细节很多人不注意,最后拿着过拟合的权重上线,测试时还一头雾水。

3.3 训练曲线主要盯哪几个指标

训练日志我会盯四个值:训练集loss、验证集mAP50、mAP50-95,以及每个类别的Precision和Recall。loss下降说明网络在拟合,mAP50代表大致框得对不对,mAP50-95代表框得准不准。火焰和烟雾的外形不规整,mAP50-95通常不会像车辆检测那么高,没必要死磕这一个数。

更实际的做法是分开看两个类别的Precision和Recall。烟雾识别经常误报,就把smoke的置信度阈值调高;火焰经常漏检,fire的阈值就适当调低。所有阈值调整完成后,用整个验证集再做一次全量评估,得到的指标才是写进项目文档的数字。只看总mAP的做法在这里不够用,因为火焰和烟雾的误报代价完全不一样。

3.4 断点恢复与候选权重保留

训练不是每次都能一口气跑完。训练脚本里定期保存断点文件,断电或显存溢出之后可以从最近的断点继续,不用从头再来。另外我会每隔20轮保留一份候选权重,不轻易删除。后期如果判断某个阈值组合下验证集表现更优,回头翻这些老权重做对比测试,比重训一轮划算得多。

到训练阶段收尾时,我还会顺手把所有训练参数记录到一份txt里,包括数据增强开关、学习率计划和最终指标。等三个月后回头来看,这份记录比什么记忆都可靠。模型训练不是只追求迭代次数,而是要能解释每一个决策为什么这么做。

4. 部署成能跑的实时检测服务

4.1 推理脚本的核心逻辑与线程模型

权重文件不是系统,部署是把模型封装成可运行服务的工程问题。我的做法是双线程模型:采集线程负责从摄像头或本地视频读取帧,放进容量固定的最新帧队列;推理线程从队列取最新一帧,执行预处理、模型推理、后处理和结果上抛。队列只保留最新帧,旧帧直接覆盖,这样端到端延迟可控,不会因为排队堆积越来越卡。

预处理必须做三件事:把图像resize到训练尺寸、把BGR通道转成RGB、把像素值归一化到0到1。三步任何一步顺序错了,检测框要么整体偏移,要么完全空白。下面给一个最小推理骨架,完整代码放在发布包里。

import cv2 import torch model = torch.hub.load('./yolo26', 'custom', path='best.pt', source='local') model.conf = 0.25 model.iou = 0.45 cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() if not ret: break results = model(frame, size=1280) for det in results.xyxy[0]: x1, y1, x2, y2, conf, cls = det.tolist() label = f"fire: {conf:.2f}" if int(cls) == 0 else f"smoke: {conf:.2f}" cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255), 2) cv2.putText(frame, label, (int(x1), int(y1) - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imshow("fire-smoke-det", frame) if cv2.waitKey(1) == ord("q"): break cap.release() cv2.destroyAllWindows()

这段代码只演示主干链路,生产环境还要补异常处理、超时重连和多路轮询,不然任何一个摄像头断流都会拖垮整个进程。

4.2 告警去重与多路摄像头并发调度

告警去重我踩过一个大坑。连续十几帧都检测到目标,系统每一帧都往外发告警,值班室的告警列表直接刷屏,不到半天就没人看了。最终我改成连续计数加冷却窗口:同一路画面检测到目标连续5帧以上才触发一次真实告警,触发后300秒内不再重复上报。这个逻辑放在独立的状态机服务里,按摄像头id分别维护,互不干扰。

多路摄像头的处理,如果每路都起一个模型实例,显存很快告急。我的做法是单实例多路轮询:多个通道的最新帧汇入统一队列,由一个模型实例按顺序消费。虽然单路帧率会下降,但总吞吐量更划算,告警链路的瓶颈通常也不在检测环节,而在推流和存储。别一上来就往检测服务上加并发,先想清楚瓶颈到底在哪一层。

4.3 模型导出与加速:ONNX和低精度优化

纯CPU环境部署时,先把模型导出成ONNX,这一步往往立竿见影。ONNX把计算图固化以后,省掉了动态图调度开销,推理耗时通常能有明显下降。显卡条件够的话,再进一步做引擎优化和半精度量化,1280输入尺寸下跑实时监控没有任何压力。

低精度量化要特别重视校准集。用一部分训练图片做量化校准后,必须比较量化前后mAP的变化。火焰的纹理细节在低位精度下容易丢失,如果mAP掉得明显,就退回FP16精度,没必要为了省那一点延迟牺牲准确率。部署的那台机器能跑多大模型,只有实测才知道,不要只看理论算力。我见过项目硬件参数写得很好看,实际吞吐量完全撑不住,就是因为没人做过真实压测。

5. 实测里的误报、漏检和性能排查心得

5.1 误报的三个主要来源与对策

实测阶段我把误报归成三类。第一类是颜色近似的静态亮斑,比如路灯光晕、工地焊点、车窗反光,模型容易把它们当成小火苗。对策是加背景差分:火焰有动态闪烁特性,静态亮斑经过连续帧确认后应当被过滤掉。第二类是形态近似的水汽蒸汽,比如厂房排气、烟囱水雾,对策是参考目标区域的纹理变化率和运动趋势,蒸汽的漂散方式和火灾浓烟有差异。第三类是低照度噪声,画面昏暗时传感器噪声可能被解读成火焰纹理,对策是部署端先做降噪和帧间去抖,再送进模型。

所有这些规则都放在检测输出的后端,成本很低。但有一点要记住:先通过日志统计确认当前场景主要误报来自哪一类,再有针对性地写规则。如果一上来就把所有规则全部堆上,各个规则之间反而会互相打架,排查问题的时候都不知道该信谁。

5.2 光照突变与半透明烟雾的工程处理

光照突变最典型的是云朵遮住太阳的瞬间,画面亮度剧烈变化,检测置信度跟着抖动。我在采帧端做了自动曝光锁定和滑动平均:亮度跳变过猛时,用缓存的历史帧均值做过渡,减少画质突变对模型的冲击。这套处理在室外监控场景里实测有效,成本也不高。

半透明烟雾漏检的问题更隐蔽。烟雾面积可能很大,中心区域却只是一层淡灰,模型在感受野里很难确认边界。我尝试过给烟雾类别加一个透明度估计分支,让网络同时输出面积和透明度区间信息,透明度低但面积大的目标也能被拉回正样本。这个改动属于二次开发范围,需要动模型结构,代码量不小,但确实能补上普通模型的一个盲区。想快速验证系统的人可以先跳过,等核心链路跑通再回来研究。

5.3 帧率瓶颈的排查顺序

部署后帧率不达标,很多人第一反应是换显卡。我的排查顺序是预处理、推理、解码、传输。先用profiling工具看推理耗时占比;再检查预处理,常见的问题是逐像素循环做resize,这种写法性能极差,应该用向量化接口替代;接着看视频解码,H.264软解码非常耗CPU,换成硬解码常常立竿见影;最后才考虑升级算力。

有一回系统看起来很卡,我查了半天,发现是解码线程占满了CPU,GPU在空等数据,根本不是推理慢。排查顺序一旦错了,很容易白花升级硬件的钱。做性能优化之前,先拿数据说话,这是调试的基本素养。

6. 免费模型包的内容说明与二次开发建议

6.1 模型包的内容和使用前提

按标题的承诺,我把训练好的火焰烟雾检测权重、最小推理脚本和一份参数说明文档打包免费提供。包里有三样东西:发布版本的权重文件、演示用的推理脚本、推荐的阈值配置说明。领取方式很简单,在文末按提示回复“火焰烟雾”即可拿到自动回复的下载入口。

要特别说清楚前提:这套模型基于公开数据集和自采素材训练,定位是技术交流和个人项目验证,不建议没经过充分测试就接入消防核心决策链路。拿到包之后的第一件事,应该在自己的场景视频上跑一整天,统计假阳率和漏检率,确认数字可控后再谈业务化。模型文件可以帮你省下训练时间,但现场适配永远省不掉。

6.2 往生产环境改造的几条忠告

如果打算把它变成正式生产系统,我有三条比较实在的建议。第一,每个摄像头的检测结果必须写结构化日志,谁在什么时间报了什么目标、置信度多少、画面快照存在哪里,全部要能回溯。没有日志的系统,出了问题就是大海捞针。第二,告警联动之前加人工确认环节,哪怕只是一张现场截图的二次确认,也能拦掉大量无谓的喷淋和声光报警。视觉AI存在边界情况,让人在回路里做最终判断,业务流程会安全得多。第三,模型不是一锤子买卖,换季节、换厂区、换光源以后,要用新采集的数据持续微调。做到这三点,这套系统才算真正从demo变成了可运营的工具。

最后再分享一个小技巧。训练时如果发现验证集和训练集指标差距大得离谱,第一件事不是调模型,而是回去检查训练集和验证集有没有同场景的相似图片。数据泄漏在火焰烟雾场景里非常容易发生,同一个摄像头拍的连续帧几乎一模一样,抽帧时不打乱就划分,得到的指标全是假的。这个坑我踩过一次,之后所有划分都先按场景分组再随机打散,省掉了大把调参时间。

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

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

立即咨询