ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLO船舶数据集详解:从标签格式到模型训练全流程

YOLO船舶数据集详解:从标签格式到模型训练全流程 简介面向YOLO系列目标检测模型训练与验证的船舶类数据集涵盖充气船、独木舟、船舶等常见水上目标适用于水域监控、航道管理、海上搜救等场景可帮助检测学习者和算法工程师快速获取带标注数据省去采集与标注环节。压缩包总计2000个文件、约88.34MB主要包含1063个XML标注文件与936个TXT标签文件并附1个YAML数据集配置XML为VOC格式框坐标TXT为YOLO格式的类别、归一化中心点与宽高信息YAML内置数据集路径、类别名称与训练验证划分可直接接入YOLOv5、YOLOv7、YOLOv8、YOLOv9、YOLOv10、YOLO11等主流版本。数据集共有1088张船舶图像已按训练与验证需求划分好解压后配合data.yaml即可直接训练、验证和测试无需额外格式转换。目前已有86人学习下载适合正在搭建检测流程、对比YOLO系列性能或开展船舶识别项目的开发者参考使用。1. yolo算法船舶数据集1088张带标签图像从文件清单到能训出模型的完整路径拆数据集拆多了会有一个直觉判断一份yolo算法目标检测数据集能不能用先别急着看图片长什么样直接去看标签文件。这份船舶数据集压缩包解压后img_0298_84.txt、img_0529_31.txt 这类文件密密麻麻排了一串很明显是yolo格式的txt标签再配合根目录下的两个标签文件夹和data.yaml基本可以断定它是按yolov5/v8/v9那套标准组织好的。它解决的核心问题是做充气船、独木舟、船舶这三类目标的检测任务时你不用再从零标注拿来划分好的训练验证测试集、两种格式标签和配置直接开训适合正在调yolov5、yolov8甚至yolov10的算法工程师也适合做毕设需要真实水域船只样本的学生。2. 数据集底细两个标签文件夹1088张图对应的格式逻辑2.1 文件命名规律从txt名反推图像匹配机制打开压缩包先看到的是几百个txt文件命名格式统一是 img_编号_编号.txt。yolo系列算法训练时的常规做法是图像和标签同名只是扩展名不同train.py 里通过 img_path 替换后缀找到对应txt。比如 img_0298_84.jpg 对应 img_0298_84.txt编号里的 0298 通常是原图序号84 可能是目标框编号或者切片序号具体语义不影响训练。这种命名方式的优势是排序稳定Windows 下按名称排序不会错位。实际训练时你不需要手动建立对应关系ultralytics 的 dataloader 会自动扫描 images 目录下的图片再去 labels 目录下找同名txt。但我一般会在拿到数据集后先写一个快速脚本核对一遍确认每张图片确实能找到同名标签不然训练到一半报 FileNotFoundError 会浪费大量时间。2.2 双格式存储的意义yolo格式和voc格式分别解决什么问题摘要里写明这个数据集包含两种标签格式分别保存在两个文件夹。yolo格式是txt文件内容形如 class_id x_center y_center width height坐标是相对图像的归一化比例范围0到1。voc格式是xml文件存储的是真实像素坐标。yolo格式是给训练直接吃的ultralytics和大多数yolo仓库都是读txtvoc格式是给人看的也想保留标注工具的原始导出结果方便你用labelImg继续编辑或者转成coco格式。这个设计有实际价值。很多时候数据集只有一种格式你想从voc转yolo还得自己写转换脚本这份直接把两种都给了。需要强调的是两类文件内容描述的是同一个标注框只是表示方式不同xml里的bndbox坐标除以图像宽高就能得到yolo格式的归一化值这是后续自己解析和校验的数学基础。2.3 数据划分状态data.yaml里能看到什么数据集已经划分好配置写在data.yaml里。yolov5和yolov8的data.yaml语法基本兼容通常包含 train、val、test 三个路径和 nc、names 两个关键字段。路径可能是相对路径格式比如 train: ../images/trainval: ../images/val这意味着你得把数据集放在特定目录结构下或者自己改成绝对路径。很多人拿到数据集直接改路径就开训但names的顺序是绝对不能动的。names: [inflatable_boat, kayak, ship] 这个排列顺序决定了txt里class_id的含义0对应充气船1对应独木舟2对应船舶。如果训练时手误改了names顺序模型学到的类别映射就全乱了推理输出的结果对不上真实物体这是一类非常隐蔽的错误。提示先打开data.yaml确认names顺序和实际图片内容是否一致再开始训练。顺序错了后面所有评估指标都失真。在数据量层面1088张图做三类检测属于中等偏小的规模。我的经验是这个量级直接上yolov8s能跑通流程但mAP可能不太稳定尤其是小目标船只在远处密集出现时。建议先把图片尺寸设成640x640batch size根据显存调整用yolov8s作为baseline先验证标签和流程没有问题再考虑上yolov8m或者加数据增强。3. YOLO txt标签解析归一化坐标的数学含义与校验脚本3.1 五个数值的物理意义别把x_center理解成像素坐标yolo格式每行五列class是类别索引从0开始后面四个值是比例值。很多人第一次接触会犯一个错误以为 x_center 是目标中心点的像素横坐标结果画框全画到左上角去了。实际上它计算的是 original_x_center / image_width也就是中心点横坐标占整张图宽度的比例。拿一个实例来说img_0298_84.txt 中某一行的内容是0 0.617651 0.442058 0.283472 0.216485其中0代表类别是充气船0.617651表示中心点离左边缘的距离是图像宽度的61.77%0.442058表示中心点离上边缘距离是图像高度的44.21%0.283472是框宽度占图像宽度的28.35%0.216485是框高度占图像高度的21.65%。这四个比例乘上原图尺寸就还原出像素坐标了。训练时这个格式不需要做任何修改ultralytics 自己会做尺度缩放。但如果你想用OpenCV画框可视化检查标签质量就需要把归一化坐标换算成像素坐标并且注意矩形框右上角的横坐标是 x_center 加 half_width纵坐标是 y_center 加 half_height不是直接拿width和height当宽高。3.2 用Python快速校验标签坐标合法性拿到数据集后我的习惯是写一段脚本遍历所有txt检查坐标是否越界。因为有时标注工具导出时会把个别框算错导致 x_center width/2 大于1或者坐标出现负数。这种脏数据不会让训练直接报错但会拉低mAP而且出错位置随机很难排查。import os label_dir labels/train bad_count 0 for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname), r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f{fname} 格式异常: {line.strip()}) bad_count 1 continue cls parts[0] x, y, w, h map(float, parts[1:]) # 类别索引必须是整数且在有效范围内 if not cls.isdigit() or int(cls) not in [0, 1, 2]: print(f{fname} 类别索引异常: {line.strip()}) bad_count 1 # 坐标必须在0到1之间宽高不能为负 if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): print(f{fname} 归一化坐标越界: {line.strip()}) bad_count 1 print(f扫描完成异常标签数量: {bad_count})这段脚本先按空格拆分标签行再逐一校验五个字段。类别索引限定在[0,1,2]是因为这个数据集只有三个类别如果你自己在扩展数据集改成你的真实类别数即可。归一化坐标理论上必须在0到1之间但要注意w和h大于1的情况一般不会出现如果出现说明标注框比整张图还大原因通常是图像尺寸取错了。扫描结果如果异常标签数量超过10个我建议直接从训练集中剔除这些文件而不是尝试修复因为修复框坐标需要原图辅助工作量大还容易改错。少量坏标签剔除后不影响整体训练。3.3 画框可视化检查标签对应目标是否准确坐标校验只是第一步更直观的检查是把框画到图上。这一步能肉眼确认类别是否标反、框是否贴边比mAP曲线更早暴露问题。import cv2 img cv2.imread(images/train/img_0298_84.jpg) h, w img.shape[:2] with open(labels/train/img_0298_84.txt) as f: for line in f: cls, x, y, bw, bh line.split() x, y, bw, bh map(float, [x, y, bw, bh]) x1 int((x - bw / 2) * w) y1 int((y - bh / 2) * h) x2 int((x bw / 2) * w) y2 int((y bh / 2) * h) color (0, 255, 0) if cls 0 else (0, 0, 255) if cls 1 else (255, 0, 0) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.imwrite(check.jpg, img)画框代码里用类别的颜色区分充气船、独木舟和船舶。看到绿色框是充气船、红色框是独木舟、蓝色框是船舶。抽20-30张图看下来如果边界框都紧贴船体且类别看起来合理标签质量就算过关。4. VOC格式xml里藏着原始像素坐标转txt时的四个边界坑4.1 读取xml标签结构理解bbox坐标存储方式voc格式的xml是Pascal VOC标准object节点下会有bndbox节点里面存 xmin、ymin、xmax、ymax 四个像素值。下面是这个数据集里典型的xml内容结构annotation folderimages/folder filenameimg_0529_31.jpg/filename size width1280/width height720/height depth3/depth /size object namekayak/name bndbox xmin412/xmin ymin233/ymin xmax587/xmax ymax401/ymax /bndbox /object /annotation转换逻辑是x_center (xmin xmax) / 2 / widthy_center (ymin ymax) / 2 / height框宽 (xmax - xmin) / width框高 (ymax - ymin) / height。四个边界坑第一个就出现在这里——有些xml的坐标不是整数而是浮点直接用int会丢失精度导致中心点偏移一两个像素目标较小的船可能因此错位明显。第二个坑是xml里的filename有时是绝对路径有时是文件名不带目录写转换脚本时不要拼路径直接用os.path.basename。第三个坑是namespace。有些标注工具会在xml根节点加自定义命名空间ElementTree解析时tag会变成带前缀的名字比如 object 变成 ns0:object按常规写法取不到值。我一般先解析一段打印根节点tag确认是否有前缀再写取值逻辑。第四个坑是坐标越限。像素坐标经过归一化后理论上应该在0到1之间但极端情况可能会出现 xmax 超出图像宽度归一化后大于1。转换脚本里要加clamp逻辑超出部分裁剪到合法区间避免训练时出现NaN。4.2 写一个可靠的xml转txt脚本虽然这份数据集自带两种格式不需要手动转换但你在实际项目中可能拿到只有voc格式的数据这个转换脚本可以复用。import xml.etree.ElementTree as ET import os class_names [inflatable_boat, kayak, ship] # 必须与data.yaml的names一致 def convert_xml_to_yolo(xml_path, output_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_names: continue cls_id class_names.index(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, xmin) ymin max(0, ymin) xmax min(img_w, xmax) ymax min(img_h, ymax) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / 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)) # 批量转换示例 xml_dir voc_labels out_dir yolo_labels os.makedirs(out_dir, exist_okTrue) for fname in os.listdir(xml_dir): if fname.endswith(.xml): convert_xml_to_yolo( os.path.join(xml_dir, fname), os.path.join(out_dir, fname.replace(.xml, .txt)) )代码里我用root.iter(object)而不是root.findall(object)是为了兼容object节点嵌套层级有差异的标注文件。float转换比int更稳避免精度损失。输出保留六位小数对yolo训练来说精度足够。4.3 校验转换结果与原有txt是否一致这个数据集同时提供了两种格式正好可以用来验证转换脚本正确性。随机挑几个文件按第3章的校验脚本重新解析txt对比自己转换输出的txt和原有txt的数值差值在0.001以内视为正常。有个容易忽略的细节原有xml里的name标签顺序可能和data.yaml的names顺序不一致。比如xml里写的是ship但在names里排第2转换脚本里用class_names.index(name)就是按names顺序映射的。如果names顺序改动过索引就会错位这是转换后模型训练效果莫名其妙变差的常见原因。5. 避坑记录训练这类船舶数据集最容易翻车的五个地方5.1 现象训练正常跑完loss曲线下降但验证集mAP只有0.1原因标签文件全部存在但image和label的目录没配对。很多人训练时设置了val路径但data.yaml里的test路径指向不存在目录ultralytics不会报错只是在验证阶段只加载了部分数据。解决训练前先打印训练集和验证集的数量以及每个数据集目录下实际有多少图片多少标签确保数字和划分文件一致。我通常写一个三行脚本统计文件数量比看日志快得多。5.2 现象img_0529_31.txt里的第一个数字是5但数据集只有三类目标原因标签文件里混入了背景类或者标注错误把多个类别索引写成了不相干的值。比较常见的是标注时复制粘贴出了错或者数据集合并不干净。解决用第3章的校验脚本扫一遍发现异常类别索引统计数量。如果不超过10个直接删除对应txt文件或修复索引值如果很多说明这个数据集标签有问题优先找作者确认是否漏传文件而不是带病训练。5.3 现象yolov8训练时报错Assertion Labels shape error原因某个图像的标签txt里存在空行或者行内字段数不对。比如文件末尾多了一个换行解析时出现一个空列表。解决读txt时strip掉末尾换行符空行直接跳过不写入训练。用第3章脚本里的 len(parts) ! 5 判断就能提前排除这类问题不要等训练报错再回头查数据。5.4 现象训练收敛很快但在小船上几乎检测不到目标原因这个数据集1088张图中很多船是小目标占图像面积不到5%anchor尺寸在640x640分辨率下覆盖不到。解决先分析标签里框的宽高分布如果小框比例高把yolov8的anchor设置通过anchors参数调整或者直接在训练时加大输入图片尺寸到960x960给网络更多像素识别细节。显存不够的话用mosic增强和9:16宽高比来近似补偿。5.5 现象拆分数据集后训练集mAP很高但测试集mAP骤降原因数据集在划分时没有做随机分层抽样同一个场景的连续帧全部进了训练集测试集里全是与训练场景差异大的图片造成过拟合错觉。解决拿到数据先跑一次训练保存best.pt然后用val模式分别测train和val两个集合的mAP。如果差值超过15个百分点说明数据分布有偏思路是重新洗牌划分或者补充测试集图片。这个数据集标注里说已划分好如果遇到这个问题优先怀疑划分逻辑而不是模型结构。6. 训练与进阶验证修改data.yaml到实际调参的完整命令6.1 修改data.yaml的关键改动点打开data.yaml后第一件事是确认路径存在第二件事是确认names顺序。假如这份数据集的data.yaml写成这样train: ../images/train val: ../images/val test: ../images/test nc: 3 names: [inflatable_boat, kayak, ship]如果你把数据集解压在D盘yolo_ship文件夹下而相对路径写法是 ../images/train程序会尝试在上一级目录找images必然失败。最稳的方式是改成绝对路径train: D:/yolo_ship/images/train val: D:/yolo_ship/images/val test: D:/yolo_ship/images/testyolov5和yolov8都接受正斜杠的Windows绝对路径不需要转义。改完后用一行命令验证配置能不能加载python -c from ultralytics import YOLO; model YOLO(yolov8s.yaml); print(model.model))这条命令会打印模型结构如果data.yaml路径有问题这里不会直接报错但至少能看到模型是否成功实例化。真正的路径验证在下一步训练命令里会触发。6.2 yolov8训练命令的参数解释基础训练命令如下yolo train modelyolov8s.pt dataD:/yolo_ship/data.yaml epochs100 batch16 imgsz640 device0epochs设100是船舶检测的常见起步值数据集1088张且目标较小100轮能看出loss收敛趋势。batch16是兼顾显存和梯度稳定性的常见选择如果你显卡只有8GB显存降到8。device0表示用第一块GPU只有CPU就写devicecpu但训练速度会非常慢不建议。训练过程中重点看的指标不是loss绝对值而是val/box_loss与val/cls_loss是否同时下降以及mAP50和mAP50-95的变化趋势。yolov8的日志里会直接打印这些不需要额外装工具。6.3 验证与进阶技巧用验证集定位误检训练结束后用best.pt做验证yolo predict modelbest.pt sourceD:/yolo_ship/images/val saveTrue然后打开输出的预测图重点看两类错误一是把水面波纹误检成充气船这类误检通常是置信度阈值太低可以调高conf到0.35二是相邻两艘船被一个框框住这需要做NMS后处理或调整anchor。这种视觉检查比单纯看mAP更能判断模型落地的可靠性。如果验证结果显示充气船类别容易被漏检我后续进阶做法是用第3章的校验脚本统计该类别框的平均面积如果远小于其他类别就在训练命令里加上 scale0.5,1.5 增强或者单独用该类别图片做一次fine-tune。从那以后我每次拿到新数据集都强制走一遍「统计标签→坐标校验→画框抽查→训练→预测图抽查」这条流程虽然多花一个小时但能省下后面反复调参的几天。希望帮到你。本文还有配套的精品资源点击获取
返回列表