简介:这份PDF文档面向遥感图像处理与目标检测方向的学习者、研究人员及工程实践者,聚焦YOLOv11在多尺度建筑物检测中的训练技巧与数据增强方案,帮助读者应对复杂遥感场景下小目标漏检、尺度差异大、样本稀缺等实际问题。文档共38页,以单一PDF形式交付,压缩包约1.97MB,支持目录章节跳转、阅读器左侧大纲显示与章节快速定位,查阅体验完整流畅。内容从YOLOv11模型结构、骨干网络与检测头讲起,系统梳理多尺度检测原理,涵盖图像金字塔、特征金字塔网络与多尺度锚框机制;训练部分展开预训练模型选择、学习率调整、优化器对比、批量大小设置、正则化与多尺度训练策略;数据增强章节则覆盖几何变换、颜色空间变换、噪声添加及Mosaic、CutMix等高级方法,并给出标注调整与组合应用策略。文末附模型评估指标、优化策略与完整案例分析,已有79人学习,适合希望系统掌握遥感建筑物检测全流程的读者参考。
1. 遥感建筑物检测为什么总在“小目标”上翻车
遥感图像里的建筑物检测,和自然场景目标检测完全不是一回事。一张 512×512 的航拍切片里,大型厂房可能占几百个像素,而城中村里的自建房、工地临时板房、郊区独立小楼,往往只有十几个像素宽。YOLOv11 在 COCO 上表现再好,直接拿来跑遥感数据,小目标召回率经常掉到 50% 以下,大目标却接近 90%。这个落差不是模型不行,是尺度分布和训练策略没对齐。
多尺度建筑物检测要解决的核心问题就三个:小目标在特征图上被下采样吃掉、正样本分配偏向大目标、数据增强把建筑物几何结构破坏掉。YOLOv11 本身提供了 P3/P4/P5 三个检测头,P3 步长 8,对 16 像素以下的目标已经接近极限。如果不做针对性处理,城中村场景的漏检基本都发生在 P3 上。
这套方案适合谁?手里有遥感影像数据集(比如 WHU、LEVIR、xBD 或者自采无人机正射图),想用 YOLOv11 做建筑物提取,但发现小目标召回上不去、验证集 mAP 卡在 0.6 左右的人。下面从数据增强、训练参数、多尺度策略到部署验证,把能复现的路径讲清楚。
2. 遥感数据增强:别把建筑物转成“抽象画”
2.1 为什么常规增强在遥感场景会失效
自然图像增强那套(随机旋转、裁剪、色彩抖动、Mosaic)搬到遥感建筑物检测上,有几个坑必须提前知道。遥感图像是正射视角,建筑物有明确的几何边界和朝向分布。随机旋转 90° 没问题,但任意角度旋转会让建筑物边缘产生插值模糊,小目标直接糊成一团。色彩抖动在 RGB 上看似无害,但遥感影像的波段响应和自然图像不同,过度抖动会让屋顶材质特征失真。
更关键的是 Mosaic 增强。YOLOv11 默认开启 Mosaic,四张图拼一张,对小目标检测本来是有利的——增加了小目标出现的频率。但遥感图像拼接后,不同切片的光照、季节、分辨率不一致,模型会学到“拼接边界”这种伪特征。我一般会在训练最后 10 个 epoch 关闭 Mosaic,让模型在真实分布上收敛。
注意:遥感数据增强的第一原则是保持建筑物的几何完整性。任何会改变建筑物轮廓形状或边缘锐度的操作,都要谨慎。
2.2 可复现的增强管线配置
下面是我在 WHU 建筑物数据集上验证过的一套增强配置,基于 Ultralytics 的 YOLOv11 训练接口。核心思路是:几何增强保守、光度增强适度、小目标过采样单独做。
from ultralytics import YOLO import albumentations as A import cv2 import numpy as np # 自定义增强管线:几何保守 + 光度适度 transform = A.Compose([ # 水平翻转和垂直翻转:遥感正射图安全 A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.5), # 90度旋转:不引入插值模糊 A.RandomRotate90(p=0.5), # 小角度旋转:限制在15度以内,减少边缘模糊 A.Rotate(limit=15, border_mode=cv2.BORDER_REFLECT, p=0.3), # 随机缩放:模拟不同分辨率 A.RandomScale(scale_limit=(-0.3, 0.5), p=0.5), # 光度增强:轻度,保持波段响应 A.RandomBrightnessContrast( brightness_limit=0.15, contrast_limit=0.15, p=0.4 ), A.HueSaturationValue( hue_shift_limit=5, sat_shift_limit=10, val_shift_limit=10, p=0.3 ), # 高斯噪声:模拟传感器噪声 A.GaussNoise(var_limit=(5.0, 20.0), p=0.2), ], bbox_params=A.BboxParams( format='yolo', label_fields=['class_labels'], min_visibility=0.3 )) def augment_image(image, bboxes, class_labels): """对单张遥感切片做增强,返回增强后的图和框""" result = transform( image=image, bboxes=bboxes, class_labels=class_labels ) return result['image'], result['bboxes'], result['class_labels']这段代码的关键参数说明:min_visibility=0.3表示增强后如果某个框可见面积低于 30%,直接丢弃,避免产生“半截建筑物”的脏标签。RandomScale的缩放范围设到 -0.3 到 +0.5,是为了让模型见到同一建筑物的不同尺度,这对多尺度检测很关键。Rotate限制在 15° 以内,是因为遥感建筑物有明确的东西南北朝向分布,大角度旋转会破坏这种先验。
2.3 小目标过采样:把稀有样本“喂饱”
遥感数据集里小目标建筑物占比通常不到 15%,但检测难度最大。光靠增强不够,需要在采样层面做文章。我的做法是:统计每个目标的像素面积,把面积小于 32×32 的样本单独建一个子集,在训练时按 2 倍权重采样。
import numpy as np from torch.utils.data import WeightedRandomSampler def build_small_object_sampler(dataset, small_threshold=32): """为小目标样本构建加权采样器""" weights = [] for idx in range(len(dataset)): img, targets = dataset[idx] # targets 格式: [class, x, y, w, h] if len(targets) == 0: weights.append(1.0) continue # 计算每个目标的像素面积 areas = targets[:, 3] * targets[:, 4] * img.shape[1] * img.shape[2] # 如果该图包含小目标,提高采样权重 if np.any(areas < small_threshold ** 2): weights.append(2.0) else: weights.append(1.0) sampler = WeightedRandomSampler( weights=weights, num_samples=len(weights), replacement=True ) return sampler逻辑说明:small_threshold=32是像素边长阈值,小于这个尺寸的建筑物在 P3 特征图上只剩 4×4 个格子,必须重点照顾。权重设为 2.0 意味着含小目标的图被采到的概率翻倍。replacement=True允许重复采样,保证每个 epoch 都能见到足够多的小目标样本。
参数调整建议:如果数据集里小目标占比超过 30%,权重降到 1.5;如果低于 5%,权重提到 3.0。这个值没有绝对标准,看验证集小目标召回率来调。
3. YOLOv11 多尺度训练参数:从输入分辨率到损失权重
3.1 输入分辨率与多尺度训练策略
YOLOv11 默认输入 640×640,但遥感建筑物检测里这个分辨率往往不够。WHU 数据集的原图是 512×512 切片,如果直接缩到 640 反而放大了。我的经验是:输入分辨率要匹配目标尺寸分布。如果小目标平均 20 像素,输入至少 1024 才能让 P3 有足够响应。
多尺度训练(Multi-Scale Training)是 YOLOv11 内置的能力,通过imgsz参数控制。但遥感场景下不能随机缩放太大,否则小目标直接消失。我一般设置imgsz=1024,并在训练中按 32 的倍数在 896 到 1152 之间随机抖动。
# YOLOv11 多尺度训练命令 yolo detect train \ data=building.yaml \ model=yolo11m.pt \ imgsz=1024 \ epochs=200 \ batch=8 \ multi_scale=True \ scale=0.5 \ mosaic=1.0 \ close_mosaic=20 \ optimizer=SGD \ lr0=0.01 \ lrf=0.01 \ warmup_epochs=5 \ box=7.5 \ cls=0.5 \ dfl=1.5 \ device=0参数逐个说:multi_scale=True开启多尺度训练,scale=0.5表示在 1024×0.5 到 1024×1.5 之间随机缩放,但实际受imgsz约束。close_mosaic=20表示最后 20 个 epoch 关闭 Mosaic,让模型在真实分布上微调。box=7.5是框回归损失权重,遥感建筑物边界清晰,可以适当提高。cls=0.5是分类损失权重,建筑物只有一类,不需要太高。dfl=1.5是分布焦点损失权重,影响边界回归精度。
提示:
batch=8是针对 1024 分辨率、单卡 24G 显存的保守值。如果显存不够,优先降 batch 而不是降 imgsz,因为分辨率对小目标检测的影响更大。
3.2 正样本分配与损失函数调参
YOLOv11 用的是 Task-Aligned Assignant(TAL),根据分类得分和回归 IoU 的加权来分配正样本。这个机制本身对小目标不算友好,因为小目标的 IoU 波动大,容易被判为负样本。解决办法是调整topk参数和alpha、beta权重。
在 Ultralytics 的默认配置里,TAL 的topk=10,alpha=1.0,beta=6.0。beta越大,回归精度在分配中的权重越高。对小目标来说,适当降低beta可以让更多小目标被选为正样本。
# 在 YOLOv11 的 loss.py 中调整 TAL 参数 # 默认配置 tal_topk = 10 tal_alpha = 1.0 tal_beta = 6.0 # 小目标优化配置 tal_topk = 13 # 增加候选正样本数量 tal_alpha = 0.8 # 降低分类权重 tal_beta = 4.0 # 降低回归权重,让小目标更容易被选中逻辑说明:topk从 10 提到 13,意味着每个 GT 会考虑更多 anchor point 作为候选正样本,小目标本身覆盖的格子少,增加 topk 能提高被选中的概率。beta从 6.0 降到 4.0,是降低回归精度在分配中的门槛,让小目标即使 IoU 不高也能被选上。alpha从 1.0 降到 0.8,是让分类得分的影响稍微减弱,避免小目标因为分类置信度低而被淘汰。
这些改动需要直接修改源码,不是官方接口。如果不想动源码,另一个办法是在数据层面把小目标复制粘贴到更多位置,增加其出现频率。
3.3 学习率与 warmup 的遥感适配
遥感数据集通常比 COCO 小得多,WHU 只有几千张切片。这种情况下,学习率策略要更保守。我一般用 SGD,初始学习率 0.01,配合 5 个 epoch 的 warmup。如果数据集小于 2000 张,初始学习率降到 0.005。
# building.yaml 数据集配置 path: ./datasets/building train: images/train val: images/val test: images/test names: 0: building# 小数据集训练命令(<2000张) yolo detect train \ data=building.yaml \ model=yolo11s.pt \ imgsz=1024 \ epochs=300 \ batch=4 \ lr0=0.005 \ lrf=0.001 \ warmup_epochs=10 \ cos_lr=True \ patience=50 \ device=0cos_lr=True开启余弦退火,比阶梯下降更平滑,适合小数据集。patience=50表示 50 个 epoch 验证集 mAP 不提升就早停,避免过拟合。warmup_epochs=10比默认的 3 更长,因为小数据集前期梯度噪声大,需要更长的预热稳定训练。
4. 多尺度检测头与特征融合:让 P3 真正干活
4.1 YOLOv11 的检测头结构回顾
YOLOv11 的 neck 用的是 PAN-FPN 结构,P3、P4、P5 三个尺度的特征图分别对应步长 8、16、32。P3 负责小目标,P4 中目标,P5 大目标。遥感建筑物检测里,P3 的利用率往往不足,因为小目标在 P3 上的响应被背景噪声淹没。
一个常见的改进思路是增加一个 P2 检测头,步长 4,专门抓极小目标。但 P2 的计算量很大,1024 输入下 P2 特征图是 256×256,显存和推理时间都会明显上升。我的建议是:如果小目标占比超过 20%,加 P2;否则优先优化 P3。
# YOLOv11 增加 P2 检测头的配置示例(需修改模型 yaml) # 在 head 部分增加 P2 分支 head: - [-1, 1, nn.Upsample, [None, 2, 'nearest']] - [[-1, 2], 1, Concat, [1]] # 融合 P2 特征 - [-1, 3, C3k2, [256, False]] # P2 检测头 # ... 原有 P3/P4/P5 分支逻辑说明:P2 检测头从 backbone 的浅层特征引出,经过上采样和 concat 融合,再经过 C3k2 模块处理。这样 P2 既有浅层的细节信息,又有深层的语义信息。代价是计算量增加约 30%,推理速度下降 20% 左右。
4.2 特征融合的加权策略
PAN-FPN 的融合是简单的 concat,不同尺度的特征贡献是等权的。但遥感场景下,P3 的小目标特征更需要被强调。一个轻量改进是给不同尺度的融合特征加可学习权重。
import torch import torch.nn as nn class WeightedFusion(nn.Module): """多尺度特征加权融合模块""" def __init__(self, channels_list, num_levels=3): super().__init__() # 每个尺度一个可学习权重,初始化为1.0 self.weights = nn.Parameter(torch.ones(num_levels)) self.conv = nn.Conv2d( sum(channels_list), channels_list[0], 1 ) def forward(self, features): # features: list of [P3, P4, P5] 上采样到同一尺寸 weighted = [] for i, feat in enumerate(features): weighted.append(feat * self.weights[i]) concat = torch.cat(weighted, dim=1) return self.conv(concat)逻辑说明:self.weights是三个可学习参数,分别对应 P3、P4、P5 的融合权重。训练过程中,如果 P3 对小目标更重要,它的权重会自动增大。self.conv是 1×1 卷积,把 concat 后的通道数降回目标通道数。这个模块可以插在 PAN-FPN 的每个融合节点上。
参数说明:channels_list是三个尺度的通道数列表,YOLOv11m 通常是 [128, 256, 512]。num_levels=3对应三个检测头。初始化权重为 1.0 是保守做法,也可以根据尺度先验设成 [1.5, 1.0, 0.8],让 P3 初始权重更高。
4.3 验证多尺度改进是否生效
改完结构不能只看 mAP,要分尺度看召回率。我一般用 COCO 的 AP 指标拆解:AP_small、AP_medium、AP_large。如果 AP_small 提升但 AP_large 下降,说明改进偏向小目标,需要回调权重。
from pycocotools.coco import COCO from pycocotools.cocoeval import COCOeval def evaluate_by_scale(anno_file, result_file): """按尺度评估检测结果""" coco_gt = COCO(anno_file) coco_dt = coco_gt.loadRes(result_file) coco_eval = COCOeval(coco_gt, coco_dt, 'bbox') coco_eval.evaluate() coco_eval.accumulate() coco_eval.summarize() # 输出 AP_small, AP_medium, AP_large return { 'AP_small': coco_eval.stats[3], 'AP_medium': coco_eval.stats[4], 'AP_large': coco_eval.stats[5], }逻辑说明:coco_eval.stats[3]对应 AP_small,stats[4]对应 AP_medium,stats[5]对应 AP_large。遥感建筑物的尺度划分建议按像素面积:小于 32² 为 small,32² 到 96² 为 medium,大于 96² 为 large。这个划分和 COCO 一致,方便对比。
参数调整:如果 AP_small 低于 0.4,说明小目标检测还有问题,优先检查 P3 特征图是否有足够响应。如果 AP_large 下降超过 3 个点,说明加权融合过度偏向小目标,把 P5 权重调高。
5. 避坑与排查:遥感建筑物训练里的血泪经验
5.1 标签格式转换后框全偏了
现象:把 WHU 的标注转成 YOLO 格式后,训练 loss 正常下降,但验证时框全部偏移,可视化发现框和建筑物对不上。
原因:WHU 原始标注是像素坐标 (x1, y1, x2, y2),转 YOLO 需要归一化到 (cx, cy, w, h)。常见错误是归一化时用了错误的宽高,比如用原图尺寸而不是切片尺寸,或者 x 和 y 的顺序搞反。
解决:转换后必须做可视化抽检。下面这个脚本可以快速验证。
import cv2 import numpy as np def visualize_yolo_label(img_path, label_path, save_path): """可视化 YOLO 格式标签,检查框是否正确""" img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path) as f: for line in f: cls, cx, cy, bw, bh = map(float, line.strip().split()) # 反归一化 x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(save_path, img)逻辑说明:cx, cy, bw, bh是归一化后的中心点和宽高,反归一化时分别乘以w和h。如果框偏移,优先检查cx和cy是否搞反,以及bw和bh是否对应宽高。
5.2 小目标召回率始终上不去
现象:训练 200 epoch 后,大目标 AP 到 0.85,小目标 AP 只有 0.35,调学习率和增强都没用。
原因:大概率是 P3 特征图上的小目标响应被背景淹没。遥感图像里建筑物周围有大量相似纹理(道路、裸地),P3 的浅层特征分辨不清。
解决:三步排查。第一,检查输入分辨率是否足够,小目标在输入图上是否小于 16 像素。第二,检查 TAL 的topk和beta是否适合小目标。第三,在验证集上单独跑小目标子集,看漏检是分类错还是回归错。如果是分类错,提高cls损失权重;如果是回归错,提高box损失权重。
5.3 多尺度训练导致显存爆炸
现象:开启multi_scale=True后,训练几个 epoch 就 OOM,batch 已经降到 2 还是不行。
原因:多尺度训练会在imgsz基础上随机缩放,最大可能到imgsz × (1 + scale)。如果imgsz=1024,scale=0.5,最大输入是 1536×1536,显存占用是 1024 的 2.25 倍。
解决:把scale降到 0.3,或者设置imgsz=896配合scale=0.5。另一个办法是用梯度累积,batch=2配合accumulate=4,等效 batch 为 8。
# 梯度累积配置 yolo detect train \ data=building.yaml \ model=yolo11m.pt \ imgsz=1024 \ batch=2 \ accumulate=4 \ multi_scale=True \ scale=0.3 \ device=05.4 验证集 mAP 高但推理结果全是框
现象:验证集 mAP 0.75,但用yolo predict跑测试图,输出几百个框,置信度都很低。
原因:验证时用的是conf=0.001的低阈值算 mAP,推理时如果没设conf,默认也是 0.25,但遥感图像背景复杂,低置信度框很多。
解决:推理时显式设置conf=0.4到0.5,并开启 NMS。如果还有大量重叠框,调低iou阈值到 0.3。
yolo detect predict \ model=runs/detect/train/weights/best.pt \ source=test_images/ \ conf=0.45 \ iou=0.3 \ save=True \ save_txt=True5.5 数据增强把建筑物转没了
现象:训练 loss 震荡,验证集 mAP 比不加增强还低。
原因:增强管线里的旋转和缩放组合后,小目标建筑物被裁掉或缩到不可见。min_visibility=0.3只过滤了部分,但有些增强后的目标虽然可见面积够,但形状已经严重变形。
解决:增强后做二次抽检,把增强后的图和框可视化,人工看 50 张。如果发现建筑物被裁成碎片,提高min_visibility到 0.5,或者降低旋转和缩放的概率。
6. 推理后处理与部署验证:从 mAP 到实际可用
6.1 保存推理结果的正确姿势
训练完模型只是第一步,实际用的时候要批量跑推理并保存结果。YOLOv11 的predict接口支持保存 txt、json 和可视化图。遥感建筑物检测通常需要 GIS 格式,比如 GeoJSON 或 Shapefile。
from ultralytics import YOLO import json import cv2 model = YOLO('runs/detect/train/weights/best.pt') def predict_to_geojson(image_path, output_path, conf=0.45): """推理并保存为 GeoJSON 格式""" results = model.predict( source=image_path, conf=conf, iou=0.3, verbose=False ) features = [] for r in results: img_h, img_w = r.orig_shape for box in r.boxes: x1, y1, x2, y2 = box.xyxy[0].tolist() # 转成像素坐标的 polygon features.append({ 'type': 'Feature', 'properties': { 'class': 'building', 'confidence': float(box.conf[0]) }, 'geometry': { 'type': 'Polygon', 'coordinates': [[ [x1, y1], [x2, y1], [x2, y2], [x1, y2], [x1, y1] ]] } }) geojson = {'type': 'FeatureCollection', 'features': features} with open(output_path, 'w') as f: json.dump(geojson, f) return len(features)逻辑说明:box.xyxy[0]是框的左上角和右下角坐标,box.conf[0]是置信度。GeoJSON 的 Polygon 需要闭合,所以坐标列表首尾相同。r.orig_shape是原图尺寸,如果推理时做了 resize,需要按比例还原。
参数说明:conf=0.45是推理阈值,比验证时的 0.001 高很多,目的是过滤背景误检。iou=0.3是 NMS 阈值,遥感建筑物密集区域容易产生重叠框,低 iou 阈值可以抑制。
6.2 部署到边缘设备的量化与加速
遥感建筑物检测经常要部署到无人机或边缘设备上。YOLOv11 支持导出 ONNX、TensorRT 和 OpenVINO。如果目标是 Jetson 系列,TensorRT 是首选。
# 导出 TensorRT FP16 引擎 yolo export \ model=runs/detect/train/weights/best.pt \ format=engine \ half=True \ imgsz=1024 \ device=0 \ workspace=4参数说明:half=True开启 FP16 量化,显存占用减半,推理速度提升约 1.5 倍,精度损失通常在 1 个点以内。workspace=4是 TensorRT 的工作空间大小,单位 GB,1024 输入建议至少 4GB。imgsz=1024必须和训练时一致,否则精度会掉。
导出后验证:用同样的测试集跑 TensorRT 引擎和 PyTorch 模型,对比 mAP。如果掉点超过 2 个,检查量化是否过于激进,可以改用 FP32 或者 INT8 校准。
6.3 一个实用的验证习惯
我自己的习惯是:每次训练完,不只看 mAP,还要做三件事。第一,按尺度拆解 AP,确认小目标没有退化。第二,抽 20 张验证集可视化,人眼看有没有系统性偏移。第三,用测试集跑一遍完整推理,统计每张图的平均检测数和置信度分布。如果平均检测数远高于标注数,说明误检多;如果远低于,说明漏检多。
这套流程跑下来,基本能判断模型是真的能用,还是只是 mAP 好看。遥感建筑物检测没有银弹,多尺度问题需要从数据、结构、训练策略三个层面一起下手。希望帮到你。
本文还有配套的精品资源,点击获取