无人机林火巡检实战:基于YOLOv11的红外小目标检测与部署
无人机林火巡检这个题目我想先跟真正做过一线项目的人握个手最难的部分永远不在飞手和飞机而在让模型在几千张红外航拍图里把那一小撮正在燃烧的东西从灌木、石头、地热和建筑余温里揪出来。我去年用一套航拍红外森林火灾图像数据集在 Ultralytics YOLOv11 框架下完整跑了一遍训练、调优、验证和端侧部署踩了不少坑也沉淀出一套可以复用的流程。这篇不是广告就是把我实际操作中验证过的东西连同失败路径一起讲清楚给准备在这个方向起步的人当个参照。1. 红外成像下的森林火灾目标跟普通目标检测到底不一样在哪1.1 可见光拍烟、红外拍热目标特征完全两个思路很多第一次接触这个项目的人会默认把 YOLOv11 当普通目标检测用拿着可见光火灾照片就去标框训练。老实说如果数据量够多可见光方案也能做出不错的结果但它在真实林区里有个致命短板烟一大火就看不见了夜里没光照火也看不见了。而无人机林火巡检真正要补的恰是这种全天时能力。红外热成像传感器抓的是物体表面的热辐射差异火焰区在热像上往往是高亮甚至饱和的白色块背景植被和地面则呈现低温暗色。这个特性带来两个直接后果模型不需要学颜色纹理只需要学“亮度分布和形态”所以灰度单通道就能训练不需要为了颜色做复杂预处理。但热成像的对比度受环境影响极大午后阳光晒热的岩石、公路、铁皮屋顶甚至反光的积水都是天然误检源。所以在动手训练之前第一件事不是装环境而是想清楚你的模型是在学“火的热特征”还是“火加背景的热特征”。我习惯把红外单通道转成伪彩后先人工看一版归一化统计确认正样本区域与背景在数值分布上有足够的可分性再决定后续增强方案。1.2 远距离火点只有十几个像素小目标问题躲不掉无人机巡航高度通常在100米以上一架 640×512 的红外相机视野里一棵树冠可能占不到 20×20 像素初起的小火点大概就落在 8×8 到 30×30 这个区间。这个尺寸在 YOLOv11 默认的输入分辨率 640×640 下经过几次下采样后特征图上的响应往往只剩下几个像素的峰值。这也是为什么有人拿通用目标检测权重直接训火灾数据mAP 很难看的原因之一。通用数据集里小目标占比不算高模型天然偏向中大型目标。针对红外林火任务我建议从模型的输入、锚框分配和增强策略三个方向同时下手后面会专门讲。2. 喂给YOLOv11之前红外数据集整理与标注里的几个硬要求2.1 数据来源、目录结构与YOLO标注格式训练一个可用于实际巡检的红外火灾模型数据来源基本有两类一类是常见的公开红外火灾图像集另一类是自采的无人机航拍红外视频抽帧。如果条件允许建议以自采为主、公开数据集为辅因为无人机视角下的俯视红外目标分布和地面手持红外相机的平视视角差别不小模型很容易在视角迁移上掉点。文件规范照着 YOLO 系列标准格式整理即可图片按images/train、images/val、images/test分目录存放标注文本放在同名的labels目录下txt 文件名与图片名严格一致每行内容为class_id x_center y_center width height坐标用相对图片宽高的比例归一化。实际整理的时候有一个很容易错的地方无人机的原始航拍图分辨率可能很高比如 3840×2160强行直接喂给 YOLOv11 训练一方面 batch size 被显存卡死另一方面大量图形细节超过模型输入尺寸反而容易过拟合。我的做法是先把原图切成 640×640 的滑动窗口块切块时相邻窗口保留 20% 重叠然后只保留包含标注目标的窗口其余全部丢弃。这样既保住了小火点的原始像素信息又不会因为整图缩放到 640 而把火点压没。2.2 红外图像的增强策略不能照搬可见光方案很多教程会让你直接用 Ultralytics 默认的 HSV 扰动增强但红外图像根本没有 H 和 S 通道HSV 扰动只作用于彩图对灰度红外图几乎不生效。我自己在代码里实际测试过把默认hsv_h、hsv_s、hsv_v全部调低对红外数据集收敛速度没有明显影响所以别在这上面浪费精力。真正有效的是这几类增强水平翻转和轻微旋转无人机姿态变化时林区地物方向会变做角度增强合理随机亮度对比度微调对应红外相机自动增益在不同高度上的波动CLAHE限制对比度自适应直方图均衡对远景低对比度火点非常友好能让灰度暗部细节更清晰随机裁剪、缩放组合帮助你模拟不同飞行高度下的尺度变化。2.3 类别设计明火、暗火、烟还是合并成一类红外热像在白天能拍到的烟往往是低温遮挡不见得是明显目标夜的烟几乎不可见。所以在红外数据集里把“烟”单独成一类的收益远不如可见光数据大。大部分项目我建议直接只设一个 fire 类最多再加一个 smoulder阴燃/暗火类别贪多。如果你的场景必须识别烟那建议把可见光图像和红外图像训练成两个并联模型而不是硬塞进同一个 YOLOv11 模型。这两个模态的目标分布差异太大硬凑在一起训练时类别间会互相抢梯度最后两边都训不好。3. Ultralytics YOLOv11起步环境装配、数据集配置与第一次启动训练3.1 环境依赖与模型规格选择Ultralytics 的安装近乎无脑Python 3.9 以上、PyTorch 2.0 以上即可执行pip install ultralytics之后命令行yolo和 Python 接口就都能用了。训练时我会习惯用 Python 脚本而不是纯命令行方便记录指标和动态调参。模型规格上YOLOv11 提供 n、s、m、l、x 几个档位是否训练更大的模型要视你的部署设备而定。我在这个项目里做了个小对比训练同样的红外火灾集yolo11n 和 yolo11m 的精度差距并没有普通目标数据集上那么大。原因还是小目标红外样本的有效特征信息量有限参数更大的模型吸收不到更多知识反而更容易记住背景噪声。如果你的最终部署目标是低功耗边缘设备直接选 n 或 s别心疼如果只是服务器做后处理用 m 求稳也可以。3.2 数据集配置文件的写法只需要写一个forest_fire.yaml把路径和类别声明清楚Ultralytics 会自动匹配图片和标注文件。path: /home/drone_ir_forest_fire train: images/train val: images/val test: images/test nc: 1 names: 0: fire这里有一个细节值得关注path字段建议写绝对路径但在项目迁移时要当成一个需要修改的配置项而不是写死到底。我遇到过几次因为换机器忘了改目录配置训练直接报了Dataset not found的错。3.3 第一次跑训练命令参数该给什么基准配置我建议这样起手yolo train modelyolo11n.pt \ dataforest_fire.yaml \ epochs200 \ imgsz640 \ batch16 \ device0 \ projectruns_fire \ namey11n_ir_v1 \ patience30 \ save_period5几个参数的选择理由epochs200看起来偏高但因为红外火灾样本量通常不大模型真正收敛经常要到 120 轮以后提前早停会损失不少 mAPpatience30是防止模型在中后期抖动明显时浪费算力save_period5是为了保留中间权重后面做损失曲线分析时你能看到每一阶段模型的性能变化而不是只有一个终点权重imgsz640是精度和速度的折中点。如果你的显存大鱼 24G直接用imgsz1280对小目标会有明显增益但推理速度会掉下来。哦对第一次训练前记得看一眼modelyolo11n.pt的下载目录Ultralytics 会自动从官方源拉权重国内网络环境慢的话可以手动下载好再放到~/.config/Ultralytics对应目录避免卡在权重下载那一步。4. 训练中最折腾人的部分损失曲线、超参与红外小目标的拉锯战4.1 判断收敛不能只看总 loss要看每一张图的难例后台打印的 loss 曲线初次看会让人心动过速前 20 轮降得飞快但 val 精度一直不高。这不是 Bug是目标分布太偏。红外火灾集里背景占比极大、目标占比极小模型前段在学“什么不是火”后段才开始真正学“什么是火”。所以训练时别只盯 loss要把每个 epoch 的 precision、recall、mAP50、mAP50-95 同时记录下来。我习惯通过下面的脚本持续看验证结果from ultralytics import YOLO model YOLO(runs_fire/y11n_ir_v1/weights/best.pt) metrics model.val(dataforest_fire.yaml, imgsz640, batch16, plotsTrue) print(metrics.box.map50, metrics.box.map)如果 mAP50 能稳定到 0.8 以上、mAP50-95 在 0.5 上下这个模型在真实场景就基本可用了。对红外火灾这种「背景极其复杂、目标极其简单」的任务mAP50 的可信度比 mAP50-95 高因为火的边界本身就不是清晰边缘过高的 IoU 阈值实际上是在惩罚正确的检测。4.2 超参调优几个关键旋钮往哪个方向拧在 Ultralytics 的训练参数里真正需要针对红外场景反复试的有这么几个lr0默认 0.01 有点激进。我用 AdamW 优化器时lr00.001起步配合lrf0.01做余弦退火收敛更稳。红外目标小、正样本少学习率太冲很容易直接把模型推到局部噪声解上。mosaic默认 0.5 或者更高。但问题来了一张 640×512 的红外图切四块合成一块原来的小火点会被进一步缩小到接近消失模型学不到东西。我的实际做法是前 100 轮mosaic0.5后 100 轮降到mosaic0.1让模型在后期回归真实目标尺度。close_mosaicUltralytics 也支持在训练后段自动关闭 mosaic这个对任何小目标任务都建议用上能明显缓解增强与真实分布之间的偏差。degrees建议 5 到 10不要随便给到 30 以上。无人机俯视图地面朝向变化没有你想象的那么大旋转太多反而把长条形的火焰方向性搞乱。box、cls、dfl这些损失权重我认为保留默认就好不要一上来就魔改先观察一轮基线再说。4.3 实测定格n 和 m 到底差多少以我自己的红外火灾数据集为例同类图像量 2500 张目标总框数约 4800 个yolo11n 训完 mAP50 能到 0.82yolo11m 提高到了 0.86 左右。差异存在但没有到“不可替代”的程度。反而推理速度的差距非常现实n 在边缘设备上能达到 40 FPS 上下m 掉到 20 FPS 左右。这就是一个典型的产品取舍无人机巡检要求的是在飞行中尽快发现火点而不是把一个框的 IoU 从 0.82 抬到 0.86。因此我最终线上方案选了 n同时配合后面会讲的切片推理来弥补小目标召回。yolo train modelyolo11m.pt \ dataforest_fire.yaml \ epochs200 imgsz640 batch16 device0 \ lr00.001 lrf0.01 optimizerAdamW \ mosaic0.5 close_mosaic10用起来会比默认配置更稳尤其当你换了一个数据分布不太一样的新林区时掉点幅度明显小于裸奔的默认参数。5. 验证集再好看也没用真实巡检场景的误检漏检排查经验5.1 红外图里最容易被当成火的几种东西在仿真/公共数据集上训出来的模型拿到真实航拍红外视频里跑一轮大概率会见到这样一批对手烈日暴晒后的裸露岩石、沙地热惯量不同导致局部热斑金属建筑屋顶、铁皮棚强反照率加高热容量形成和火相似的亮块道路、停机坪这类大面积高温区域正在运行的工程机械排气管、发动机舱是天然的“热点”。处理办法不能只靠继续堆数据。我记得很清楚第一次跑实飞视频时模型把一条晒了一下午的土路识别成了条状火带。我当时的解决思路是给训练集增加“负样本”比例但亲手把几千张单纯背景图塞回去标负样本这事又太蠢——最后发现更实际的方法是调置信度阈值把默认的 0.25 提到 0.4误检直接降了一半真火召回率几乎没有损失。5.2 漏检高发区逆光、烟雾遮挡、远距离小目标与误检相对的漏检通常发生在三种条件下火点过小且对比度低白天强烈的阳光压制了火焰的热信号距离稍远就融进了背景烟遮挡红外热像里烟呈现为低温半透明区火被半层烟盖住时边缘亮度下降模型会犹豫传感器噪声干扰个别边缘像素过热或坏点形成假热点反而把注意力引开。在实际工程里我发现漏检几乎都是“切片推理”能救回来的。做法很简单把原始大图按 640×640 滑窗切块每一块独立推理再将结果映射回原图坐标做 NMS。在 3840×2160 的航拍原始帧上切片推理能把小火点检测率提升明显代价是推理耗时翻倍。为了控制实时性我设置了轮流切片策略每隔一帧做全图推理中间帧只做疑似火点区域局部推理效果和耗时都能兼顾。5.3 置信度、NMS 和帧间逻辑三重过滤只靠单帧检测结果上报告警会被闪烁噪声打爆。我的最终判断管线分成三层模型层YOLOv11 输出所有conf 0.3的框单帧层对框做merge和过滤只留下置信度高于 0.45 的框帧间层同一个 GPS 位置连续 3 帧以上出现框才触发上报。红外相机随机噪声不会连续多帧叠到同一个坐标上这个逻辑能滤掉九成以上的虚警。from ultralytics import YOLO model YOLO(runs_fire/y11n_ir_v1/weights/best.pt) res model.predict( sourcefly_frames, conf0.3, iou0.45, imgsz640, device0, save_txtTrue, save_confTrue, )这样输出的 txt 结果再脚本做 GPS 坐标映射就能直接对接地面站的告警列表了。6. 从训练机到无人机模型导出、量化与端侧部署的一段记录6.1 从 PyTorch 权重到可上机的推理引擎训练完毕best.pt还只是一个 PyTorch 权重。真实部署到无人机边缘板卡上这一步必须做个“格式转换”否则推理延迟没法看。yolo export modelruns_fire/y11n_ir_v1/weights/best.pt formatonnx imgsz640 yolo export modelruns_fire/y11n_ir_v1/weights/best.pt formatengine device0 halfTrue imgsz640我用 TensorRT 导出 engine 后在同样的边缘设备上推理速度比 PyTorch 原生模式提升了约 3 倍。FP16 精度在这类任务上完全够用除非你要部署的芯片不支持 FP16才考虑 INT8 量化。INT8 在小目标任务上风险很高红外火点和背景之间的数值差异一旦被量化到 256 级里静默失真的可能性非常大训好的模型可能直接趴窝。我这里踩过的坑就是强行 INT8结果漏检率翻倍后来老老实实退回 FP16。6.2 帧率、功耗和检测距离的三方平衡无人机端侧部署最大的敌人永远是功耗和散热。红外相机本身工作温度就高板卡再满负载推理机器很容易热降频。一个可落地的配比是模型yolo11nFP16 TensorRT输入640×640 单通道灰度推理时强制转三分通道喂入频率常规巡航 5 FPS发现疑似目标后自动切到 10 FPS 锁定峰值功耗控制在 8W 左右整机续航不会被拖垮。检测距离是一个非常诚实的指标大目标一米见方的火堆在 300 米高度能被稳定检出小火点如烟头引燃的初期灌木在 150 米以上就开始不稳定这个性能分布必须写在项目文档里别给业务方超预期的承诺。6.3 一套可以带走的优化清单最后把我跑通整个流程后认为最值得复用的优化点整理如下当你自己动手训练时直接照着检查数据层面优先自采无人机视角红外视频抽帧不要只依赖公开红外火灾图集切块训练而非整图缩放。增强层面关掉 HSV 默认增强打开 CLAHE、水平翻转、轻微旋转后 10% epoch 调低 mosaic。超参层面用 AdamW、lr00.001、mosaic0.5、close_mosaic10、imgsz640显存大就 1280。推理层面大图切片推理 帧间稳定性过滤 置信度阈值提到 0.4 以上。部署层面导出 TensorRT FP16谨慎对待 INT8 量化预留热降频余量。照这个流程走一遍哪怕你手里的红外火灾数据和我的分布差异很大至少能保证第一版模型就落在可迭代的区间里而不是在乱调参数的道路上白白烧掉一周时间。