消防救援场景里的无人机视觉,和普通安防、巡检完全是两码事。我这两年一直在做无人机低空感知方向,正好接手了一个面向火情处置的目标检测项目——从自建数据集到改进模型再到真机验证,整套走下来,踩坑比写代码多。今天把这套东西完整拆开讲:数据集怎么采集、标注规范怎么定、模型怎么改、训练参数怎么调、部署时哪些细节最容易翻车,给同样在做消防救援、应急巡检或者无人机边缘视觉的朋友做个参考。
先说结论:通用目标检测模型直接搬到火场上,效果很差。原因在于火场环境的特殊性——浓烟遮挡、火焰形态不定、目标尺度跨度大,这些都不是常规模型优化能解决的,必须有针对性地设计数据和模型。这套方案最终命名为 FireRescue,包含完整的无人机火场数据集(约 12000 张标注图像、8 万多个目标实例)和基于 YOLOv8 扩展的增强型检测模型。在自建测试集上,mAP50 达到 0.874,比基线模型提升了将近 12 个百分点,同时在小目标类别(受困人员、零星火点)上的召回率提升尤其明显。下面按项目推进的顺序,把关键环节逐个说透。
1. 项目核心问题:为什么火场目标检测不能用现成模型
1.1 火场场景和常规检测场景的本质差异
常规物体检测面对的目标,比如行人、车辆、猫狗,形态相对固定,模型可以从大量公开数据集里学到稳定的特征表达。但火焰不一样——它是非刚体,每时每刻都在跳动变形,没有固定的边缘轮廓和表面纹理,而且火焰本身会发光,在可见光图像里很容易过曝,导致内部的纹理信息完全丢失。烟雾更麻烦,它没有一个明确的结构边界,半透明、随风扩散,同一团烟雾在不同角度、不同光照条件下看起来完全是两回事。
还有一个客观限制:公开数据集里几乎没有真正的无人机视角火场图像。主流火焰数据集大多来自监控摄像头或者普通手持设备拍摄,视角低、距离近,目标占画面比例大。而无人机执行火情侦查时,飞行高度通常在 30~120 米,目标在画面中占比极小,一棵树的火焰可能只有 20×30 像素。直接拿 COCO 或 VisDrone 预训练的权重来迁移,小目标检测能力根本不够用。
1.2 无人机视角带来的额外约束
无人机平台带来的不只是视角变化,还有一连串工程问题。首先是运动模糊——多旋翼在悬停时会有高频抖动,尤其是在消防现场巨大热气流扰动下,云台很难完全稳定,图像拖影严重。其次,火场图像往往伴随严重的色彩偏移:火光把整个画面染成橙红色,暗部细节被压缩在一起。如果模型只学过低照度和正常光照的数据,到了火场上很容易把路灯、车灯、甚至是阳光反射误判成着火点。
另外,消防救援场景的检测类别也不能照搬通用模型。我们最终确定的是四类目标:fire(明火区域)、smoke(烟雾区域)、person(受困人员)、vehicle(消防车辆及救援车辆)。人员检测的关键是"在烟里找人"——被烟雾半遮挡、姿态异常(躺卧、蜷缩),这在标准行人检测数据集里几乎找不到。所以,与其等一个无所不能的通用模型,不如自己把数据和模型都按场景重新设计一遍。
我说句实在话:如果你的目标是做一个能落地的消防救援无人机检测系统,就别指望"下载个开源模型,微调一下就能用"。数据决定了模型能力的上限,这部分功夫省不了。
2. FireRescue 数据集:从采集到标注的完整流程
2.1 数据采集方案设计:真实性和覆盖度的平衡
数据集建设的第一步是要想清楚数据从哪来。真实火场数据是有的,但出于安全原因不会公开,一般人也拿不到。我们的方案是用"受控燃烧实验 + 模拟现场 + 比例注入"的三层策略。
受控燃烧实验是主体,占总数据的 60% 左右。具体做法是租用了一处空旷场地,联合当地消防训练机构,分批次进行可控的燃烧演练。场景覆盖建筑火灾、车辆火灾、林草火情和堆放物火灾四类。无人机在 30、60、90、120 米四个高度悬停采集,云台角度分别设定为 0 度(正射)和 30 度、45 度(倾斜视角),这样能模拟侦查航线的几种典型视角。同时搭载了可见光和热红外双光相机,因为消防救援中有大量夜间任务,热红外数据对找人是决定性的。
另外 30% 的数据来自模拟现场——用烟雾机加橙色灯光在废弃厂房里人为布置"火场",主要补充烟雾遮挡下的低能见度样本。剩下 10% 是从现有公开数据中筛选出来的、经过人工确认与火场场景高度相关的图像,比如工业火灾、森林火灾的新闻图片,用来补充极端燃烧状态下的形态多样性。三类数据合并后一共 12000 多张图像,其中约 3500 张是热红外图像。单看规模不算大,但火场数据天然稀疏,能有这个量的自采数据已经非常难得了。
采集时还有一个容易忽略的点:在飞行前先校正云台和相机参数,记录每张图的拍摄高度、角度和时间。这些元信息后面做数据分析和场景分层评估时非常有用,比如可以单独统计 60 米高度、45 度角条件下的检测精度,定位模型在哪个高度下降最快。
2.2 标注规范:火焰和烟雾怎么画框
标注规范是整个数据集里最容易被低估的部分。常规目标标注规则在火焰和烟雾上根本行不通——它们没有清晰边界,不同标注员画出来的框可能相差很大,框住的范围直接影响模型的收敛效果。
我们最终定了一条原则:标注明火时,框取"视觉上燃烧最强烈、灰度值最高的核心区域";标注烟雾时,框取"肉眼可辨认的、浓烟聚集的不透明区域",半透明扩散区不标注。这么做是为了保证正样本的置信度——宁可漏标模糊区域,也不引入大量高噪声框。
具体标注时,火焰框要求紧贴核心燃烧区,允许跳过零星飞溅的小火苗(这些被视为背景上下文);烟雾框可以使用多边形标注后转为外接矩形,但边界点不少于 6 个;人员标注则要求包含全身,即使被烟雾遮挡到只剩部分肢体,也按可见范围画满框并调整类别置信度——不过检测模型一般没有置信度标注,所以这个信息主要靠训练时的人工复核来把关。
标注类别采用四类结构:fire、smoke、person、vehicle。在 8 万多个实例中,fire 和 smoke 占了大约 70%,person 约 18%,vehicle 约 12%。这个分布明显不平衡,后面训练时需要在损失函数上做针对性处理。标注完成后,我组织了三轮交叉复核:每一张图像的标注结果至少由另一名标注员独立复核一遍,出现不一致的框全部重新讨论修正。最终随机抽取了 500 张图像做了二次标注质量评估,框级 IoU 一致性超过 0.82,基本达到了可用级别。
2.3 数据增强:不只是简单的翻转和色彩抖动
通用检测项目常用的翻转、缩放、色彩抖动这些增强手段,在火场场景里只能算热身。真正有效果的是以下几类针对性增强。
第一类是烟雾覆盖模拟。从标注好的 smoke 实例里裁剪出真实的烟雾纹理块,随机粘贴到图像中其他区域,叠加半透明混合,模拟不同浓度的烟雾遮挡效果。这样做的好处是能成倍增加"人员被烟雾遮挡"的样本数量,同时不破坏真实纹理。
第二类是火焰光晕模拟。火场中,火焰周围空气中的颗粒物会散射光线,形成光晕效应,让边缘信息损失严重。在增强阶段,我用高斯模糊叠加橙色光晕作用到局部区域,模拟这种低清晰度下的观测状态,逼着模型学会从模糊中找特征。
第三类是亮度与色温扰动。火场的整体色调偏橙红,但强度变化极大。我们在 HSV 空间中做随机扰动,特别是把色相向红色方向偏移,明度随机拉伸,让模型对主色调不敏感,更多依赖形状和上下文判断。
至于 Mosaic、MixUp 这类通用增强,同样有效,但不是火场场景的特异性关键。我的建议是:通用增强默认开 8 成,场景特有增强开 5 成,这样能最大程度保持真实分布,不让增强数据喧宾夺主。
3. 增强型 YOLO 模型:针对火情场景的网络改进
3.1 基线模型选择:YOLOv8 是起点,但不是终点
模型基座我们比较了 YOLOv5、YOLOv7 和 YOLOv8,最终选了 YOLOv8s。理由有三个:第一,训练收敛速度快,迭代效率高,适合在数据集频繁调整的阶段反复实验;第二,C2f 结构在小目标特征提取上优于之前的 C3,配合高分辨率输入有更好的上限;第三,生态成熟,导出 ONNX、TensorRT 的链路顺畅,方便做边缘部署。
但 YOLOv8s 直接上火车场数据,效果只能算及格。在内部测试集上,mAP50 大约在 0.78 左右,问题集中在两个方向:一是 30×30 像素以下的小目标召回率不到 0.5;二是烟雾遮挡场景下人员漏检率明显偏高。这促使我们对模型结构做了四处针对性改动。
3.2 四处关键改动:小目标、烟雾遮挡和尺度平衡
第一处改动是在 Backbone 的高分辨率特征层增加了一条 P2 检测分支。YOLOv8 的标准输出从 P3 开始(8 倍下采样),对低空大目标足够,但对 60 米以上的无人机视角,很多目标在 P3 层上只有一个点左右的信息量,根本检测不出。增加 P2 分支(4 倍下采样)后,特征图分辨率翻倍,小目标的几何信息保留明显更完整。代价是计算量增加大约 18%,但换来的是小目标召回率从 0.42 提升到 0.63,这笔账很划算。
第二处改动是在 Neck 部分引入了一个轻量级注意力模块,放在特征融合之前,专门处理烟雾遮挡问题。核心做法是对特征图的通道维度做分组注意力计算,让模型自适应地增强有目标信号的特征通道、抑制被烟雾均匀化的纹理通道。这个模块的参数量很小,只有几十 K,但在烟雾遮挡子集上的 mAP50 提高了 5 个百分点左右。关键点在于注意力要加在融合前而不是融合后——融合后的特征已经是多尺度的综合表达,再施加注意力容易让不同尺度的信息互相干扰。
第三处改动是把 Neck 中用于特征融合的普通卷积替换为可变形卷积。火焰形态不定、边缘很不规则,固定感受野的卷积在拟合这种几何变化时效率低。可变形卷积允许采样点根据输入特征自适应偏移,等于是让卷积核"跟着火焰的边缘走"。这一项改动对 fire 类别的 AP 提升贡献最大,尤其是火灾现场常见的大面积扩散性燃烧。
第四处改动在检测头部分,把分类损失从 BCE 换成了 focal loss,并针对 fire、smoke、person、vehicle 四类设置了不同权重。理由很简单:person 在数据集中占比只有 18%,但重要性权重最高——救援场景里,漏检一个人的后果远大于多报一个火点。实际训练时类别权重设置为 person=1.5,fire=1.2,smoke=1.0,vehicle=0.8,同时把 focal loss 的 gamma 定为 2.0,可以让模型把注意力集中到那些难分类的少数样本上。
3.3 红外与可见光融合的取舍
很多人问双光数据是不是应该设计一个双流网络,分别提特征再融合。我做过分组实验,结论是:在训练数据量一万多张这个级别,双流结构的增益不足以弥补部署复杂度的上升。双流网络意味着两套预处理流程、两套推理管线,边缘设备上资源消耗翻倍不说,对传感器同步的要求也极其苛刻,稍有偏差反而引入特征错位损失。
我更推荐的方案是"图像级融合":可见光图像作为主输入,热红外图像只在烟雾率较高或夜间模式下替换输入通道。也就是说,训练两个输入分支——一个吃可见光,一个吃热红外图,共享同一个模型主干,只在输出层根据场景做决策融合。这样做简单、稳定,工程上可行,效果也不差。我们实测下来,在夜间测试集上,热红外输入的 mAP50 能达到 0.89,而可见光仅 0.73。既然模型本身对输入通道没有偏好,那就让数据决定该用哪个传感器。
4. 训练实施与参数调优记录
4.1 数据划分与预处理细节
数据划分上,我先按照"场景不重叠"原则切分:同一场燃烧实验的图像全部放进同一份数据集,不允许一个场景的图像同时出现在训练集和验证集里。否则,模型学到的可能是"这个场地的地形特征"而非"火情目标特征",造成虚高的精度。最终划分比例为训练集 9600 张、验证集 1200 张、测试集 1200 张,按场景分层抽样,保证每个集合里都有白天、夜间、可见光、红外数据。
预处理环节最核心的参数是输入分辨率。通用检测模型的默认输入一般是 640×640,但火场无人机图像中目标普遍偏小,640 分辨率下信息损失太大。我们尝试了 960、1280、1536 三档分辨率,1280 是性价比最高的——相对于 960,mAP50 提升了 4 个百分点;继续上到 1536,只再涨 0.8 个百分点,但训练速度慢了将近一倍,显存占用也逼近单卡极限。最终确定 1280×1280。
数据增强在这一轮要克制。1280 输入配合大力度的 Mosaic 增强,训练后期容易出现增强分布的偏移,导致验证集上精度波动很大。我的做法是:前 200 个 epoch 开启 Mosaic 和 MixUp,后 100 个 epoch 关闭这两种强增强,只保留翻转、缩放和色彩类弱增强,让模型在真实分布上做最后精调。这个方法在很多目标检测项目里都有效,可以在收敛末期稳定提升 1~2 个点的 mAP。
4.2 训练超参数配置
把这些参数直接抄走能省你很多时间。优化器用的 SGD,momentum 0.937,weight decay 5e-4,初始学习率 0.01,配合前 3 个 epoch 的 warm-up 和余弦退火衰减。batch size 用 16,在单张 24GB 显存的 GPU 上跑 300 epoch 大概耗时 40 小时。考虑到数据量只有一万多张,这个训练成本完全可以接受。
损失函数方面,边框回归用 CIoU loss,分类用 focal loss(gamma=2.0),置信度用 BCE。类别权重按前面说的设置。还有一个训练细节:因为 smoke 和 fire 经常同时出现且位置相近,我在数据加载阶段强制部分 batch 内成对采样,让每个 batch 中同时包含大比例的 fire+smoke 共现样本。这样模型在推理时更容易学习"烟火的共生关系",能明显减少孤立判断造成的误检。
模型 EMA(指数移动平均)在这里一定要开。火场数据的标注噪声比常规数据集高,EMA 相当于对参数做了时间维度的平滑,等于变相去噪。我们对比过,开启 EMA 后验证集 mAP 能稳定提升 1.5 个百分点左右,几乎是零成本收益。
4.3 性能评估:模型改的每一步都要有量化佐证
评估指标不能只看 mAP。对于消防救援场景,我额外关注三个指标:小目标(面积小于 32×32 像素)的召回率、烟雾遮挡子集的 mAP50、夜间子集的 mAP50。这三个指标直接对应实际任务中的关键风险点。
ablation 实验的结果我整理成了一张表:
| 模型版本 | mAP50 | mAP50-95 | 小目标召回率 | 烟雾子集 mAP50 | 夜间子集 mAP50 | 参数量 |
|---|---|---|---|---|---|---|
| YOLOv8s 基线 | 0.782 | 0.431 | 0.42 | 0.561 | 0.584 | 11.2M |
| +P2 检测层 | 0.811 | 0.462 | 0.63 | 0.593 | 0.611 | 13.8M |
| +注意力模块 | 0.835 | 0.498 | 0.64 | 0.642 | 0.638 | 13.9M |
| +可变形卷积 | 0.852 | 0.517 | 0.65 | 0.661 | 0.652 | 14.2M |
| +focal loss | 0.874 | 0.539 | 0.67 | 0.688 | 0.671 | 14.2M |
每一处改动都有明确的增益,没有一项是负优化。最终版本的 mAP50 达到了 0.874,对比基线模型提升了 9 个百分点;最关键的烟雾遮挡子集从 0.561 提升到了 0.688,这是对救援任务最有价值的一栏数字。
注意:消融实验的前提是每一处改动都固定其他变量。如果贪心一次性把四个改动全部加进去再调参,出了问题你根本不知道是哪个改动引起的。我的习惯是每加一个模块就跑一次完整的训练——耗时是长了点,但排查问题的时候省下的时间远超训练成本。
5. 常见问题与排查技巧实录
5.1 烟雾遮挡导致人员漏检,最有效的解法是什么
这是整个项目里最头疼的问题,也是救援场景的生命线。我试过的思路有三个方向:高分辨率输入、注意力机制、多帧信息融合。
高分辨率输入是最直接的,1280 输入比 960 的 person 召回率提升 7 个百分点,但帧率下降也明显,真机部署时经常跑不满实时。注意力机制是折中方案,效果不错但上限有限。真正让召回率再往上走的,是多帧时序信息的引入——不是复杂的时序网络,而是简单的帧间聚合推理:取视频流中相邻三帧,按时间顺序叠加求均值作为输入,相当于给模型提供了一个"看穿烟雾抖动"的上下文。这个 trick 在可视化对比中特别明显,但要注意 Holdout 验证时必须保证输入数据没有时序泄漏,否则指标是虚高的。
5.2 火点误检率居高不下,问题不一定在模型本身
很多人一上来就改网络结构,我的经验是先看数据分布。火点误检大多是把太阳反射、红色建筑物、车灯误判成 fire,根本原因是训练数据里缺少这些"难负样本"。我们对测试集上的误检案例做了聚类分析,发现接近一半的假阳性来自强烈反光表面。应对方法不复杂:从公开数据集和自有数据里专门收集 6000 张包含橙色、红色物体但不含明火的图像,做成负样本集参与训练。这一招把误检率几乎减半,比改网络结构有用得多。
还有一个容易被忽视的点:NMS 阈值。火场中火焰相连成片,检测框密集重叠,默认的 NMS 阈值 0.45 会把大量相邻的火点框合并成一个,造成整体火势规模被低估。我把 NMS 的 IoU 阈值调到 0.3,同时把置信度阈值从 0.25 降到 0.2,火焰框的分离效果好很多。
5.3 训练数据标注不一致导致模型反复震荡怎么办
火场数据标注的主观性比常规目标强太多。同一个火焰区域,两个标注员的框可能差 30% 的 IoU,这在训练时就会表现为 loss 不下降、验证集精度来回跳动。我们做了三件事解决。
第一,在标注文档里放入大量典型样例作为"锚定参考图",遇到拿不准的区域对照参考图决策;第二,把标注界面里的图像显示亮度统一校准,因为不同显示器的亮度差异会导致人们对火焰边缘的判断不同;第三,训练阶段在损失函数上对 DFL 分支加大一点权重,它的梯度特性对噪声标签不那么敏感,相当于给标注误差加了缓冲。做完这三步,验证集精度的波动幅度从 ±4% 收敛到了 ±1.5% 以内。
5.4 部署时显存不足、速度慢的问题怎么排查
模型在小目标检测上效果好,很大程度上靠的是高分辨率输入,但高分辨率在 Jetson 这类边缘设备上非常吃显存。我的解决思路是"切片推理":把 1280×1280 输入切成四张 640×640 的子图,分别推理再合并结果。实测证明,在设备端推理速度反而比单张 1280 输入更快,因为边缘设备的计算单元利用率在 640 粒度上更充分,同时显存占用降低了大约 60%。
切片推理要注意两个细节:一是切片之间要设置重叠区域,我设的是 48 像素的 overlap,避免目标在切片边缘被裁掉;二是合并结果时要对重叠区域做基于置信度的 NMS,不然目标在切片边界会产生重复框。
6. 落地部署与后续扩展方向
6.1 模型压缩和 TensorRT 加速的实际经验
模型本身 14.2M 参数,FP16 精度下部署到边缘侧大约是 28MB 大小,不算大,但速度上有优化空间。我做了两阶段优化:先用 torch 自带的剪枝工具对颈部通道做稀疏化剪枝,剪掉 40% 的通道,参数降到 8.7M,mAP50 几乎没降(从 0.874 到 0.869)。然后把模型导出 ONNX,用 TensorRT 做 FP16 量化加速,在嵌入式 GPU 平台上最终拿到约 24ms/帧的推理耗时(1280 输入),基本满足 10 帧以上的实时侦查需求。
需要特别提醒的是,剪枝必须从头做一遍微调训练,直接把剪完的权重拿去推理会掉点严重。微调 30 个 epoch、学习率降到初始值的 1/10,就能恢复到 95% 以上的精度。
6.2 在真实场景验证时发现的几个有意思的现象
我们和一线救援队伍做了一次联合演练。现场环境中发现几个实验室里注意不到的细节:第一,无人机在火场上空飞行时,热气流会造成图像周期性呼吸效应,目标的尺度会以大约 5% 的幅度来回变化,这在静态测试集里完全模拟不出来;第二,云台正射视角下地面目标有时会被机体自身遮挡,导致检测结果出现周期性丢帧;第三,飞控下发的 GPS 信息和视频帧之间往往存在几百毫秒的时延,做目标定位标记时必须考虑这个时间偏移。
这些现象让我意识到,模型精度再高,也只是系统的一部分。真正落地要解决的是传感器同步、数据链路稳定性、人机协同流程这些工程问题。目前 FireRescue 模型在可见光和热红外两条推理管线之间切换大约需要 20ms 的延迟,已经能做到飞行中实时切换传感器模式。
6.3 数据集的持续迭代思路
FireRescue 数据集在第一版之后必然要持续更新。目前规划的迭代方向是:一是从每次实际演练和真实任务中回流数据,关键帧自动上传后经过人工筛选重新进入数据集,形成数据闭环;二是增加更多极端场景——大风条件下的快速蔓延火、多层建筑内部燃烧、水域油面火等,这些场景的样本在现有数据里明显缺失;三是补充更细粒度的属性标注,比如火势等级、烟雾浓度、人员姿态,为后续多任务学习留出空间。
数据迭代环节有个工具层面的建议:一定要搭建一个简单的数据版本管理流程,记录每一次数据集的增删改和对应的模型版本。我在早期项目里吃过亏——训练了一个模型,效果很好,但回查数据时发现 2000 张图像的标注版本已经变了,导致后续所有对比实验都不可信。后来才用上数据版本管理,现在每次训练前都会核对数据集哈希值和标注版本号。
最后再分享一点个人体会。做 FireRescue 这个项目,我最深的感受是:在垂直场景里,模型的网络结构创新往往不是瓶颈,数据质量和系统集成的工程能力才决定最终落地效果。很多做检测的朋友把精力都花在调网络结构上,但在消防这种数据极度特殊的场景,把标注规范、数据增强、场景分层评估、部署适配这一整条链路做扎实,收获远比换一个更新的 Backbone 要大。这套流程跑通之后,不只是消防场景,其他垂直行业——工业安全、农业防火、环境监测——的无人机视觉项目,也都可以复用同样的方法框架,只要把你的场景数据按这个逻辑组织起来,模型自然会长成适配你场景的样子。