YOLO卫星遥感多类别检测数据集:从格式解析到训练调参的完整工具链 简介一套面向卫星遥感目标检测的多类别数据集共包含1000张真实场景高清图片由LabelImg人工标注标注框质量高、场景覆盖丰富。标签提供VOC(xml)、COCO(json)、YOLO(txt)三种格式分别存放在独立文件夹中下载后即可直接接入YOLO系列模型训练无需再做格式转换。资料同时附赠三个Python数据集划分脚本支持按指定比例生成训练集、验证集和测试集另有Linux与Windows双平台的YOLO环境搭建及训练教程HTML文档便于新手对照完成从环境配置到自定义数据训练的完整流程。压缩包共2000个文件以xml、txt标注文件为主并包含html教程、py脚本、yaml配置等辅助内容总体积约114.64MB。目前已有635人学习下载。整套资料适合目标检测入门者、遥感方向研究人员及算法竞赛队伍能够显著减少数据准备时间是快速启动遥感多类别检测实验的实用素材。1. YOLO卫星遥感多类别检测数据集一套能直接跑通的完整训练工具链做目标检测最烦的不是调模型而是整理数据。相信不少人都经历过从网上吭哧吭哧爬了几千张遥感图用LabelImg一张张画框画到半夜发现类别标错了还得回去改XML。更头疼的是好不容易标完发现框架要COCO格式而你手里只有VOC。这个名为“YOLO卫星遥感多类别检测数据集”的项目说白了就是来解决这个痛点的。它包含1000张遥感影像并且每张图都带VOC、COCO、YOLO三种格式的标签文件。这意味着不管你是用Ultralytics YOLO、MMDetection还是Detectron2拿过来都能直接训练。再加上它自带的划分脚本和训练教程对刚入门遥感目标检测的工程师来说相当于跳过数据采集和格式转换两大坑直接进入模型调参环节。当然1000张图的规模对深度学习来说不算大但做迁移学习、跑通基线、验证算法思路完全够用。本文就顺着这个数据集的使用链条从格式解析到训练调参再到踩坑复盘给你捋一条能直接落地的主线。2. YOLO标签格式解析与数据集划分先搞懂txt里每一行是什么2.1 YOLO格式的标签结构和读取逻辑拿到数据集后第一步绝对不是急着训练而是先打开一个标签文件看看内容长什么样。YOLO的标注格式极简每张图片对应一个同名txt文件文件里每一行代表一个目标格式是class_id x_center y_center width height。这四个坐标值全部相对于图片尺寸做了归一化范围在0到1之间。很多新手第一次看到0 0.514 0.328 0.084 0.061这样的数据会发懵其实拆开来看就清楚第一个数字是类别编号从0开始计数后面四个浮点数分别是目标的中心点x坐标、中心点y坐标、宽度、高度占图片宽高的比例。这个设计的好处是模型在训练时不需要关心输入图片的具体像素尺寸无论图片是512还是1980标签都能直接用。下面这段Python代码是我平时用来快速检查YOLO标签是否正常的工具在没有LabelImg的情况下能帮你把标签可视化地画在图片上。import cv2 def draw_yolo_labels(image_path, label_path, class_names): img cv2.imread(image_path) h, w img.shape[:2] with open(label_path, r) as f: for line in f.readlines(): parts line.strip().split() if len(parts) ! 5: continue cls, x_c, y_c, bw, bh parts cls int(cls) x_c, y_c, bw, bh map(float, (x_c, y_c, bw, bh)) # 将归一化坐标还原为像素坐标 x1 int((x_c - bw / 2) * w) y1 int((y_c - bh / 2) * h) x2 int((x_c bw / 2) * w) y2 int((y_c bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_names[cls], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) return img if __name__ __main__: names [airplane, ship, vehicle] # 根据数据集实际类别修改 img draw_yolo_labels(datasets/images/train/0001.jpg, datasets/labels/train/0001.txt, names) cv2.imshow(check, img) cv2.waitKey(0)这里的核心逻辑就是把归一化坐标乘以图片的实际宽高还原成像素级坐标框。我一般会在训练前随机挑十几张图跑一遍这个脚本确保标签没有偏移、类别没有标反。如果发现框的位置明显不对劲八成是归一化时除错了尺寸或者txt和jpg文件名没对齐。2.2 划分脚本的设计思路按哈希分配而不是纯随机做数据集划分时最容易犯的错误是直接train_test_split随机打乱。遥感影像和普通照片不一样相邻的图片高度相关如果同一场景的相邻帧被分到了训练集和验证集验证指标会虚高模型实际泛化能力并没有那么好。因此在划分脚本里我一般会按文件名的哈希值取模来做保证同一区域的图片尽量进同一个集合。import os import hashlib import shutil import random def split_dataset(image_dir, label_dir, output_dir, val_ratio0.1, test_ratio0.2): random.seed(42) # 固定随机种子保证复现 images [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.shuffle(images) total len(images) test_count int(total * test_ratio) val_count int(total * val_ratio) splits { test: images[:test_count], val: images[test_count:test_count val_count], train: images[test_count val_count:], } for split_name, file_list in splits.items(): os.makedirs(f{output_dir}/{split_name}/images, exist_okTrue) os.makedirs(f{output_dir}/{split_name}/labels, exist_okTrue) for fname in file_list: src_img os.path.join(image_dir, fname) src_label os.path.join(label_dir, fname.replace(.jpg, .txt)) shutil.copy(src_img, f{output_dir}/{split_name}/images/) shutil.copy(src_label, f{output_dir}/{split_name}/labels/) print(f{split_name}: {len(file_list)} images) if __name__ __main__: split_dataset(images, labels, yolo_split)这段脚本做了三件事固定随机种子保证划分可复现、按比例切分训练验证测试集、保持图片和标签的文件名对应关系。注意验证集和测试集的比例可以按需调整但测试集尽量保持原样不要参与训练否则后面评价模型性能时就没有说服力了。我在实际使用中会把test_ratio设为 0.2因为 1000 张图本身就不多测试集留 200 张已经能提供足够置信度。有些场景如果类别极不均衡建议改成按类别比例分层抽样简单随机在少数类上可能分不准。3. 从VOC到COCO再到YOLO三种格式的互相转换与细节坑3.1 VOC格式到COCO格式的转换脚本数据集的第一个卖点就是提供了VOC和COCO两种格式的标签但实际使用时你依然需要自己做转换。比如想用MMDetection训练它虽然支持VOC和COCO但很多较新的模型只接受COCO格式的JSON。VOC格式是把每张图的标注写在一个XML文件里COCO则是把所有图片的标注汇总到一个JSON里两者的组织方式完全不同。我自己写过很多次转换脚本最稳妥的做法不是从零解析XML重新构建JSON而是先把VOC的XML转成更容易调试的中间格式比如字典列表或 pandas DataFrame再序列化为COCO结构。下面这段代码以训练集为例演示完整的转换过程import json import os from xml.etree import ElementTree as ET def voc_to_coco(xml_dir, output_json, category_map): coco { images: [], annotations: [], categories: [ {id: cat_id, name: name} for name, cat_id in category_map.items() ] } annotation_id 1 image_id 1 for xml_file in sorted(os.listdir(xml_dir)): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() filename root.find(filename).text size root.find(size) width int(size.find(width).text) height int(size.find(height).text) coco[images].append({ id: image_id, file_name: filename, width: width, height: height }) for obj in root.iter(object): name obj.find(name).text if name not in category_map: continue bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) w max(xmax - xmin, 1.0) h max(ymax - ymin, 1.0) coco[annotations].append({ id: annotation_id, image_id: image_id, category_id: category_map[name], bbox: [int(xmin), int(ymin), int(w), int(h)], area: int(w * h), iscrowd: 0 }) annotation_id 1 image_id 1 with open(output_json, w, encodingutf-8) as f: json.dump(coco, f) print(fimages: {len(coco[images])}, annotations: {len(coco[annotations])})这段代码的重点在三个容易出错的地方类别ID必须连续并从1开始不能跳号bbox的宽高至少为1像素避免出现0宽度的非法框IS_CROWD固定为0遥感数据集里如果没标群体目标就不能设为1。输出后我一般会再用COCO API加载那个JSON做一次完整校验确保能正确读取。3.2 类别映射的一致性最容易忽略的跨格式问题数据集同时提供VOC和COCO标签时一个潜在陷阱是VOC里的class name和COCO里category的排序不一定一致。我们在训练前必须把所有格式统一到同一个类别名和类别ID映射表否则会出现标签错乱模型的损失函数里找不到对应的类别。确保三种格式的标签用的是同一套类别顺序我的做法是写一个总映射文件比如把类别映射为{airplane: 0, ship: 1, vehicle: 2}然后分别用这个映射去生成YOLO txt和COCO JSON。如果发现COCO JSON里的类别列表标号是1、3、5而YOLO txt里是0、1、2这直接打断了训练流程。稳妥的验证方式是用COCO API重新加载JSON并画出几张图确认每个框的类别名实际对应了正确的对象。4. 训练教程实操用Ultralytics YOLO跑通完整流程4.1 准备YAML文件和模型选择拿到数据集之后训练端的流程很明确。如今Ultralytics YOLO已经成为入门目标检测的事实标准它的CLI和Python API都很友好且对VOC、COCO的支持很完善。与数据集配套的训练教程基本也是围绕它展开的。训练前需要准备一个YAML文件指定数据集的路径、类别数、类别名。比如下面的remote.yamltrain: /path/to/yolo_split/train/images val: /path/to/yolo_split/val/images test: /path/to/yolo_split/test/images nc: 3 names: [airplane, ship, vehicle]这里的路径可以指向图片文件夹Ultralytics会自动在同级或上级目录寻找对应该图片名的标签文件。需要留意的是如果你把图片和标签分开放需要在YAML里指定label路径的规则。模型选择上我建议从YOLOv8s或YOLOv9t开始。1000张的训练数据不足以支撑大模型从零开始训练。虽然YAML里没有写预训练路径但Ultralytics会默认从官方权重仓库下载对应的预训练权重到本地缓存这样迁移学习就有了一个不错的起点。4.2 训练命令行和参数调优的七个关键设置接下来就是训练命令了。一个最简化的训练入口是yolo train modelyolov8s.pt dataremote.yaml epochs300 imgsz640 batch16 lr00.001不过参数优化空间很大实际操作时我一般会在配置里加这些关键参数yolo train modelyolov8s.pt dataremote.yaml epochs300 imgsz640 batch16 optimizerAdamW lr00.001 mosaic0.5 close_mosaic10 patience50 valTrue cacheTruemosaic0.5是训练早期的数据增强策略将4张图拼成1张对增加目标数量有很大帮助但对小目标也容易造成标注混乱所以建议在最后10个epoch通过close_mosaic10关闭它。cacheTrue用于把图片加载进内存1000张图约占用几十GB显存如果显存不够就设为False。patience50是防止过拟合的早停机制。对于遥感小目标imgsz640只能算起步。如果显存足够我通常会调到960甚至1280检测精度提升明显。显存不足时把batch降到8或4同时可以考虑用YOLOv8n来验证数据集是否有问题——小模型速度快、显存消耗低适合先跑通流程再换大模型。我习惯把这两个阶段分开进行先用小模型快速验证流程再用大模型冲精度。5. 从训练到测试验证指标、推理和部署前的四道检查训练完成后进入验证阶段这里要养成一个习惯不要只盯着训练集上的损失曲线要看val/*.txt里的mAP50和mAP50-95指标再跑一遍测试集确认模型没有过拟合到验证集。Ultralytics会在训练结束后自动运行验证集评估。yolo val modelruns/detect/train/weights/best.pt dataremote.yaml splittest加了splittest就可以用测试集来评估。如果训练集mAP很高但测试集明显下降说明数据划分或过拟合有问题。另个排查看板是confusion_matrix.png如果发现两个类别经常互相误检最好回查一下训练样本中那两个类别的标注框质量可能是类别定义本身有重叠。推理预测用起来也很直接yolo predict modelruns/detect/train/weights/best.pt sourcetest/images saveTrue conf0.25conf0.25是置信度阈值遥感检测场景目标多且尺度小如果漏检较多可以降到0.1如果误检多再往上调。我通常还会加save_txtTrue来输出检测结果的标签文件这样便于做定量对比。在部署之前我给自己设了几道检查模型在训练集上是否过拟合测试集和验证集是否交叉是否存在类别不均衡或对小目标漏检的典型问题以及在不同天气光照示例上能不能检测出来。如果这些检查都通过部署到服务端或边缘设备时会少很多意外问题。6. 常见坑与排查遥感小数据集的5个典型问题做遥感目标检测数据集训练最怕的不是模型不收敛而是你花了两天时间调参最后发现数据本身有问题。这类数据集尤其是公开或买卖的数据的坑通常很隐蔽下面是我在这个数据集的典型实践中遇到且解决过的问题按“现象→原因→解决”顺序列出来。问题1训练到一半loss突然变成nan。现象训练时loss值正常但某几个batch后直接变成nan后面无法恢复。原因数据集中存在损坏的图片0字节、格式异常或包含极端的标注值比如width或height小于等于0的非法框导致loss反向传播时出现异常。解决先用PIL或OpenCV批量循环读取每一张图片对所有图片做完整性校验对异常图片直接删除或替换。同时写一个标签扫描函数一旦发现某个gt框宽度或高度小于等于1立即打印图片名和标注行人工复核。遥感影像里某些小目标可能只有几个像素标注时容易意外出现0宽或0高这个必须过滤掉。问题2训练时mAP50很高但mAP50-95惨不忍睹。现象保存的模型在验证集上mAP50有0.7以上但mAP50-95却只有0.3。原因目标框定位不精确。遥感小目标对IoU非常敏感稍微偏移几个像素IoU就从0.5掉到0.1导致严格指标大幅下降。解决这大概率是标签框本身边界画得粗糙用训练集上预测出的框和实际标注做Visual Comparison。优先用标注框更密集的类别单独评测如果该类mAP50-95极低说明标注质量不过关需要重新规范GT框。问题3同一个物体在连续多帧的标注框抖动严重。现象视频连续帧里检测框忽大忽小静态物体也会出现明显的框跳变。原因数据集里的遥感影像可能来自视频抽帧抽帧标注时每一帧都是独立标注时间维度上的标注不一致没有被修正。解决如果你计划把这个模型用于视频检测或业务要稳准框需要对这批数据做时间维度的后处理。最简单的方法是在推理时对检测框使用NMS的变体或对关键帧做插值平滑处理。如果条件允许重新标注时应该用视频标注工具做跟踪式的框传播保证框在序列里平滑变化。问题4测试集和训练集的mAP差异巨大。现象验证集mAP0.65测试集只有0.4差距始终存在。原因数据划分时没有彻底隔离开。遥感影像的场景相关性高如果你随机划分同类地物和区域可能同时出现在训练测试里但测试集稍微换一个区域模型就崩。解决重做划分。按照2.2节的方法要么按图片的哈希值分层划分要么按区域/瓦片号做一个组级别划分group split确保测试集的地理场景在训练时从未出现过。对于这种1000张的小数据集把测试集准备成一个独立的区域集合更好。问题5推理时对屋顶、公路、地面纹理的误检特别多。现象模型的precision不高大量误检集中在背景纹理上。原因遥感影像里的纹理和目标容易混淆尤其是当你用简单的模型跑时背景和物体的语义特征区分度不足。解决先从模型能力入手把模型从s换成m或l然后考虑收集一些难负样本比如误检的那段背景图加入训练集并标为背景类别。如果不想重新训练在部署时提高置信度阈值并加上面积过滤能明显减少误报个数。这些坑中前三个是我自己踩过次数最多的后面两个在数据集交接场景里也常见。核心思路是小数据集上精度排名不是第一优先级数据的干净程度、划分的严谨性、对模型瓶颈位置的判断才是决定成败的环节。7. 进阶从单一模型到遥感检测的工程扩展一次顺利的训练只是起点拿这个数据集跑通之后要往实际任务转移还有几个方向值得延伸。在精度提升上遥感小目标检测的高性价比操作是切图tiling。原始影像分辨率往往在几千像素直接resize到640会丢失小目标信息常见做法是不resize整图而是把一张大图切成多个带重叠的patch分别推理最后再做NMS融合。配合SAHI或自己写滑窗逻辑小目标mAP提升通常比换更大模型还有效。在数据扩充上1000张图作为基础数据集可以配合公开的遥感目标数据集做联合训练。遥感数据的特点就是来源多、尺度杂从多个数据源里抽出同名类别合并训练模型的域适应能力会好很多。注意合并前需要统一类别定义和标签格式如果类别冲突建议要么放弃精细类别只做粗类如“船”“飞机”“车辆”要么用子类层级分别建模。在落地部署上这种三格式数据集一般最终会走向服务化或边缘化。Ultralytics支持直接导出ONNX和TensorRT engine如果你的业务只要求实时推理而不要求batch训练把模型转为FP16的TensorRT推理后配上图像预处理pipeline缩小、归一化和小目标tiling后处理整个系统的吞吐量还会上一个台阶。说句实在话做遥感目标检测这几年最深的体会就是数据和标签的质量决定了一个模型的天花板模型结构反而只是逼近这个天花板的手段。用这套数据集时先把标签可视化和划分检查做扎实比急着换YOLO版本更有效。遇到验证指标虚高别急着高兴先怀疑泄露遇到小目标漏检别只加分辨率先看GT框有没有包全。这套方法论是我踩了一年多坑换来的希望帮你少走一点弯路。本文还有配套的精品资源点击获取