ARTICLE DETAIL

资讯详情

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

基于YOLOv8的鱼类检测实战:8843张带标签图像从数据体检到模型调优

基于YOLOv8的鱼类检测实战:8843张带标签图像从数据体检到模型调优 简介这是一份面向目标检测学习者的鱼类检测数据集适用于yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等系列算法的训练与验证可帮助初学者和算法工程师快速搭建鱼类识别模型省去自行采集与标注的成本。压缩包共2000个文件以xml标注文件为主同时提供yolo格式的txt标签两种格式分别存放便于直接接入不同训练框架yolo标签采用类别索引与归一化中心点、宽高坐标符合主流检测模型输入规范。资源包整体约243.91MB目录划分清晰训练集与验证集已预先切分开箱即可投入实验。目前已有261人学习下载适合需要现成鱼类检测数据、想快速验证模型效果或进行算法对比的读者参考使用。1. 鱼类检测数据集到手之后8843 张带标签图像到底怎么用拿到># 解压并查看顶层结构 unzip>import os, glob, random label_dir fish_data/labels txt_files glob.glob(os.path.join(label_dir, *.txt)) print(标签文件总数:, len(txt_files)) # 随机抽 5 个看内容 for f in random.sample(txt_files, 5): print(---, os.path.basename(f)) with open(f) as fp: for line in fp.readlines()[:3]: print(line.strip()) # 统计所有出现过的 class_id from collections import Counter cid_counter Counter() for f in txt_files: with open(f) as fp: for line in fp: parts line.strip().split() if parts: cid_counter[parts[0]] 1 print(类别 id 分布:, cid_counter)逻辑说明抽样看内容能立刻判断是 YOLO txt 还是别的格式。统计 class_id 分布能发现两个致命问题一是 id 从 1 开始YOLO 要求从 0 开始二是出现了训练配置里没定义的 id。参数说明parts[0]是类别 id后面四个是归一化坐标。如果某行有 5 个以上的值可能是分割标签polygon那这个数据集就不只是检测还带实例分割信息训练时要换yolov8-seg模型。2.3 图像-标签配对校验与损坏文件排查8843 张里只要有一批图打不开训练时就会报corrupt image直接中断。提前用脚本过一遍。from PIL import Image import os img_dir fish_data/images bad_images [] for name in os.listdir(img_dir): path os.path.join(img_dir, name) try: img Image.open(path) img.verify() # 验证文件完整性 except Exception as e: bad_images.append((name, str(e))) print(损坏图像数量:, len(bad_images)) for n, e in bad_images[:10]: print(n, e) # 检查图像与标签是否一一对应 img_stems {os.path.splitext(f)[0] for f in os.listdir(img_dir)} label_stems {os.path.splitext(f)[0] for f in os.listdir(fish_data/labels)} print(有图无标签:, len(img_stems - label_stems)) print(有标签无图:, len(label_stems - img_stems))逻辑说明img.verify()只检查文件头速度快适合大批量筛查。配对校验用集合差集能精确找出缺失项。有图无标签的图可以直接移走或补标有标签无图的标签直接删掉否则训练时 dataloader 会报错。参数说明如果损坏图像占比超过 1%建议重新下载数据集包可能是传输损坏。少量损坏直接剔除即可8843 张的基数损失几十张不影响。2.4 鱼类检测的类别定义与数据划分先确认这个数据集是单类fish还是多类按鱼种分。单类的话data.yaml里nc: 1多类就要列出所有names。划分训练集/验证集建议 8:2 或 7:2:1。import os, random, shutil random.seed(42) img_dir fish_data/images label_dir fish_data/labels out_dir fish_dataset for split in [train, val]: os.makedirs(f{out_dir}/images/{split}, exist_okTrue) os.makedirs(f{out_dir}/labels/{split}, exist_okTrue) stems [os.path.splitext(f)[0] for f in os.listdir(img_dir)] random.shuffle(stems) split_idx int(len(stems) * 0.8) train_stems stems[:split_idx] val_stems stems[split_idx:] def copy_pair(stem_list, split): for stem in stem_list: for ext in [.jpg, .jpeg, .png]: src os.path.join(img_dir, stem ext) if os.path.exists(src): shutil.copy(src, f{out_dir}/images/{split}/{stem}{ext}) break src_label os.path.join(label_dir, stem .txt) if os.path.exists(src_label): shutil.copy(src_label, f{out_dir}/labels/{split}/{stem}.txt) copy_pair(train_stems, train) copy_pair(val_stems, val) print(训练集:, len(train_stems), 验证集:, len(val_stems))逻辑说明固定随机种子保证可复现。按 stem 配对复制避免图像和标签错位。鱼类检测里如果某些鱼种样本极少划分时要保证每个类别在验证集里都有出现否则验证指标会失真。参数说明0.8是训练集比例数据量小于 1 万时常用 8:2。如果要做交叉验证就改成多折。random.seed(42)换成别的数字结果不同但同一数字每次结果一致。3. 环境配置与 YOLO 训练从 data.yaml 到第一个 baseline3.1 环境选型为什么优先用 ultralytics 而不是自己搭鱼类检测这种任务除非你要改网络结构否则没必要从 Darknet 源码编译。ultralytics 的 YOLOv8 封装了训练、验证、推理、导出全流程pip 装完就能跑。Anaconda 建环境时 Python 选 3.9 或 3.10PyTorch 按显卡 CUDA 版本对应装。conda create -n fish_yolo python3.10 -y conda activate fish_yolo # 按 CUDA 版本装 PyTorch这里以 CUDA 11.8 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 装 ultralytics pip install ultralytics # 验证 yolo checks逻辑说明yolo checks会打印环境信息重点看 CUDA 是否可用、版本是否匹配。如果显示 CPU only训练会慢到无法接受。鱼类检测 8843 张在单卡 3060 上大约 1~2 小时跑完 100 epoch。参数说明CUDA 11.8 对应cu11812.1 对应cu121装错版本会报CUDA error。没有 NVIDIA 显卡就用 CPU 版但只建议做推理验证不建议训练。3.2 data.yaml 的写法与鱼类类别配置path: /absolute/path/to/fish_dataset train: images/train val: images/val nc: 1 names: 0: fish逻辑说明path必须是绝对路径相对路径在不同工作目录下会找不到。train和val是相对path的路径。nc是类别数单类鱼就写 1。如果数据集是多鱼种names按 id 顺序列出id 必须从 0 连续。参数说明names的顺序必须和标签里的 class_id 严格对应。写反了模型会把 A 鱼认成 B 鱼mAP 看着还行但实际全错。改完 yaml 用yolo train datafish.yaml前先yolo val空跑一次确认路径通。3.3 启动训练与关键参数设置yolo detect train \ datafish.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectfish_runs \ namebaseline逻辑说明modelyolov8n.pt是最小的预训练权重适合先跑 baseline。epochs100配合patience2020 轮没提升就早停省时间。imgsz640是默认输入尺寸鱼类小目标多的话可以提到 960 或 1280但显存占用翻倍。参数说明batch16在 8G 显存上比较稳显存不够就降到 8 或 4。lr00.01是初始学习率微调预训练模型时常用 0.001~0.01。project和name决定结果保存路径跑多次实验时改name避免覆盖。3.4 训练过程监控与指标解读训练时终端会打印每轮的box_loss、cls_loss、mAP50、mAP50-95。重点看mAP50是否稳定上升box_loss是否下降。如果mAP50在 0.5 以下徘徊先查标签质量而不是调参。# 训练结束后用验证集评估 yolo detect val modelfish_runs/baseline/weights/best.pt datafish.yaml # 对单张图推理看效果 yolo detect predict modelfish_runs/baseline/weights/best.pt sourcetest_fish.jpg saveTrue逻辑说明best.pt是验证集上表现最好的权重last.pt是最后一轮。推理时saveTrue会把带框的图存到runs/detect/predict。鱼类检测常见问题是框重叠严重可以调iou阈值和conf阈值。参数说明conf0.25是默认置信度阈值鱼群密集时调到 0.4 减少误检。iou0.45控制 NMS 合并框的力度遮挡严重时调低到 0.3 保留更多框。4. 鱼类检测训练避坑5 个让 mAP 卡住不动的真实原因4.1 现象mAP50 一直在 0.2 附近loss 不降原因标签 class_id 从 1 开始而data.yaml里nc: 1只定义了 id 0。模型把 id 1 当成背景所有鱼都被忽略。解决用脚本把所有标签的 class_id 减 1或者把nc改成 2 并在names里加一个占位类。推荐前者改完重新训练。4.2 现象训练报No labels found in ...原因data.yaml里train路径写的是images/train但实际标签在labels/trainYOLO 会自动把images替换成labels去找如果目录名不是这个对应关系就找不到。解决确保目录结构是images/train和labels/train平行。如果标签目录叫Annotations要么改目录名要么在 yaml 里显式指定train: ../labels/train。4.3 现象验证集 mAP 很高但实际推理全是错框原因训练集和验证集划分时没有按图像分组同一张图的增强版本同时出现在训练和验证里造成数据泄漏。解决划分前先按原始图像 stem 去重确保同一来源的图只进一个 split。鱼类数据集如果是从视频抽帧来的相邻帧高度相似更要按视频段划分。4.4 现象小目标鱼检测不到大框正常原因imgsz640下小鱼只有十几个像素特征图下采样后信息丢失。解决把imgsz提到 960 或 1280同时batch降到 8。或者在data.yaml里开rectTrue做矩形训练减少 padding 浪费。还可以用yolov8s或yolov8m换更大的模型。4.5 现象训练到一半显存溢出CUDA out of memory原因batch太大或imgsz太高加上 dataloader 的workers占用额外显存。解决先把batch减半再把workers从 8 降到 4。如果还不行开ampTrue混合精度训练显存占用能降 30% 左右。最后手段是cacheFalse关掉图像缓存。5. 从 baseline 到可用模型鱼类检测的进阶调参与验证技巧跑通 baseline 只是起点。8843 张的鱼类数据集想做到实际可用的检测效果重点在数据增强策略和阈值调优上。YOLOv8 默认开了 mosaic、HSV 增强和随机翻转但水下图像有它的特殊性偏色严重时 HSV 增强的hsv_h可以调大浑浊图像加高斯模糊增强能提升鲁棒性。yolo detect train \ datafish.yaml \ modelyolov8s.pt \ epochs200 \ imgsz960 \ batch8 \ lr00.005 \ hsv_h0.03 \ hsv_s0.9 \ hsv_v0.6 \ mosaic1.0 \ mixup0.1 \ copy_paste0.1 \ patience30 \ projectfish_runs \ nameadvanced逻辑说明换yolov8s提升容量imgsz960改善小目标。hsv_s0.9加大饱和度扰动模拟水下偏色。mixup和copy_paste对遮挡和密集场景有帮助。lr00.005比 baseline 低因为模型更大需要更稳的更新。参数说明hsv_h是色调扰动幅度默认 0.015水下图像可以到 0.03。mosaic1.0表示始终启用马赛克增强最后 10 轮建议关掉让模型适应真实分布。copy_paste0.1对鱼类重叠场景有效但太高会引入不真实组合。验证阶段除了看 mAP还要做阈值扫描。用yolo detect val加不同conf跑几组找 F1 最高的点。conf 阈值precisionrecallF10.150.720.850.780.250.810.790.800.350.880.710.790.450.920.620.74从表里能看出conf0.25附近 F1 最高。实际部署时如果更怕漏检就选 0.15更怕误检就选 0.35。这个权衡没有标准答案取决于你的业务场景。导出模型时如果部署到边缘设备用yolo export formatonnx或formatengine。ONNX 通用性好TensorRT engine 在 NVIDIA 设备上推理最快但绑定硬件。yolo export modelfish_runs/advanced/weights/best.pt formatonnx imgsz960 yolo export modelfish_runs/advanced/weights/best.pt formatengine halfTrue逻辑说明halfTrue用 FP16 推理速度提升明显精度损失通常在 1% 以内。导出后务必用同一张测试图对比 PyTorch 和 ONNX 的输出框确认没有偏移。我自己的习惯是每次改完增强参数或换模型先跑 20 epoch 看趋势别一上来就 200 epoch。趋势不对就停省下的时间够试三组参数。鱼类检测这个方向数据质量比模型大小重要得多标签框得准、类别分得清比换什么 backbone 都管用。希望帮到你。本文还有配套的精品资源点击获取
返回列表