ARTICLE DETAIL

资讯详情

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

YOLO海洋目标检测数据集使用指南:标签格式、数据集划分与训练环境搭建

YOLO海洋目标检测数据集使用指南:标签格式、数据集划分与训练环境搭建 简介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/pngVOC 标签目录里每个图片对应一个同名 xmlYOLO 标签目录里每个图片对应一个同名 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(fYOLO 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-CNNYOLO每个图一个 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 都除以 widthy 都除以 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(parentsTrue, exist_okTrue) (Path(out_dir) / labels / split_name).mkdir(parentsTrue, exist_okTrue) 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_emptyTrue把前面统计出的空标签文件从训练集里剔除不然训练日志一直刷 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 python3.8 -y conda activate yolo # 安装 PyTorch按你的 CUDA 版本选见下方说明 pip install torch1.12.1 torchvision0.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 0YOLOv8 风格则是yolo detect train dataocean.yaml modelyolov8s.pt \ imgsz640 batch16 epochs100 device0参数说明--img 640 是输入尺寸不是原始图片尺寸运行时会 resize5000 张海洋图里如果小目标很多可以试试 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 结束时的mAP0.5和mAP0.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 一直下降mAP0.5 始终为 0。**现象val 每个 epoch 都能降低但验证集精确率和召回率均为 0。原因data.yaml 的 names 顺序和 txt 中的类别 id 不对应模型预测的类别编号与标注编号错位导致 IoU 正确但类别全错。解决打印训练集前 20 个 txt 的类别 id统计实际出现的 id 集合再核对 names 列表确保 names[0] 对应 id0。还有个辅助手段是在训练早期用 detect.py 跑一张测试图看预测框的颜色和标签是否正常。**坑五显存不够一开训练就 OOM。**现象报错CUDA out of memory且通常发生在第一个 batch 前向传播时。原因batch、imgsz、模型大小三者没有互相适配常见于直接用教程里的 batch32 在 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, pathruns/train/exp/weights/best.pt, force_reloadTrue) model.conf 0.25 model.iou 0.45 results model(dataset/images/test, save_txtTrue, save_confTrue) print(results.pandas().xyxy[0].head())逻辑说明模型从本地 best.pt 加载不再下载权重conf 设 0.25 是把你预测中低置信度框过滤掉跑测试集的目的是看“真实能用”的预测结果。save_txt 会把每个检测框写进 txtsave_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 试跑”三段流程再谈加入新算法或调参数。这套习惯帮我挡掉了很多次无谓的返工也让我在复现同类资源时更敢说“能直接用”。希望帮到你。本文还有配套的精品资源点击获取
返回列表