☰
森林火灾目标检测数据集构建与训练部署实战
2026/10/18 3:09:52 网站建设 项目流程

从去年开始我就在陆续整理目标检测相关的数据集,森林火灾这块算是我踩坑最多的一个方向。先说结论:火灾检测和普通的目标检测完全不是一个难度等级,火焰边缘模糊、烟雾半透明、目标尺度变化大,这三座大山摆在面前,任何一个都足以让模型崩溃。第5期这个森林火灾目标检测数据集,是我在之前几版基础上重构而成的,重点解决了小目标漏检和烟雾误检两个老大难问题。这篇文章把整个数据集的构建思路、标注规范、训练复盘和部署经验一次性说清楚,希望对正在做类似项目的朋友有点帮助。

1. 项目背景与设计思路

1.1 为什么单独做森林火灾检测数据集

市面上公开的火灾数据集其实不少,比如常见的火灾图片分类数据集、室内火焰检测数据集,但直接拿来做森林火灾检测,效果往往一言难尽。原因很简单:森林场景太复杂了。室内火灾背景干净,火焰区域大而集中;森林火灾恰恰相反,火焰可能被树干遮挡、烟雾弥漫导致可见度骤降、远距离的火点只有几十个像素。这些差异意味着模型的训练分布和推理分布严重不匹配。

所以我做这个数据集的出发点很明确:不追求图像数量有多惊人,而是追求场景覆盖的广度和标注的精细度。第5期是系列迭代的结果,前几期要么小目标标注不完整,要么烟雾类目噪声太大,这次干脆推倒重来,按工业级标准重新清洗了一遍。数据集定位是面向森林防火监控场景的专用检测数据集,服务的目标是林区视频监控、无人机巡检和卫星遥感初判。

1.2 森林火灾检测的三大技术难点

搞明白难点,才能明白数据集为什么要这么设计。

第一是火焰形态的不规则性。火焰没有固定形状,颜色从橙红到亮黄渐变,边缘与背景融合度高,这导致传统的矩形框标注本身就存在很大歧义。标注员面对一张火焰图,框大一点把烟雾带进去了,框小一点漏掉了外焰,标注一致性极难保证。

第二是烟雾的物理特性。烟雾是半透明的,能看到背后的树木轮廓,这意味着一部分目标边界不是靠像素差异来界定的,而是靠亮度衰减趋势。深度学习模型对这类弱边界目标极其敏感,训练数据不足的情况下,模型很容易把灰白色的树干、云层、雾气误判为烟雾。

第三是尺度极端不均衡。森林火灾监控的视场范围广,一个1080P的帧里,近处的火焰可能占几百乘几百像素,远处的火点只有8-12像素。目标检测模型对中等尺度目标最友好,小目标天然存在特征不足的问题。如果数据集里小目标占比不高,训练出来的模型在实际部署时基本等于半残。

1.3 数据集版本更新逻辑

第5期主要做了三个方向的更新。一是扩充了远距离火点样本,加入大量无人机高空视角和监控塔远视角图像;二是重新标注了烟雾类别,去掉了大量因雾气、逆光产生的干扰样本;三是统一了标注规范,所有火焰框必须紧贴可见焰体,不允许把热辐射区框进去。

整个数据集的核心指标如下:总计4052张标注图像,火焰实例数超过8600个,烟雾实例约3400个,平均每张图像包含2.1个目标实例。训练集、验证集、测试集按8:1:1划分。图像分辨率全部统一到1920x1080或等效比例,不同来源的数据做了色调统一预处理。

2. 数据集的构成与标注规范

2.1 数据来源与场景分层

数据来源主要分为三块:公开视频监控截图、无人机航拍素材、模拟仿真环境渲染图。这三类来源各有优劣,组合使用才能覆盖实际部署中的大部分场景。

监控截图是最接近真实部署场景的数据,视角固定、背景复杂、火焰可能被遮挡,但缺点是分辨率参差不齐,老旧监控设备拍摄的画面噪声大。无人机航拍素材提供的是高空视角,火焰和烟雾在画面里占比小,是训练小目标检测的关键数据。仿真环境渲染图解决了极端场景样本不足的问题,比如夜间火灾、暴雨后火灾等,渲染图可以在光照条件、烟雾浓度上做精细控制,但需要做域适应处理,避免模型学到过多的渲染痕迹。

场景分层上,我按天气、光照、植被类型、地形四个维度做了标签管理。晴天、阴天、雾天、夜间四类光照条件各占约25%;植被类型覆盖针叶林、阔叶林、混交林和灌木丛四种;地形包含平地、坡地、山谷三类。这么做的好处是训练时可以针对性做采样均衡,避免模型在某一类场景上过拟合。

2.2 目标类别设计与标注规则

类别只设置了两类:fire和smoke。有人会问为什么不加burned_area(过火区域)或person(人员),原因很简单:类别越多,标注一致性越差。过火区域通常是大片不规则连通区域,强行用矩形框标注价值不大;人员检测在森林火灾场景下多用于逃生识别,属于另一个任务方向,混在一起反而干扰主检测目标。第5期只保留fire和smoke,做细做精。

标注规则的细节值得多说几句:

  • 火焰框:必须紧贴可见焰体的外缘,包含从焰心到外焰的完整区域。如果火焰被树干遮挡成多个可见块,分别标注,不强行合并成一个框。
  • 烟雾框:只标注浓度足够形成明显视觉遮挡的区域。淡淡的、仅对背景产生轻微颜色影响的薄雾不算目标,这一条是清洗阶段砍掉最多数据的地方。
  • 小目标标准:小于32x32像素的目标一律标注。很多数据集为了省事直接忽略小目标,这恰恰是森林火灾检测最致命的伤。
  • 遮挡处理:目标遮挡超过80%的不标注,但在图片级标签里记录“含遮挡目标”标记,供训练时做cutout数据增强的参考。

标注工具用的是CVAT,团队多人并行标注时CVAT的任务分配和标签审查流程最成熟。如果个人使用,LabelImg也够用,但LabelImg对多边形标注支持太弱,火焰这种不规则目标建议至少用矩形框精修模式。

2.3 标注格式转换与数据清洗

原始标注从CVAT导出是VOC格式(XML),但训练YOLO系列模型需要YOLO格式的txt文件。转换脚本实现起来不复杂:VOC的bbox是左上角坐标加宽高,YOLO需要归一化到[0,1]区间的cx,cy,w,h,转换时重点注意坐标系和归一化的坑。

import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_path, class_dict): tree = ET.parse(xml_path) root = tree.getroot() img_w = int(root.find('size').find('width').text) img_h = int(root.find('size').find('height').text) lines = [] for obj in root.iter('object'): cls_name = obj.find('name').text if cls_name not in class_dict: continue bbox = obj.find('bndbox') xmin = float(bbox.find('xmin').text) ymin = float(bbox.find('ymin').text) xmax = float(bbox.find('xmax').text) ymax = float(bbox.find('ymax').text) x_center = (xmin + xmax) / 2 / img_w y_center = (ymin + ymax) / 2 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{class_dict[cls_name]} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") with open(out_path, 'w') as f: f.write('\n'.join(lines))

转换脚本写好后,我额外做了一轮自动化清洗:删除标注框超出图像边界的样本、删除面积小于15像素的疑似误标样本(这类样本即使真目标,对训练贡献也极小且容易变成噪声)、用脚本检查同类目标的框之间是否出现大面积重叠(排除重复标注)。清洗完还保留了约400幅标注边界存在争议的图像,放到独立的“待人工复核”目录,这一步很笨但确实有效。

3. 模型训练与调优实践

3.1 基线与数据划分

为了验证数据集质量,我先后跑了YOLOv8和YOLO11作为基线对比。之所以选YOLO系列,一是森林防火边缘设备(比如Jetson系列盒子)资源有限,YOLO系列轻量且推理性能好;二是Ultralytics生态配套完善,从训练到导出再到TensoRT部署是一条龙,对工程落地来说效率最高。

数据划分我特意做了场景层面的人工控制。纯随机划分会造成同一视频连续帧的相似图像同时出现在训练集和验证集,评估结果虚高。划分逻辑是按“场景会话”划分,即同一个视频来源的连续帧必须分配在同一集合,这样验证集的泛化表现更接近真实部署。

path: ./forest_fire_dataset train: ./images/train val: ./images/val test: ./images/test names: 0: fire 1: smoke

3.2 训练参数与增强配置

这里给出我最终使用的训练配置,按这个参数训练了200轮,效果比较稳定。模型选择YOLO11m,输入分辨率640x640,batch size 16,优化器SGD初始学习率0.01,warmup 3轮,最终余弦学习率衰减到0.0001。

比较关键的几个增强项:mosaic增强在火灾场景下其实很容易产生假目标,因为拼接图像时火焰区域可能被硬生生切到图像边缘,形成半截目标。我用mosaic 0.8的概率,在最后50轮关闭mosaic,让模型在真实分布上精调。copy_paste增强对火灾检测非常有用,可以把小目标的火焰区块粘贴到无火图像上,扩展小目标样本数量。实测下来,copy_paste对小目标AP的提升达到4到6个百分点,效果显著。

mixup增强也开着,但强度控制在0.3,火焰目标在mixup下变成半透明叠加,模型学习的其实是模糊特征,过头了反而会对烟雾这类本来就低对比度的目标造成混淆。

自动化增强策略AutoAugment我没有用,原因在于火灾目标本身存在高亮和暗光两种极端分布,自动策略很容易把暗光下的火焰增强到几乎不可见,造成标注与内容脱节。

3.3 训练过程复盘与关键评估

训练过程要盯两个指标:验证集mAP50和mAP50-95。前者只看框的定位和类别对了多少,后者对框的精确度更敏感。森林火灾检测的实际部署对误报率极其敏感,所以我更关注mAP50-95的变化曲线。

迭代到第60轮左右,mAP50-95的增长开始变缓,火焰类目的AP在0.78附近徘徊。我排查后发现大部分漏检发生在远距离火点,也就是小目标上。于是针对性做了三件事:

第一,把输入分辨率从640x640提到800x800。小目标在原图里可能只有10像素,放大后特征区域扩大,检测器能提取到更丰富的纹理信息。代价是训练速度下降约30%,但效果值得:小目标AP提高了6个百分点。

第二,增加小目标过采样。训练时按目标面积对图像分组,当一幅图的小目标数量超过3个时,采样权重翻倍。这一点在Ultralytics里需要自定义dataset类才能实现,代码不复杂但比较繁琐,具体做的时候可以参考官方文档中关于自定义数据集加载器的方法。

第三,关闭了分类损失中的大量背景样本挖掘。默认配置下,训练前期大量容易区分的纯背景块会主导损失函数,模型还没学到火焰特征就先学会了“什么都别检测”。把负样本比例调低后,模型学习火焰特征的注意力明显增强。

训练结束后,最优权重在测试集上的成绩为:火焰AP50达到0.921,烟雾AP50达到0.833,混合mAP50为0.887;小目标(面积小于32x32)单独评估AP50为0.764。相比上一版数据集训练出的模型,小目标AP提升了9.7个百分点,烟雾误检率下降了接近40%。这个结果说明数据集重构的方向是有效的。

4. 部署落地与工程化经验

4.1 模型压缩与推理加速

模型训练完只是第一步,真正部署到边缘设备才是考验。森林防火监控塔和无人机搭载的算力平台通常有限,像Jetson Orin Nano这类设备,理论算力有20到40TOPS,但实际跑浮点模型,帧率往往只有10到15FPS,无法满足多路视频流实时分析的需求。

我的处理流程是:先做通道剪枝,再用INT8量化。通道剪枝可以直接在训练时通过稀疏训练实现,在loss中加入BN层缩放因子的L1正则,让一部分通道的缩放系数趋近于0,然后剪掉这些低贡献通道。稀疏训练权重设0.0001,从第80轮开始,直到训练结束,剪枝后模型参数量从YOLO11m的约2000万降到约1300万,mAP50-95只掉了0.9个百分点,可以接受。

量化用的是TensorRT的INT8量化,校准数据集从训练集里挑选400幅覆盖不同光照条件的图像。注意校准集一定不能只用简单场景,否则量化后模型对复杂场景的适应力会断崖式下跌。INT8量化后,推理速度从18FPS提升到42FPS,实测单路1080P视频流完全够用。

4.2 视频流的滑窗推理策略

森林防火监控有一个特殊性:视野范围固定,场景变化缓慢,但火灾一旦出现就要求极低的响应延迟。直接用逐帧检测会有两个问题:算力浪费和短期抖动。

我采用的是一个双阶段策略:抽帧检测 + 变化触发。平时每5秒抽一帧做检测,一旦某帧出现fire或smoke目标且置信度超过阈值,立刻切换为连续帧检测模式,直到连续30帧无目标才恢复抽帧模式。这个策略在部署现场实测里表现很稳定,既能保证正常监控的算力占用,又能在火情发生时快速响应。

辅助后处理方面,我做了一个NDT(邻近帧跟踪)模块,用简单的IoU匹配做短时目标关联。同一目标连续3帧稳定存在的才上报,单帧偶发的高分目标直接丢弃。这个模块大幅压低了误报率,林区监控里的飞鸟、飘动树叶、光影变化造成的闪烁误检基本都被过滤掉了。

4.3 误报抑制与置信度动态调节

实际部署中,误报比漏报更难缠。漏报可以靠多角度监控弥补,误报过多则会让人工值守的巡检员产生“狼来了”效应,最终不再关注系统告警。所以我花了不少时间做误报抑制。

比较有效的三条经验:一是对fire和smoke分别设置独立置信度阈值,火焰阈值可以低到0.35,因为火焰特征强、误检概率低;烟雾阈值至少0.5起步,烟雾和云、雾气、逆光区域的混淆太严重,阈值定得太低告警会爆炸。

二是利用场景语义做约束。部署的每个监控点位会有自己的地理语义,比如朝东的监控塔下午逆光严重,东侧山谷区域烟雾误检率高,这时候可以根据监控点位的方向配置光学特异性阈值。这一层规则逻辑在上层业务系统中实现,不写在模型推理代码里,便于灵活调整。

三是加入“目标最小持续时间”过滤。上报逻辑里要求目标至少持续出现2秒以上才推送告警,配合滑窗策略里的连续检测模式,误报率能再降低一半。

5. 常见问题与排查技巧实录

5.1 标注质量相关的坑

Q1:火焰框紧贴焰体后,训练时发现模型预测框偏小,几乎只框住焰心。原因是对火焰这类边界模糊目标,标注框“内缩”一个像素还是“外扩”一个像素,对IoU的影响远大于一般物体。模型通常会学一个折中归一化策略,如果训练集里存在系统性的内缩偏差,预测框就会偏小。处理办法是统一标注规则:宁可外扩2像素,不要内缩1像素。

Q2:烟雾标注的不一致性比火焰更严重。同一幅图像,两个标注员可能一个框整团烟雾,一个只框浓烟核心区域。我的经验是做两轮标注加一轮专家复核,第一轮粗标,第二轮对照参考图精修,专家只处理边界争议框。虽然人力成本增加,但数据集可用性提升明显。

5.2 训练效果相关的坑

Q3:训练初期火焰和烟雾的loss都降得不错,到后期烟雾AP突然暴跌。这通常是验证集里混入了一些高难度烟雾样本,模型过拟合训练集中特定烟雾形态后,对这些样本表现骤降。缓解办法是加强训练集的烟雾形态多样性,这个多样性不是指数量,而是指透明度梯度、背景遮蔽率、光照条件三个维度的分布。我补充了一批背景明亮的薄雾样本后,这个现象基本消失。

Q4:小目标AP始终上不去。除了前面提到的分辨率提升和过采样,还要检查NMS策略。小目标密集环境下,默认的NMS IoU阈值0.5会抑制掉大量相邻的火焰框。森林火灾中近距离的火焰常常被树干分裂成多个相邻块,这些块的真实语义可能是同一个火焰区域,也可能不是。我实测的折中方案是把NMS阈值调到0.45,同时开启class-agnostic NMS,效果比默认配置好一些。

5.3 部署部署相关的坑

Q5:TensorRT量化后模型在夜间场景的检测能力大幅下降。原因是夜间图像的动态范围极大,火焰高亮区和背景暗部同时存在,INT8量化在校准时容易把暗部的量化步长压得太粗。解决方案是在校准集里强制加入30%的夜间图像,并且对夜间图像做直方图均衡化后再参与校准。

Q6:边缘设备掉电后模型推理结果不稳定。排查后发现问题出在CUDA的随机数生成器状态没有固定,导致部分操作(如NMS的随机排序)在不同运行时产生不同结果。解决办法是在推理前固定随机种子,并在导出引擎时锁定运算顺序。

6. 数据集使用建议与后续规划

做了几期数据集之后,我的一个核心体会是:数据集的价值不在于绝对数量,而在于它能在多大程度上逼近目标部署场景的分布。如果你的模型训练基于通用数据集,但部署环境是林区监控,效果不好是必然的。第5期这个数据集的价值,恰恰在于围绕森林火灾场景做了精细的分布控制,把小目标、烟雾形态、光照变化这些真正影响部署效果的维度做到了可量化、可复现。

对想直接使用这份数据集的开发者,几个小建议供参考:

  1. 训练前先按场景分层做一次可视化检查,确认自己的部署场景和数据集的场景分布在哪些维度上有差异,差异大的话优先做域适应增强。
  2. 不要照搬我的训练参数,输入分辨率和增强策略要跟你的算力平台匹配。算力不够的时候,宁可用更小的模型配更高的分辨率,也别用大模型配低分辨率。
  3. 数据集的验证集划分是按场景会话隔离的,评估结果比随机划分更保守,如果你发现模型在验证集上AP偏低,不一定是数据或代码有问题,很可能是评测基准变严格了。

后续我计划在这个数据集上做两个方向的延伸:一是加入时序模块,利用连续帧间的光流信息来辅助烟雾检测,烟雾在静态单帧里是弱特征,但在时间维度上有明显的扩散趋势,这个时序信号值得挖;二是做多光谱融合,结合红外热成像数据训练多模态检测模型,红外通道对火焰的响应远优于可见光,尤其适合夜间场景。

做数据集是个持续投入的活,每一次迭代都是在跟模型短板较劲。第5期解决的是小目标和烟雾误检,下一期要解决的是复杂地形下的目标连续跟踪和遮挡鲁棒性。路还长,但方向是清楚的。希望这篇内容能给正在做火灾检测、目标检测数据集或者林区监控系统的朋友一些参考。

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

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

立即咨询