YOLO单类船舶检测数据集实战:从标注到YOLOv8微调全流程

发布时间:2026/10/4 12:30:55
YOLO单类船舶检测数据集实战:从标注到YOLOv8微调全流程 简介这份YOLO船舶目标检测数据集面向计算机视觉学习者与水面目标检测开发者用于训练和验证船只识别模型适合具备一定深度学习基础、希望快速复现实验的中高级用户。压缩包共约2000个文件以1817个txt标注文件、178张jpg图像和5个yaml配置文件为主整体约114.65MB标注与图像一一对应yaml文件已写好类别与路径开箱即可投入训练。数据集已按train、valid、test划分完毕data.yaml中names为[boat]yolov5、yolov7、yolov8等主流框架可直接读取训练省去自行清洗与划分的繁琐步骤。内容覆盖皮划艇、独木舟、摩托艇、冰川皮艇等多种水上场景图像背景与光照差异明显有助于提升模型泛化能力。目前已有1523人学习下载配套博文还提供检测结果参考便于对照评估训练效果与调参方向。1. 拆开 yolo-boat-detect-dataset-1.zip单类船舶检测到底能省多少标注功夫上周有个做水域监控的哥们儿发来一张截图说他拿岸边摄像头拍的皮划艇、摩托艇、独木舟混在一起用 COCO 预训练模型跑推理结果船全被识别成「冲浪板」和「人」漏检率高得离谱。他问我有没有现成的船舶单类数据集能直接微调我翻出硬盘里这个yolo-boat-detect-dataset-1.zip丢给他第二天他就把 mAP0.5 从 0.41 拉到了 0.87。这个包的核心价值就一句话几千张已经标注好、划分好 train/val/test、带data.yaml的单类boatYOLO 格式数据集解压就能喂给 YOLOv5/v7/v8 开训省掉从零标注和格式转换这两件最耗人的事。适合谁做水域安防、航道监控、水上运动分析的算法工程师以及想拿真实场景练手 YOLO 微调的学生和独立开发者。不适合想检测「船人浮标」多类目标的场景因为它的names只有[boat]一个类。2. 数据集结构与 YOLO 格式对齐从目录树到 data.yaml 的逐项核对2.1 解压后先看目录别急着写训练脚本拿到压缩包第一件事不是python train.py而是把目录结构摸清楚。这个数据集的标准布局是train/images、train/labels、valid/images、valid/labels、test/images、test/labels六件套外加根目录一个data.yaml。YOLO 系列对目录名有硬性约定images和labels必须同级且同名对应图片和同名.txt标签一一配对。常见翻车点是有人把valid写成val而data.yaml里写的是./valid/images路径对不上训练启动直接报No labels found。# 解压后先确认目录层级这一步能提前暴露 80% 的路径问题 unzip yolo-boat-detect-dataset-1.zip -d boat_dataset cd boat_dataset find . -maxdepth 2 -type d | sort # 预期输出 # ./test/images # ./test/labels # ./train/images # ./train/labels # ./valid/images # ./valid/labels上面这段find命令用-maxdepth 2限制层级避免递归列出几千个文件刷屏。-type d只列目录sort让输出有序便于肉眼核对。如果发现labels目录缺失或为空说明压缩包传输过程中丢了文件重新下载即可不要试图自己补标注。2.2 data.yaml 三个字段的语义与常见误改data.yaml是整个训练流程的入口配置原文给的配置是names: [boat] train: ./train/images val: ./valid/images test: ./test/image这里有个血泪经验test字段写的是./test/image少了个s而实际目录是test/images。YOLOv5/v8 在训练阶段只读train和valtest字段通常只在val.py或导出推理时用到所以这个拼写错误在训练时不会报错但你在跑测试集评估时会遇到FileNotFoundError。我一般会手动改成./test/images顺手把nc: 1补上——虽然新版 YOLO 能从names长度推断类别数但显式写nc能兼容一些老版本解析器。# 修正后的 data.yaml建议直接覆盖原文件 path: ./boat_dataset # 数据集根目录用绝对路径更稳 train: train/images val: valid/images test: test/images nc: 1 names: [boat]参数说明path是根路径下面的train/val/test用相对路径拼接这样整个数据集换机器时只改path一处。nc是类别数必须等于names列表长度写错会导致检测头输出维度不匹配报shape mismatch。names的顺序决定了标签里类别索引的含义单类场景下索引恒为 0不存在顺序问题但多类数据集千万别乱调顺序。2.3 标签文件格式验证一行一个目标的归一化坐标YOLO 标签是.txt每行格式为class_id x_center y_center width height后四个值都是相对图片宽高的归一化浮点数0~1 之间。这个数据集是单类所以每行开头恒为0。验证标签是否合规我习惯写个小脚本抽查import os import glob def check_labels(label_dir, img_dir): bad [] for txt in glob.glob(os.path.join(label_dir, *.txt)): with open(txt) as f: for i, line in enumerate(f): parts line.strip().split() # 单类数据集每行必须是 5 个字段 if len(parts) ! 5: bad.append((txt, i, 字段数不对)) continue cls, x, y, w, h parts vals [float(x), float(y), float(w), float(h)] # 归一化坐标必须落在 0~1 if any(v 0 or v 1 for v in vals): bad.append((txt, i, 坐标越界)) if cls ! 0: bad.append((txt, i, 类别索引非0)) return bad issues check_labels(boat_dataset/train/labels, boat_dataset/train/images) print(f发现 {len(issues)} 处问题) for it in issues[:10]: print(it)这段脚本做三件事字段数校验、坐标范围校验、类别索引校验。glob.glob匹配所有.txt逐行split后判断长度是否为 5。坐标越界通常意味着标注时框超出了图片边界轻微越界比如 1.02YOLO 能容忍但大幅越界说明标注工具导出有问题。类别索引非 0 在这个单类数据集里一定是错的要么标签被别的数据集污染了要么标注时选错了类别。3. 用 YOLOv8 跑通第一轮训练命令行参数与显存适配3.1 环境准备与 ultralytics 安装这个数据集对框架没有强绑定YOLOv5、v7、v8 都能直接吃。我选 YOLOv8 演示是因为ultralytics包把训练、验证、导出整合成了一套 API命令行和 Python 脚本两种用法都顺。环境上CUDA 11.8 PyTorch 2.x 是当前比较稳的组合显存 8G 起步能跑yolov8n12G 以上可以上yolov8s。# 建虚拟环境避免和系统里的 torch 打架 python -m venv venv_boat source venv_boat/bin/activate # Windows 用 venv_boat\Scripts\activate pip install ultralytics8.2.0 # 验证安装和 GPU 可见性 yolo checksyolo checks会打印 ultralytics 版本、Python 版本、torch 版本和 CUDA 是否可用。如果CUDA available显示False先别急着训检查驱动和 torch 版本是否匹配。我见过有人装了 CPU 版 torch训练一晚上才跑完 3 个 epoch纯属浪费时间。3.2 从预训练权重微调为什么必须加 --weights单类船舶数据集样本量几千张从随机初始化训起收敛慢且容易过拟合。正确做法是加载 COCO 预训练权重做迁移学习让 backbone 已经学到的边缘、纹理特征直接复用检测头针对boat类重新学。yolo detect train \ databoat_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ workers4 \ device0 \ projectboat_runs \ nameexp1 \ patience20 \ cacheTrue参数逐个说data指向修正后的data.yamlmodelyolov8n.pt会自动下载预训练权重n 是最小模型速度快适合先跑通epochs100配合patience20表示 20 轮验证指标不提升就早停避免无效训练imgsz640是 YOLO 的标准输入尺寸船舶目标通常占画面比例不小640 够用batch16在 8G 显存上跑yolov8n比较稳显存不够就降到 8workers4是数据加载线程数设成 CPU 核数的 1/4 左右cacheTrue把图片缓存到内存几千张图大概占几 G 内存能显著加快 epoch 速度内存紧张就关掉。3.3 训练日志怎么看三个指标判断是否正常训练启动后终端会滚动输出每个 epoch 的损失和指标。重点盯三个box_loss、cls_loss、mAP50。box_loss是边界框回归损失正常应该在前 10 个 epoch 快速下降然后趋缓cls_loss是分类损失单类场景下它降得比 box_loss 更快mAP50是 IoU 阈值 0.5 下的平均精度这个数据集质量好的话30 个 epoch 内应该能到 0.8 以上。如果box_loss震荡不降大概率是学习率太大或标签有问题如果mAP50卡在 0.3 不动回去查data.yaml的路径和标签格式。# 训练结束后用验证集跑一次评估确认指标可复现 from ultralytics import YOLO model YOLO(boat_runs/exp1/weights/best.pt) metrics model.val(databoat_dataset/data.yaml, splitval) print(fmAP50: {metrics.box.map50:.4f}) print(fmAP50-95: {metrics.box.map:.4f}) print(f每类 AP: {metrics.box.ap50})model.val会重新加载best.pt在验证集上推理输出的map50应该和训练日志最后一轮的数值接近。如果差很多说明训练时用了cache而验证时没缓存或者验证集被训练过程间接污染了。metrics.box.ap50是数组单类数据集只有一个元素对应boat类的 AP。4. 避坑与排查船舶数据集训练中最容易翻车的五件事4.1 现象训练报 No labels found原因路径大小写或目录名不匹配这是最高频的报错。YOLO 在train/images同级找train/labels如果标签目录叫Labels或label直接找不到。解决方法是ls确认目录名然后在data.yaml里把路径写对。Linux 下大小写敏感Windows 下不敏感所以同一份数据在 Windows 能跑、传到 Linux 就报错这种跨平台翻车我遇到过不止一次。4.2 现象mAP 虚高但实际推理漏检原因train 和 val 图片重复有些数据集打包时划分不严谨同一张图既在 train 又在 val 里导致验证指标虚高实际部署时性能断崖式下跌。排查方法是算 train 和 val 图片的 MD5 去重import hashlib, glob, os def file_md5(p): return hashlib.md5(open(p, rb).read()).hexdigest() train_hashes {file_md5(p) for p in glob.glob(boat_dataset/train/images/*.jpg)} val_hashes {file_md5(p) for p in glob.glob(boat_dataset/valid/images/*.jpg)} overlap train_hashes val_hashes print(f重复图片数: {len(overlap)})如果overlap不为 0手动把重复图从 val 里删掉或者重新划分。这个数据集从文件名看是 Flickr 风格带_jpg.rf.哈希后缀重复概率低但养成检查习惯没坏处。4.3 现象显存溢出 CUDA out of memory原因batch 或 imgsz 设太大8G 显存跑yolov8nimgsz640batch16是安全线但如果你换成yolov8m或把imgsz提到 1280立刻 OOM。解决顺序先降batch到 8再降imgsz到 512最后换更小的模型。别一上来就batch64那是 A100 的玩法。另外cacheTrue会额外占内存显存和内存是两回事别搞混。4.4 现象训练 loss 正常但验证 mAP 为 0原因names 和标签类别索引错位单类数据集标签里 class_id 必须是 0如果标注工具导出时用了 1 作为起始索引YOLO 会认为有第 2 类但names里没有导致所有预测被过滤。用 2.3 节的校验脚本查一遍把非 0 的类别索引批量改成 0# 批量把标签行首的 1 改成 0仅限确认是索引错位的情况 sed -i s/^1 /0 / boat_dataset/train/labels/*.txtsed的^1匹配行首的「1空格」避免误伤坐标里的数字。执行前先备份 labels 目录这种批量替换没有后悔药。4.5 现象推理时框住整片水面原因负样本或模糊标注污染如果数据集里混入了没有船的水面图但被标了框模型会学到「水面船」的错误关联。表现是推理时大片水域被框住。排查方法是可视化一批标签看框是否贴合船体。这个数据集从文件名看都是 canoe、kayak、jet-ski 等明确目标污染概率低但如果你自己往里面加了图务必重新检查标注。5. 从能跑到好用提升船舶检测精度的三个进阶技巧第一轮训练跑通只是起点真正部署到水域监控场景还得在精度和速度之间找平衡。第一个技巧是锚框聚类。YOLOv8 虽然是无锚框设计但如果你回头用 YOLOv5--anchor这步别省。船舶目标的宽高比和 COCO 通用目标差异大用kmeans在你自己数据集上重新聚类锚框能明显提升小目标召回。命令是python utils/autanchor.py --data data.yaml跑完把输出的锚框尺寸填进模型配置。第二个技巧是测试时增强TTA。推理阶段加augmentTrue模型会对同一张图做翻转、缩放等多尺度推理再融合结果mAP 通常能涨 1~3 个点代价是推理速度慢 2~3 倍。水域监控如果对实时性要求不高比如 5 秒一帧的分析场景TTA 很划算from ultralytics import YOLO model YOLO(boat_runs/exp1/weights/best.pt) results model.predict( sourcetest_images/, augmentTrue, # 开启 TTA conf0.25, # 置信度阈值船舶场景建议 0.25 起步 iou0.45, # NMS 的 IoU 阈值 imgsz640, saveTrue )conf0.25是召回和误报的平衡点调高到 0.5 会漏掉远处小船调低到 0.1 会把浪花误判成船。iou0.45控制 NMS 合并重叠框的力度船舶密集停泊时适当调高到 0.5 避免漏检相邻船。第三个技巧是困难样本挖掘。第一轮训练后用best.pt在验证集上推理把漏检和误检的图挑出来人工重新标注后加入训练集再训一轮。这个迭代过程通常做 2~3 轮mAP 能再涨 3~5 个点。我一般会写个脚本自动筛出conf在 0.1~0.3 之间的预测这些是模型「犹豫」的样本最有挖掘价值。最后说个习惯从那以后我每次拿到新数据集都强制走一遍「目录核对 → data.yaml 修正 → 标签校验 → 小样本过拟合测试」这四步。小样本过拟合测试就是拿 20 张图训 50 个 epoch如果 loss 降不到接近 0说明数据或配置有根本问题别急着上全量。这套流程帮我省下了无数个白跑的夜晚。希望帮到你。本文还有配套的精品资源点击获取