☰
卫星遥感舰船检测数据集VOC+YOLO双格式:2238张17类别训练全流程解析
2026/10/1 10:39:10 网站建设 项目流程

简介:面向遥感图像目标检测与舰船识别任务,这份数据集提供2238张卫星遥感舰船影像及对应标注,涵盖航空母舰、驱逐舰、潜艇、货船、油轮等17个细分类别,并以Pascal VOC和YOLO两种主流格式同步交付,可直接用于YOLO系列模型训练,也可借助xml文件转换为COCO等格式,省去自行标注和格式转换的繁琐环节。压缩包共2000个文件,其中包含1999个xml标注文件和1个使用说明txt,资源整体约109.32MB,适合中高级算法工程师、科研人员及竞赛选手作为目标检测模型训练数据。随包附带“使用前必读”说明,方便快速了解目录结构与标注规则。目前已有835人学习下载,数据经过整理归类,便于直接开展实验对比与模型调优。

1. 卫星遥感舰船检测数据集 VOC+YOLO 格式:2238 张图能训出什么效果

做遥感目标检测的人多半遇到过同一个尴尬:公开数据集要么是航母级的几万张,要么类别单一到只有 ship 一类。卫星遥感舰船检测数据集 VOC+YOLO 格式 2238 张 17 类别.7z 这类资源,正好卡在中间——2238 张图、17 个舰船相关类别,双格式标注,解压即用,不用自己拿 LabelImg 重新画框。它的价值不在于"大",而在于"已经按 VOC 和 YOLO 两种格式组织好了",省掉的是数据准备阶段最琐碎、最容易出错的那一步。

这个数据集适合两类人:一是刚接触 YOLO 训练、想拿一份干净数据跑通全流程的入门者;二是做港口监测、海域态势、船舶识别等实际项目的工程师,需要一份带多种船型的样本做预训练或迁移学习。17 个类别意味着不是简单的"有船/没船"二分类,而是驱逐舰、货轮、渔船、油轮等细分识别,这比二分类难一截,但也更贴近真实业务。YOLO 格式的 txt 标注和 VOC 格式的 xml 标注都存在,意味着你既可以直接扔进 YOLOv5/v8 训练,也可以转回 mmdetection、Faster R-CNN 这类以 VOC 为输入的主流框架,两边都不耽误。

后面我会按"解压 7z → 核对标注格式 → 配好 YOLO 训练环境 → 调参跑通 → 处理高频踩坑"的顺序,把这条链路完整走一遍。中间会给出解压命令、格式转换脚本和训练参数,都是可以直接复制去用的。

2. 先解压 .7z:环境安装、解压命令与目录结构核对

2.1 Linux 与 Windows 下的 7z 安装方式

拿到手是一个 .7z 压缩包,第一步不是写训练脚本,而是把它安全解压。7z 格式比 zip 压缩率高不少,但系统默认不带解压工具,Linux 上尤其明显——你敲unzip它不认识,因为压根不是 zip。

Linux 下(Ubuntu/Debian 系)装 p7zip:

sudo apt update sudo apt install -y p7zip-full

装完以后验证一下:

7z i | head -n 20

能打印出 7-Zip 版本信息就是成功了。CentOS/RHEL 系把包管理器换成yum install p7zip p7zip-plugins即可。Windows 用户直接装 7-Zip 官方客户端,右键菜单里就有"解压到当前文件夹"。

2.2 解压命令、输出路径与完整性检查

解压 .7z 有几种方式,区别在于是否保留原始压缩包。我一般先建一个独立目录再解,避免把文件散到当前目录到处都是:

mkdir -p ship_dataset && cd ship_dataset 7z x ../卫星遥感舰船检测数据集VOC+YOLO格式2238张17类别.7z

7z x会保留压缩包内的完整目录层次,7z e则会把所有文件摊平到同一目录——这里必须用x,因为后面要引用 images 和 labels 两套平行目录,摊平了路径就全乱了。解压过程中如果报Cannot open file as archive,先检查下载是否完整,对比压缩包大小是否和源站一致;如果报Wrong password,那就是包有加密,得找发布方要口令,无解。

解压完成后建议做一次目录核对:

find . -type f | wc -l du -sh .

2238 张图 + 对应标注文件,文件数通常在 4000 以上,总大小几百 MB 到 1GB 左右都属于正常范围。如果文件数少了一大截,说明压缩包被上传端截断过,重新下载更稳妥。

2.3 解压后必须核对的四个关键目录

解压完别急着开训,先把目录结构理清楚。这类数据集普遍按下面的布局组织:

路径内容说明
JPEGImages/2238 张原图卫星/遥感影像的舰船切片
Annotations/VOC 格式 xml每张图一个 xml,含目标框和类别名
labels/YOLO 格式 txt每张图一个 txt,内容为 class cx cy w h(归一化)
ImageSets/Main/数据集划分 txttrain.txt、val.txt 等,列出不帶后缀的图片名

JPEGImages 和 Annotations 是 VOC 的老搭档,labels 是 YOLO 的标注目录,ImageSets/Main 则是划分训练集和验证集的清单。不要自己凭感觉随机抽样分配,直接用 .txt 里的划分——这是数据集的"官方答案",复现结果时和其他人用同一份划分才有可比性。这里有个容易被忽略的点:labels 里的 txt 文件名必须和 JPEGImages 里的 jpg 文件名完全一致,不能有前缀或后缀不一致的情况,YOLO 训练是按文件名去匹配的,对不上直接报Dataset is empty或者训练时找不到标注。

3. VOC 与 YOLO 双格式对照:XML 转 TXT 脚本与格式边界

3.1 VOC 的 XML 里藏着哪些关键字段

VOC 格式是很多检测框架的"通用语言",它的标注是一个 xml 文件,和图片同名。打开一个典型的 xml,里面真正影响训练的就几块:

<annotation> <filename>000001.jpg</filename> <size> <width>1024</width> <height>768</height> </size> <object> <name>cargo_ship</name> <bndbox> <xmin>256</xmin> <ymin>200</ymin> <xmax>512</xmax> <ymax>400</ymax> </bndbox> </object> </annotation>

filename在跨平台处理时要注意大小写问题;size里的宽高是转 YOLO 格式时做归一化的分母,必须和实际图片分辨率一致;object可以出现多个,每个代表图里的一艘船;bndbox是左上角和右下角的像素坐标。框架解析 xml 时读的就是这几项,多出来的difficult、truncated这类字段,在纯 YOLO 训练里通常会被忽略,不用管。

3.2 用 Python 把 VOC 转成 YOLO txt 的通用脚本

虽然这份数据集双格式都给了,但你以后自己标注数据或者拿别人的 VOC 数据集迁移时,九成会用到转换逻辑。核心是把像素坐标归一化到 0~1 之间,YOLO 格式一行一个目标:类别索引、中心点 x、中心点 y、框宽 w、框高 h。

import xml.etree.ElementTree as ET import os # 类别列表必须和训练时用的 data.yaml 完全一致 class_names = ["aircraft_carrier", "warship", "cargo_ship", "liquid_cargo_ship", "fishing_boat", "passenger_ship", "fuel_ship", "tug", "submarine", "coast_guard_ship", "law_enforcement_ship", "inflatable_boat", "wooden_boat", "canoe", "other_ship", "unknown_ship", "civilian_ship"] xml_dir = "Annotations" txt_dir = "labels" os.makedirs(txt_dir, exist_ok=True) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(".xml"): continue tree = ET.parse(os.path.join(xml_dir, xml_file)) root = tree.getroot() img_w = int(root.find("size/width").text) img_h = int(root.find("size/height").text) txt_name = xml_file.replace(".xml", ".txt") with open(os.path.join(txt_dir, txt_name), "w") as f: for obj in root.iter("object"): cls_name = obj.find("name").text.strip() if cls_name not in class_names: continue # 类别不在名单里的直接跳过,防止训练报错 cls_idx = class_names.index(cls_name) xmin = int(obj.find("bndbox/xmin").text) ymin = int(obj.find("bndbox/ymin").text) xmax = int(obj.find("bndbox/xmax").text) ymax = int(obj.find("bndbox/ymax").text) 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 f.write(f"{cls_idx} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n")

这段脚本有几个细节值得展开。class_names的排列顺序不是随便定的——它决定了 YOLO 格式里第一列数字代表哪个类别,训练配置里的names列表必须和这里完全一致,错一位全盘皆错。归一化时w和h用的是像素宽高除以图片宽高,而不是中心点坐标的差值,这是新手最容易算错的地方。脚本里对不在类别白名单内的目标做了跳过处理,因为遥感数据里偶尔会有ignored或拼写错误的类别名,硬转进去会让类别索引错位。

3.3 两种格式的使用边界:别混着喂给模型

VOC 的 xml 包含图片尺寸像素坐标,人类可读、适合标注工具读取,但训练时框架要现做归一化;YOLO 的 txt 已经归一化,训练时直接读字符串、毫秒级加载,省掉了前处理。两者信息等价,但使用场景不同:你在 YOLOv5/v8 里训练就用 txt,你把数据喂给 mmdetection 的 VOC 类检测器就用 xml。不要做"用 YOLO 训练时还在 xml 里抠坐标"这种绕路操作,也别把 labels 目录交给 VOC 系框架——它们不认。数据集同时提供两份,不是因为冗余,而是让你省掉转换这一步,直接用你熟悉的那一套。

4. 用 YOLO 跑通舰船检测:数据配置、训练命令与损失函数

4.1 先准备 data.yaml 与数据集划分脚本

YOLO 训练的第一步是写数据配置 yaml。它告诉模型三件事:训练集和验证集的图片路径、有几个类别、类别名是什么。路径建议写绝对路径,省得软链接和相对路径把新手绕晕:

# ship.yaml path: /home/yourname/ship_dataset train: images/train val: images/val nc: 17 names: ['aircraft_carrier', 'warship', 'cargo_ship', 'liquid_cargo_ship', 'fishing_boat', 'passenger_ship', 'fuel_ship', 'tug', 'submarine', 'coast_guard_ship', 'law_enforcement_ship', 'inflatable_boat', 'wooden_boat', 'canoe', 'other_ship', 'unknown_ship', 'civilian_ship']

如果解压出来的目录不是严格的images/train结构,而是JPEGImages/和labels/两根平行目录,先用一个脚本按 ImageSets/Main 里的 txt 划分。这个划分逻辑以后自己准备数据集时也能复用:

import os, shutil images_dir = "JPEGImages" labels_dir = "labels" os.makedirs("images/train", exist_ok=True) os.makedirs("images/val", exist_ok=True) os.makedirs("labels/train", exist_ok=True) os.makedirs("labels/val", exist_ok=True) with open("ImageSets/Main/val.txt") as f: val_ids = [line.strip() for line in f if line.strip()] for img_name in os.listdir(images_dir): stem = os.path.splitext(img_name)[0] src_img = os.path.join(images_dir, img_name) src_lbl = os.path.join(labels_dir, stem + ".txt") if not os.path.exists(src_lbl): # 没有标注的图不参与训练,直接跳过 continue if stem in val_ids: shutil.copy(src_img, "images/val") shutil.copy(src_lbl, "labels/val") else: shutil.copy(src_img, "images/train") shutil.copy(src_lbl, "labels/train")

val.txt里放的是不带扩展名的文件主名,判断时拿图片名去掉后缀后的 stem 去比。os.path.splitext提取主名是常规操作,不要直接拿img_name[:-4]切,万一图片是 .png 或 .jpeg 就出错了。没有标注文件的图直接跳过——这种图放进训练集,YOLO 会对一个空 txt 做处理,轻则 loss 波动,重则报错。

4.2 训练启动命令与关键参数说明

划分好目录后,启动训练的命令如下:

python train.py --data ship.yaml --weights yolov5s.pt \ --img 1024 --batch 16 --epochs 100 --project ship_experiment \ --name baseline_ship --exist-ok

这段命令对应 YOLOv5 的入口;v8 的话把train.py换成yolo train,参数名的语义一致,比如--img对应imgsz。几个参数按经验给个参考:

参数建议值说明
--img1024遥感舰船目标尺寸占比小,默认 640 容易把小船细节磨掉,升到 1024 有明显收益
--batch168~32 均可,显存不够时用--batch 8配合梯度累积
--epochs1002238 张图的数据量不算大,太多轮过拟合,太少训不透
--weightsyolov5s.pt从 COCO 预训练权重起步,比从零训练收敛快得多

--img 1024不是玄学。舰船目标在遥感图里经常只占几十个像素,你缩到 640 时小目标区域可能只剩十几个像素,模型根本学不到纹理特征。当然显存会吃紧,1080Ti 的 11GB 跑 batch 8 基本上稳,batch 16 要看运气。

4.3 用损失函数曲线判断训练有没有跑偏

训练日志里会持续打印三组 loss:box_loss、cls_loss和obj_loss。box loss 负责回归框的位置和大小,cls loss 负责类别判断,obj loss 负责判断"这个格子有没有目标"。这三个值各自承担不同职责,不要只盯总 loss。

对遥感舰船数据,我一般重点看 obj loss 和 box loss。开场几轮 obj loss 下降极快是正常的——模型在快速学会"哪里有东西";如果经过 20 轮 obj loss 还在高位反复横跳,先考虑两类问题:学习率太大导致震荡,或者标注噪声太高(框位置偏了、漏标了)。box loss 如果完全不降,查看是不是有小船目标因为下采样直接消失——这时--img提高或加数据增强里的scale参数更有效。这类数据量级的训练,前 20 轮看趋势,50 轮后看 mAP 的绝对涨幅,曲线没有单一帅哥曲线,别幻觉。

5. 舰船检测数据集踩坑记录:五条高频翻车与排查路径

5.1 类别索引整体错位,loss 却一直正常下降

现象:训练了几十轮 loss 降到很低,Train/val mAP 看起来还行,但推理时看到一艘货轮却标成了军舰。

原因:labels 里第一列数字是按某个顺序编码的类别索引,而你 data.yaml 里的 names 列表顺序和它不一致。VOC 的 xml 是字符串类名,不容易错;YOLO 的数字索引一旦和 data.yaml 错位,整个模型学的是"索引 0 是驱逐舰"但你喂给它的索引 0 是货轮。

解决:训练前写一条最笨的检查逻辑——随机抽 3 张图,打开 txt,把每行第一个数字对应到 names 里的类别名,与原图对照确认。这比事后分析混乱矩阵快得多。

5.2 验证集 mAP 很高,但实际检测漏掉大量小船

现象:训练集和验证集上的 mAP@0.5 到了 0.8 以上,但丢到一张港口全景图上,只检出大船,很多几像素的渔船完全没框出来。

原因:2238 张的规模决定了它和 MS COCO 这类大库完全不同,小目标占比高但绝对数量少。YOLO 的默认锚框尺寸是按 COCO 目标分布设计的,对小目标召回天然偏弱;此外--img 640会把小船缩得更小,被骨干网络下采样到 8 倍甚至 16 倍之后特征直接丢失。

解决:把--img提到 1024 或 1280;启用 YOLOv5 的--multi-scale;如果用 v8 做迁移,检查 anchors 分布,必要时启用 autoanchor。更直接的方案是切 patch 训练,把大图切成 640×640 的块再训练,后面第 6 章会展开说明。

5.3 同一艘船被重复框出七八个框,NMS 压不下去

现象:密集港口场景,一艘船周围堆了多个高置信框,非极大值抑制之后还会残留重复框。

原因:舰船排列密、多船紧挨,NMS 用的 IoU 阈值默认 0.45 在遥感场景偏向保守;另一层面,目标密集时相邻船体的特征在深层特征图上彼此干扰,产生重复预测。属于模型和 NMS 参数的双重问题。

解决:YOLOv5/v8 的推理参数里把--iou-thres适当降到 0.3~0.35,允许抑制更激进的重复框;另一个经验是把类别置信度阈值--conf-thres从默认 0.25 提到 0.35,重复框一般置信度偏低,会被先一步滤掉。还没有改善的话,检查是不是--agnostic-nms开了,遥感多类密集场景下按类别独立的 NMS 效果往往更好。

5.4 解压后 labels 目录出现一堆 0KB 空 txt

现象:训练日志报Train dataset is empty或No labels found in,检查 labels 下有些 txt 是完全空的。

原因:原图存在但标注缺失的图片被一起打进了压缩包,或者转换脚本对没有目标的图片生成了空文件。个别空 txt 不影响大局面,但如果几百个空文件且恰好集中在某类,会让模型对该类别的学习直接降级。

解决:解压后先清理。把所有空 txt 对应的图片从训练目录移除,只留"有图有标"的干净样本。同时可以把空 txt 收集起来统计哪些类别缺失,如果空文件刚好集中在小船上,这个数据集的完整性就要打个问号了。

5.5 训练时 BN 层崩溃或 loss 变成 NaN

现象:训练到中途,obj_loss突然变成nan,随后整个日志输出异常,模型权重无法保存。

原因:遥感图像里偶尔有全黑或过曝的切片,像素分布极端,在训练前几轮触发数值不稳定;另一常见原因是学习率配合大 batch 时带动量积压,梯度爆炸。

解决:先把--batch调小看是否复现,如果 NaN 只在 batch 大时出现,就是显存发散问题;把--lr从默认 0.01 降到 0.005。另外在 Dataset 加载前加一道过滤,把灰度方差过低(全黑全白)的图片剔除。这两个操作成本低,但能救回一半以上的 NaN 情况。

6. 把舰船检测精度再往上顶:mAP 验证方法与三个进阶技巧

训练完成后别急着部署,先在 val 集上跑一次标准验证,得到 mAP@0.5、mAP@0.5:0.95 和每类的 AP 曲线。v5 里直接:

python val.py --data ship.yaml --weights runs/train/baseline_ship/weights/best.pt --img 1024

最值得看的不是总 mAP,而是混淆矩阵里哪两类互相串。遥感船舶里货轮和油轮长得像、小渔船和木质船边界模糊,类别串扰是这类数据集的家常便饭。如果某两类 AP 互相拉低,用类名里的"confusion"去针对性增补样本,比盲目调训练参数有效得多。

验证完做三件事。第一件是 patch 推理——把测试大图切成 1024×1024 的 patch,每个 patch 独立推理再用权重合并结果,小目标召回通常能拉回 5~8 个点;第二件是 TTA 推理,--augment打开水平翻转和缩放融合,跑一次增加 1~2 个点,代价是推理时间翻几倍;第三件是锚框重聚类,用 K-Means 在这个数据集上重新算锚框,替换默认值,小目标 AP 提升非常明显。

这个数据集我实际跑过类似配置,说句掏心窝的话:2238 张的体量能支撑你把一款 YOLO 从零训到业务可用,但别指望它覆盖所有港口场景——特征分布偏单一,换一片海域风格后掉点是正常现象。拿它做预训练,再用自己业务数据微调,才是性价比最高的用法。希望帮到你少走点弯路,训出一个能真正上线的检测模型。

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

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

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

立即咨询