ARTICLE DETAIL

资讯详情

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

海底鱼类检测数据集:1000张图、三种标签格式与YOLO11训练脚本

海底鱼类检测数据集:1000张图、三种标签格式与YOLO11训练脚本 简介这份资源面向从事水下视觉与目标检测的算法工程师、研究生及竞赛选手提供一套真实场景海底鱼类检测数据集可用于海底监测场景下的鱼类识别项目也可作为通用鱼类检测数据的补充。数据集共1000张高质量图片覆盖浅海珊瑚礁、深海沉船周边、沙底海草区以及鱼类遮挡与严重遮挡等多种场景统一划分为“Fish”一个类别采用labelimg标注并同时提供VOC(xml)、COCO(json)、YOLO(txt)三种主流格式可直接接入YOLO等检测算法训练。资源包为1个PDF文件大小约3.81MB内含数据集基本情况介绍与获取方式因数据量较大原始数据托管于百度网盘。此外还附赠YOLO11一键训练脚本支持GPU、CPU及MacM芯片多平台方案并给出博主训练结果日志供参考。目前已有90人学习适合希望快速验证海底鱼类检测方案、减少数据准备成本的读者。1. 海底鱼类检测数据集1000 张图、三种标签格式和一套能跑通的 YOLO11 脚本水下图像的目标检测和陆上场景完全不是一个难度等级。光在水里衰减极快红色通道最先丢失画面整体偏蓝绿悬浮颗粒造成的前向散射让边缘发糊鱼群密集时遮挡严重同类目标尺度差异能拉到十倍以上。所以当你拿到一份「海底鱼类检测数据集」时真正决定它能不能用的不是图片数量而是标注质量、类别定义和格式兼容性。这份数据集给的是 1000 张图配 VOC、COCO、YOLO 三种格式标签外加一份 YOLO11 一键训练脚本。它解决的核心问题是让你跳过最耗时的数据清洗和格式转换环节直接把精力放在模型调优上。适合做水下机器人、渔业资源监测、海洋生态研究以及想拿一个非标准场景练手目标检测的工程师。下面我按「数据长什么样 → 三种格式怎么用 → 脚本怎么跑 → 坑在哪」的顺序拆开讲。2. 先看清数据1000 张海底图里到底有什么2.1 类别定义与标注粒度决定了模型上限拿到任何检测数据集第一件事不是跑训练而是打开标注文件看类别。海底鱼类数据集的类别体系通常有两种组织方式一种是粗粒度只标「fish」一个大类另一种是细粒度按物种分比如石斑、鲷鱼、小丑鱼等。这两种没有绝对优劣但直接决定你的任务定义。如果你要做的是「有没有鱼」粗粒度足够如果你要做的是「什么鱼、多少条」就必须细粒度而且类别数会直接抬高分类头的负担。1000 张图在细粒度场景下其实偏少。假设分 10 个类平均每类只有 100 张图再考虑遮挡和小目标某些类的有效样本可能不到 50。这时候你要做的不是硬训而是先统计分布。用下面这段脚本快速摸清类别和框的分布import os import xml.etree.ElementTree as ET from collections import Counter # 指向 VOC 格式的 Annotations 目录 anno_dir dataset/Annotations class_counter Counter() box_sizes [] for xml_file in os.listdir(anno_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(anno_dir, xml_file)) root tree.getroot() for obj in root.findall(object): name obj.find(name).text class_counter[name] 1 bbox obj.find(bndbox) w float(bbox.find(xmax).text) - float(bbox.find(xmin).text) h float(bbox.find(ymax).text) - float(bbox.find(ymin).text) box_sizes.append((w, h)) print(类别分布:, class_counter) print(总框数:, sum(class_counter.values())) print(平均框尺寸:, sum(w*h for w, h in box_sizes) / len(box_sizes))这段代码做三件事遍历所有 XML、统计每个类别的框数量、计算框的平均面积。逻辑很直白但输出信息量很大。如果某个类的框数低于总框数的 5%训练时几乎必然被其他类压制你需要考虑合并类别或者做重采样。平均框面积如果很小比如小于图像面积的 1%说明小目标占比高YOLO11 默认的 640 输入尺寸可能不够要往上调。提示统计完先别急着改数据把类别分布和框尺寸分布记下来后面调参时这两个数字是你的判断依据。2.2 水下图像的质量问题会直接传导到训练海底图像有几个典型退化色偏、低对比度、模糊、光照不均。这些问题不会因为换了 YOLO11 就消失它们会体现在损失曲线上。具体表现是训练前期 loss 下降正常但 mAP 涨得很慢验证集上的框位置抖动大。原因在于水下目标的边缘本身就不清晰模型学到的特征边界模糊。我一般会先做一轮可视化抽查随机抽 20 张图把标注框画上去肉眼确认框有没有明显偏移。代码不复杂import cv2 import os import random import xml.etree.ElementTree as ET img_dir dataset/JPEGImages anno_dir dataset/Annotations samples random.sample(os.listdir(img_dir), 20) for img_name in samples: img cv2.imread(os.path.join(img_dir, img_name)) xml_path os.path.join(anno_dir, img_name.replace(.jpg, .xml)) if not os.path.exists(xml_path): continue tree ET.parse(xml_path) for obj in tree.getroot().findall(object): bbox obj.find(bndbox) x1 int(float(bbox.find(xmin).text)) y1 int(float(bbox.find(ymin).text)) x2 int(float(bbox.find(xmax).text)) y2 int(float(bbox.find(ymax).text)) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(fcheck_{img_name}, img)跑完打开生成的图片看一遍。如果发现大量框只覆盖鱼身一半、或者把背景噪点框进去说明标注质量有问题这种数据训出来的模型上限很低。1000 张图里如果有超过 10% 的标注需要修建议先修再训否则后面调参全是玄学。3. VOC、COCO、YOLO 三种格式什么时候用哪个3.1 三种格式的本质差异与转换逻辑VOC 格式是每张图一个 XML结构清晰适合人工检查和修改。COCO 格式是一个大 JSON包含 images、annotations、categories 三个核心字段适合多任务检测分割关键点统一管理。YOLO 格式是每张图一个 txt每行class_id x_center y_center width height全部归一化到 0-1读取最快训练框架直接吃。这三种格式没有谁替代谁的关系关键看你的下游工具链。如果你用 LabelImg 标注默认出 VOC如果用 CVAT 或 Labelme可能出 COCO但几乎所有 YOLO 系训练框架最终都要转成 YOLO txt。所以实际工作流通常是VOC 或 COCO 作为存档和交换格式YOLO 作为训练格式。转换时最容易翻车的是坐标归一化和类别 ID 映射。VOC 的坐标是绝对像素值YOLO 需要除以宽高COCO 的 bbox 是[x, y, width, height]而 YOLO 需要x_center, y_center, width, height。下面是一个 VOC 转 YOLO 的完整脚本import os import xml.etree.ElementTree as ET # 类别列表必须固定顺序否则 ID 会错乱 classes [fish_a, fish_b, fish_c] # 按你的实际类别替换 class_to_id {name: i for i, name in enumerate(classes)} anno_dir dataset/Annotations img_dir dataset/JPEGImages out_dir dataset/labels os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(anno_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(anno_dir, xml_file)) 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.findall(object): name obj.find(name).text if name not in class_to_id: continue # 跳过未定义类别避免 ID 越界 bbox obj.find(bndbox) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # 归一化并转为中心点格式 x_center ((x1 x2) / 2) / img_w y_center ((y1 y2) / 2) / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h # 裁剪到 0-1防止标注越界导致训练报错 x_center min(max(x_center, 0), 1) y_center min(max(y_center, 0), 1) w min(max(w, 0), 1) h min(max(h, 0), 1) lines.append(f{class_to_id[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))这段代码的关键点有三个。第一classes列表的顺序必须和训练时的data.yaml完全一致否则类别 ID 对不上模型学出来的东西全是错的。第二归一化后做了裁剪因为有些标注框会超出图像边界不裁剪的话 YOLO 训练时可能报错或者产生异常梯度。第三跳过了未定义类别这在多人标注或者类别体系变更时很常见不跳过会直接崩溃。注意转换完成后一定要抽查几个 txt 文件确认每行的数值都在 0-1 之间且类别 ID 没有超出类别总数。3.2 COCO 格式在什么场景下更值得保留如果你的项目后续要扩展到实例分割、关键点检测或者要和其他团队交换数据COCO 格式的扩展性更好。它的 JSON 结构可以同时容纳检测框、分割多边形和关键点而 VOC 和 YOLO 做不到这一点。另外很多预训练模型和评估工具比如 pycocotools原生吃 COCO 格式直接用可以省掉转换步骤。但 COCO 的 JSON 在 1000 张图规模下会变得很大人工检查不现实。我的做法是保留 COCO 作为存档训练时转 YOLO。转换逻辑和 VOC 转 YOLO 类似只是读取源从 XML 变成 JSON核心公式不变。如果你拿到的是 COCO 格式先确认categories字段里的id是不是从 1 开始连续有些工具生成的 ID 是乱的直接映射到 YOLO 的 0-based ID 会错位。4. YOLO11 一键训练脚本从环境到跑通4.1 环境配置与数据目录结构YOLO11 的训练环境不复杂但版本兼容性是个老问题。我一般用 Python 3.9 到 3.11PyTorch 2.0 以上CUDA 版本跟显卡驱动匹配。安装命令就一行pip install ultralytics装完之后用yolo checks确认环境状态。如果输出里显示 CUDA 可用说明 GPU 能正常调用如果显示 CPU only检查 PyTorch 是不是装成了 CPU 版本。数据目录按 YOLO 的标准结构组织dataset/ images/ train/ val/ labels/ train/ val/ data.yamldata.yaml是训练脚本的入口配置内容如下path: ./dataset train: images/train val: images/val nc: 3 names: [fish_a, fish_b, fish_c]nc是类别数names的顺序必须和转换脚本里的classes完全一致。1000 张图按 8:2 划分训练集 800 张验证集 200 张。如果某些类别样本特别少划分时要做分层抽样保证验证集里每个类都有出现。4.2 一键训练脚本的参数怎么设标题里说的「一键训练脚本」核心就是一行yolo train命令加上合适的参数。但参数不是随便填的下面这份是我在水下数据集上跑过比较稳的配置yolo train \ modelyolo11n.pt \ datadataset/data.yaml \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience30 \ device0 \ projectruns/fish \ nameexp1逐个说参数含义。modelyolo11n.pt用的是 nano 版本参数量小适合 1000 张图这种小数据集不容易过拟合。如果你有 V100 或者更好的卡可以换yolo11s.pt或yolo11m.pt但小数据集上大模型未必更好。imgsz640是默认输入尺寸如果前面统计发现小目标多可以调到 960 或 1280但显存占用会成倍增加。batch16在 8GB 显存上比较稳显存不够就降到 8。lr00.01是初始学习率lrf0.01是最终学习率系数YOLO 默认用余弦退火这两个值控制下降曲线。patience30表示 30 个 epoch 没有提升就早停省时间。训练启动后重点看三个指标box_loss是否稳定下降、mAP50是否在涨、cls_loss有没有异常波动。如果box_loss下降但mAP50不涨大概率是学习率太大或者数据标注有问题。如果cls_loss突然飙升检查类别 ID 有没有越界。提示第一次跑先设epochs10做冒烟测试确认数据加载、前向传播、反向传播都正常再跑完整训练。这样能省掉大量等待时间。4.3 训练过程中的显存与批次调优显存不够是训练中最常见的问题。报错信息通常是CUDA out of memory。解决办法有三个降batch、降imgsz、换更小的模型。优先级是先降 batch因为 batch 对显存的影响是线性的imgsz 的影响是平方级的降太多会损失小目标检测能力换模型是最后手段。另外YOLO11 支持ampTrue自动混合精度默认开启。如果你的显卡支持 FP16这个选项能省不少显存。但如果训练中出现 loss 变成 NaN先关掉 AMP 试试有些老卡对混合精度支持不好。5. 避坑与排查水下数据集训练最容易翻车的 5 个点5.1 类别 ID 错位导致 mAP 恒为零现象训练 loss 正常下降但验证集 mAP 始终是 0 或者极低。原因data.yaml里的names顺序和转换脚本里的classes顺序不一致模型学到的类别和评估时的类别对不上。解决把两个文件并排打开逐行核对顺序确保完全一致。这个坑我踩过不止一次血泪经验是转换脚本里的类别列表单独存一个classes.txt训练配置直接从它生成。5.2 标注框越界导致训练中途崩溃现象训练到某个 batch 突然报错提示坐标超出范围或者除零错误。原因VOC 或 COCO 里存在超出图像边界的标注框转换时没有裁剪。解决在转换脚本里加裁剪逻辑把所有坐标限制在 0-1 之间。另外宽度或高度为 0 的框也要过滤掉这种框在计算 IoU 时会产生除零。5.3 小目标太多导致 mAP 上不去现象模型能检测到大鱼但小鱼几乎全漏。原因水下小鱼在 640 输入下可能只有十几个像素特征图上的响应太弱。解决把imgsz调到 960 或 1280同时在数据增强里开启mosaic和scale增加小目标的出现频率。如果还是不行考虑用切片推理把大图切成小块分别检测再合并。5.4 验证集划分不合理导致指标虚高现象验证集 mAP 很高但实际测试时效果很差。原因验证集和训练集来自同一段视频的连续帧画面高度相似模型相当于在「背答案」。解决划分时按视频或按场景分组确保验证集的画面和训练集有足够差异。1000 张图如果来自少数几段视频这个问题会非常严重。5.5 学习率过大导致 loss 震荡不收敛现象训练前期 loss 下降中期开始剧烈震荡mAP 忽高忽低。原因初始学习率相对数据集规模偏大或者 batch 太小导致梯度噪声大。解决把lr0从 0.01 降到 0.001同时开cos_lr让学习率平滑下降。如果 batch 小于 8考虑用梯度累积模拟更大的 batch。6. 进阶技巧用预训练权重和冻结策略把 1000 张图榨干1000 张图在目标检测里属于小数据集从零训练几乎不可能收敛到理想效果。我的习惯是永远从预训练权重起步。YOLO11 官方提供的yolo11n.pt是在 COCO 上训过的虽然 COCO 里没有海底鱼类但底层特征边缘、纹理、颜色块是通用的。加载预训练权重后模型不需要从随机噪声开始学收敛速度快很多。具体做法是在训练命令里指定modelyolo11n.ptYOLO 会自动加载权重。如果你想更激进一点可以冻结 backbone 的前几层只训检测头。冻结的层数用freeze参数控制yolo train \ modelyolo11n.pt \ datadataset/data.yaml \ epochs100 \ imgsz640 \ batch16 \ freeze10 \ lr00.001 \ device0freeze10表示冻结前 10 层。冻结的好处是减少可训练参数量降低过拟合风险同时省显存。但冻结太多会导致模型无法适应水下场景的特征分布所以我的经验是先不冻结跑一轮看 mAP 曲线如果过拟合明显训练 loss 降但验证 loss 涨再加冻结。另一个技巧是分阶段训练。第一阶段用较大的学习率0.01跑 50 个 epoch让检测头快速适应新类别第二阶段把学习率降到 0.001解冻所有层跑 100 个 epoch做精细调优。这个策略在小数据集上比一次性训练效果更稳。验证阶段不要只看 mAP50还要看 mAP50-95。水下目标的框位置本身就不如陆上精确mAP50-95 更能反映模型的定位能力。如果 mAP50 高但 mAP50-95 低说明模型能找到鱼但框不准这时候要检查标注框的紧密度或者调整损失函数里 box 和 cls 的权重比例。最后说一个我自己的习惯每次训练完把results.csv里的关键指标抄到一个单独的表格里记录日期、模型版本、数据版本、超参和最终指标。看起来麻烦但当你跑到第十次实验的时候这份记录能帮你快速定位哪次改动是有效的哪次是白跑。水下检测这个方向数据比模型重要耐心比技巧重要。希望帮到你。本文还有配套的精品资源点击获取
返回列表