☰
航空卫星图像数据集YOLO训练实战:小样本遥感目标检测全流程
2026/10/1 18:06:32 网站建设 项目流程

简介:本资源为面向YOLO系列目标检测算法的航空卫星图像数据集,适用于遥感场景下的地物分类与目标检测任务,可支撑森林、公路、作物、河流、住宅、工业、果园、牧场及贫瘠土地等多类地物的识别模型训练与验证。数据集已按训练与验证需求划分完毕,并附带data.yaml配置文件,兼容yolov5、yolov7、yolov8、yolov9、yolov10及yolo11等主流版本,方便直接投入实验。压缩包共2000个文件,其中1230个xml文件对应VOC格式标注,770个txt文件对应YOLO格式标注,两种标签体系分别存放,便于按框架灵活选用;包体约60.51MB,含1366张带标签图像。YOLO格式采用归一化中心点与宽高比例,便于直接读取训练。目前已有42人学习下载,适合遥感检测方向的初学者与研究者快速搭建基线、验证算法效果并开展对比实验。

1. 航空卫星图像数据集与 YOLO 落地:1366 张图能训练出什么

拿到一个标题写着「1366 张图像带标签、覆盖森林公路作物河流住宅工业果园牧场贫瘠土地」的航空卫星数据集,多数人第一反应是直接丢进 YOLO 训练脚本里跑一遍。但真实情况是:1366 张遥感图像在目标检测任务里属于小样本量级,如果按 8:1:1 切分,验证集只有 136 张左右,单类目标可能不到 200 个实例。这个量级下,YOLO 能不能收敛、mAP 能到多少、哪些类别会拖后腿,取决于你怎么处理数据、选哪个版本、怎么配置增强。这篇内容面向已经了解 YOLO 基础、手头有遥感标注数据、想跑通一条完整训练流水线的从业者,从数据检查、格式转换、模型选型、训练参数到部署验证,把每一步的参数含义和踩坑点讲清楚。适合做土地利用分类、遥感目标检测、边缘端部署的工程师参考,不适合完全没接触过目标检测的新手直接照搬。

2. 遥感数据集进 YOLO 之前:格式、分布与标签质量核查

2.1 先搞清楚标注格式和坐标体系

航空卫星图像数据集的标签常见有三种格式:Pascal VOC 的 XML、COCO 的 JSON、以及 YOLO 的 TXT。标题里写「带标签」但没有说明具体格式,所以第一步不是写训练脚本,而是打开标注文件看一眼。如果是 VOC 格式,每个图像对应一个 XML,里面记录了 bbox 的 xmin、ymin、xmax、ymax;如果是 YOLO TXT,每行是class_id x_center y_center width height,且全部归一化到 0~1。

遥感图像有个特殊点:图像尺寸往往很大,比如 1024×1024 或 2048×2048,而 YOLO 默认输入是 640×640。直接缩放会导致小目标(比如河流的窄段、公路的细线)在特征图上只剩几个像素,检测效果断崖式下降。所以核查标签时,要同时统计目标框的绝对像素尺寸分布。

import os import xml.etree.ElementTree as ET from collections import Counter # 统计 VOC 格式标签的类别分布和 bbox 尺寸 def parse_voc_annotations(anno_dir): class_counter = Counter() size_list = [] for xml_file in os.listdir(anno_dir): if not xml_file.endswith('.xml'): continue tree = ET.parse(os.path.join(anno_dir, xml_file)) root = tree.getroot() for obj in root.findall('object'): name = obj.find('name').text class_counter[name] += 1 bbox = obj.find('bndbox') w = float(bbox.find('xmax').text) - float(bbox.find('xmin').text) h = float(bbox.find('ymax').text) - float(bbox.find('ymin').text) size_list.append((w, h)) return class_counter, size_list # 输出:每个类别的实例数,以及 bbox 宽高的分布 class_counter, size_list = parse_voc_annotations('./annotations') print("类别分布:", class_counter) print("bbox 平均宽高:", sum(w for w,h in size_list)/len(size_list), sum(h for w,h in size_list)/len(size_list))

这段代码做两件事:统计每个类别的实例数量,以及 bbox 的平均宽高。如果某个类别实例数低于 100,比如「工业」或「果园」可能只有几十个,训练时该类别的 AP 会非常不稳定。bbox 平均宽高如果小于 32 像素,说明小目标占比高,需要考虑增大输入分辨率或使用 P2 特征层。

参数说明:anno_dir指向 XML 文件所在目录;class_counter输出各类别实例数;size_list用于判断小目标比例。如果发现某个类别实例数过少,常见做法是合并相似类别,比如把「牧场」和「贫瘠的土地」合并为「草地/裸地」,或者对该类别做过采样。

2.2 类别不平衡与长尾分布的处理策略

1366 张图覆盖 9 个类别,大概率存在长尾分布:森林、住宅、公路可能占多数,工业、果园、牧场可能很少。YOLO 的损失函数默认对所有类别等权重,长尾会导致模型偏向头部类别。常见做法有三种:一是调整损失函数中各类别的权重,二是对尾部类别做数据增强(旋转、裁剪、色彩抖动),三是在数据加载时对尾部类别样本过采样。

我一般会先跑一遍上面的统计脚本,如果头部和尾部实例数差距超过 10 倍,就在训练配置里加cls_pw(类别权重)或者用 focal loss 替代默认的 BCE loss。YOLOv8 的配置里可以通过cls参数调整分类损失的增益,但更直接的方式是在数据集 YAML 里给每个类别设置权重,不过官方接口不直接支持,需要改损失函数源码。

提示:遥感图像的类别定义往往有歧义,比如「贫瘠的土地」和「牧场」在视觉上可能高度相似,标注一致性差。训练前最好抽样 50 张图人工复核,把混淆严重的类别合并,否则 mAP 会被拉低。

2.3 从 VOC 到 YOLO 格式:转换脚本与四个边界坑

如果原始标签是 VOC XML,需要转成 YOLO TXT。转换逻辑不复杂,但遥感图像有几个边界情况容易翻车。

import xml.etree.ElementTree as ET import os # VOC 转 YOLO,处理边界溢出和类别映射 def voc_to_yolo(xml_path, output_path, class_map, img_w, img_h): tree = ET.parse(xml_path) root = tree.getroot() lines = [] for obj in root.findall('object'): name = obj.find('name').text if name not in class_map: continue # 跳过未定义类别 cls_id = class_map[name] bbox = obj.find('bndbox') xmin = float(bbox.find('xmin').text) ymin = float(bbox.find('ymin').text) xmax = float(bbox.find('xmax').text) ymax = float(bbox.find('ymax').text) # 边界裁剪:防止坐标超出图像范围 xmin = max(0, min(xmin, img_w)) xmax = max(0, min(xmax, img_w)) ymin = max(0, min(ymin, img_h)) ymax = max(0, min(ymax, img_h)) # 跳过无效框 if xmax <= xmin or ymax <= ymin: continue x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") with open(output_path, 'w') as f: f.write('\n'.join(lines)) class_map = {'森林': 0, '公路': 1, '作物': 2, '河流': 3, '住宅': 4, '工业': 5, '果园': 6, '牧场': 7, '贫瘠的土地': 8}

四个边界坑:第一,xmax 或 ymax 可能等于图像宽度或高度,归一化后是 1.0,YOLO 能接受但某些版本会报错,建议裁剪到 img_w - 1;第二,有些标注框的 xmin 大于 xmax,属于标注错误,必须跳过;第三,类别名如果有空格或特殊字符,映射时要统一;第四,图像尺寸要从对应的图像文件读取,不能硬编码,因为遥感数据集可能混合了不同分辨率。

参数说明:class_map是类别名到 id 的映射,必须和数据集 YAML 里的 names 顺序一致;img_w和img_h从图像文件读取,不要假设所有图像尺寸相同。转换完成后,随机抽 10 张图用可视化脚本画框验证,确认没有偏移或漏框。

3. YOLO 版本选型与训练参数:从 v8 到 v11 的遥感适配

3.1 为什么遥感任务优先选 YOLOv8 或 v11 而不是 v5

YOLOv5 在 2020 年发布时是工业界默认选择,但遥感图像有几个特性让 v8/v11 更有优势:一是 v8 的 C2f 模块和 v11 的 C3k2 模块在浅层特征提取上更强,对小目标更友好;二是 v8 开始支持 anchor-free 检测头,减少了遥感图像中密集小目标的 anchor 匹配问题;三是 v8/v11 的官方仓库集成了更完整的数据增强和混合精度训练,配置成本低。

如果手头有 V100 或同级别显卡,YOLOv8m 或 v11m 是性价比最高的选择,参数量在 25M 左右,640 输入下推理速度约 5ms/图。如果要做边缘部署,比如 RK3588 或 Jetson 系列,选 YOLOv8n 或 v11n,参数量 3M 左右,但小目标检测会明显下降,需要把输入分辨率提到 1024。

注意:YOLOv5 的很多教程还在流传,但它的 SPPF 和 PANet 结构对遥感图像的密集小目标已经不够用。除非你有历史项目必须兼容 v5 的权重格式,否则新项目直接上 v8 或 v11。

3.2 训练配置:学习率、batch size 与输入分辨率的三角权衡

遥感数据集的训练配置和自然图像数据集有区别。自然图像常用 640×640 输入、batch size 16、初始学习率 0.01。但遥感图像的目标尺寸分布更极端,如果小目标多,输入分辨率要提到 1024 甚至 1280,此时 batch size 要降到 4 或 8,学习率也要相应降到 0.001~0.005。

# data.yaml path: ./dataset train: images/train val: images/val test: images/test names: 0: 森林 1: 公路 2: 作物 3: 河流 4: 住宅 5: 工业 6: 果园 7: 牧场 8: 贫瘠的土地
# 训练命令:YOLOv8m,1024 输入,batch 8,100 epoch yolo detect train \ data=data.yaml \ model=yolov8m.pt \ imgsz=1024 \ batch=8 \ epochs=100 \ lr0=0.005 \ lrf=0.01 \ warmup_epochs=3 \ cos_lr=True \ mosaic=1.0 \ mixup=0.1 \ copy_paste=0.1 \ device=0 \ amp=True \ patience=20

参数说明:imgsz=1024是遥感小目标的关键,640 下很多河流和公路的细段会消失;batch=8是 1024 分辨率下 16G 显存的极限,如果显存不够降到 4;lr0=0.005比默认 0.01 低,因为小数据集上大学习率容易震荡;mosaic=1.0开启马赛克增强,但遥感图像拼接后可能出现不自然的边界,如果验证集 mAP 波动大可以降到 0.5;copy_paste=0.1对实例分割有用,纯检测任务可以关掉;patience=20表示 20 个 epoch 没有提升就早停,小数据集上防止过拟合。

3.3 数据增强的取舍:哪些增强对遥感图像有效

遥感图像和自然图像的数据增强策略不同。水平翻转、垂直翻转、90 度旋转对遥感图像完全合理,因为卫星视角没有固定的上下方向。但色彩抖动要谨慎,森林和作物的颜色是重要特征,过度抖动会让模型混淆。Mosaic 增强在遥感图像上容易把不同地物拼接到一起,产生不真实的边界,建议从 1.0 开始,如果验证集 mAP 下降就降到 0.5。

Mixup 增强在遥感图像上效果一般,因为不同地物的混合会产生现实中不存在的纹理。Copy-paste 增强对稀有类别有帮助,比如把工业区的建筑复制到其他区域,但要注意粘贴时的光照一致性。

我一般会先跑一组基线:只开水平翻转和垂直翻转,mAP 作为基准;然后逐步加入 mosaic、mixup、copy-paste,每次只加一个,观察验证集 mAP 变化。如果某个增强让 mAP 下降超过 2 个点,就关掉。

4. 训练过程排查:BN 崩溃、混淆矩阵与 mAP 不升的常见原因

4.1 BN 层崩溃:现象、原因与解决

训练遥感数据集时,BN 层崩溃是高频问题。现象是 loss 突然变成 NaN,或者验证集 mAP 从某个 epoch 开始断崖式下跌。原因通常是 batch size 太小,BN 层在计算均值和方差时统计量不稳定。遥感图像输入分辨率高,batch size 被迫降到 4 或 8,BN 层的滑动平均跟不上。

解决办法有三种:一是改用 GroupNorm 或 LayerNorm 替代 BN,YOLOv8 的配置里可以通过修改模型 YAML 把 BN 换成 GN;二是冻结 BN 层的 running mean 和 variance,在训练脚本里设置bn_momentum=0.01或更低;三是用梯度累积模拟大 batch,比如batch=4但累积 4 次梯度,等效 batch size 16。

# 在 YOLOv8 训练脚本中冻结 BN 层统计量 import torch import torch.nn as nn def freeze_bn_stats(model): for module in model.modules(): if isinstance(module, nn.BatchNorm2d): module.momentum = 0.01 # 降低滑动平均动量 module.eval() # 冻结 running mean/var return model # 在训练循环中调用 model = freeze_bn_stats(model)

参数说明:momentum=0.01让 BN 层更依赖当前 batch 的统计量,适合小 batch 场景;module.eval()冻结 running mean 和 variance,但会影响推理时的归一化,建议只在训练前期用,后期解冻。

4.2 混淆矩阵总合不唯一:类别定义与标注一致性

YOLO 训练完成后会输出混淆矩阵,如果发现矩阵的行和列总和对不上,或者某些类别的预测数远大于标注数,通常是类别定义有歧义。比如「牧场」和「贫瘠的土地」在视觉上都是草地或裸地,模型很难区分,导致大量误分类。另一个原因是标注不一致,同一张图里类似的地物被标成了不同类别。

解决办法:先跑一遍验证集的可视化,把误分类最多的类别对找出来,比如「牧场→贫瘠的土地」有 50 个误判,那就考虑合并这两个类别。如果不想合并,就在数据加载时对这两个类别做难例挖掘,把误判样本单独拿出来重新训练。

4.3 mAP 不升的五个排查方向

训练 50 个 epoch 后 mAP 还在 0.2 以下,或者验证集 loss 不降,按以下顺序排查:第一,检查标签格式是否正确,用可视化脚本画框,确认没有偏移;第二,检查类别映射是否一致,data.yaml 里的 names 顺序和转换脚本里的 class_map 必须完全对应;第三,检查输入分辨率是否足够,小目标多的话 640 不够;第四,检查学习率是否过大,小数据集上 0.01 容易震荡,降到 0.001 试试;第五,检查数据增强是否过度,mosaic 和 mixup 同时开可能让模型学不到真实分布。

提示:遥感数据集的验证集 mAP 波动大是正常的,因为验证集只有 100 多张图,单个类别的 AP 可能因为几张图的检测结果变化 10 个点。建议用 k 折交叉验证,或者至少跑 3 次不同随机种子的训练,取平均 mAP。

5. 从训练到部署:ONNX 导出、RK3588 适配与误检率控制

5.1 导出 ONNX 并验证推理一致性

训练完成后,部署前必须导出 ONNX 并验证推理结果和 PyTorch 一致。YOLOv8 的导出命令很简单,但遥感图像的高分辨率输入在导出时要注意动态轴设置。

# 导出 ONNX,固定输入 1024x1024 yolo export model=best.pt format=onnx imgsz=1024 opset=12 simplify=True # 验证 ONNX 推理结果 python -c " import onnxruntime as ort import numpy as np sess = ort.InferenceSession('best.onnx') input_name = sess.get_inputs()[0].name dummy = np.random.randn(1, 3, 1024, 1024).astype(np.float32) output = sess.run(None, {input_name: dummy}) print('输出形状:', [o.shape for o in output]) "

参数说明:opset=12兼容大多数推理框架;simplify=True会优化计算图,但某些自定义算子可能被简化掉,导出后要用真实图像对比 PyTorch 和 ONNX 的输出差异,如果 mAP 下降超过 1 个点,关掉 simplify。

5.2 RK3588 边缘部署的量化与误检率控制

RK3588 的 NPU 支持 INT8 量化,但遥感图像的 INT8 量化容易导致小目标漏检。常见做法是先用 FP16 跑基线,如果速度不够再上 INT8。量化时要用校准集,校准集要从训练集里随机抽 200 张,覆盖所有类别。

误检率高是边缘部署的常见问题,原因通常是量化误差导致背景被误判为目标。解决办法:一是在后处理里提高置信度阈值,从 0.25 提到 0.4;二是用 NMS 的 IoU 阈值调低,从 0.45 降到 0.3,减少重叠框;三是在训练时加入背景样本,把纯背景图像也放进训练集,让模型学会抑制背景。

5.3 验证部署效果:用混淆矩阵和 PR 曲线定位问题

部署后不要只看 mAP,要导出混淆矩阵和 PR 曲线,按类别分析。如果某个类别的召回率低但精确率高,说明模型保守,可以降低置信度阈值;如果精确率低但召回率高,说明误检多,可以提高阈值或增加背景样本。

# 用验证集跑推理,生成混淆矩阵 from ultralytics import YOLO model = YOLO('best.pt') metrics = model.val(data='data.yaml', imgsz=1024, conf=0.3, iou=0.4) print(metrics.confusion_matrix) print(metrics.box.map) # mAP50-95 print(metrics.box.map50) # mAP50

参数说明:conf=0.3是推理置信度阈值,部署时根据误检率调整;iou=0.4是 NMS 的 IoU 阈值,密集小目标场景可以降到 0.3。混淆矩阵会显示每个类别的误分类情况,比如「牧场」被误判为「贫瘠的土地」的数量,据此决定是否合并类别或补充训练数据。

6. 小样本遥感检测的进阶技巧:从 1366 张图里榨出更多信息

1366 张图在遥感检测里不算多,但通过几个技巧可以把数据利用率提到更高。第一个技巧是切图训练:把 1024×1024 的原图切成 512×512 的切片,重叠 128 像素,这样训练样本数翻 4 倍,小目标的像素占比也更大。切图后每个切片单独训练,推理时再把切片结果拼回原图。切图的代价是边缘目标可能被切断,需要在拼接时做 NMS 合并。

第二个技巧是用预训练权重。YOLOv8 和 v11 都有在 COCO 上预训练的权重,虽然 COCO 是自然图像,但浅层的边缘和纹理特征对遥感图像也有用。加载预训练权重后,冻结前 10 层训练 20 个 epoch,再解冻全部层微调 80 个 epoch,比从头训练收敛快一倍。

第三个技巧是半监督学习。如果手头还有未标注的遥感图像,可以用训练好的模型生成伪标签,置信度高于 0.7 的保留,低于 0.3 的丢弃,中间的交由人工复核。伪标签数据加入训练集后,mAP 通常能提升 3~5 个点,但要注意伪标签的噪声会累积,每轮迭代后要重新评估。

# 切图脚本:1024 切 512,重叠 128 from PIL import Image import os def slice_image(img_path, output_dir, slice_size=512, overlap=128): img = Image.open(img_path) w, h = img.size stride = slice_size - overlap count = 0 for y in range(0, h - slice_size + 1, stride): for x in range(0, w - slice_size + 1, stride): crop = img.crop((x, y, x + slice_size, y + slice_size)) crop.save(os.path.join(output_dir, f"{os.path.basename(img_path)}_{count}.jpg")) count += 1 return count # 对训练集所有图像切图 for img_file in os.listdir('./images/train'): slice_image(f'./images/train/{img_file}', './images/train_sliced')

参数说明:slice_size=512是切片大小,根据 GPU 显存调整;overlap=128是重叠像素,防止目标被切断;切图后标签也要同步转换,把原图坐标映射到切片坐标,超出切片范围的框要裁剪或丢弃。

最后一个习惯:每次训练完,把最佳权重、data.yaml、训练命令和 mAP 结果存到一个独立目录,命名带上日期和关键参数,比如20250115_v8m_1024_b8_lr005。遥感数据集的训练周期长,参数组合多,没有版本管理很容易忘记哪个权重对应哪组配置。我吃过这个亏,后来每次训练都写一个train_log.md,记录改动和结果,复现和对比省了很多时间。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询