☰
海洋垃圾检测数据集与YOLO11一键训练:从1000张图到三平台跑通
2026/9/30 4:09:27 网站建设 项目流程

简介:这份资源面向从事海洋环境监测、水下目标检测的算法工程师与深度学习学习者,提供一套真实拍摄的海洋海底垃圾检测数据集,可用于海底监控场景下的垃圾识别项目,也可作为通用水下检测任务的数据补充。数据集共1000张高质量图像,覆盖海底塑料、铁罐、纸张、海洋生物与垃圾同框、水下探测器与垃圾同框、打光拍摄等多种场景,标注包含plastic、bio、rov、metal、paper、wood、rubber、timestamp、unknown九个类别,采用labelimg标注,质量较高。资源以PDF形式交付,文件总数1个,大小约2.77MB,内附数据集基本情况介绍与获取方式,并同步提供VOC、COCO、YOLO三种主流格式标签,可直接用于YOLO等算法训练。此外还附赠YOLO11一键训练脚本,支持GPU、CPU及Mac多平台方案,并给出博主训练结果日志供参考。目前已有540人学习,适合希望快速上手水下垃圾检测、验证模型效果的读者参考使用。

1. 海洋垃圾检测数据集与 YOLO11 一键训练:从 1000 张图到三平台跑通

海面漂浮物检测这件事,真正卡住大多数团队的往往不是模型结构,而是数据。你拿到一批无人机或岸基摄像头拍的海洋垃圾照片,想训一个能识别塑料瓶、泡沫箱、渔网碎片的检测器,第一步就会撞上标注格式不统一、训练环境配不通、换台机器就跑不起来这三堵墙。这个标题讲的方案,核心是把 1000 张海洋垃圾图像连同 VOC、COCO、YOLO 三种格式标签打包好,再配一套能在 GPU、CPU、Mac 三平台一键启动的 YOLO11 训练脚本。它解决的是从数据到可训练模型之间的工程摩擦,适合手里有图但不想在格式转换和环境配置上耗掉一周的算法工程师、研究生和做环保监测落地的开发者。下面按数据格式、环境准备、训练脚本、参数调优、踩坑排查的顺序,把这条链路拆开讲清楚。

2. 三种标签格式到底怎么选:VOC、COCO、YOLO 的差异与转换逻辑

拿到一个标注数据集,第一件事不是急着训,而是先搞清楚三种格式各自长什么样、什么时候用哪个。海洋垃圾检测这个场景里,VOC 格式常见于早期标注工具导出,COCO 格式适合做多任务扩展和与检测框架对接,YOLO 格式则是直接喂给 YOLO11 训练脚本的最终形态。三者不是随便选的,选错了要么训练脚本读不进去,要么评估指标对不上。

2.1 VOC、COCO、YOLO 三种格式的结构对比

VOC 格式的核心是每张图对应一个 XML 文件,里面用<object>标签记录每个目标的类别名和边界框的左上角、右下角坐标。它的坐标是绝对像素值,原点在图像左上角。COCO 格式则把所有标注集中到一个 JSON 文件里,用images、annotations、categories三个主键组织,边界框用[x, y, width, height]表示,同样是绝对像素值,但原点也是左上角,且类别用数字 id 映射。YOLO 格式最简洁,每张图对应一个 txt 文件,每行是class_id x_center y_center width height,全部归一化到 0 到 1 之间,原点在左上角。

这三种格式的差异不只是文件结构,还影响训练时的数据加载逻辑。YOLO11 官方训练脚本默认读 YOLO 格式,如果你直接拿 VOC 的 XML 或 COCO 的 JSON 去训,脚本会在数据加载阶段报错。所以数据集里同时提供三种格式,本质是让你少写转换代码,但你要知道什么时候该用哪个。

格式单图标注文件坐标类型类别表示典型用途
VOCXML绝对像素字符串名称早期标注工具、Pascal VOC 评估
COCO单个 JSON绝对像素数字 id多任务、COCO 评估、框架对接
YOLOTXT归一化 0-1数字 idYOLO 系列训练

2.2 从 VOC 转 YOLO 的脚本与四个边界坑

如果你手里的原始标注是 VOC 格式,想转成 YOLO 格式喂给 YOLO11,下面这段 Python 脚本可以直接用。它遍历 VOC 的 XML 文件,读取图像宽高,把绝对坐标转成归一化坐标,再按类别名映射到数字 id 写入 txt。

import os import xml.etree.ElementTree as ET # 类别名到 id 的映射,必须和训练时的 data.yaml 一致 class_map = { "plastic_bottle": 0, "foam_box": 1, "fishing_net": 2, "plastic_bag": 3, "other_trash": 4 } def voc_to_yolo(xml_dir, img_dir, out_dir): os.makedirs(out_dir, exist_ok=True) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(".xml"): continue tree = ET.parse(os.path.join(xml_dir, xml_file)) root = tree.getroot() # 图像宽高从 XML 的 size 节点读取 size = root.find("size") img_w = int(size.find("width").text) img_h = int(size.find("height").text) lines = [] for obj in root.findall("object"): cls_name = obj.find("name").text if cls_name not in class_map: continue 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 lines.append(f"{class_map[cls_name]} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") txt_name = xml_file.replace(".xml", ".txt") with open(os.path.join(out_dir, txt_name), "w") as f: f.write("\n".join(lines)) voc_to_yolo("annotations_xml", "images", "labels_yolo")

这段脚本的逻辑很直接:读 XML、取宽高、算归一化中心点和宽高、写 txt。参数上唯一需要你改的是class_map,它必须和后续训练用的data.yaml里的names列表顺序完全一致,否则类别 id 会错位,训练出来的模型会把塑料瓶认成泡沫箱。四个边界坑分别是:第一,XML 里size节点的宽高必须和实际图像一致,有些标注工具会写错,导致归一化后框偏移;第二,xmin可能大于xmax,标注时拖拽方向不同会导致这个问题,脚本里没做交换,需要你提前检查;第三,类别名大小写和空格必须和class_map完全匹配,plastic_bottle和Plastic_Bottle是两个东西;第四,空标注图会生成空 txt,YOLO11 训练时默认会跳过,但如果你开了某些增强策略,空文件可能引发警告,建议保留但确认脚本能处理。

2.3 COCO 转 YOLO 时容易忽略的 id 重映射

COCO 格式的类别 id 不一定是连续的,也不一定从 0 开始。比如 COCO 官方数据集里person是 1,bicycle是 2,但你的海洋垃圾数据集可能只有 5 个类,标注工具导出的 id 可能是 1 到 5。YOLO 格式要求类别 id 从 0 开始连续,所以转换时必须做一次重映射。常见做法是读 COCO JSON 的categories列表,按顺序建立旧 id 到新 id 的映射,再遍历annotations写 txt。这一步如果偷懒直接用原 id,训练时 YOLO11 会报类别数不匹配或者把背景当成某个类。转换完记得抽查几张图的 txt,用cat看一眼坐标是否在 0 到 1 之间,超出范围说明宽高读错了。

3. GPU、CPU、Mac 三平台环境准备:从驱动到 YOLO11 安装

数据格式理顺之后,下一步是让 YOLO11 能在你的机器上跑起来。这个数据集标题里强调支持 GPU、CPU、Mac 三平台,意思是训练脚本要能自动检测硬件并选择对应的计算后端。但自动检测的前提是你把基础环境装对了,否则脚本再智能也救不了缺驱动或版本冲突。

3.1 GPU 平台:CUDA 驱动与 PyTorch 版本匹配

GPU 训练是首选,1000 张图在单卡上通常几十分钟就能跑完几十个 epoch。但 GPU 环境最容易翻车的地方是 CUDA 驱动版本、CUDA Toolkit 版本和 PyTorch 版本三者不匹配。常见做法是先用nvidia-smi看驱动支持的 CUDA 最高版本,再去 PyTorch 官网找对应版本的安装命令。比如驱动显示 CUDA 12.1,你可以装 PyTorch 的 cu121 版本。不要直接pip install torch,那样装的是 CPU 版,训练时torch.cuda.is_available()会返回 False,脚本会静默切到 CPU,速度慢几十倍。

# 查看驱动和 CUDA 版本 nvidia-smi # 安装对应 CUDA 版本的 PyTorch,以 cu121 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 # 验证 GPU 是否可用 python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"

这段命令的关键在第二行,--index-url指定了 PyTorch 的 CUDA 12.1 轮子仓库,装出来的 torch 才能调用 GPU。第三行验证时如果输出True和你的显卡型号,说明环境通了。如果输出False,先检查驱动版本是否太低,再检查是不是装成了 CPU 版。另外,如果你用的是 RTX 4060 Laptop 这类移动端显卡,功耗墙和散热会影响持续训练速度,建议把 batch size 调小一点,避免显存溢出。

3.2 CPU 与 Mac 平台:线程数与 MPS 后端配置

没有 GPU 或者用 Mac 的读者,YOLO11 也能跑,只是速度慢。CPU 训练时要设置torch.set_num_threads()来充分利用多核,一般设成物理核心数。Mac 用户如果用的是 Apple Silicon 芯片,可以启用 MPS 后端,让训练跑在 GPU 上,比纯 CPU 快不少。启用方式是在训练脚本里判断torch.backends.mps.is_available(),然后指定 device 为mps。

import torch # CPU 平台:设置线程数,一般等于物理核心数 torch.set_num_threads(8) # Mac MPS 平台:检测并启用 if torch.backends.mps.is_available(): device = "mps" elif torch.cuda.is_available(): device = "cuda" else: device = "cpu" print(f"使用设备: {device}")

这段代码做了三平台自动检测,优先级是 MPS 大于 CUDA 大于 CPU。参数上,set_num_threads不要设成逻辑核心数,超线程对训练帮助有限,反而可能增加调度开销。Mac 用户注意,MPS 后端对某些算子支持不完整,如果训练中途报错,可以回退到 CPU 跑通流程再排查。另外,Mac 的 unified memory 和显存共享,batch size 设太大可能触发内存交换,建议从 4 或 8 开始试。

3.3 YOLO11 安装与一键训练脚本的入口逻辑

YOLO11 通过ultralytics包安装,一条pip install ultralytics就能搞定。一键训练脚本的入口逻辑通常是:解析命令行参数、加载data.yaml、根据设备选择device参数、调用model.train()。下面是一个最小可用的训练脚本骨架。

from ultralytics import YOLO import argparse parser = argparse.ArgumentParser() parser.add_argument("--data", default="data.yaml", help="数据集配置文件") parser.add_argument("--epochs", type=int, default=100) parser.add_argument("--imgsz", type=int, default=640) parser.add_argument("--batch", type=int, default=16) parser.add_argument("--device", default="", help="留空自动检测") args = parser.parse_args() model = YOLO("yolo11n.pt") # 加载预训练权重 model.train( data=args.data, epochs=args.epochs, imgsz=args.imgsz, batch=args.batch, device=args.device if args.device else None, project="runs_ocean_trash", name="exp1" )

这个脚本的核心是model.train()的参数。data指向data.yaml,里面写清楚训练集、验证集路径和类别名。imgsz是输入分辨率,海洋垃圾目标通常较小,640 是起点,如果小目标漏检多可以提到 1280,但显存占用会翻倍。batch根据显存调整,GPU 上 16 或 32,CPU 上 4 或 8。device留空时 ultralytics 会自动选,但自动选有时会选错,建议显式指定。project和name控制输出目录,跑多次实验时改name避免覆盖。

4. 用 1000 张图跑通 YOLO11 训练:参数设置与训练过程监控

环境通了,数据格式也对了,接下来是把 1000 张海洋垃圾图真正喂进 YOLO11 并观察训练是否正常。这个规模的数据集属于小样本,容易过拟合,也容易因为类别不平衡导致某些类学不出来。参数设置和监控指标要盯紧。

4.1 data.yaml 的写法与类别名顺序

data.yaml是 YOLO11 训练的数据入口,格式很简单但容易写错。它包含path、train、val、names四个关键字段。path是数据集根目录,train和val是相对路径,names是类别名列表,顺序必须和 YOLO 标签里的 class_id 对应。

path: ./ocean_trash_dataset train: images/train val: images/val names: 0: plastic_bottle 1: foam_box 2: fishing_net 3: plastic_bag 4: other_trash

这里最常见的错误是names写成列表而不是字典,或者顺序和标签 id 不一致。YOLO11 读names时会按 key 排序,如果你写成names: ["plastic_bottle", "foam_box"],它也能读,但 id 从 0 开始按列表顺序分配。两种写法都行,但一旦定了就不要混用。另外,train和val路径下要有images和labels两个子目录,YOLO11 会自动去labels找同名 txt,找不到会报 warning 并跳过该图。

4.2 小样本下的 batch size、学习率与增强参数

1000 张图分到 5 个类,平均每类 200 张,属于小样本。默认学习率 0.01 可能偏大,容易在早期震荡。常见做法是把初始学习率降到 0.001 到 0.005,配合余弦退火调度。batch size 在 GPU 上可以设 16,CPU 上设 4 到 8。数据增强方面,YOLO11 默认开了 mosaic、mixup、HSV 抖动等,对小样本有帮助,但海洋垃圾场景里有些增强会引入噪声,比如 mixup 把两张图叠在一起,可能让模型学到不存在的组合。如果发现验证集指标波动大,可以关掉 mixup,把mosaic概率从 1.0 降到 0.5。

model.train( data="data.yaml", epochs=150, imgsz=640, batch=16, lr0=0.003, # 初始学习率降低 lrf=0.01, # 最终学习率因子 mosaic=0.5, # mosaic 概率减半 mixup=0.0, # 关闭 mixup patience=30, # 30 轮无提升则早停 device=0 )

参数上,lr0是初始学习率,lrf是最终学习率相对于初始值的比例,余弦退火会从lr0降到lr0 * lrf。patience是早停轮数,小样本训练容易过拟合,早停能省时间。mosaic和mixup是增强强度,海洋垃圾目标通常比较独立,mixup 的收益不大,关掉更稳。

4.3 训练日志里该盯哪几个指标:mAP50、mAP50-95 与混淆矩阵

训练启动后,日志会每轮输出 box_loss、cls_loss、dfl_loss 和验证集的 mAP50、mAP50-95。box_loss 是边界框回归损失,cls_loss 是分类损失,dfl_loss 是分布焦点损失。这三个 loss 应该整体下降,如果某个 loss 震荡不降,说明对应部分有问题。mAP50 是 IoU 阈值 0.5 时的平均精度,mAP50-95 是 0.5 到 0.95 多个阈值的平均,后者更严格。海洋垃圾检测里,如果 mAP50 高但 mAP50-95 低,说明框的位置不够准,可能需要调box损失权重或增加定位精度相关的增强。

混淆矩阵在训练结束后会生成,它能告诉你哪个类容易被认成哪个类。比如塑料瓶和塑料 bag 在颜色和形状上接近,混淆矩阵里可能看到它们互相误判。这时候可以考虑增加这两类的区分性特征,或者检查标注是否把两者标混了。另外,YOLO 混淆矩阵的总合不唯一是常见现象,因为多分类的混淆矩阵按行归一化和按列归一化结果不同,看的时候要确认用的是哪种归一化方式。

5. 海洋垃圾检测训练避坑:5 个血泪踩坑记录

这一章把实际跑这个数据集时最容易翻车的地方列出来,每条按现象、原因、解决写。这些坑不挑平台,GPU、CPU、Mac 都可能遇到。

5.1 现象:训练启动即报 “No labels found”

原因通常是data.yaml里的train路径指向了images/train,但labels/train不存在,或者 txt 文件和图片文件名不对应。YOLO11 要求图片和标签同名,只是扩展名不同。比如img_001.jpg对应img_001.txt,如果标签叫img_001_label.txt就找不到。

解决:检查labels/train目录是否存在,文件名是否和图片一一对应。可以用一条 shell 命令快速比对。

# 列出图片文件名(去扩展名)和标签文件名(去扩展名),找差集 comm -3 <(ls images/train | sed 's/\.[^.]*$//' | sort) <(ls labels/train | sed 's/\.[^.]*$//' | sort)

如果输出不为空,说明有图片缺标签或有标签缺图片,补上或删掉即可。

5.2 现象:GPU 显存溢出,报 “CUDA out of memory”

原因通常是 batch size 太大或 imgsz 太高。1000 张图里如果有些图分辨率很高,YOLO11 会按 imgsz 缩放,但缩放后的 batch 仍然可能撑爆显存。另外,如果开了 mosaic 增强,一个 batch 里会拼四张图,等效 batch 翻四倍。

解决:先把 batch 降到 8 或 4,再把 imgsz 从 640 降到 416 试。如果还不行,检查是不是有其他进程占着显存,用nvidia-smi看。Mac 用户如果报内存不足,同理降 batch 和 imgsz。

5.3 现象:训练 loss 不降,mAP 始终在 0.01 左右

原因可能是学习率太大导致梯度爆炸,也可能是标签格式错了但没报错。比如 YOLO 标签里的坐标没有归一化,还是绝对像素值,YOLO11 读进去后框全在图像外面,模型学不到东西。

解决:先抽查几个 txt 文件,确认坐标都在 0 到 1 之间。如果坐标没问题,把lr0降到 0.001 再跑。另外检查data.yaml的names数量和标签里的最大 class_id 是否一致,不一致会静默错位。

5.4 现象:验证集 mAP 比训练集低很多,过拟合明显

原因:1000 张图对 5 个类来说偏少,模型容易记住训练集。另外如果验证集和训练集分布差异大,比如训练集是晴天拍的,验证集有阴天,也会导致指标差距。

解决:增加增强强度,比如开 mosaic、HSV 抖动、随机翻转。加 weight decay,YOLO11 默认有,可以适当调大。如果还不行,考虑用预训练权重冻结 backbone 先训几轮,再解冻全量微调。早停 patience 设小一点,比如 20。

5.5 现象:Mac 上训练到一半报 “MPS backend out of memory” 或算子不支持

原因:MPS 后端对某些算子支持不完整,比如某些池化或插值操作。另外 unified memory 被其他应用占用也会导致训练中断。

解决:先关掉其他占内存的应用,把 batch 降到 4。如果还报算子不支持,设置环境变量PYTORCH_ENABLE_MPS_FALLBACK=1,让不支持的算子回退到 CPU 执行,速度会慢但能跑通。实在不行就切回 CPU 训练,1000 张图在 CPU 上跑 100 轮大概几小时,能接受。

6. 小目标漏检怎么救:从 1000 张图里榨出更高精度的三个技巧

海洋垃圾检测里最头疼的是小目标,比如远处的塑料瓶、海面上的泡沫碎片,在 640 分辨率下可能只有十几个像素。YOLO11 本身对小目标有一定能力,但 1000 张图的规模下,想再往上提几个点,得在数据和推理两端做文章。

第一个技巧是切图训练。把原图切成 640 乘 640 的块,重叠 20%,这样小目标在切块里相对变大,模型更容易学到。切图后样本量会翻几倍,1000 张可能变成 3000 到 5000 张,但要注意切图后边缘目标会被截断,标注也要跟着切。切图脚本可以用 PIL 或 OpenCV 写,核心是遍历原图、按步长裁剪、同步裁剪标签框、过滤掉截断后面积太小的框。

from PIL import Image import os def slice_image(img_path, label_path, out_img_dir, out_lbl_dir, size=640, overlap=128): img = Image.open(img_path) w, h = img.size step = size - overlap idx = 0 for y in range(0, h, step): for x in range(0, w, step): box = (x, y, min(x + size, w), min(y + size, h)) crop = img.crop(box) crop.save(os.path.join(out_img_dir, f"{os.path.basename(img_path)}_{idx}.jpg")) # 标签同步裁剪逻辑略,核心是坐标平移和过滤 idx += 1

这段代码只演示了切图部分,标签同步裁剪需要读原 txt、把归一化坐标转回绝对坐标、减去切块偏移、再归一化到切块尺寸,最后过滤掉宽或高小于 2 像素的框。参数上overlap控制重叠区域,128 像素是个经验值,太小会漏掉边缘目标,太大则冗余样本多。

第二个技巧是推理时用 TTA,也就是测试时增强。对同一张图做水平翻转、多尺度缩放,分别推理后再把结果融合。YOLO11 的model.predict()支持augment=True,开启后会做简单的 TTA。这个技巧不增加训练成本,只在推理时多花时间,适合对精度要求高、对速度不敏感的离线检测场景。

第三个技巧是调整 NMS 的 IoU 阈值和置信度阈值。海洋垃圾目标密集时,默认 NMS 的 IoU 0.7 可能把相邻目标误删,可以降到 0.5 到 0.6。置信度阈值默认 0.25,如果漏检多可以降到 0.1,但会引入更多误检,需要根据业务权衡。我一般会在验证集上画一条 precision-recall 曲线,找 F1 最高的那个阈值点,而不是拍脑袋定。

这三个技巧里,切图训练收益最直接,但工作量也最大,需要重新生成数据集和标签。TTA 和阈值调整是推理端的后悔药,训练完发现漏检多时可以立刻试。我自己的习惯是先把 1000 张图用默认参数跑一版 baseline,看 mAP50 和漏检情况,再决定要不要上切图。如果 baseline 已经够用,就不折腾了。希望帮到你。

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

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

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

立即咨询