news 2026/9/16 20:29:56

无人机航拍小目标检测:YOLOv11与SAHI切片推理实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
无人机航拍小目标检测:YOLOv11与SAHI切片推理实战指南

1. 为什么无人机航拍的小目标检测这么难

先说一个很多人踩过的坑:把VisDrone这类无人机数据集直接丢进YOLOv11里训练,出来的mAP50可能只有10%上下,推理时远处的行人、车辆压根检测不出来,全是漏检。这不是模型不行,而是无人机航拍场景和常规目标检测场景的底层逻辑完全不一样。

无人机航拍的图像有几个天然的特点。第一,拍摄高度决定了目标在图像中的像素占比极其小,一辆车在2448x2048的原始图中可能只有20x20像素,一个行人更是只有8x15像素,这种尺寸在COCO数据集里连小目标的下限都够不着。第二,目标分布极度不均匀,画面里往往几十个目标挤在一块区域,其余大片区域空荡荡。第三,光照条件复杂,无人机在不同高度、不同时段拍摄,阴影、反光、遮挡问题交织在一起。

在这样的场景下,普通的目标检测训练策略会系统性失效。输入尺寸设成640x640时,一个20x20像素的小车被压缩到5x5像素,特征图上的信息几乎全部丢失,模型根本学不到有效特征。即便强行把输入尺寸提到1280x1280,显存占用暴涨,训练速度也拖慢好几倍,而且对极小目标的提升依然有限。

所以做无人机小目标检测,核心思路必须调整:不是把整张大图硬塞给模型,而是先切块放大目标,再检测,最后把结果拼回去。这个思路正是SAHI(Slicing Aided Hyper Inference)的设计初衷,也是当前工程界验证过最有效的小目标检测方案之一。

2. YOLOv11与SAHI组合的整体设计思路

2.1 YOLOv11在航拍场景下的优势与局限

YOLOv11虽然是目前YOLO系列里综合表现很好的版本,但它本身并不会自动解决小目标问题。它的C3k2模块和C2PSA注意力结构在特征提取上确实比前代更强,推理速度也有提升,但对无人机航拍场景而言,单靠模型结构改进是不够的。

真正的问题在于特征金字塔的底层细节保留能力。YOLOv11的P3层(80x80特征图)对小目标来说依然太粗糙,一个只有8x15像素的行人映射到P3层上只有约1x2个像素,几乎无法形成有效的特征响应。这就是为什么即便用YOLOv11,直接检测航拍小目标依然会大量漏检。

2.2 SAHI切片推理的核心思路

SAHI的思路非常朴素但极其有效:既然目标在整张大图上太小,那就把大图切成若干小块,每块用一个合适的尺寸去检测。比如2448x2048的图,切成640x640的小图,每个行人的像素就放大了好几倍,原本只有8x15像素的目标,现在变成40x75像素左右,特征信息丰富得多。

SAHI的关键在于切片重叠机制。如果直接把大图切成不重叠的块,位于切缝边缘的目标会被拦腰截断,一半在左边图,一半在右边图,两张图都识别不出来。SAHI通过设置overlap ratio参数,让相邻切片之间有一定重叠区域,比如20%的重叠,这样切缝处的目标至少在一张切片中是完整的,检测概率大幅提升。

切片检测完之后,SAHI还会做一次跨切片的合并去重。同一个目标可能出现在多个切片中,模型会对它产生多个检测框,SAHI通过NMS(非极大值抑制)机制将这些重复框合并为一个,最终输出完整的大图检测结果。

2.3 为什么选择YOLOv11与SAHI的组合

这个组合之所以主流,核心原因是分工明确。SAHI负责解决“目标太小”的问题,YOLOv11负责提供强大的特征提取和实时推理能力。单用SAHI配旧版YOLO也能跑,但YOLOv11的新结构在同等算力下精度更高;单用YOLOv11不配SAHI,航拍小目标场景下几乎没法用。

从实际工程角度看,这套组合还有一个优点——不用改模型结构。很多人一上来就想着改进Backbone、加注意力模块,但改动结构容易引入训练不稳定的问题。SAHI方案在推理层面解决问题,训练层面用有针对性的数据增强和调参,整体改动成本低,效果提升却非常明显。我实测下来,VisDrone数据集上,YOLOv11直接训练的mAP50大约11%左右,加上SAHI切片推理和针对性的训练调参后可以到25%上下,翻了一倍多。

3. 环境准备与基础模型训练

3.1 软硬件环境配置

先说一下我实测稳定的环境组合,不同版本的库混用容易出问题,踩坑成本很高。

Python 3.9+ torch 2.0.1+cu118 torchvision 0.15.1+cu118 ultralytics 8.3.x sahi 0.11.x opencv-python 4.8+

安装命令:

pip install ultralytics sahi opencv-python pip install torch==2.0.1 torchvision==0.15.1 --index-url https://download.pytorch.org/whl/cu118

注意ultralytics版本最好选8.3.x以上,因为YOLOv11的模型定义在这个版本才完整支持。SAHI建议用0.11.x版本,新版API变动不大,但部分函数参数有调整,参照我这边的版本号可以少踩一些坑。

硬件方面,训练阶段建议至少12GB显存,因为后续会把输入尺寸提到1280,显存不够会很痛苦。推理阶段8GB显存即可,SAHI切片推理本来就是为了在有限算力下跑大图。没有高显存显卡的,训练时可以适当降低输入尺寸,但代价是小目标精度下降。

3.2 VisDrone数据集的下载与预处理

VisDrone数据集是天津大学发布的无人机视觉数据集,包含288个视频片段,约261,908帧图像和超过1000万标注目标。常用的静态图像版本有6471张训练图、548张验证图和1610张测试图,标注了10个类别:pedestrian(行人)、people(人群)、bicycle(自行车)、car(汽车)、van(货车)、truck(卡车)、tricycle(三轮车)、awning-tricycle(带棚三轮车)、bus(公交车)、motor(摩托车)。

下载地址在官方github仓库可以找到,需要提交申请表单,审核后通过网盘下载。下载后目录结构大概是这样:

VisDrone2019-DET/ ├── annotations/ ├── images/ ├── train/ ├── val/ └── test/

这里有个格式转换的问题要处理。VisDrone的标注格式不是YOLO格式,而是自有的格式,每一行代表一个目标,包含目标类别、边界框的左上角坐标和宽高、置信度分数以及省略号中的额外属性。需要把标注转成YOLO格式的txt文件,每个txt文件对应一张图片,每行是“类别ID 中心点x 中心点y 宽 高”,所有坐标都归一化到0-1之间。

建议直接用官方提供的转换工具,或者写一段转换脚本,处理时注意类别映射关系。VisDrone的类别ID是从1开始的,而YOLO从0开始,需要整体减1。转换脚本我会在后面的实操章节给出可用的版本。

3.3 数据增强与类别不均衡处理

VisDrone数据集的类别不均衡问题非常严重。car和pedestrian占了绝大多数标注,而bus、awning-tricycle这些类别样本量很少。如果不做处理,模型会过度偏向高频类别,低频类别的召回率会非常惨。

处理方案有三层。第一层是基础数据增强,包括随机翻转、颜色抖动、亮度调整、缩放等,ultralytics框架里默认开启了一部分,但需要根据航拍场景调整参数。第二层是Mosaic增强,把四张图拼成一张训练,这个对提升小目标检测效果帮助很大,因为它扩充了单张图的目标数量和多样性。第三层是类别权重调整,对低频类别提高loss权重,让模型更关注这些难学类别。

VisDrone还有一个特点是目标密集,一张图里可能有几十上百个目标。训练时batch size不能设太大,否则单张图的目标数量过多会导致梯度更新过于剧烈,训练不稳定。我实测batch size 8配合输入尺寸1280比较稳。

4. YOLOv11训练与调参实操

4.1 基础训练命令

数据格式整理好之后,先跑一个baseline,用默认参数训练80轮。配置文件放在visdrone.yaml,内容大概如下:

path: /data/VisDrone2019-DET train: train/images val: val/images nc: 10 names: ['pedestrian', 'people', 'bicycle', 'car', 'van', 'truck', 'tricycle', 'awning-tricycle', 'bus', 'motor']

训练命令:

yolo detect train data=visdrone.yaml model=yolo11s.pt epochs=80 imgsz=640 batch=8 device=0

这里先用默认的640输入尺寸跑一轮baseline,确认代码流程和数据没有问题,同时也是为了后面对比输入尺寸对效果的影响。训练结束后看runs/detect/train/下的结果,重点看results.png里的mAP曲线和PR曲线。

baseline跑完之后,记录几个关键指标:mAP50、mAP50-95、precision、recall以及各类别的AP。这些指标后续调参都要拿来做对比。

4.2 输入尺寸的影响与选择

这是调参中最重要的一步。输入尺寸从640提升到1280,对航拍小目标检测的影响是决定性的。我用同一套配置分别跑了640和1280的实验,结论很明确:mAP50从约11%提升到约18%,mAP50-95也有明显提升。

但输入尺寸不是越大越好。1280已经是很均衡的选择,再往上到1536,显存占用急剧上升,训练速度明显下降,精度提升却很有限。原因在于YOLOv11的backbone下采样倍率固定,输入尺寸提升后,特征图尺寸也线性增长,但超过一定程度后,小目标特征信息的边际收益递减。

选择输入尺寸还需要考虑部署场景。如果做实时视频流分析,1280的推理速度可能不够,需要结合SAHI切片尺寸来综合权衡。理想的做法是:训练时用1280,推理时用SAHI配640切片,这样既保证了训练时模型见过的特征足够丰富,又控制了推理成本。

4.3 关键超参数调优技巧

VisDrone上最值得调的超参数,我按影响程度排序:

anchors。YOLOv11默认anchor是COCO数据集聚类出来的,尺度和宽高比与VisDrone的小目标严重不匹配。强迫模型去适配不适配的anchor会浪费大量学习能力。ultralytics框架支持自动anchor调整,在训练时使用auto_anchor=True参数即可,这会在训练前对标注框做聚类分析,重新生成适合当前数据集的anchor尺寸。实测这个操作对VisDrone的mAP50有2-4个点的提升,非常划算。

mosaic和mixup。这两个增强对密集小目标场景帮助很大。YOLOv11默认训练前10轮关闭mosaic,后续开启。对VisDrone建议把mosaic的关闭时机延迟到前20轮,让模型先用真实场景的图像稳定学习一下,再切换到增强数据,避免早期训练被过于复杂的合成图像干扰。

学习率和warmup。VisDrone数据量大且目标密集,学习率设置不当会导致loss直接炸掉或收敛缓慢。推荐初始学习率设为0.01以下,配合3轮warmup,让优化器先在小学习率下预热。如果用AdamW优化器,初始学习率可以设到0.001左右。

weight_decay。VisDrone的类别不均衡问题,适当增大weight_decay可以抑制过拟合。我实测从默认的0.0005调到0.001,验证集mAP有轻微提升。注意这个参数不宜过大,设到0.01以上模型可能欠拟合。

下面是我在VisDrone上验证过的一套稳定配置:

yolo detect train data=visdrone.yaml model=yolo11m.pt epochs=150 imgsz=1280 batch=8 device=0 optimizer=AdamW lr0=0.001 weight_decay=0.001 mosaic=1.0 mixup=0.2 close_mosaic=20

这套配置在我这边的实验环境下大约需要12-15小时训练完成,输出模型的mAP50在20%-22%之间。作为参考,直接跑默认参数在VisDrone上大约只有11%左右。

4.4 训练过程中的监控与判读

训练过程中不要只盯着终端里的loss数值,更关键的是看验证集上的指标曲线。我习惯每10轮记录一次验证集mAP,绘制成曲线观察收敛趋势。训练到60轮左右时,如果mAP增长明显放缓,说明模型开始收敛,可以考虑提前终止;如果loss继续下降但mAP不再上升,说明模型开始过拟合,这时可以停止训练了。

另外强烈建议开启ultralytics的plots=True参数,训练过程会自动生成各类曲线图和混淆矩阵,方便定位哪些类别的检测效果差。在实际项目中,VisDrone数据集中表现最差的通常是pedestrian和people这两个类别,因为它们尺寸最小且外观高度相似,模型经常混淆。

5. SAHI切片推理实战与参数配置

5.1 SAHI安装与模型封装

训练好模型之后,接下来是SAHI推理。安装sahi库后,需要把YOLOv11模型封装成SAHI支持的格式。SAHI对ultralytics模型有内置支持,用AutoDetectionModel接口可以方便地加载:

from sahi.model import Yolov8DetectionModel detection_model = Yolov8DetectionModel( model_path="runs/detect/train/weights/best.pt", confidence_threshold=0.15, device="cuda:0", )

这里的confidence_threshold我特意设低到了0.15,原因会在后面的4.1节细说。注意当前SAHI版本的模型类名还是Yolov8DetectionModel,但它是兼容YOLOv11权重文件的,因为ultralytics导出的模型结构格式是一致的。

5.2 切片推理核心参数配置

SAHI推理的核心参数有两个:slice_sizeoverlap_ratio。这两个参数直接决定了推理效果和速度。

slice_size是切片边长,通常设为640或512。在VisDrone场景下,我强烈建议640。原因是训练时YOLOv11的输入尺寸是1280,但SAHI会把切片直接缩放到模型的输入尺寸。640切片缩放到1280,相当于模型实际看到了原始图的一小块被放大两倍的画面,小目标的特征被显著放大,这是SAHI提高小目标精度的核心机制。

overlap_ratio是切片间的重叠率,默认0.2。这个值建议至少保持0.2,低于这个值会明显增加切缝截断目标的风险。如果目标特别密集,可以调到0.3甚至0.4。但重叠率越高,推理时间越长,计算量大约是1/(1-overlap)倍,0.2重叠就有1.25倍的冗余计算量,0.4重叠则接近1.67倍。

我常用的推理配置是:

from sahi.predict import get_prediction, get_sliced_prediction result = get_sliced_prediction( image="val_image.jpg", detection_model=detection_model, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2, )

5.3 完整推理脚本与结果保存

要让推理结果落地,还需要做两件事:结果可视化和保存检测结果。VisDrone的visdrone_map指标计算需要标准格式的检测结果文件,所以保存格式很重要。

一个完整的推理脚本示例:

import cv2 import glob from sahi.model import Yolov8DetectionModel from sahi.predict import get_sliced_prediction from sahi.utils.cv import visualize_object_predictions detection_model = Yolov8DetectionModel( model_path="runs/detect/train/weights/best.pt", confidence_threshold=0.15, device="cuda:0", ) output_dir = "results/" image_paths = glob.glob("val/images/*.jpg") image_paths.sort() for idx, image_path in enumerate(image_paths): result = get_sliced_prediction( image=image_path, detection_model=detection_model, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2, ) # 保存检测结果txt(VisDrone格式) result.export_visuals(export_dir=f"{output_dir}/visuals/", file_name=str(idx)) result.export_visuals( export_dir=f"{output_dir}/labels/", file_name=str(idx).zfill(6), export_format="txt", ) # 可视化 image = cv2.imread(image_path) visualization = visualize_object_predictions(image, result.object_prediction_list) cv2.imwrite(f"{output_dir}/visuals/{idx}.jpg", visualization) print(f"Processed {idx + 1}/{len(image_paths)}")

这里的保存格式需要注意。SAHI的export_visuals输出的是YOLO格式的归一化坐标,如果想计算VisDrone官方的visdrone_map,需要额外写一个转换函数把归一化坐标转换回VisDrone格式,包括目标类别、边界框左上角坐标、宽度、高度、置信度分数。这个环节的细节处理会直接影响最后评估分数的正确性。

5.4 推理加速策略

SAHI切片推理最大的痛点是速度。2448x2048的大图切成640x640的切片,重叠率0.2,大概会生成20-30个切片,单张图的推理时间可能是直接推理的5-10倍。

一个实用的加速方案是使用batch_size参数进行批量推理。SAHI支持对多张切片的批量推理,能显著提升GPU利用率:

result = get_sliced_prediction( image=image_path, detection_model=detection_model, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2, batch_size=8, )

另一个思路是按需切片。如果已知目标的先验尺寸范围,可以动态调整切片大小——目标越小用越小的切片,目标较大时直接把input_size缩小。当然这需要根据具体场景灵活应用。

6. 常见问题与排查技巧

6.1 检测结果大量漏检的原因与对策

问题1:检测框全在切片边缘被截断。这种问题一般是overlap_ratio设置过小导致的。如果画面中目标分布密集,0.2的重叠率不够,切缝处的目标会同时被两个切片截断,两边都识别不出来。对策是把overlap调整到0.3。另一种有效方案是设置postprocess_match_metric=IOS(Intersection over Smaller),这会改变跨切片匹配策略,让SAHI更倾向于保留小框,对密集小目标场景有用。

问题2:目标检测出来了但置信度极低。这是置信度阈值设置不匹配导致的。YOLOv11训练时默认的置信度阈值是0.25,但在SAHI中我们要检测的是小目标,模型给出0.2甚至0.15的置信度是完全正常的。如果始终用0.25以上阈值,很多真实目标会被直接过滤掉。我在VisDrone上的实测结果,置信度阈值从0.25降到0.15,召回率提升了约8个百分点。代价是假阳性变多,需要后续做NMS过滤。

问题3:类别混淆严重,行人和骑摩托车的人分不清。这是在训练阶段就需要解决的问题。VisDrone中pedestrian和motor类别高度相似,远处看都是一个小直立目标。训练时增加scale数据增强的强度,让模型见过更多不同尺度下的目标,同时确保mixup增强合理,能帮助模型从上下文背景中学习区分。

6.2 训练阶段常见报错

CUDA out of memory。这是最常遇到的问题,特别是用1280输入尺寸训练时。处理方法:减小batch size到4甚至2,开启梯度累积。ultralytics的batch参数设为-1可以自动检测显存并调整batch size,实测效果不错。如果还爆显存,就要考虑关闭部分数据增强,mosaic增强本身很耗显存。

标注格式报错。VisDrone转YOLO格式时容易踩坑的是坐标越界。有些标注框的边界坐标略微超出了图像范围,YOLO格式要求坐标归一化后必须在0-1之间。转换脚本里需要加一个clip操作,把所有坐标限制在[0, 1]区间内。

类别ID对不上。VisDrone的类别标签和YOLO模型的类别索引必须严格对齐,否则模型会把一个类别错当成另一个类别。验证方法是用转换脚本处理完数据后,随机挑几张图,把YOLO格式的标注转回图像坐标,画框可视化检查。

6.3 推理测试时常见坑点

切片图片变形严重。如果直接拿任意大小的切片喂给模型,模型输入尺寸和切片尺寸不一致,ultralytics会自动resize,但比例如果不一致会导致图像被拉伸,目标形变,检测精度明显下降。使用SAHI时,建议模型输入尺寸与切片尺寸保持一致或倍数关系,SAHI底层会处理好缩放,但手动操作时需要注意。

显存占用计算错误。切片推理的显存占用不等于单次推理的显存,因为batch_size参数决定了同时推理的切片数量。显存较小的设备建议把batch_size设小,或者用device="cpu"(当然速度会很慢)。

保存结果重复。如果在推理循环中不做文件名唯一化处理,多个结果会互相覆盖。由于批处理时SAHI内部会生成自适应文件名,建议在迫不得已手动处理时统一加上图像索引,避免重复。

6.4 无人机场景独有的注意事项

无人机航拍图像存在大量小目标密集分布的区域,这些区域的检测结果经常出现高密度重叠框。如果直接输出,可视化时画面全是框,很难看,后续做统计时也会重复计数。建议在输出结果前做二次NMS,把IoU大于0.5的框合并。

另一个细节是VisDrone数据集中有大量含遮挡的目标,特别是树荫下、车辆缝隙中的人。模型检测这类目标的置信度普遍偏低。如果业务场景对召回率要求高,可以把置信度阈值往低调,然后用NMS和跟踪算法处理后续的误检问题。

7. 调参心得与实操总结

整套方案跑下来,我个人的体会是:无人机小目标检测,90%的收益来自三个决策——输入尺寸用1280、用SAHI切片推理、置信度阈值调到0.15。剩下10%的提升来自训练细节的打磨,比如anchor自适应、mosaic策略调整、类别不均衡处理。

有一个细节值得多说一句:训练和推理时的图像尺度最好保持一致逻辑。训练时用1280,推理时SAHI切片640再放大到1280,本质上是同一套尺度逻辑,模型看到的特征分布是一致的。很多人训练用1280、推理时直接压到640,效果打折严重,就是这个原因。

另外,VisDrone的官方评估指标和COCO的评估指标有差异。VisDrone的mAP计算时有一个特殊规则——小目标的匹配IoU阈值更低,对检测框的定位精度要求更宽松。这意味着你在VisDrone的evaluation server上看到的分数不一定和本地的COCO风格mAP一致。所以做实验对比时,务必使用同一种评估方式。

最后分享一个小技巧:用Ultralytics训练完成之后,记得用yolo export导出一下模型格式。在SAHI中加载模型时,直接把best.pt传给model_path是可以的,但如果将模型导出为ONNX或TensorRT格式再加载,推理速度会明显提升。我实测同一套配置TensorRT模式下推理速度大约提升3倍,对大规模影像处理非常有帮助。

这套方案目前已经在不少无人机巡检和智慧城市项目中作为基础pipeline使用。如果你想在工程落地时再进一步压缩推理时间,后续可以从模型剪枝、蒸馏和TensorRT优化三个方向继续深挖,但先把YOLOv11加SAHI这套基础流程跑通、跑稳,收益就已经非常可观了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 20:29:49

Rust具身智能执行层:ZeroClaw的确定性调度与物理世界映射

1. 项目概述:从 Rust 运行时到具身智能体的“心跳”执行流ZeroClaw 是 OpenClaw 生态中一个关键的轻量级具身硬件控制层,它不是传统意义上跑在服务器上的大模型服务,而是一个扎根于物理设备边缘、直连电机/传感器、以毫秒级响应驱动真实动作的…

作者头像 李华
网站建设 2026/9/16 20:26:00

企业官网建设:展示型与获客型的技术架构与策略

1. 企业官网的核心定位之争这个问题困扰着无数企业主和营销负责人。上周刚帮一家制造业客户重新规划官网,老板开门见山就问:"我们每年花十几万维护的官网,到底该做成电子版宣传册还是销售漏斗?"这其实反映了企业官网建设…

作者头像 李华
网站建设 2026/9/16 20:25:43

CentOS 7 GNOME桌面无限转圈?SELinux安全上下文修复实录

先交代一下背景:我这边遇到的情况是VMware虚拟机里装好了CentOS 7的GNOME桌面,第一次重启还能进系统,第二次启动直接卡在登录界面的“花瓣”加载动画上——转圈、转圈、再转圈,鼠标还能动,但就是进不了桌面。试过等待十…

作者头像 李华
网站建设 2026/9/16 20:23:47

STM32空气监测系统源码拆解:从ADC采样到数据可视化全流程解析

简介:基于STM32单片机空气监测系统设计毕业设计资料包,主要面向嵌入式、自动化、电子信息等专业的在校学生与开发者,适用于毕业设计、课程设计、项目初期演示及二次开发入门。压缩包内共包含312个文件,整包大小15.32MB&#xff0c…

作者头像 李华