☰
YOLO海洋目标检测数据集使用指南:标签格式、数据集划分与训练环境搭建
2026/9/28 22:34:30 网站建设 项目流程

简介:YOLO海洋目标检测数据集面向目标检测初学者与研究开发者,基于真实海洋场景的5000张高质量图片制作,使用LabelImg工具标注,标注框规范、场景丰富,能直接用于YOLO系列模型的训练与验证。压缩包内共2000个文件,整体大小约75.39MB,其中以xml标注文件为主,同时配套py数据划分脚本、txt列表文件以及html格式的环境搭建与训练教程,目录结构清晰,便于按需检索。资源提供voc、coco、yolo三种主流格式标签,并分别存放在不同文件夹下,避免了自行转换格式的麻烦;随包附赠Windows/Linux双版本YOLO环境搭建教程、训练案例教程及数据集划分脚本,支持一键划分训练集、验证集、测试集,也可通过脚本生成ImageSets下的txt文件,方便自定义数据流程。目前已有264人学习下载,适合需要快速构建海洋目标检测数据集、动手训练YOLO模型的用户参考使用。

1. YOLO海洋目标检测数据集:为什么我建议直接拿它开刀

做海洋目标检测的人,第一道坎通常不是模型选哪个,而是手里没有能直接上手的干净数据。YOLO海洋目标检测数据集这套资源,核心是5000张真实场景图片,用labelimg逐张手工标注,同时给出VOC(xml)、COCO(json)、YOLO(txt)三种格式标签,文件夹按格式分好,拿到就能直接喂给YOLO系列训练,不用再写转换脚本。更实用的是压缩包里还附带三个数据集划分脚本,以及Linux/Windows两套环境搭建和训练教程,从解压到训练出自己的best.pt,全程路线清楚。适合做目标检测算法对比、需要快速跑通海洋场景训练流程的从业者和学生。下文我按自己复现顺序,把目录、脚本、训练和容易翻车的地方逐一拆开。

2. 目录和三种标签格式:先搞清手里到底有什么

2.1 解压后建议先做三件事

拿到 rar 后,我最先做的是把文件列表列出来,而不是急着跑脚本。资源里有一批 html 教程、两个“图片标签划分写入新文件夹”的脚本、一个 split_train_val 生成 ImageSets 脚本、一个 train_list.txt,以及图片和三种格式标签目录。我一般会执行下面这条命令,把顶层结构先看清楚:

# 在解压后的根目录执行 find . -maxdepth 2 -type d | sort

执行后你应该能看到类似 images、Annotations、labels、coco_annotations 这样的目录。我这里不写死目录名,因为不同版本打包略有差异,但核心是确认三件事:图片目录里有 5000 张左右 jpg/png;VOC 标签目录里每个图片对应一个同名 xml;YOLO 标签目录里每个图片对应一个同名 txt,每行一个目标。确认完这三个基本点,后面训练才不会突然缺文件。

很多人忽略第三步:打开一个 xml 和一个 txt,人工核对同一个目标是否都能找到。VOC 里记录的是“左上右下”绝对坐标,YOLO 里是归一化的中心点与宽高,两者坐标系不同,肉眼不容易直接对比。我的习惯是先用下面这一小段 Python 把任意一对文件打出来:

# 快速抽查一对 VOC/YOLO 标签,target_xml 和 target_txt 换成实际路径 from xml.etree import ElementTree as ET xml_path = "Annotations/000001.xml" txt_path = "labels/000001.txt" tree = ET.parse(xml_path) img_w = int(tree.find("size/width").text) img_h = int(tree.find("size/height").text) print("VOC size:", img_w, img_h) for obj in tree.iter("object"): name = obj.find("name").text bndbox = obj.find("bndbox") xmin = int(bndbox.find("xmin").text) ymin = int(bndbox.find("ymin").text) xmax = int(bndbox.find("xmax").text) ymax = int(bndbox.find("ymax").text) print("VOC object:", name, xmin, ymin, xmax, ymax) with open(txt_path) as f: print("YOLO lines:") for line in f.read().strip().splitlines(): parts = line.split() cls = int(parts[0]) cx, cy, w, h = map(float, parts[1:]) # 转回绝对坐标,便于和 VOC 对照 cx_abs, cy_abs = cx * img_w, cy * img_h w_abs, h_abs = w * img_w, h * img_h xmin2, ymin2 = cx_abs - w_abs / 2, cy_abs - h_abs / 2 xmax2, ymax2 = cx_abs + w_abs / 2, cy_abs + h_abs / 2 print(f"YOLO cls={cls} converted: {xmin2:.1f} {ymin2:.1f} {xmax2:.1f} {ymax2:.1f}")

这里最关键的是尺寸那几行:VOC 的 bndbox 是像素绝对值,YOLO 的 cx/cy/w/h 都必须除以图宽高做归一化。抽查时如果换算出来的坐标和 VOC 里的框对不上,基本可以确定标签有问题,不要去赌训练时模型自己纠正。

2.2 三种格式分别给谁用

很多新人对格式有误解,总觉得“反正能训练就行”。实际上 VOC、COCO、YOLO 三种标签对应的是不同训练生态。我用一张表快速给出结论:

格式文件内容坐标表达直接对接的框架
VOC每个图一个 xmlbndbox 绝对像素坐标原始 Faster R-CNN、mmdetection 配置
COCO整个集合一个 json图片与标注分离,像素坐标Detectron2、mmdetection、Mask R-CNN
YOLO每个图一个 txt归一化相对坐标YOLOv5/v8/官方 YOLO 系列

所以这套资源值钱的地方在于:同一个数据集已经导出了三种格式,你跑 YOLO 用 txt,跑 mmdetection 用 coco json,跑老派 VOC pipeline 用 xml,不需要在格式之间来回倒腾。尤其做算法对比的实验中,三个基线分别用不同框架时,这个便利能省下一个下午。

需要注意,三种格式是“同一份标注的三种表达”,不是三份独立标注。它们的内容应该完全一致。如果你改其中一个格式,另外两个不会自动更新,这是我后面章要单独讲的重点。

2.3 坐标换算公式与常见误用

假如你日后拿到只有 VOC 的别人数据集,转 YOLO 时用到的公式就是五年前我踩过的坑。正确写法是:

x_center = (xmin + xmax) / 2 / width y_center = (ymin + ymax) / 2 / height box_w = (xmax - xmin) / width box_h = (ymax - ymin) / height

注意四点:一是中心点要除以图宽高,个别教程偷懒不除,导致训练时全部目标跑到左下角;二是 x_center 和 width 都除以 width,y 都除以 height,不要混用;三是如果图集里有 exif 旋转过的图片,VOC size 必须按 JPEG 真实读出来的宽高,而不是文件名后缀给的宽高;四是 txt 的类别 id 从 0 开始,而 VOC 里 class name 是字符串,转换时要用一份 id→name 映射,顺序一旦写错,你的十类数据可能被模型学成一个“混杂类”。

做格式转换时不要轻信“一键转换”就完事,转换完抽出三张图人工看框,比直接训练后再发现问题快得多。资源自带的教程里多半也会提这个关系,但真正到了自己切格式时,很多人还是会漏掉 exif 这一点。

2.4 训练前必做的数据体检:类别分布与空标签

在划分之前,我还会做一个统计,防止被某些极不均衡的类别带偏。下面的代码会扫一遍所有 YOLO 格式 txt,统计每个类别 id 的出现次数,并列出空标签文件:

# 统计 labels 目录下所有 txt 的类别分布和空标签 from collections import Counter from pathlib import Path cnt = Counter() empty = [] for txt in Path("labels").glob("*.txt"): lines = [l.strip() for l in txt.read_text().splitlines() if l.strip()] if not lines: empty.append(txt.name) continue for line in lines: cnt[int(line.split()[0])] += 1 print("category -> count:", cnt.most_common()) print("empty label files:", len(empty), empty[:10])

逻辑说明:对每个 txt 先过滤空行,读取第一个位置的类别 id;如果没有有效行,记录为空标签文件。这样做的目的不是找茬,而是提前知道你的数据是不是只有一个类别占到九成以上。如果某类只有个位数样本,训练时模型基本学不到它,后面 mAP 再高也掩盖不了漏检。

空标签文件如果留在训练集里,YOLO 会一直刷 no labels 的 warning,虽然不致命,但会干扰你对训练日志的判断。我的做法是把空标签从训练列表里剔除,或者专门放到一个负样本目录做 hard negative 处理。如果你不想动原始数据,至少要在 data.yaml 里别让它出现在 val 中,否则验证集的 loss 会被这些空图拖得忽高忽低。

3. 划分训练集、验证集、测试集:三个脚本用哪个、怎么改

3.1 三个脚本的定位差异

资源里给的三个脚本不是随机的,是我见过最容易让人选错的部分。区分标准就一条:你手里的标注格式和你想要的训练管线。

“训练集、验证集、测试集划分脚本(图片标签划分写入新文件夹).py”负责一次性分出 train、val、test 三个新目录,并把图片和标签一起复制过去。适合标准流程,即训练完再用测试集做最终评估。“训练集、验证集划分脚本(图片标签划分写入新文件夹).py”只分出 train、val 两个目录,适合你已经有独立测试资源,或只想快速把模型跑通。第三个“split_train_val 生成 ImageSets 下 txt 文件划分脚本.py”生成的是 ImageSets/Main 下的 train.txt、val.txt、test.txt、trainval.txt,这是 VOC 风格训练管线的标准入口,mmdetection/VOC 用的就是它。三个脚本本质都是“按比例切分列表”,只是输出形式不同。

我经常看到有人把第三个脚本和第一个脚本混用,先复制了新目录,然后又跑 ImageSets 脚本去生成不含相对路径的 txt,结果训练时找不着图片。我的建议:你的训练代码读目录就选第一个脚本,读 txt 列表就选第三个脚本,不要两个都跑。

3.2 动手前先改的三个变量

脚本大概率没有 argparse,因为它是给使用者直接改头部变量的。常见做法是把开头这几个值写清楚:

# 划分脚本头部常见配置,按你的实际目录改 src_images = "images" # 原始图片目录 src_labels = "labels" # 原始 YOLO 标签目录,也可以是 Annotations out_dir = "dataset" # 输出根目录 ratio = (0.8, 0.1, 0.1) # train/val/test 比例,总和要为 1 random_seed = 42 # 固定随机种子,保证多次划分一致

这里最容易被忽略的是 random_seed。如果你不固定,每次运行都会得到不同划分,尤其是小数据集中,某类目标只在测试集出现的情况会被放大。我一般会先设 42 跑一遍,记录生成的 txt,之后无论调什么参数都不再改 seed。比例那一项按数据量调整:5000 张时 8:1:1 是合理默认;如果图片只有几百张,建议改成 7:2:1 或采用交叉验证思路,而不是硬套 8:1:1。

3.3 核心划分逻辑拆解

不用打开脚本,你大概能猜到它怎么写的。无非是读图片列表、按比例切分、复制图片与标签到新目录三段。但我建议你验证一件事:它是否把同名前缀的所有标签格式都一起复制了。最容易错的点如下代码所示,我只保留最关键部分:

import random, shutil from pathlib import Path # 常见划分逻辑伪代码,实际脚本请以自带的为准 def split_and_copy(images, labels, ratio, out_dir): random.seed(42) files = sorted(Path(images).glob("*.jpg")) + sorted(Path(images).glob("*.png")) random.shuffle(files) n_train = int(len(files) * ratio[0]) n_val = int(len(files) * ratio[1]) splits = { "train": files[:n_train], "val": files[n_train:n_train + n_val], "test": files[n_train + n_val:] } for split_name, flist in splits.items(): (Path(out_dir) / "images" / split_name).mkdir(parents=True, exist_ok=True) (Path(out_dir) / "labels" / split_name).mkdir(parents=True, exist_ok=True) for f in flist: shutil.copy2(f, Path(out_dir) / "images" / split_name / f.name) # 同步复制同名标签,注意可能的后缀 for ext in (".txt", ".xml", ".json"): label_file = Path(labels) / (f.stem + ext) if label_file.exists(): shutil.copy2(label_file, Path(out_dir) / "labels" / split_name / label_file.name)

逻辑说明:先随机打乱图片列表,再按比例切三段。注意后面对标签的处理——我特意写成“三个后缀都尝试复制”,很多原版脚本只写死了 .txt。如果资源里的脚本只复制 .txt 且你需要同时保留 VOC/COCO 标签,就要手动加一行。参数上我建议设 exclude_empty=True,把前面统计出的空标签文件从训练集里剔除,不然训练日志一直刷 no labels 的 warning。

3.4 划分完如何和 YOLO 的 data.yaml 对接

划分后的目录如果长这样,就是 YOLO 期望的标准布局:

dataset/ images/{train,val,test}/... labels/{train,val,test}/...

在 YOLOv5/v8 里,配置 data.yaml 指向这组目录即可。注意类别顺序不能随便写,它必须和 txt 里的数字一一对应:

# ocean.yaml train: dataset/images/train val: dataset/images/val test: dataset/images/test nc: 1 names: ["ship"] # 修改成你实际的类别列表

参数说明:train 和 val 是目录路径,YOLO 会自动往同级找 labels,所以只要把图片路径给全,它会默认把 test 目录下的图片也评估。nc 必须等于 names 列表长度,多一个少一个都会在训练前直接报错。用它训练时注意不要再在命令行里传 --classes,否则会覆盖 yaml 里的类别。

另外 train_list.txt 不要丢掉。YOLOv5 支持在 train 字段里写一个 txt,每行是图片的绝对路径;当你把数据放在多个磁盘时,这个列表比目录形式更灵活。但相对目录则简单得多,我一般测试阶段直接用目录,部署到另一台机器时才改成绝对路径 txt。

4. YOLO环境搭建与训练:从教程到改自己的数据

4.1 Linux/Windows 双教程怎么配合用

资源里同时给了“YOLO 环境搭建 Linux 版本”“YOLO 训练教程 Linux 版本”“YOLO 环境搭建 Windows 版本”“YOLO 训练教程 Windows 版本”,还有一个 Ubuntu 安装教程。我的建议是:训练优先在 Linux 服务器上做,Windows 留给标注和数据预览。原因不是 Windows 不行,是深度学习生态里驱动、CUDA、cuDNN 版本组合在 Linux 上最稳,网上能找到的对应关系也最多。Windows 教程适合你有 N 卡但没有 Linux 环境时,用 Anaconda 走一条同样能跑通的路径。不要两边同时装,环境变量冲突是常见翻车源头。

教程的核心顺序其实一致:装 Python、装 PyTorch、装 YOLO 依赖,然后跑通自带 demo,最后换数据。我一般会先把教程里自带 demo 跑通一次,再换自己的数据集,这能帮你把“环境问题”和“数据问题”分开。如果 demo 都跑不通,先解决环境,不要急着怪数据。

4.2 用 conda 搭一个不污染系统的环境

不管哪份教程,我都推荐用 conda 单独建环境,方便后续多版本切换。Linux 下最省事的命令序列是这样:

# 创建名为 yolo 的 Python 3.8 环境 conda create -n yolo python=3.8 -y conda activate yolo # 安装 PyTorch(按你的 CUDA 版本选,见下方说明) pip install torch==1.12.1 torchvision==0.13.1 --index-url https://download.pytorch.org/whl/cu113 # 安装 YOLO 训练依赖;v5 用官方仓库,v8 可直接用 ultralytics pip install -r requirements.txt # YOLOv5 仓库内执行 # 或 pip install ultralytics # YOLOv8 使用

这里 PyTorch 版本是我常用的组合,不代表资源教程固定用这套。CUDA 11.3 配 torch 1.12.1 是一个经过考验的组合。先运行nvidia-smi看驱动支持的 CUDA 上限,再决定是否调整 cu113 那一段。如果机器没有 GPU,就装 CPU 版 torch,训练会很痛苦但也算能跑通,只适合验证代码。

需要特别提醒的是“第一次下载预训练权重”这件事。YOLO 训练默认会从官方链接拉 yolov5s.pt / yolov8s.pt,网络不稳定时经常卡在 0%。我会先手动把权重文件放到工程根目录,再执行训练命令,让程序检测到文件后跳过下载。这一步能省掉很多无意义的等待。

4.3 把官方案例改成你的海洋数据

资源附带的训练教程应该是用官方案例(类似 coco128)带你走流程。改成自己的数据只需要替换两个东西:数据配置和命令参数。

第一步写 yaml,参考前面 3.4 的 ocean.yaml。第二步执行训练。YOLOv5 风格命令:

python train.py --data ocean.yaml --weights yolov5s.pt \ --img 640 --batch 16 --epochs 100 --device 0

YOLOv8 风格则是:

yolo detect train data=ocean.yaml model=yolov8s.pt \ imgsz=640 batch=16 epochs=100 device=0

参数说明:--img 640 是输入尺寸,不是原始图片尺寸;运行时会 resize,5000 张海洋图里如果小目标很多,可以试试 1280,但显存占用会翻倍。batch 16 以 8G 显存为参考,显存不足优先降 batch,而不是调小 img。epochs 100 在 5000 张图上足够看到收敛趋势,先跑 100 轮去找最佳权重,再根据曲线决定是否加轮。device 0 指第一张卡,多卡时把 0 换成 0,1,2,3。如果类别只有一两类,可以从更小的 yolov5s/yolov8s 开始;目标小或需要精度时再上 m/l 版。

4.4 训练日志里看哪些关键指标

训练开始后不要盯着 loss 的每一行,重点看 val/box_loss、val/cls_loss 和 mAP。我在前几次跑这种真实场景数据时总会忽略 val_cls_loss,只关注总 loss,结果模型收敛得“很好”但预测全是同一类。在资源自带的训练教程中应该也有指标说明。另外留意每个 epoch 结束时的mAP@0.5和mAP@0.5:0.95。前者是 50% IoU 下的均值精度,后者是更严苛的综合指标。前几十轮 mAP 大概率在低位波动,这正常;真正异常的是过了 30 轮还一直为 0。

训练完的产物在 runs/train/exp*/weights/ 下,best.pt 是验证集上分数最高的权重,last.pt 是最后一轮的。部署和推理都用 best.pt。按我的习惯,best.pt 出来后第一件事就是把它拿去跑演示视频,而不是继续训。

5. 常见问题排查:我遇到过的五个真实“翻车”现场

5.1 标签与路径问题

**坑一:图片有 5000 张,labels 里只有 4800 个,少的那批在训练中期才爆 warning。**现象:训练日志间歇出现“WARNING: no labels found in ...”。原因:原始的图片目录存在非 jpg/png 格式,或某些图片被标注工具跳过,划分时又没有剔除无标签图片。解决:跑一遍 2.4 的空标签统计脚本,把缺失标签的图片从训练列表里删掉;如果那些图片确实有目标,就用 labelimg 补标,不要留半套数据。

**坑二:COCO 的 json 和 YOLO 的 txt 坐标不一致。**现象:同一张图在 YOLO 训练中正常,切到 mmdetection 后框全部偏移一个固定距离。原因:转换 JSON 时读取的 image width/height 和处理 exif 后的实际尺寸不一致。解决:统一用 PIL 或 cv2 读取图片真实宽高重新生成所有格式;生成后重新抽查一组坐标。那套核对代码我在 2.1 给出过,务必养成习惯。

**坑三:三个划分脚本分别跑一次,结果互相污染。**现象:训练集目录里既有 train 的图片,又有 test 的残留文件,或者 ImageSets 里的 txt 指向的文件根本不存在。原因:脚本输出目录覆盖不干净,或者一个是复制模式、一个只生成 txt,但 path 都指向同一个 dataset 目录。解决:固定输出目录,每跑一个脚本前清空该目录;不同脚本之间不要把输出叠在同一个文件夹下。我现在的做法是对每个脚本单独设 out_dir,并把脚本日期写入目录名,避免旧文件干扰。

5.2 训练与推理问题

**坑四:loss 一直下降,mAP@0.5 始终为 0。**现象:val 每个 epoch 都能降低,但验证集精确率和召回率均为 0。原因:data.yaml 的 names 顺序和 txt 中的类别 id 不对应,模型预测的类别编号与标注编号错位,导致 IoU 正确但类别全错。解决:打印训练集前 20 个 txt 的类别 id,统计实际出现的 id 集合,再核对 names 列表,确保 names[0] 对应 id=0。还有个辅助手段,是在训练早期用 detect.py 跑一张测试图,看预测框的颜色和标签是否正常。

**坑五:显存不够,一开训练就 OOM。**现象:报错CUDA out of memory,且通常发生在第一个 batch 前向传播时。原因:batch、imgsz、模型大小三者没有互相适配;常见于直接用教程里的 batch=32 在 8G 卡上跑。解决:batch 从 4 开始逐步抬到显存占用 85% 左右;imgsz 从 640 降到 416 也是一种治法,但损失对小目标检测不利。注意不要只看“显存没满”,PyTorch 的缓存会让 OOM 延后出现,用torch.cuda.empty_cache()清理后再跑一次,比反复调小 batch 更有效。

5.3 排查完再跑的验证命令

每次排查完,我会强制跑一组计数命令,确认目录是干净的。这组命令不训练,只花两分钟,但能挡住 90% 的低级错误:

# 对比三个目录文件数量,确认无缺漏 wc -l train_list.txt find dataset/images -name "*.jpg" | wc -l find dataset/labels -name "*.txt" | wc -l

如果图片数量和标签数量不一致,不要继续往下走。先找到是哪个目录少了,再决定是补标签还是清图片。这一步看起来简单,但我见过太多人因为少一个标签文件,训练到一半才在日志里发现问题,白白浪费几小时。不要省这几十秒。

6. 用 best.pt 验证并迁移:一个让结果可复现的小习惯

6.1 先跑测试集再谈精度

训练结束后,我很少直接看 runs/train/exp 里的曲线图就宣布完成。我会先用最佳权重跑一遍测试集并输出可视化结果,确认框和类别确实正确。展示行为是否正常,比任何一个指标都重要:

# 使用训练出的 best.pt 跑测试集,保存可视化图片和 txt 结果 import torch model = torch.hub.load('ultralytics/yolov5', 'custom', path='runs/train/exp/weights/best.pt', force_reload=True) model.conf = 0.25 model.iou = 0.45 results = model('dataset/images/test', save_txt=True, save_conf=True) print(results.pandas().xyxy[0].head())

逻辑说明:模型从本地 best.pt 加载,不再下载权重;conf 设 0.25 是把你预测中低置信度框过滤掉,跑测试集的目的是看“真实能用”的预测结果。save_txt 会把每个检测框写进 txt,save_conf 会同时输出置信度。如果第一张图的框完全对不上目标,回头查数据,不要查模型。

6.2 迁移到相邻场景时最省事的做法

如果你后续要做的是“码头船只检测”或“水下目标检测”,最优解不是重新收集几千张图,而是用这份海洋数据训练出的 best.pt 做预训练,再在小规模新数据上微调。做法很简单:把 data.yaml 的 names 改成新类别,weights 指向原来的 best.pt,然后较小学习率继续训练。例如 YOLOv5 里:

python train.py --data new.yaml --weights runs/train/exp/weights/best.pt \ --epochs 50 --batch 16 --img 640 --lr0 0.003

参数说明:--lr0 从默认的 0.01 降到 0.003 是为了不让预训练权重被过大的梯度破坏,50 轮足以在几百张图上完成迁移。如果你的新场景类别和海洋数据有重叠,迁移效果通常很稳;如果完全没重叠,至少也保留了对框位置和纹理的底层特征。

从那以后,我每次拿到新数据集都强制走一遍“文件计数 + 标签抽查 + 小 batch 试跑”三段流程,再谈加入新算法或调参数。这套习惯帮我挡掉了很多次无谓的返工,也让我在复现同类资源时更敢说“能直接用”。希望帮到你。

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

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

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

立即咨询