
简介面向目标检测算法训练与验证的捕鱼识别数据集包含1813张已标注图像适配yolov5、yolov7、yolov8、yolov9、yolov10及yolo11等主流yolo系列模型已按训练/验证/测试划分下载后即可直接投入训练与验证。资源同时提供yolo格式txt与VOC格式xml两套标注分别保存在独立文件夹中yolo格式文件按class、中心坐标、宽高记录归一化信息其中class为类别索引从0开始坐标与尺寸均为0~1的相对比例值可直接被yolo系列框架读取。压缩包共2000个文件其中1584个xml标注便于用labelImg等工具查看校验416个txt标签可直接用于模型训练整体大小约96.7MB目录结构清晰、转换零成本。目前已有75人学习下载适合渔业监测、水下目标识别及yolo算法练习者快速获得高质量标注数据大幅节省人工标注时间将精力集中在模型调参与效果优化上。1. 捕鱼识别数据集为什么说这 1813 张图能让你少加两周班做渔获识别这类项目的人应该都有同感目标检测本身不难难的是数据。水产养殖监控、垂钓行为分析、渔港分拣这些场景的公开数据集少得可怜去爬图自己标一天能标 300 张就算手快。这套 yolo 算法捕鱼识别数据集一共 1813 张带标签图像压缩包同时给了 yolo 格式txt和 voc 格式xml两套标注并且已经划分好训练集、验证集和测试集适用 yolov5、yolov7、yolov8、yolov9、yolov10、yolo11 全系列算法。对新手来说这是走通「数据 → 训练 → 验证 → 部署」全流程的最短路径对熟手来说它省掉的是最磨人的数据准备阶段拿到手改一个 data.yaml 就能开工。这套数据的核心价值不在数量而在双格式标签和划分完整性——这两个点能省掉后续大量不必要的 debug 时间。2. 解压后的目录与标签格式先搞懂 txt 和 xml 的对应关系数据集这种资源最怕的不是标注不准而是拿到手不知道目录怎么排、标签长什么样。第一件事不是急着开训练而是把压缩包解压后整体摸一遍结构。下面是我拿到这套数据集后的标准检查流程。2.1 目录结构核对图片、txt、xml 三件套必须一一对应解压后一般会看到 train、val、test 三个顶层目录具体命名可能带 train_images 之类的后缀但结构本质一致。每个划分集内部是三个平级文件夹图片目录、txt 标签目录、xml 标签目录。对应关系如下表目录存放内容文件名规则images原始图片jpg/pngimg_0506_487.jpglabels_txtyolo 格式标注img_0506_487.txtannotations_xmlvoc 格式标注img_0506_487.xml提示这套数据是「一份图片对应两份标注」训练时只用其中一套即可不要两套混用。拿到手先做一次文件数量核对用下面三条命令分别统计三个文件类型的数量数量应该完全一致find train/images -name *.jpg | wc -l find train/labels_txt -name *.txt | wc -l find train/annotations_xml -name *.xml | wc -l如果图片数量大于标签数量说明有漏标样本如果标签数量大于图片数量多半是残留了训练过程中生成的文件。数量不一致时不能直接开训练后面第 4 章会专门讲怎么排查。统计完后再随机抽三个文件名做交叉比对图片、txt、xml 三者的文件名主体不含扩展名必须完全一致这是后面所有流程能跑通的前提。2.2 yolo 格式的五列数字归一化坐标到底怎么读yolo 格式的 txt 文件每一行代表一个目标框五列数字的含义是class x_center y_center width height其中class是类别索引从 0 开始计数x_center和y_center是目标框中心点的相对坐标width和height是目标框的相对宽高。所有值都在 0 到 1 之间是相对于图片宽高的比例值而不是像素值。这种设计的好处是标签不依赖图像分辨率同一个 txt 文件用在 640×640 和 1920×1080 的图上含义完全一致。我习惯随机抽一个 txt 文件用 Python 读出来还原成像素坐标验证标注是否落在目标区域# 读取一个 yolo 标注并换算成像素坐标 img cv2.imread(train/images/img_0506_487.jpg) h, w img.shape[:2] with open(train/labels_txt/img_0506_487.txt, r) as f: lines f.readlines() for line in lines: parts line.strip().split() cls int(parts[0]) # 类别索引 x_center float(parts[1]) * w # 中心点像素 x y_center float(parts[2]) * h # 中心点像素 y box_w float(parts[3]) * w # 框宽 box_h float(parts[4]) * h # 框高 x1 int(x_center - box_w / 2) # 左上角 x y1 int(y_center - box_h / 2) # 左上角 y x2 int(x_center box_w / 2) # 右下角 x y2 int(y_center box_h / 2) # 右下角 y print(fclass{cls}, box({x1},{y1})-({x2},{y2}))代码逻辑是把归一化的中心点坐标和宽高分别乘以图像宽高得到像素坐标再算出左上角和右下角用于画框验证。注意x1、y1如果出现负数或超出图像尺寸说明原始标注边界越界训练时 yolo 会自动裁剪但精度会受影响建议提前筛掉。2.3 voc 格式的 xml从左上右下到中心宽高的换算规律voc 格式的 xml 文件和 yolo txt 是同一批标注的两种表达核心差异在于边界框的表示方式。yolo 用「中心点 宽高」的归一化坐标voc 用「左上角 右下角」的像素绝对坐标。看一个典型文件annotation filenameimg_0506_487.jpg/filename size width1280/width height720/height /size object namefish/name bndbox xmin412/xmin ymin235/ymin xmax687/xmax ymax489/ymax /bndbox /object /annotationname是类别名称bndbox里是边界框的左上和右下像素坐标。很多新手同时打开 txt 和 xml 后一脸懵为什么 txt 里写的是 0.43 0.51 0.21 0.35xml 里却是几百几百的大数字其实就是坐标系定义不同。yolo 和 voc 之间的换算公式很固定x_center (xmin xmax) / 2 / widthy_center (ymin ymax) / 2 / heightbbox_width (xmax - xmin) / widthbbox_height (ymax - ymin) / height反向转换就是把这些公式逆运算。如果你想把这套 voc 标注转成别的框架格式直接套这个公式就能得到 yolo 格式不需要重新标。验证两个文件是否对应同一目标可以把 xml 的name和 txt 的class索引做一张映射表这是我拿到数据集后必做的步骤能避免后面训练时类别错位自己还不知道。3. 训练前的准备改 yaml、选参数、先跑一个 epoch 验证数据流目录和标签格式都确认没问题后进入实际训练准备。这个阶段最容易翻车的不是模型结构而是数据配置和路径问题。下面是完整的一套准备流程从 data.yaml 到启动命令最后落到「一个 epoch 验证」这个关键动作。3.1 data.yaml 的正确写法路径、类别数量和类别顺序无论用 yolov5 还是 yolov8 系列训练前都要准备一个数据集配置文件。这个文件告诉框架三件事训练集在哪、验证集在哪、一共有几个类别以及类别名称。参考写法如下# fish_dataset.yaml train: ./fish_dataset/train/images val: ./fish_dataset/val/images test: ./fish_dataset/test/images nc: 3 names: [ white_fish, dark_fish, shrimp ]路径可以是相对路径也可以是绝对路径但从踩坑经验看第一次训练建议直接用绝对路径能排除掉「当前工作目录不对导致找不到图片」这类低级问题。nc是类别总数必须和names列表长度一致也和标签文件里的 class 索引最大值 1 一致。如果标签里有 class2那 nc 至少是 3少了训练时会直接报索引越界。类别顺序尤其要核对。txt 标签里 class0 对应的是什么类别必须和names[0]一致。我用一个简单 Python 脚本扫描全部标签文件统计每个 class 索引出现次数再对照 xml 里的name值确认映射# 统计标签中各类别索引的分布 import os from collections import Counter label_dir train/labels_txt counter Counter() for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname)) as f: for line in f: parts line.strip().split() if parts: counter[int(parts[0])] 1 print(counter) # 例如输出 Counter({0: 1523, 1: 610, 2: 288})说明 class0 样本最多这段代码扫描目录下所有 txt 标签统计每个类别索引的实例数量。输出结果既能帮你确认类别编号没有异常跳变也能直观看出类别是否均衡——如果有一个类明显很少后面训练完会发现那个类的 recall 指标会很难看得提前想好对策。3.2 训练命令写法差异yolov5 与 yolov8/yolo11 的命令行参数yolov5 和 yolov8 之后的版本训练命令差很多网上教程容易混着看。yolov5 是传统的 train.py 方式cd yolov5 python train.py --data fish_dataset.yaml --weights yolov5s.pt \ --batch-size 16 --epochs 100 --img 640 --device 0 \ --project runs/train --name fish_baselineyolov8、yolo11 用的是新的 CLI 风格yolo detect train datafish_dataset.yaml modelyolo11n.pt \ batch16 epochs100 imgsz640 device0 \ projectruns/detect namefish_baselinebatch-size或batch取决于显存大小一般 8GB 显存跑 640 分辨率用 16 是安全的如果显存不够优先调小 batch 而不是调小 imgsz因为分辨率变化会改变小目标的检测效果。imgsz或img是训练输入尺寸默认 640。device 0指用第一张 GPU没有 GPU 就改成device cpu但训练速度会慢到让你怀疑人生。3.3 用 epoch1 先验证数据流比直接跑 100 个 epoch 靠谱得多我见过太多人把参数调好直接跑 100 个 epoch跑了两个小时发现日志里一直在报no labels found等于白等。正确的做法是先跑一个 epoch 验证整个数据管道通畅yolo detect train datafish_dataset.yaml modelyolo11n.pt \ batch8 epochs1 imgsz640 device0 cacheTrueepochs1表示只跑一轮目的是让框架完整走一遍「读配置 → 加载图片 → 解析标签 → 前向传播 → 反向传播 → 输出日志」全流程。cacheTrue会在第一次加载数据时把图像缓存到内存里加快验证速度同时能暴露出图片文件损坏、路径错误这类问题。跑完一个 epoch 后看两个关键输出Labels数量是否和标签文件数一致Images数量是否和图片文件数一致。这两个数字对不上后面跑多少轮都是徒劳。另外一个必须检查的点是日志里有没有出现val相关的输出如果没有说明val路径配置有问题模型训练完也不会有验证指标。4. 翻车现场五条高频排查记录这套流程我前后带过不少人跑过数据集本身没问题但实操中每个人都能踩出不一样的坑。下面五条是频率最高的按「现象 → 原因 → 解决」记录都是血泪经验。4.1 标签文件全被忽略txt 和图片的名字对不上现象训练日志显示labels0但标签目录里明明有几百个 txt 文件。原因图片文件名和标签文件名主体不一致。比如图片叫img_0506_487.jpg标签却是img_0506_487_v1.txt或者img_0506_487 (1).txtyolo 框架按图片名去找对应 txt找不到就跳过。这套数据集本身不会出现这个问题但中间如果你自己做过重命名或二次划分很容易把名字弄歪。解决写一个批量改名脚本把每个 txt 的文件名主体强制改成对应图片的主体名再去掉多余符号。改完后重新扫描确认标签比例到 100%。4.2 中文路径导致读图失败现象训练时频繁报错日志里有cannot identify image file或图片解码失败。原因数据集的完整路径中包含中文目录名比如E:\项目\渔获检测\fish_dataset\train\images。Windows 下 opencv 的 imread 对中文路径支持不好要么返回 None要么读出来是空图yolo 遇到空图会直接跳过或中断。解决把整个数据集目录放到纯英文路径下比如D:\fishtest\datasets\fish_dataset。这不是玄学是 opencv 底层编译时对系统编码的处理缺陷换路径是成本最低的解法。如果你必须用中文路径可以改数据加载逻辑用 PIL 读图再转 numpy 数组喂给模型但那样要改框架源码不建议新手碰。4.3 类别编号错位txt 和 xml 的类别定义对不上现象训练的 loss 一直不降或者 mAP 出来了但混淆矩阵里全是奇怪的对角线错位。原因txt 里的 class0 在你心里是白鱼但 xml 里对应的是别的东西。数据集的 voc 标注是用名称记录的yolo 标注是用索引记录的如果有人在生成 txt 时改了类别排序但 xml 的name没同步调整两个文件看似一致语义上已经完全错位。解决按第 2.2 节的方法抽几个样本把 txt 的 class 索引和 xml 的name做对照表确认一一对应后再写 data.yaml。我拿到这套数据的第一反应就是抽了三个文件做交叉验证确认索引映射没问题才开始写配置。4.4 类别不平衡导致 mAP 虚高现象整体 mAP0.5 有 0.86看起来很漂亮但看每个类别的 AP某个稀有类只有 0.3 甚至更低。原因数据集里不同类别实例数量差距过大。比如背景是养殖池鱼的密度高虾或蟹只有零星几个样本模型对多数类过拟合对少数类基本没学会。总量 1813 张图是够用的但如果三类样本比例悬殊到 10:1直接训练就会出这个问题。解决先统计类别分布用 2.2 的脚本如果少数类占比太低两个办法——第一对少数类做简单的复制粘贴式过采样让它们在训练集中出现更多次第二调整 loss 权重给稀有类别更高的权重。在 yolo 里最省事的是前者直接改 train 目录中的划分比例成本很高建议优先试过采样数据量翻几倍不影响训练时间太多。4.5 数据增强参数太激进把鱼的颜色都扭曲了现象loss 曲线前期下降正常到中期开始震荡val 的 mAP 反而往下掉。原因yolo 自带的数据增强中hsv_h、hsv_s、hsv_v默认值对这套水下或养殖场景的数据不太友好。鱼在水里颜色本来就偏暗偏蓝如果饱和度扰动开得太大训练样本里鱼的颜色被随机调得发白或发红模型学到的颜色特征失真。这种问题最难察觉往往被误判为学习率太大或模型过拟合。解决训练前在 yaml 配置里调低颜色增强参数比如hsv_s: 0.2、hsv_v: 0.3保留基本曝光扰动的同时不让颜色失真。这个参数调整前后 mAP 能差 2 到 5 个点不算玄学属于典型的数据相关问题。5. 进阶让 1813 张图发挥更多价值——验证闭环和鲁棒性优化数据准备和基础训练走通之后别急着收工。1813 张图对一个检测任务来说属于刚够用的量级想提升模型的场景泛化能力还有两件不用额外标注就能做的事。5.1 训练完先看难例图而不是只看指标很多人的习惯是 mAP 上来了就认为训练圆满结束但目标检测的验收标准应该放在具体画面上。我每次训练完都会从 val 目录随机抽 20 张图跑一次推理并把预测框画在原图上yolo detect predict modelruns/detect/fish_baseline/weights/best.pt \ sourcetest/images img640 save_txtFalse然后翻看输出目录里的预测图。重点看三类图像遮挡严重的鱼群、背景里有杂物干扰、目标在画面边缘。指标高不代表这三类情况都做得好因为测试集的分布往往偏向简单样本。这一轮人工筛查消耗时间不多但能比指标暴露更多真实问题。5.2 用数据增强模拟更多工况如果发现模型在小尺寸目标上表现不稳定可以直接在推理时增加输入分辨率imgsz960往往比从头训练一个高分辨率模型更简单。如果要从根本上提升鲁棒性可以用外置增强库离线生成补充训练样本import albumentations as A from albumentations.core.composition import Compose # 定义适合捕鱼场景的增强流程 transform Compose([ A.HorizontalFlip(p0.5), A.RandomBrightnessContrast(brightness_limit0.1, contrast_limit0.1, p0.5), A.Rotate(limit10, border_mode0, p0.3), ]) # image: BGR numpy 数组, boxes: 归一化坐标 [n,4] for i, (image, boxes) in enumerate(dataset): transformed transform(imageimage, bboxesboxes, class_labelscls) # 保存增强后的图和同步变换的 bbox注意两点bboxes参数必须传入 yolo 格式的归一化坐标albumentations 会自动同步变换 bboxRotate的border_mode0表示用黑色填充旋转后的空白区域避免引入不存在的背景纹理。不要用随机擦除或 cutout 这类增强鱼体被擦掉后标签语义会出错。从那以后我每次拿到新数据集第一件事不是开训练而是先抽三张图看标签、跑一个 epoch 验证数据流这两个动作加起来不到十分钟却帮我避掉了后面几小时甚至几天的无用功。这套流程执行到位1813 张图已经足够支撑一个能交付的捕鱼识别原型。希望帮到你。本文还有配套的精品资源点击获取