多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

遥感卫星图像YOLOV5三类别检测数据集构建与训练实战

遥感卫星图像YOLOV5三类别检测数据集构建与训练实战 简介这份资源面向从事遥感图像目标检测的算法工程师、研究生及竞赛选手提供一套按YOLOv5目录规范整理的卫星图像数据集可直接投入训练省去格式转换与清洗环节。数据覆盖飞机、油罐、船只三个类别图像为800×600的RGB卫星图标注清晰适合做遥感场景下的检测模型训练与算法验证。包内共2000个文件以1999个txt标注文件和1个Python可视化脚本为主压缩包约237.68MB其中txt文件对应训练集2398张、验证集1393张图片的边界框标签脚本可随机读取一张图片绘制检测框并保存到当前目录无需修改即可运行。资源按datasets-images-train与datasets-images-val分目录存放并附类别说明文件目录结构清晰便于快速接入YOLOv5训练流程。目前已有219人学习下载适合需要遥感小目标检测数据、希望快速复现实验或开展课程项目的读者参考使用。1. 遥感卫星图像下的飞机、油罐、船只检测为什么这三类目标值得单独做一个 YOLOV5 数据集拿到一张遥感卫星图你想让模型自动框出停机坪上的飞机、储油区的油罐、港口里的船只——这件事听起来像是把 YOLOV5 跑通就行但真正动手过的人都知道卡住你的往往不是模型结构而是数据。遥感图像里的飞机可能只有十几个像素宽油罐是密集排列的圆形船只有时贴着码头、有时在开阔水面三类目标的尺度、背景、分布规律完全不同。这就是为什么一个按 YOLOV5 目录格式整理好的三类别遥感检测数据集比随便找一堆图丢进网络要值钱得多。这篇文章面向的是想用 YOLOV5 训练自己数据集、尤其是做遥感卫星图像目标检测的从业者。不管你是刚接触 YOLOV5 训练自己数据集的新手还是已经在调 yolov5 超参数的老手下面会从目录结构、标注格式、类别设计、训练配置到量化部署前的数据准备把这条链路拆开讲清楚。遥感卫星图像和普通自然图像最大的区别在于目标小、方向任意、背景纹理复杂这三类目标恰好覆盖了遥感检测里最典型的几种难点。读完你应该能判断这个方向值不值得投入以及怎么用最小成本先跑通一版。2. YOLOV5 目录格式到底长什么样从 images 到 labels 的映射关系2.1 标准目录结构与文件命名约定YOLOV5 对数据集的目录组织有比较固定的约定核心就两条图片和标签分开放文件名一一对应。常见做法是建一个数据集根目录下面分 images 和 labels 两个子目录各自再分 train、val、test。结构如下dataset/ ├── images/ │ ├── train/ │ │ ├── rs_aircraft_0001.jpg │ │ ├── rs_tanker_0002.jpg │ │ └── ... │ ├── val/ │ └── test/ └── labels/ ├── train/ │ ├── rs_aircraft_0001.txt │ ├── rs_tanker_0002.txt │ └── ... ├── val/ └── test/这里有个血泪经验images/train 下的 rs_aircraft_0001.jpg 对应的标签必须是 labels/train/rs_aircraft_0001.txt文件名主干完全一致只是扩展名不同。YOLOV5 在加载时会用图片路径替换 images 为 labels、替换扩展名为 .txt 去找标签找不到就当作负样本处理。很多人第一次训练 loss 不降排查半天发现是标签文件名带了多余后缀或者大小写不一致。图片格式常见的是 jpg 或 png遥感卫星图像原始可能是 tif建议先转成 jpg 或 png避免训练时解码开销过大。标签文件是纯文本每行一个目标格式为class_id x_center y_center width height这五个值都是归一化到 0 到 1 之间的浮点数x_center、y_center 是目标框中心点相对整图宽高的比例width、height 是框宽高相对整图宽高的比例。注意不是像素值也不是左上角坐标。遥感图像里目标小归一化后数值可能只有 0.01 量级这是正常的。2.2 三类别标签的类别索引与 data.yaml 配置三类别分别是飞机、油罐、船只需要给它们分配 class_id。常见做法是按字母序或按重要性排class_id类别名英文名典型尺度0飞机aircraft小目标10-40 像素1油罐tanker中小目标15-50 像素2船只ship变化大10-100 像素然后在数据集根目录建一个 data.yamlYOLOV5 训练时通过这个文件找到数据# data.yaml path: /data/rs_dataset # 数据集根目录 train: images/train # 相对 path 的训练图片目录 val: images/val test: images/test nc: 3 # 类别数 names: [aircraft, tanker, ship] # 类别名顺序必须和 class_id 对应参数说明path 可以写绝对路径也可以写相对路径但 train/val/test 是相对 path 的。nc 必须等于 names 长度否则训练时报维度不匹配。names 的顺序决定了 class_id如果标注时飞机是 0、油罐是 1、船只是 2这里就必须一致否则模型学出来的类别会错位。我一般会在 data.yaml 旁边放一个 README 记录标注规则避免多人协作时类别索引对不上。2.3 从原始标注到 YOLO 格式的转换脚本遥感数据集的原始标注可能是 VOC XML、COCO JSON 或者 shapefile。假设你拿到的是 VOC 格式每个图片对应一个 XML里面记录了目标的左上角和右下角像素坐标。转成 YOLO 格式的脚本如下import os import xml.etree.ElementTree as ET from PIL import Image # 类别名到 class_id 的映射必须和 data.yaml 一致 CLASS_MAP {aircraft: 0, tanker: 1, ship: 2} def voc_to_yolo(xml_path, img_path, out_txt_path): # 读取图片宽高用于归一化 with Image.open(img_path) as im: img_w, img_h im.size tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text.strip() 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) # 计算归一化的中心点和宽高 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 # 裁剪到 0-1防止标注越界 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) w min(max(w, 0.0), 1.0) h min(max(h, 0.0), 1.0) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines))逻辑说明先读图片宽高再把 VOC 的左上右下坐标转成中心点加宽高最后除以宽高归一化。参数上保留 6 位小数足够YOLOV5 内部会再处理。裁剪到 0-1 是防止有些标注框超出图片边界导致训练异常。如果原始标注是 COCO JSON思路一样只是解析方式换成读 JSON 的 annotations 字段注意 COCO 的 bbox 是左上角加宽高转换时先算中心点。转换完建议抽查几个标签文件用可视化脚本画框确认。遥感图像目标小标注偏移几个像素在归一化后可能看不出但训练时会影响回归精度。3. 遥感卫星图像的目标特性飞机、油罐、船只为什么不能混在一起训3.1 三类目标的尺度分布与锚框选择遥感卫星图像里飞机通常停在机场长度几十米在 0.5 米分辨率下大概 20 到 40 像素油罐是圆形或椭圆形直径十几米到几十米像素尺度 15 到 50船只变化最大小渔船可能 10 像素大型货轮能到 100 像素以上。这三类目标的尺度分布差异明显如果直接用 YOLOV5 默认的 COCO 锚框小目标召回会很低。YOLOV5 默认锚框是在 COCO 上聚类得到的最小锚框对应约 8x8 像素但遥感小目标可能只有 10 像素宽默认锚框偏大。常见做法是用自己的数据集重新聚类锚框。YOLOV5 仓库里提供了 kmeans 脚本但更直接的是用下面这段代码快速统计import numpy as np from sklearn.cluster import KMeans # 假设所有标签的宽高已经收集到 wh 列表单位是像素 # wh [(w1,h1), (w2,h2), ...] wh np.array(wh) k 9 # YOLOV5 用 9 个锚框 kmeans KMeans(n_clustersk, random_state0).fit(wh) anchors kmeans.cluster_centers_ # 按面积排序YOLOV5 要求锚框按从小到大排列 anchors anchors[np.argsort(anchors[:, 0] * anchors[:, 1])] print(anchors)参数说明k 固定为 9因为 YOLOV5 每个检测层 3 个锚框共 3 层。聚类前要把所有训练标签的宽高从归一化值还原成像素值否则聚类结果没有物理意义。得到锚框后在训练配置里替换 anchors 字段。我一般会对比默认锚框和聚类锚框在验证集上的 mAP遥感小目标通常能提升 3 到 8 个点。3.2 方向任意性与旋转框的取舍遥感图像里的飞机和船只方向是任意的水平框会引入大量背景。比如一架斜向停放的飞机水平框面积可能是实际目标的 1.5 到 2 倍框内混入跑道或水面。油罐相对好一些圆形目标用水平框也能接受。如果你追求更高精度可以考虑旋转框检测但 YOLOV5 原生不支持旋转框需要改网络头或换用 YOLOV5 的旋转框变体。对于大多数落地场景我的建议是先用水平框跑通因为标注成本低、生态成熟、部署简单。如果水平框的 mAP 已经满足业务要求没必要上旋转框。只有在密集排列的船只或飞机场景下水平框重叠严重导致 NMS 误删才考虑旋转框。一个折中做法是在数据增强里加入随机旋转让模型对方向更鲁棒。YOLOV5 的 augment 配置里可以开 degrees 参数但注意遥感图像旋转后目标可能超出边界需要配合平移和缩放。3.3 背景纹理与负样本策略遥感卫星图像的背景非常复杂机场跑道有标线海面有波浪和云影储油区有管道和建筑。这些纹理容易被模型误检成目标。常见做法是加入负样本即没有三类目标的图片标签文件为空。YOLOV5 支持空标签文件训练时会把这些区域当作背景抑制。负样本的比例需要控制。我一般按正样本的 10% 到 20% 加入负样本太多会导致模型过于保守、召回下降。负样本要选那些容易混淆的场景比如带标线的跑道、有波浪的海面、圆形建筑屋顶。这些在遥感图像里很常见不加负样本的话模型可能把圆形屋顶当成油罐。另外遥感图像常有云层遮挡被云遮住的目标标注时应该跳过不要强行标一个看不见的框。训练时模型会学到云层区域没有目标反而有助于抑制云层误检。4. 用 YOLOV5 训练三类别遥感数据集配置、命令与参数调优4.1 环境准备与最小训练命令假设你已经装好 PyTorch 和 YOLOV5 依赖数据集按第 2 章的目录结构放好data.yaml 也写好了。最小训练命令如下python train.py \ --data /data/rs_dataset/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --project runs/train \ --name rs_3cls参数说明--data 指向 data.yaml--weights 用预训练权重遥感数据量不大时从 COCO 预训练迁移能加快收敛--img 是输入尺寸遥感小目标建议用 640 或更大但显存有限时 640 是平衡点--batch 根据显存调16 是 8G 显存的保守值--epochs 100 起步看验证集 mAP 是否还在涨。--project 和 --name 决定输出目录。训练过程中重点看几个指标box_loss、obj_loss、cls_loss 是否下降验证集 mAP0.5 和 mAP0.5:0.95 是否上升。如果 box_loss 不降先检查标签格式如果 obj_loss 高可能是负样本太少或背景太复杂如果 cls_loss 高检查类别是否平衡。4.2 针对小目标的超参数调整YOLOV5 的超参数在 hyp.scratch.yaml 里遥感小目标需要调几个关键项参数默认值遥感建议值作用img640640-1024输入尺寸越大越小目标越清晰anchor_t4.03.0-4.0锚框匹配阈值小目标可适当降低fl_gamma0.01.0-1.5focal loss缓解正负样本不平衡box0.050.03-0.05框回归权重cls0.50.3-0.5分类权重obj1.00.7-1.0目标置信度权重img 增大能提升小目标召回但显存和推理时间也增加。如果显存够建议用 1024 训练推理时再降到 640。anchor_t 控制锚框和真实框的匹配小目标匹配更难适当降低可以让更多锚框参与。fl_gamma 开 focal loss 对遥感小目标有帮助因为小目标正样本少focal loss 能聚焦难样本。另外YOLOV5 的 mosaic 增强对小目标有效但遥感图像拼接后目标可能出现在不合理的位置比如飞机出现在海面。如果发现模型学出奇怪的上下文可以降低 mosaic 概率或关闭。4.3 训练日志解读与早停策略训练日志里每轮会打印各类损失和验证指标。重点看验证集的 P、R、mAP0.5。如果训练集 mAP 很高但验证集低说明过拟合需要加数据增强或减模型容量。如果两者都低说明欠拟合需要加训练轮数或调大模型。YOLOV5 默认 patience 是 100即 100 轮没有提升就早停。遥感数据集通常不大我一般设 patience 50避免浪费时间。早停后取 best.pt 做推理。如果训练过程中 mAP 波动大可能是 batch 太小或学习率太高可以调低学习率或增大 batch。还有一个玄学问题同样的配置不同随机种子结果可能差几个点。建议固定种子或者跑两三次取平均。如果时间紧至少固定种子保证可复现。5. 避坑与排查遥感三类别数据集训练中最容易翻车的 5 个点5.1 标签归一化用错基准尺寸现象训练 loss 正常下降但推理时框的位置整体偏移或大小不对。 原因标注时用了缩放后的图片尺寸做归一化但训练时加载的是原图或者反过来。遥感图像经常被裁剪或缩放基准尺寸不一致就会导致归一化错误。 解决统一以训练时实际加载的图片尺寸为基准。转换脚本里读图片宽高要用同一份图片。如果图片被预处理过确保标签和图片同步处理。5.2 类别索引与 data.yaml 不一致现象模型能检测到目标但类别全错飞机被标成船只。 原因标注文件里的 class_id 和 data.yaml 的 names 顺序不一致。比如标注时飞机是 1但 data.yaml 里 aircraft 在索引 0。 解决转换脚本里的 CLASS_MAP 和 data.yaml 的 names 必须严格对应。建议在 data.yaml 里用注释写明每个索引对应的类别转换后抽查几个标签文件确认。5.3 小目标被下采样丢失现象大目标检测正常小目标召回极低。 原因YOLOV5 的 stride 8 检测层对应 80x80 特征图输入 640 时每个格子 8 像素小于 8 像素的目标在特征图上可能消失。 解决增大输入尺寸到 1024 或 1280或者修改网络增加更浅的检测层。另一个办法是把小目标图片裁剪成小块训练推理时再拼接。常见做法是滑窗裁剪每块 512x512重叠 128 像素。5.4 负样本过多导致召回下降现象误检少了但漏检多了mAP 反而降。 原因负样本比例过高模型学到背景占主导对目标变得保守。 解决负样本控制在正样本的 10% 到 20%并且选容易混淆的场景。如果已经加多了减少负样本或提高 obj 权重。5.5 验证集和训练集分布不一致现象训练集指标很好验证集差很多。 原因验证集图片来自不同区域、不同季节或不同传感器分布和训练集差异大。 解决划分数据集时按区域或时间划分确保验证集能代表真实场景。如果无法避免在训练集里加入类似分布的图片。遥感图像尤其要注意不同光照、云量、地物类型的影响。6. 从训练到落地量化部署前的数据准备与验证技巧训练出 best.pt 只是第一步真正落地还要考虑推理速度和部署平台。如果你打算把模型量化后部署到 RK3568 或树莓派 4B 这类边缘设备数据准备阶段就要为量化做铺垫。量化对数据分布敏感校准集最好从训练集里抽覆盖三类目标和各种背景。常见做法是抽 100 到 200 张按类别和场景分层采样。验证量化后模型是否掉点不能只看 mAP还要看单类召回。遥感小目标量化后容易丢失因为量化误差对小目标的特征影响更大。我一般会单独统计飞机、油罐、船只的召回率如果某一类掉超过 5 个点就要考虑混合量化或保留部分层为浮点。另一个技巧是推理时用 TTA测试时增强比如水平翻转和缩放把多次结果融合。遥感图像方向任意TTA 对旋转敏感水平翻转可能反而有害。我试过只做多尺度 TTA即 640 和 1024 两个尺度各跑一次再 NMS 融合小目标召回能提升 2 到 3 个点代价是推理时间翻倍。边缘设备上要权衡。最后说一个我自己的习惯每次训练完我会把验证集里漏检和误检的图片单独挑出来按类别和场景归类看看是标注问题还是模型问题。遥感数据集标注成本高很多漏检其实是标注漏了。这个复盘习惯帮我省了很多调参时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表