ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

YOLOv11小目标检测实战:无人机飞机直升机数据集训练与优化

2026/9/17 5:13:14 拓冰建站 浏览量
YOLOv11小目标检测实战:无人机飞机直升机数据集训练与优化 无人机、飞机、直升机这类目标在画面里往往只占十几个像素甚至更小。用YOLOv11训练这种小目标检测数据集如果只是套用网上的默认命令基本都会翻车不是把云层和建筑当成飞机就是远处的小型无人机完全没被框出来更常见的是一训练loss就剧烈震荡mAP怎么都上不去。我这两年一直在做空中目标识别相关的项目从军事遥感到低空安防都接触过用YOLO系模型反复折腾过不少数据集和优化方案积累了一些经验。这篇文章就把我对“无人机、飞机、直升机检测数据集 YOLOv11训练小目标”这件事的完整理解和实操记录写下来从数据集怎么准备、模型怎么选到训练参数怎么调、小目标专项优化怎么做再到常见问题怎么排查都尽量讲透。适合正在用YOLOv11做小目标检测的朋友参考尤其是做无人机反制、遥感目标识别、智慧城市低空监控这类场景的。1. 项目整体思路与难点拆解1.1 核心需求检测“空中小目标”到底难在哪里先说清楚我们面对的任务输入一张航拍图或监控画面输出图中无人机、飞机、直升机的位置框和类别。听起来跟通用目标检测没区别但真正跑起来就知道难度完全不在一个量级。难点主要来自三个层面。第一是目标尺寸太小。在常见的1920x1080监控画面中一架距离较远的无人机可能只有10x10像素即便是客机在大多数场景下也只是几百像素。小目标在卷积网络中经过多层下采样后特征图上的响应非常微弱到深层的特征图甚至只剩下一两个像素点信息几乎丢失。第二是特征信息匮乏。小目标的纹理、边缘、颜色信息都极其有限模型很难学到有区分度的表达容易出现“看起来像鸟就框出来”的误检。第三是样本不均衡。大量图像中小目标数量稀少而背景区域极大正负样本极度失衡模型训练时容易偏向学习背景特征。针对这些难点我们必须在数据集构建和训练策略上都做出调整而不是单纯改几个epoch或batch size。1.2 为什么选择YOLOv11来做这项任务当前YOLO系列已经迭代到YOLOv11相比前代它在骨干网络和训练策略上做了不少优化。首先是模型结构上使用了C3k2模块和更高效的SPPF结构在降低计算量的同时保持了较好的特征提取能力其次是整个检测流程采用了Anchor-Free设计不再依赖预设的锚框尺寸。这个特性对小目标检测其实是个好消息因为传统YOLO需要手动设置或聚类选择anchor尺寸而小目标的尺度变化极大固定anchor很容易漏掉。Anchor-Free方式直接回归目标中心点和边长能更灵活地适应不同大小的目标。不过我还是要泼一盆冷水YOLOv11默认配置是为MS COCO这种通用数据集优化的COCO中的小目标占比并不高而且小目标定义是“边长小于32像素”。直接拿默认权重在无人机数据集上微调效果只能算差强人意。所以我们需要做的不是盲目套用而是理解它的结构然后对数据、输入分辨率、训练参数和检测头配置做针对性调整。1.3 小目标检测的数据集是成败的关键很多同学上来就急着下载pretrained weights然后跑训练脚本结果效果不好第一反应是模型不行。实际上对小目标检测来说数据集的优先级远高于模型结构。我见过太多样本数量足够但标注质量差的数据集比如标注框严重偏离目标、把整片云都框进一个框里、或者同一目标在连续帧中标签不一致这些都会导致模型学到错误信息。一个好的小目标数据集应当满足几个条件目标清晰可辨即使只有10像素也应当是一个紧凑的框类别平衡不能一个类别有十万个目标而另一个只有几十个场景多样包含不同光照、天气、背景和视角。公开数据集方面常用的是VisDrone无人机视角下的目标检测、UAVDT无人机视频任务、还有自己爬取叠加构建的遥感数据集。如果做更专业的反制场景往往需要自建数据集这点我会在下一节详细讲。2. 数据集准备与预处理这一步决定模型上限2.1 数据采集与标注的规范细则我先说结论数据质量比数据量更重要尤其对小目标。这里的“质量”不只是指图像清晰度更关键的是标注边界框的准确度和一致性。标注小目标最常犯的错误就是“顺手把周围背景一起框进去”。比如一架飞机在远处只有20x15像素但标注时手一抖框成了40x30像素包含了一部分云层或地面。这样的标签会让模型学习时认为目标周围的背景也是目标推理时自然会把相似背景误检成飞机。反过来如果框太紧比如只框了机身而漏掉机翼模型学习时又难以定位到完整目标。所以小目标标注有一套经验对于小于32x32像素的目标框紧一点优于框松一点对于较大的目标应该准确贴合目标的实际轮廓。建议使用专业的标注工具比如LabelImg、X-AnyLabeling或CVAT放大图像仔细标注并且由多人交叉验证统一标注标准。此外类别定义要明确。比如“无人机”和“飞机”在图像上确实差异较大但“直升机”和“大型四轴无人机”从俯视角度看起来可能很相似。务必定好类别边界避免人为引入噪声。2.2 数据增强针对小目标的特殊处理YOLOv11训练时默认开启了很多数据增强包括Mosaic、MixUp、随机缩放、平移、翻转、HSV变化等。这些增强方式对中大型目标有效但小目标往往会“遭殃”。一个典型问题是Mosaic增强把四张图拼成一张在随机裁剪和缩放后原本就小的目标可能直接消失了或者被截断掉一半。这反而会让模型学不到小目标的完整形态。针对小目标我做过的几种有效处理方式供参考在Mosaic操作中限制缩小的比例避免小目标被缩到不可见。可以修改ultralytics中对mosaic的scale参数或者对小目标样本单独关闭mosaic。使用“复制粘贴”增强从图像中裁剪出小目标缩放到随机尺度然后粘贴到背景图像中的随机位置。这样可以人为增加小目标的数量和场景多样性效果非常显著尤其当你的数据集小目标数量不足时。调整增强的重叠概率。将hsv_h、hsv_s、hsv_v、degrees、translate、scale等参数适当降低减少极端形变对小目标特征的影响。不要对整张图做过强的模糊或噪声增强小目标的纹理信息本来就很脆弱过度的加噪会进一步淹没特征。我自己的经验是增强策略必须和数据分布相匹配。如果数据集中小目标占比高建议关闭Mosaic或设置mosaic0.5左右如果中大型目标多则保持默认就行。2.3 数据集划分与格式整理YOLOv11可以直接使用YOLO格式的数据集目录结构一般是这样datasets/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/每张图像对应一个同名的txt文件每行表示一个目标class_id cx cy w h其中cx、cy是中心点坐标w、h是宽高全部以图像宽高归一化到0-1之间。这里有几处非常容易出错一是坐标必须归一化忘了除以宽高会导致训练直接爆炸二是类别id必须从0开始连续排列比如你有drone、airplane、helicopter三个类别那么类别id分别是0、1、2不能跳号三是检查是否存在空标签文件如果某张图没有任何目标label文件可以是空文件但最好不要有缺少文件的情况否则读取会报错。划分数据时我建议不要让同一条视频或者同一架次的图像同时出现在train和val中。否则模型相当于看到过这些目标验证集的分数会虚高实际部署时表现反而缩水。按视频段或按拍摄地点划分更可靠。2.4 负样本和难例挖掘提升精度的隐形变量许多人训练目标检测模型时只把所有包含目标的图像拿来做数据集这是错误的。如果训练集中没有负样本不含目标的图像模型在推理时会倾向于在任意位置都输出一个框导致大量误检。尤其在空中目标检测中云层、飞鸟、树枝、远处信号塔都极易成为假阳性。我建议在训练集中加入10%-20%的纯背景图像这些图像的label为空文件。如果你已经有一个初步训练好的模型还可以用它在大量无目标图像上做一次推理把模型错误检出的目标框作为“难例”重新标注确认确实是假阳性后保留空标签再加入到训练数据中这就是典型的难例挖掘Hard Negative Mining。这一步能显著减少部署时的虚警率。3. YOLOv11环境配置与模型训练基础3.1 搭建训练环境从零开始并不难YOLOv11主要依赖PyTorch框架和ultralytics库。环境安装其实是一个体力活按照以下顺序基本不会出错。首先安装CUDA和cuDNN。如果你使用的显卡是NVIDIA的建议装CUDA 11.8或12.1然后pip安装对应版本的PyTorch。比如CUDA 12.1版pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121安装完成后验证一下import torch print(torch.__version__) print(torch.cuda.is_available())能输出True就说明环境OK。接着安装ultralyticspip install ultralytics它会自动拉取需要的依赖项。建议使用Python 3.8到3.11之间的版本我目前用的是3.10实测稳定。如果想要复现实验可以固定ultralytics版本比如8.3.x。3.2 准备数据配置文件与模型配置训练前需要在ultralytics中定义一个数据集yaml文件内容类似这样path: ./datasets/aircraft train: images/train val: images/val test: images/test nc: 3 names: [drone, airplane, helicopter]path是数据集根目录train和val是相对路径。注意YOLOv11中如果你的图像和label目录不在同一层级它通常会自动将images替换为labels来寻找标签文件。如果你使用了自定义目录名可以用train_labels字段显式指定。这里最常遇到的问题是路径写错导致训练开始时直接报错“Dataset not found”或“No labels found”。模型配置可以通过命令行选择预定义模型。比如使用nano尺寸yolo detect train dataaircraft.yaml modelyolo11n.pt epochs100 imgsz640 batch163.3 关键训练参数详解与调优建议很多新手对训练参数不理解盲目照搬别人的参数其实每个参数都有它的意义。下面我把几个关键参数逐一分析。imgsz是输入图片尺寸这是影响小目标检测最为关键的一个参数。默认值是640这对通用检测合理但对小目标来说640分辨率下原本10像素的目标会被进一步压缩到几个像素几乎不可用。建议小目标场景至少使用1024或1280。高分辨率带来的收益非常直接但显存消耗也是成倍增加需要结合硬件条件取舍。batch是批次大小直接影响训练稳定性和显存占用。如果一张1280x1280的图batch8都会爆显存可以考虑batch4同时开启梯度累积或者在ultralytics中直接设batch-1让它自动选择。要注意batch太小会导致BatchNorm统计不稳定loss容易震荡。epochs代表训练轮数。小目标数据集的收敛速度通常比通用目标慢因为每个目标携带的信息量少需要更多迭代才能学到稳定特征。我一般的做法是先用150轮跑一次看趋势如果val_loss还在下降就继续轮数或使用早停。lr0是初始学习率默认0.01SGD或0.001AdamW。小目标数据中如果存在类别不均衡学习率过大会导致后期震荡过小收敛太慢。建议使用默认值然后观察前10轮的loss变化。如果出现loss爆炸或NaN大概率是学习率过大或数据中有异常标签。mosaic默认是1.0即每轮都启用mosaic增强。如果你发现训练中的小目标表现一直不好可以尝试设置为0.5或0。另外close_mosaic参数可以设定在最后10轮自动关闭mosaic让模型在最终阶段适应更真实的数据分布这是个很实用的技巧。patience是早停耐心值设置为20-50可以在验证集指标停止提升时自动终止训练节省时间。workers是数据加载线程数。建议根据自己的CPU核数设置4-8即可。设置太大会出现“DataLoader worker exited unexpectedly”的问题。3.4 预训练权重选择与迁移学习策略YOLOv11提供n、s、m、l、x五种尺寸分别对应不同的深度和宽度。对小目标检测哪些预训练权重效果好我的经验是如果你追求速度和实时性并且数据量不大yolo11s.pt是比较平衡的选择如果数据量较大且有充足显存yolo11l.pt的效果通常优于yolo11n因为更大的模型有更强的特征表达能力。但也要注意小目标检测中模型过深不一定是好事深层特征图分辨率严重降低反而丢失小目标信息。因此我更推荐中档模型s或m然后依靠输入分辨率和优化技巧提点。迁移学习时需要注意预训练权重是在COCO上训练的其中可能包含80个类别但当你使用自己的数据集时模型会自动调整输出层类别数。正常情况下你只需要加载预训练权重并进行完整的模型参数微调。我习惯冻结backbone层前几层只训练后面部分这样既快又能在数据量不足时防止过拟合。但冻结的比例不宜过高否则模型对小目标的适应性不足。一般冻结前三层即可。4. 小目标优化从模型结构到训练策略的硬核手段4.1 提高输入分辨率最直接有效的“野路子”如果你想快速看到小目标mAP提升我首推调大imgsz。当输入从640增加到1280小目标在特征图上的像素占比成倍提高模型能够学到的细节更加丰富。但代价也很明显推理速度下降、显存消耗加大、训练时间变长。比如RTX 3090在1280分辨率下训练yolo11mbatch4大约是8个多小时一百轮。这需要在效果和成本之间做权衡。对于远距离小目标我认为使用1024是一个折中选择如果你做的是离线分析而不是实时告警1280甚至1536都值得尝试。补充一下推理阶段需要保持与训练阶段一致的输入尺寸否则会出现域偏移。有的同学训练用1280推理用640结果性能下降明显就是这个原因。4.2 借用多尺度训练与测试增强鲁棒性多尺度训练是指每轮迭代随机选择一个尺寸比如从640到1280中随机选一个让模型适应不同尺度的目标。YOLOv11本身就支持多尺度训练在训练时通过scale参数控制比例。但对于小目标检测建议把多尺度范围限制在1088到1280之间不要使用过小的尺寸否则小目标又会被缩没了。多尺度测试TTA通常是在测试时对图像做多种尺寸缩放然后融合结果。这样做通常能提升1-3个点的mAP代价是推理时间成倍增加。一般只在打比赛或做离线评测时使用。4.3 增加P2检测层让小目标“看见”高分辨率特征这是一个非常关键的结构优化。YOLOv11的检测头通常输出三个尺度分别来自不同的特征金字塔层对应大中小目标。但对小目标来说最浅层的特征图分辨率仍然不够。我们可以手动在模型yaml中添加一个更浅层的检测头也就是P2层它的步长只有4相比默认的P3步长8特征图尺寸扩大一倍对应小目标的信息更完整。修改方式是在配置文件中增加一个检测头分支并在head部分把输出尺度数量从3改为4。具体做法参考ultralytics官方或社区中的yolo11-p2.yaml。比如在backbone中取出第二层特征送入head然后与neck融合。这样修改后模型参数量略有增加但对小目标的recall往往有明显提升。我实测在VisDrone子集上增加P2层后mAP0.5提升了2到4个百分点。不过要注意增加P2层也会带来更多的计算量和显存消耗而且如果噪声多反而容易误检。建议在已经使用1280输入分辨率的前提下再考虑P2层。4.4 损失函数与后处理参数优化YOLOv11默认采用BCEWithLogitsLoss作为分类损失CIoU和DFL等作为回归损失。对于小目标默认的置信度阈值和IoU阈值常常导致大量漏检。训练时可以通过调整box_loss的权重来增强定位精度但这个参数需要仔细调优我一般把它设为7.5左右默认可能不同版本不同。在推理阶段conf阈值决定只输出置信度高于该值的框iou阈值决定NMS去重时的IoU阈值。很多用户因为误检多就把conf设得非常高比如0.6结果把真实的小目标也给滤掉了。对于小目标场景我更建议把conf设置在0.15-0.25之间先保证recall再用特定规则比如目标面积、类别概率过滤。NMS的iou可以适当调大一些比如0.7因为小目标之间的重叠区域不会像大目标那么夸张过高iou也不至于抑制过多。4.5 基于数据层面的人工难例增强除了模型和参数还有一种被验证非常有效的做法在小目标数据集中人工把裁剪好的目标贴到背景图像中生成合成数据。这可以解决小目标稀疏的问题也叫“Copy-Paste”增强。实现方式并不复杂从训练集中抠出远处的飞机、无人机随机旋转缩放后粘贴到没有目标的场景图上同时生成对应的标签。注意要处理遮挡关系不要让粘贴的目标边缘看起来太假否则模型会学到不自然的特征。我曾在一次数据集中将小目标数量增加了3倍配合这种增强模型的recall从0.6提升到0.78效果立竿见影。5. 训练实操过程、日志解读与问题排查5.1 一次完整的训练命令与日志解读以一个典型的小目标数据集为例我训练的启动命令如下yolo detect train \ datadatasets/aircraft.yaml \ modelyolo11s.pt \ imgsz1280 \ batch8 \ epochs200 \ lr00.005 \ optimizerAdamW \ patience30 \ close_mosaic10 \ cacheTrue \ projectruns/aircraft \ nameexp1这里选择用AdamW而不是默认的SGD因为AdamW在小目标场景下往往更快稳定尤其是数据量不大的时候。训练开始后你会看到类似下面的输出Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size 1/200 8.1G 1.102 2.351 1.118 12 1280 5/200 8.1G 0.872 1.701 0.952 21 1280 10/200 8.1G 0.734 1.234 0.831 34 1280判断训练是否健康的主要指标有三个box_loss在初期快速下降中后期缓慢下降cls_loss稳定下降没有反复波动每个epoch的目标数量Instances基本能覆盖各类别。如果某一类别的Instances始终为0说明该类别的标签可能有错误或者数据分布严重不均衡。每轮epoch结束后会输出验证集指标包括mAP50、mAP50-95等。当mAP50-95连续多轮不升反降并且box_loss还在下降可能过拟合了此时需要增加数据增强或引入正则化。5.2 显存不足的根本解决思路训练小目标时使用大分辨率和较大模型最常见的报错就是CUDA out of memory。这时候不要急着换显卡先试以下组合技降低batch_size比如从8降到4或2同时增加accumulate参数实现梯度累积保持等效batch大小。ultralytics支持设置batch4 accumulate2效果与batch8近似。降低模型尺寸从m降到s。使用AMP混合精度训练ultralytics默认开启ampTrue它会大幅降低显存占用对小目标训练影响很小。关闭cacheTrue的RAM缓存。如果机器内存不够缓存图片会爆内存。 使用cacheFalse或cachedisk。5.3 训练不收敛的常见原因与对策训练loss居高不下或直接变成NaN原因通常是以下几个方面标签文件格式错误。坐标没有归一化或者出现负数、大于1的值。可以写个脚本扫描所有txt文件检查是否存在非法值。类别ID超出nc范围。比如nc3但标签里出现了class_id4这会导致训练loss异常。学习率过大。尝试降低lr0到0.001并开启warmup。图像数据损坏。个别图片文件损坏或通道数异常比如4通道PNG导致DataLoader读取错误表现为训练中途崩溃。可以先用脚本遍历一下图片用PIL验证能否打开并统一转换为三通道RGB。5.4 小目标漏检严重的排查方向训练完后跑测试集发现小目标漏检很多我建议先做这几步排查检查是不是输入分辨率还不够高。把imgsz调到1280再测一下。如果效果明显提升说明分辨率是瓶颈。检查验证集标注是否准确。用训练好的模型直接可视化预测把预测和标签画在同一张图上看小目标是否真实存在但标注框偏移或缺失。检查是否使用了过高的置信度阈值。在predict时设conf0.05看看候选框中是否包含小目标。如果置信度都集中在0.1以下则说明模型对这部分目标不够自信需要从数据增强和P2层入手。检查数据增强在小目标上的破坏程度。你可以临时关闭mosaic、mixup等增强在相同参数下训练10个epoch对比看小目标recall是否有变化。5.5 其他常见报错与速查表我整理了一份速查表基本涵盖了训练中遇到的高频问题报错信息常见原因解决办法No labels found标签路径错误或标签文件不存在检查数据集目录结构确认labels相对images的映射关系Label class 1 exceeds nc3对应类别ID超过类别数检查标签文件重新编号或扩展ncCUDA out of memory显存不足降低imgsz、batch或模型尺寸开启AMP梯度累积RuntimeError: CUDA error: device-side assert triggered标签中有非法值常伴随类别越界扫描并清洗标签文件NaN loss学习率过大或有异常数据降低lr检查数据开启warmup训练很快结束但结果很差早停误触发或数据集划分不合理增大patience检查train/val分布是否独立6. 模型评估、预测结果保存与部署经验6.1 小目标场景下该关注哪些评估指标通用检测报告一般会打印mAP50和mAP50-95但对小目标检测我们需要额外关注小目标特定指标。一种做法是把COCO定义的small、medium、large分别评估ultralytics的验证脚本会自动输出这些分段的AP。在代码中你可以通过以下方式查看from ultralytics import YOLO model YOLO(runs/aircraft/exp1/weights/best.pt) metrics model.val(datadatasets/aircraft.yaml, imgsz1280) print(metrics.box.ap50) # 各类别mAP0.5 print(metrics.box.ap) # 各类别mAP0.5:0.95 print(metrics.box.small_ap) # 小目标面积小于32x32的AP此外定性查看预测结果是必要的。建议在测试图像上把GT框和预测框画在一起用不同颜色区分能够直观看到漏检和误检。特别注意一个模型mAP看起来不错但可能大目标AP很高而小目标AP几乎为0。小目标场景必须以小目标AP作为主要优化导向。6.2 预测后保存结果的多种方式训练、验证完成后你需要把模型用于测试集或实际输入图片。常见需求包括保存带框的图片、保存txt检测结果、保存可视化视频等。ultralytics提供非常简洁的推理接口from ultralytics import YOLO model YOLO(runs/aircraft/exp1/weights/best.pt) results model.predict(test_images/, imgsz1280, conf0.2, iou0.7, saveTrue) for i, r in enumerate(results): # 保存txt标签到文件 r.save_txt(output_labels/ str(i) .txt, save_confTrue) # 返回numpy数组格式的检测框 boxes r.boxes.xyxy.cpu().numpy()也可以保存JSON格式输出需要设置save_jsonTrue。注意save_txt输出的是归一化坐标和训练标签格式一致方便后续二次处理。无论是保存图片还是保存推理结果都要保证给imgsz赋值与训练一致避免尺寸不匹配带来的性能下降。6.3 部署时的一些经验之谈小目标检测部署在实时系统中时最大的矛盾是精度与速度的平衡。1280分辨率虽然效果好但在边缘设备上可能无法达到实时帧率。一种折中方案是先用大分辨率模型做稀疏帧检测再用小分辨率模型做连续帧跟踪。也可以考虑将训练好的模型导出为ONNX或TensorRT格式以加速推理。导出ONNX非常简单model.export(formatonnx, imgsz1280, halfTrue)如果是边缘设备建议导出FP16版本的ONNX再转换为TensorRT能显著降低延迟。我在NVIDIA Jetson设备上实测yolo11s 1280输入 TensorRT FP16大约可以跑到15-25 FPS基本满足低速监控场景。最后再分享一点我个人的体会做小目标检测这几年最大的感受就是不要神化模型结构。YOLOv11确实很好用但真正拉开效果差距的往往是那些“笨功夫”——把数据集标注质量提上去把分辨率舍得提高把数据增强对应用场景适配好再叠加精细化的训练策略。每次我在项目里遇到小目标漏检第一反应都是回去检查数据而不是马上换模型。只有这些基础工作扎实了像P2层这样的结构优化才能发挥真正作用。如果你正在跑无人机、飞机、直升机这类数据集不妨先按照前面的步骤梳理一遍自己的数据和参数很多卡住的问题都会迎刃而解。