尧图精选

YOLO实战:SSDD遥感舰船数据集处理与训练全流程解析

🕒 发布时间:2026/10/2 9:31:28 📁 来源:尧图网络
简介这份用于YOLO目标检测的SSDD遥感检测数据集包含1160张JPEG遥感图像及对应的1160个XML标注文件打包为48.12MB的RAR压缩包共2000个文件可直接投入YOLO系列模型训练与验证。数据集面向计算机、电子信息工程、数学等专业的大学生课程设计、期末大作业及毕业设计也适合需要遥感舰船检测样本的算法工程师快速上手。资源附带清晰的参数化编程思路代码结构简洁、注释明细便于使用者按需调整网络参数与训练配置。目前已有2787人学习下载实用性经过较多使用者验证。下载后即可获得完整的图像-标注配对数据免去自行采集与标注的时间成本直接用于目标检测模型训练、评估和论文实验。1. YOLO 目标检测遇上 SSDD 遥感数据集1160 张图能做什么坑在哪里做目标检测的人手里最不缺的就是数据集但缺的是「拿来就能用」的遥感方向数据集。SSDDSAR Ship Detection Dataset是合成孔径雷达图像上的舰船检测公开集这份资源把原始图像和对应的 XML 标注文件打包好共 1160 张图像标注格式是 PASCAL VOC 的 XML意味着你不必再自己对着遥感图框舰船省掉最枯燥的标注环节。尤其适合刚入门 YOLO 系列、想用真实遥感场景跑通训练流程的人以及要做遥感目标检测毕设或小规模预研的工程师。这类数据的价值不在数量大而在场景特殊。SAR 图像和日常照片差别很大灰度成像、强噪声、舰船目标小且密集、背景是水面和陆地混合。你用 COCO 或 VOC 训练出来的模型直接拿去推理 SAR 图像大概率翻车因为域差异太大了。SSDD 正好是拿来验证迁移效果和微调流程的合适规模。如果你是第一次碰遥感目标检测或者想把自己熟悉的 YOLO 训练流程换到 SAR 域这份资源能让你少走很多弯路。2. SSDD 数据集的内在结构XML 标注里藏着哪些关键信息2.1 数据集文件构成与标注格式拿到压缩包后解压核心是 images 和 annotations 两个目录。images 下是 JPG 或 PNG 格式的 SAR 图像annotations 下是对应的 XML 文件文件名一一对应。XML 遵循 PASCAL VOC 格式每个文件包含图像尺寸、目标类别、边界框坐标。由于 SSDD 本身是舰船检测数据集类别只有一个 ship个别版本可能区分不同船型但主流版本就是单类检测任务。打开一个 XML 文件常见的结构如下annotation folderJPEGImages/folder filename0001.jpg/filename size width512/width height512/height depth3/depth /size object nameship/name bndbox xmin120/xmin ymin200/ymin xmax180/xmax ymax230/ymax /bndbox /object /annotation这段 XML 的逻辑很直白filename告诉标注对应哪张图size给出图像的宽高和通道数object块里的name是类别名bndbox是真实边界框坐标。注意这里坐标是绝对像素值不是归一化后的 YOLO 格式所以后续要转训练格式时必须做换算。我一般建议拿到数据集后先写个脚本统计一下边界框的尺寸分布而不是急着训练。SSDD 里舰船目标普遍偏小很多框只有二三十个像素宽。如果你直接拿默认的 YOLO 输入尺寸 640x640 去训练小目标会被严重压缩导致召回率很低。先做统计再决定训练时的输入尺寸和 anchor 设置这是遥感检测项目的常识。2.2 图像数量分布与训练验证集划分逻辑1160 张图不算多但足够跑通实验。通常做法是按 8:1:1 或 7:2:1 划分训练集、验证集、测试集。由于 SAR 图像可能包含同一场景不同时相的重复目标简单随机划分可能会让相似图像同时出现在训练集和测试集导致指标虚高。我见过有人随机划分后 mAP 达到 0.9换一种划分方式直接掉到 0.7这就是泄漏问题。所以划分时最好基于图像来源场景分组或者至少保证测试集里的图像与训练集不是同一场景的邻近帧。但这份资源没有提供原始场景分组信息退而求其次的常见做法是按文件名前缀分组如果文件名前缀相同则视为同一场景。如果你只做算法验证随机划分也能接受但要清楚指标会偏乐观。标注文件本身是 XML如果你不打算用 YOLO直接把它转成 COCO JSON 或 PASCAL VOC 原格式去训练 Faster R-CNN 或 RetinaNet 也顺畅。问题在于 YOLO 训练要吃 txt 文件所以 XML 转 txt 是绕不开的一步。3. XML 标注转 YOLO 格式转换脚本到边界框与类别映射3.1 转换脚本的完整实现这一步是动手复现的关键必须把 XML 转成 YOLO 需要的 txt 文件。YOLO 格式每行一个目标字段依次是 class_id、x_center_norm、y_center_norm、width_norm、height_norm全部归一化到 0~1。下面这个脚本我一直在用处理 SSDD 这种 VOC 格式数据集足够稳定。import os import xml.etree.ElementTree as ET from tqdm import tqdm def convert_xml_to_yolo(xml_path, out_path, class_list): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_list: continue class_id class_list.index(name) bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(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 lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) if lines: with open(os.path.join(out_path, os.path.splitext(os.path.basename(xml_path))[0] .txt), w) as f: f.write(\n.join(lines) \n) annotations_dir annotations out_dir yolo_labels os.makedirs(out_dir, exist_okTrue) class_list [ship] for xml_file in tqdm(os.listdir(annotations_dir)): if not xml_file.endswith(.xml): continue xml_path os.path.join(annotations_dir, xml_file) convert_xml_to_yolo(xml_path, out_dir, class_list)这段代码的逻辑分三步先解析 XML 拿到图像宽高再遍历每个 object 读取类别名和边界框坐标最后把绝对坐标换算成归一化的中心点形式。class_list里只有一个ship如果你后续想合并其他类别只需要在这个列表里扩展并保证顺序与训练配置一致。这里有两个参数很容易出错。一是img_w和img_h必须取 XML 里的size而不是用 PIL 去读图。SAR 图像偶尔存在 EXIF 旋转或尺寸不一致的情况以 XML 为准才能保证坐标不偏移。二是输出文件名要和图像名保持一致否则 YOLO 训练时找不到对应标注。脚本中用splitext去掉了 XML 后缀再拼.txt正好对应图像的 basename。3.2 图像路径与标注路径的组织方式YOLO 训练时需要的不是单个 txt而是一个 data.yaml 文件加四个路径train、val、test 的图片路径以及 names 列表。常见做法是把图像和标注分目录但文件名前部分保持一致。我用这样的目录结构ssdd_yolo/ images/ train/ val/ test/ labels/ train/ val/ test/转换脚本生成的是全量 labels需要根据划分列表把对应的图像和 txt 分别放到 train、val、test 下。这一步用简单的 Python 划分脚本就能完成import os import shutil import random random.seed(42) image_dir images label_dir yolo_labels train_ratio 0.8 val_ratio 0.1 test_ratio 0.1 all_images [f for f in os.listdir(image_dir) if f.endswith(.jpg)] random.shuffle(all_images) train_cnt int(len(all_images) * train_ratio) val_cnt int(len(all_images) * val_ratio) train_imgs all_images[:train_cnt] val_imgs all_images[train_cnt:train_cnt val_cnt] test_imgs all_images[train_cnt val_cnt:] for split, img_list in zip([train, val, test], [train_imgs, val_imgs, test_imgs]): os.makedirs(fimages/{split}, exist_okTrue) os.makedirs(flabels/{split}, exist_okTrue) for img in img_list: base os.path.splitext(img)[0] shutil.copy(os.path.join(image_dir, img), fimages/{split}/{img}) if os.path.exists(os.path.join(label_dir, base .txt)): shutil.copy(os.path.join(label_dir, base .txt), flabels/{split}/{base}.txt) else: print(fWARN: {base} has no label)随机种子固定为 42便于复现。如果某些图像没有对应的 txt说明原 XML 里可能没有目标对象脚本会输出警告。建议你手动查看这类图像SSDD 里的负样本极少但确实存在。训练时如果没有 txtYOLO 会自动跳过该图问题不大但测试集里出现无目标的图会影响 AP 计算最好单独处理。3.3 data.yaml 配置与训练参数选择data.yaml 是 YOLO 训练的数据入口内容如下path: ssdd_yolo train: images/train val: images/val test: images/test nc: 1 names: [ship]path是相对 yaml 文件所在位置的根目录train和val填相对路径。nc是类别数这里为 1。names顺序必须与转换脚本里的 class_list 一致否则类别 ID 会对不上导致模型学到错误的映射。训练参数上我从 SSDD 这类小目标遥感数据总结的经验是imgsz先用 640但开启mosaic增强后注意目标被裁剪的概率变大所以建议mosaic概率调到 0.5 以下。batch取决于显存单卡 8G 左右用 1616G 用 32。epochs一般 100 到 300 之间数据集小收敛快也容易过拟合我常用 150 左右配合早停。patience设为 20如果验证集 mAP 连续 20 个 epoch 不提升就停止。workers根据自己的 CPU 核数调整Windows 下建议设为 0 以免 dataloader 报错。运行训练的基本命令yolo train datassdd_yolo/data.yaml modelyolov8n.pt epochs150 imgsz640 batch16 patience20 optimizerAdamW lr00.001这里我选择yolov8n作为初始权重是因为 SSDD 数据量小大模型容易过拟合。AdamW和较低的学习率在小数据集上比 SGD 更稳定尤其当标注框有小目标时AdamW 对梯度的平滑效果更好。如果你只有 CPU把模型换成yolov8n并减小imgsz到 320 也能跑但速度会比较感人。4. 训练 SSDD 的常见坑标注错位、目标过小与过拟合4.1 标注错位XML 坐标与图像尺寸不一致现象训练时 loss 正常下降但验证集的 PR 曲线极差precision 和 recall 都不超过 0.5。把预测结果可视化后发现预测框总是偏离目标一小段距离。原因部分 XML 里的size宽度和高度与图像实际尺寸不一致。有的标注工具保存的 size 是原始分辨率但图像被缩放后没有更新 XML。YOLO 训练时读取图像实际尺寸而转换脚本用的是 XML 里的尺寸两者不一致导致归一化坐标错误。解决转换前写一个校验脚本用PIL打开图像获取真实尺寸与 XML 里的 width/height 对比不一致的打印出来。我遇到这种情况直接以 XML 为准因为标注框是从 XML 坐标里来的如果图像实际尺寸和 XML 不一致通常是图像被外部工具处理过此时需要重命名或者重新生成正确的 XML。最保险的做法是统一把图像 resize 到 XML 描述的尺寸但会引入插值误差一般不建议。更常见的解决方法是手动修正 XML 的 size 字段让它与图像实际尺寸一致然后重新转换。4.2 目标过小导致训练不收敛现象训练前几个 epoch loss 下降明显但到后期 mAP 停滞在 0.4 左右小目标几乎检测不到。用val可视化时画出的预测框只盖住舰船的一个角。原因SSDD 中舰船目标平均像素尺寸约 30x30在 640x640 输入下归一化宽高只有 0.05 左右属于典型的小目标问题。YOLO 默认 anchor 是针对 COCO 设计的不适应这么小的目标。解决调整imgsz到 960 或者 1280让目标在输入图像中占据更多像素。显存不足时可以改用yolov8n并使用rect模式按图像长宽比分批减少无效填充。另一个有效手段是开启scale增强但限制缩放范围让scale0.5而不是默认的 0.9避免小目标被进一步缩小。如果你用的是 YOLOv5直接修改模型 yaml 里的anchors按 SSDD 框尺寸重新聚类。4.3 数据集太小导致过拟合现象训练集 loss 降得很低验证集 loss 先降后升mAP 在某个 epoch 后开始震荡下降权重大小在验证集上表现远不如 train。原因1160 张图按 8:1:1 划分后训练集只有 928 张对于深度学习模型来说很容易把背景噪声和特定船只的纹理记忆下来而不是学到泛化特征。解决用预训练权重做微调而不是从头训练。modelyolov8n.pt就是加载 COCO 预训练权重。增强策略上调高hsv_h、hsv_s、hsv_v的随机扰动把翻转概率设到 0.5但不要动mosaic和mixup同时开启否则样本分布被抹平。另外一个我常用的做法是先把输入分辨率降到 320 做预训练再把模型移到 640 上 finetune 几个 epoch相当于课程学习能有效抑制过拟合。4.4 无标签图像的干扰现象生成的 labels 里某些 txt 文件是空的训练时没有报错但验证集的召回率异常低且预测结果里常有漏检。原因部分 XML 虽然存在但里面没有object块可能是标注过程中跳过的负样本。空 txt 文件让 YOLO 认为这张图没有目标训练时当作背景如果这类图像出现在测试集且里面确实有舰船就会漏检。解决划分数据前先统计空 txt 数量。如果只是少数几张直接从数据集中剔除避免训练时引入歧义。我的做法是在划分脚本里加了过滤逻辑if not os.path.exists(label_path) or os.path.getsize(label_path) 0: skip_image()。这个逻辑看起来简单但能省掉很多后期排查时间。5. 训练效果验证与可视化别只盯 mAP要看特征图和预测框5.1 验证集指标解读与边界框置信度调参训练结束后YOLO 会输出results.csv里面包含每个 epoch 的 precision、recall、mAP50、mAP50-95。遥感目标检测场景下mAP50 的参考价值高于 mAP50-95因为 SAR 图像中目标边界框本身带有噪声更严格的 IoU 阈值对标注不确定性过于敏感。SSDD 这类数据集上mAP50 达到 0.85 以上算是可用状态mAP50-95 只要不低于 0.5 就不算翻车。我习惯用yolo val命令验证特定权重yolo val modelruns/train/exp/weights/best.pt datassdd_yolo/data.yaml imgsz640验证结果里会有F1曲线和confusion_matrix.png。F1曲线的峰值对应的置信度阈值可以当作推理时的 conf 参数参考。如果我在应用时希望降低漏检会把 conf 调到 0.2 左右如果希望减少虚警调到 0.4 以上。SSDD 中的舰船在 SAR 图像里信噪比低我通常推荐conf0.25这是检测效果和虚警率的折中点。5.2 预测结果落盘与批量推理脚本训练完成后对测试集做批量推理并生成带框图像方便检查模型在真实场景中的表现。以下脚本是在 YOLOv8 环境下的常用写法from ultralytics import YOLO import os model YOLO(runs/train/exp/weights/best.pt) test_dir ssdd_yolo/images/test save_dir ssdd_yolo/predictions os.makedirs(save_dir, exist_okTrue) for img_name in os.listdir(test_dir): if not img_name.endswith(.jpg): continue img_path os.path.join(test_dir, img_name) results model.predict(sourceimg_path, conf0.25, imgsz640, saveTrue, projectsave_dir, nametest) boxes results[0].boxes print(f{img_name}: {len(boxes)} ships detected)这段代码的核心是把每张测试图喂给模型saveTrue会把框画在图上。project和name控制输出目录避免覆盖。控制台打印出每张图检测到的目标数量如果某张图上明显有多个舰船却没检测出来说明该图里的目标尺寸或对比度超出模型的泛化范围这时候回到数据增强或输入分辨率上找原因。验证预测框时我有个习惯把conf分别设成 0.1、0.25、0.5 各跑一遍对比检测结果。如果 0.1 和 0.5 的结果差异非常大说明模型对目标的置信度普遍偏低需要检查是否迁移学习不够彻底或者输入分辨率不足。如果三个阈值下结果几乎一致说明模型预测很自信这时候可以放心地把 conf 设高降低虚警率。5.3 用网格搜索调 anchor 与超参数的思路SSDD 数据量小手动调参有不少玄学成分但 anchor 这一步是确定的。YOLOv8 默认从预训练权重继承 anchor但训练时会自动重新聚类。你可以用下面的脚本单独看数据集的 anchor 分布yolo detect train datassdd_yolo/data.yaml modelyolov8n.pt epochs0epochs0不实际训练会在数据加载阶段做 anchor 分析并输出到控制台。如果 anchor 尺寸和目标的实际分布差距大模型收敛速度会明显变慢。SSDD 的舰船宽高比变化较大从 1:1 到 1:5 都有普通 anchor 未必覆盖得了。若发现“anchor 精度低”的提示建议改用 YOLOv5通过utils/autoanchor.py手动跑 k-means 聚类再替换模型 yaml 里的 anchor 值。数据集小还有个隐藏问题训练和验证的图像之间可能存在背景分布差异即使随机划分也很难完全一致。为了更严谨可以在验证时增加max_det1000参数避免某些图上检测框超出默认 300 的限制SSDD 中近岸港口区域的舰船密集一张图出现几十个目标不稀奇。max_det设大些指标统计更完整。6. 进阶用法把 SSDD 模型迁移到自制遥感图像上的微调套路训练完 SSDD 之后你很可能想把自己的遥感图像用起来比如无人机光学图像或者另一颗 SAR 卫星的数据。直接拿 SSDD 训练好的权重去推理新数据通常会掉点原因是传感器差异和成像角度差异。这时候正确的做法是把 SSDD 权重当作预训练权重在你的新数据上做短周期微调而不是重新训练。具体套路是冻结前 10 层只训练检测头先跑 30 个 epoch让模型适应新图像的对比度和背景噪声模式再全局解冻跑 50 个 epoch。这个流程我用过几次mAP50 的恢复速度比从 COCO 预训练快很多。YOLOv8 里冻结层可以用freeze参数比如yolo train datayour_own_data.yaml modelssdd_best.pt freeze10 epochs30 imgsz640freeze10表示冻结模型前 10 层这些低层特征提取器处理的是颜色、边缘、纹理等通用信息传感器差异主要影响高层语义所以先不动它们。等检测头适应了新的域再解冻全部层用更小的学习率lr00.0001做精细调整。如果你的新数据和 SSDD 差异特别大比如把灰度 SSDD 换成三通道光学图像建议不要用 SSDD 权重直接回到 COCO 预训练更靠谱。另一个进阶场景是数据增强策略的定制。SAR 图像的噪声模式是特有的一类干扰普通的数据增强反而会破坏噪声纹理的特征。我一般会关闭mosaic因为 mosaic 将四张不同场景的图拼接在一起会让模型把不同背景的边界误当成舰船特征。替换成copy_paste或mixup效果通常更好。而且 SSDD 中的目标方向不固定旋转增强要开但旋转角度限制在正负 30 度以内超过 45 度的旋转会让舰船的形状特征失真。最后说下我个人的习惯任何训练跑完后我都会强制做一次全测试集可视化打印每张图的检测数量和置信度分布而不只是看一眼 mAP 就收工。从那以后我每次拿遥感数据集做实验都会坚持这个流程因为指标可以骗人但预测图骗不了人。这份 SSDD 数据集虽然小但足够你把整套流程走通也足够让你理解遥感数据与自然图像之间的本质差别。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →