ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

YOLOv11无人机检测实战:小目标识别、训练调参与部署

YOLOv11无人机检测实战:小目标识别、训练调参与部署 简介基于YOLOv11的智能无人机检测系统完整项目资源面向从事图像识别、目标检测研发的工程师及科研人员用于快速搭建可落地部署的无人机识别与安防监控方案。资源包共669个文件包含Python源码172个py、模型配置82个yaml、权重文件1个pt、文档说明369个md及GUI界面相关组件整体6.51MB结构清晰便于二次开发与学习。目前已有122人浏览学习。整套代码与文档覆盖了完整检测流程支持图片、视频与摄像头实时检测附带PySide6图形界面可调整模型与阈值并提供了模型训练、推理与部署的代码框架及配套文档适合作为课题设计、算法实证或项目参考。1. 用yolov11做无人机检测最先要解决的是“小目标”问题监控大屏上出现一个只有十几个像素的黑点人眼往往要盯两三秒才能确认那是一架无人机而一套基于yolov11算法的智能无人机检测系统必须在两三百毫秒内完成从检出、框选到告警的全过程。无人机在视觉检测里恰好落在最尴尬的区间目标小、速度快、容易和背景融为一体典型的“低慢小”目标。把yolov11落成一套可用的检测系统难点不在训练脚本本身而在于网络结构如何选、数据怎么标、推理参数怎么调。这篇文章按我实际做类似项目的顺序来写覆盖yolov11的模型选型、无人机数据集的组装、训练调参以及预测后保存和告警闭环新手能跟着跑通做过一段时间目标检测的人也能对照自己的参数设定找差距。2. yolov11的网络结构对无人机检测意味着什么2.1 检测头改为anchor-free后小目标训练少了一个坑无人机在画面里的尺度变化远大于行人和车辆。近处的大疆四轴能占到半个屏幕300米外的微型穿越机只有几个像素。在旧版YOLO里anchor的预设尺寸和长宽比需要根据标注数据重新聚类聚类结果又和相机焦距、安装高度强相关换个机位就得重算。yolov11沿用anchor-free设计检测头直接用解耦分支回归目标的四条边不再依赖预设先验框。这对无人机检测有一个直接被感知的好处不用再维护一套随场景漂移的anchor参数。模型在训练时通过回归损失自己学习目标的宽高分布只要训练数据里覆盖了大目标和小目标部署时换一个视野更窄的摄像头不需要重聚类。另一个改动是检测头的解耦分类和回归走独立分支避免两个任务互相干扰。低空场景里无人机和飞鸟外形接近解耦头让分类分支可以有更高的判别独立性从训练曲线上看收敛更平稳。2.2 C3k2与C2PSA在特征提取上补了什么yolov11把之前的C3模块换成了C3k2。C3k2维持两个分支结构一个分支做残差短路径保留原始信息另一个分支通过多级拆分再融合来提取深层特征。这个模块用更少的参数量保留了特征融合能力对无人机这类外形紧凑、纹理细节集中在桨叶和机架上的目标比较友好细微纹理不容易在网络加深时被稀释掉。深层部分引入了C2PSA模块。C2PSA是在特征图内部做空间自注意力让模型不只盯着局部几个像素来判断“这是不是无人机”而是结合周围云层、楼宇、植被的上下文综合判断。远距离无人机经常只有几个像素局部纹理信息非常有限如果没有全局上下文模型很容易把飞鸟、风筝甚至镜头污点误判成目标。C2PSA对这类模糊判别的场景有实际提升代价是推理耗时增加。边缘设备上跑yolov11n时我会考虑关闭或替换这一层来换帧率服务器端保持默认即可。2.3 从n到x先定算力再定精度yolov11官方提供n/s/m/l/x五种尺寸参数按深度和宽度因子缩放。实际选型时不是越大越好而是先确定部署设备的推理预算。模型深度因子宽度因子参数量约适用场景yolov11n0.330.252.6M嵌入式设备、边缘盒子要求实时yolov11s0.330.509.4M中端GPU、安防NVRyolov11m0.670.5020M服务器端精度优先yolov11l1.001.0025M离线分析、教师模型yolov11x1.001.5057M最高精度、模型蒸馏选择建议监控场景实时视频流用s或mm在小目标检出上明显强于s但显存占用约翻倍。边缘设备选n但要注意n对10像素以下的极小目标几乎不敏感必须配合更高的输入分辨率和后处理优化。服务器端做非实时巡检用l起步x留给蒸馏或困难样本挖掘。还有一个更实用的原则同样算力下优先把输入分辨率从640提到960比直接换大尺寸模型对小目标的提升更明显。3. 无人机数据集构造与标注规范把“低慢小”变成可学习的样本3.1 三路并行的数据来源真实监控帧、公开数据、合成图像无人机检测的数据集比行人或车辆难凑核心原因是大多数监控场景里无人机出现的频率太低。我一般用三路并行来组第一路是实际场景里的监控视频抽帧覆盖早晚不同光线、顺光逆光、不同相机位姿这部分占比最高因为部署时遇到的场景分布主要靠它兜底。第二路是公开数据集中包含无人机、航空器类别的子集清洗后并入训练集用于扩充目标姿态的多样性。第三路是合成数据把无人机贴图叠加到真实背景上注意光照方向和阴影角度要和背景一致否则模型学到的是贴图的边缘痕迹。合成数据占比建议控制在三成以内。超过这个比例模型容易把高对比度的矩形边缘误判成无人机真机上误报率会明显升高。三类数据合并后按场景打散划分训练集和验证集不能按来源划分否则验证集和训练集的分布差异过大指标会失真。3.2 统一标注与格式转换从VOC的XML到YOLO的txt标注规则要先定死。无人机整体遮挡超过一半且无法判断外形的样本直接丢弃旋翼旋转产生的模糊光影不单独标框只标机身主体远处的极小目标只要人眼能定位就要标出来不标会让模型产生系统性漏检。类别名统一为小写的drone避免混入大写变体导致类别数量膨胀。标注完成后大多数标注工具导出的是VOC格式的XML文件yolov11的ultralytics框架需要YOLO格式的txt。下面这个脚本做一次性转换 xml_to_yolo.py 将VOC格式标注转为YOLO格式txt 用法python xml_to_yolo.py xml_dir txt_dir import os import sys from xml.etree import ElementTree as ET classes [drone] # 类别列表只保留无人机 def convert(xml_path, out_dir): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) out_name os.path.splitext(os.path.basename(xml_path))[0] .txt with open(os.path.join(out_dir, out_name), w) as f: for obj in root.iter(object): cls obj.find(name).text if cls not in classes: continue box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # 归一化YOLO需要相对坐标而非像素坐标 cx (x1 x2) / 2 / img_w cy (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h f.write(f0 {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}\n) if __name__ __main__: xml_dir, txt_dir sys.argv[1], sys.argv[2] os.makedirs(txt_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): convert(os.path.join(xml_dir, xml_file), txt_dir) print(转换完成)转换逻辑里有几个关键点。一是类别编号固定由classes列表顺序决定当前只有无人机所以写死为0。二是x1、y1、x2、y2必须转成中心点加宽高的归一化形式除以图片宽高保证数值落在0到1之间否则训练时回归目标会失真。三是脚本对无效类别做了跳过如果XML里混入了bird、kite之类的负样本标签不会污染类别空间。3.3 增强策略要偏向小目标yolov11训练默认启用Mosaic增强但对无人机数据集我会再追加几项针对性增强。增强方法推荐参数对无人机检测的作用Mosaic概率0.5最后10轮关闭拼接多图增加小目标上下文CopyPaste概率0.3把无人机复制到新背景扩充样本量随机HSV扰动H±30S±25V±20适应早晚和逆光的光照差异小目标过采样对短边小于32像素的目标重复标注并放大改善极小目标的权重占比小目标过采样是需要手动处理的。Mosaic虽然能拼接图片但目标在拼接后仍然是小尺寸模型还是学不到足够的细节。常见做法是把包含极小目标的图片按区域裁剪放大1.5倍再塞进训练集让模型有机会看到放大的桨叶纹理。代价是训练集体积增大但收敛速度会更快。4. 训练与调参yolov11环境配置和核心参数怎么定4.1 最小环境配置与第一个训练命令yolov11环境配置比预期简单用ultralytics这个库就能跑通全部训练和推理流程不需要手动搭建网络结构。Python 3.10、PyTorch 2.x、CUDA 11.8以上这三样是基础。创建虚拟环境后安装ultralytics# 创建虚拟环境避免污染系统Python conda create -n yolov11 python3.10 -y conda activate yolov11 # 安装ultralytics会自动拉取依赖的torch、opencv等 pip install ultralytics # 训练用m尺寸做迁移学习 yolo detect train \ modelyolov11m.pt \ datadrone.yaml \ epochs150 \ imgsz640 \ batch16 \ device0 \ projectrun/drone_det各参数含义如下model指定预训练权重迁移学习在数据量不充足时收敛更快data指向数据集配置文件yaml里写好train和val的路径、nc1、names[drone]epochs设150起步后续根据验证集曲线决定是否加训imgsz是输入分辨率640是默认值batch按显存调整16对应约24GB显存8GB卡建议降到8device指定GPU编号。第一次训练建议用ms在小目标上的表现明显偏弱debug排错时不差那几分钟。4.2 三个必调参数imgsz、batch、epochs这三个参数对无人机检测的影响最大我每次换数据集都会先固定一组基准值再逐个调。参数基准值调整方向影响imgsz640小目标多时提到960输入分辨率翻倍极小目标的有效像素变成4倍显存约翻两倍batch16显存不足降到8影响BN统计和收敛稳定性太小会震荡epochs150看mAP曲线决定太少欠拟合太多过拟合且浪费算力不建议动的参数是anchor相关配置。yolov11是anchor-free设计强行修改anchor只会破坏训练稳定性。另外一个隐性问题在Mosaic增强默认开启但最后10到20轮建议通过配置文件里的mosaic0.0关闭让模型适应真实的单图分布否则验证时遇到无增强图片会掉点。4.3 从loss曲线和mAP指标判断模型是否健康训练过程中要盯两组指标。一组是loss曲线box_loss、cls_loss和dfl_loss三类损失都要下降其中box_loss波动大是正常的但如果持续上升而cls_loss在下降优先怀疑标注框质量有问题多半是中心偏移或宽高标错。另一组是验证集指标mAP50反映整体检出能力mAP50-95对边界框精度更敏感。无人机检测里mAP50达到0.85而mAP50-95只有0.3的情况很常见说明模型能找到目标但框不够准集中体现在小目标上。遇到训练震荡先查数据里是否存在空标签图片即没有标注目标的背景图混进了训练集。yolov11对这类图片会输出巨大的分类损失导致梯度异常。排查方法是在data.yaml配置里把train路径的图片和对应txt做一次数量匹配数量对不上就是漏标了。5. 推理部署与低慢小识别预测后保存、NMS调优与告警演示5.1 推理命令与预测后保存的完整写法模型训练完成后推理和结果保存直接用ultralytics的predict接口关键参数是save、save_txt和save_conf决定预测后保存的是图片、标签还是置信度# detect.py 推理入口 from ultralytics import YOLO # 加载训练阶段保存的最佳权重 model YOLO(run/drone_det/weights/best.pt) # 对视频流做推理逐帧返回结果 results model.predict( sourcecamera_0.mp4, conf0.25, iou0.45, imgsz640, saveTrue, # 保存绘制了检测框的视频帧 save_txtTrue, # 保存类别和坐标到txt save_confTrue, # 在txt里追加置信度 streamTrue # 视频流场景必须开避免一次性加载全部帧 ) for r in results: for box in r.boxes: if int(box.cls) 0 and box.conf 0.3: print(box.xyxy.tolist(), box.conf.item())代码里的参数按实际部署场景调整。conf0.25是置信度阈值低慢小场景建议降到0.2到0.3之间太高会漏掉远处小目标太低会产生大量误报。iou是NMS阈值默认0.45多目标聚集时调到0.5到0.6让重叠框合并更充分。save_txt配合save_conf会把最终置信度写到txt这个文件作为检测日志留存后续做告警追溯时可以直接读取。streamTrue必须开否则对长视频推理会吃满内存。5.2 低慢小场景提升检出的三个实践手段手段效果代价imgsz从640提到960小目标mAP提升3到8个百分点显存占用约两倍推理延迟变长多尺度推理尺度波动大的场景更稳推理耗时约三倍连续帧状态机告警抖动大幅下降实现成本低第一种是提升输入分辨率。GPU显存允许时imgsz从640提到960对远距离“低慢小”目标几乎是最有效的一步但帧率会下降需要实测确认。第二种是多尺度推理把单帧分别缩放到0.8倍、1.0倍、1.2倍输入模型再用NMS合并三组结果。第三种是连续帧状态机单个模型的输出只是原始检测框未经平滑直接弹告警会导致画面闪烁、误报频出。5.3 一个可演示的告警状态机与弹窗逻辑演示系统要识别“低慢小”无人机并弹出告警信息不能只靠单帧置信度我通常加一个极简状态机# alert.py 告警状态机 class DroneAlert: def __init__(self, min_confirm3): self.min_confirm min_confirm # 连续命中帧数 self.confirm_count 0 self.alerting False def update(self, detections): if len(detections) 0: self.confirm_count 1 else: self.confirm_count max(0, self.confirm_count - 1) if self.confirm_count self.min_confirm and not self.alerting: self.alerting True x1, y1, x2, y2 detections[0].xyxy[0].tolist() print(f无人机告警 坐标({int(x1)}, {int(y1)})-({int(x2)}, {int(y2)})) # 这里接前端弹窗或声光联动 elif self.confirm_count 0 and self.alerting: self.alerting False print(告警解除)min_confirm设为3即连续三帧检测到才触发告警缺帧时只减一不会因为单帧漏检就立刻解除。这样在远处小目标时隐时现的情况下告警不会闪烁。坐标输出做一次取整便于日志归档。如果要做持久化把这一行输出改写成写入SQLite或JSON文件即可。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进