YOLO金鱼疾病检测数据集构建与训练调参实战

发布时间:2026/10/12 0:31:14
YOLO金鱼疾病检测数据集构建与训练调参实战 简介这份资源是面向深度学习开发者、水产养殖研究者与鱼类爱好者的金鱼及疾病目标检测数据集覆盖健康金鱼、腹水病、白点病与败血症等类别可用于训练YOLO系列模型实现家庭或商业养鱼场中金鱼疾病的自动识别与及时干预也可作为鱼类健康科普的教育素材。资源包共1657个文件以828张jpg图像与828个同名txt标注文件为主另含1个yaml配置文件用于定义类别与训练路径压缩包约33.74MB图像涵盖不同光线、角度与背景均由专家筛选验证标准化程度高可直接接入YOLOv8等框架。数据集已按684个训练样本、96个验证样本、48个测试样本划分开箱即可训练与评估。目前已有816人学习下载适合希望快速验证检测方案、补充渔业数据或开展课程实践的中高级读者参考使用。1. 金鱼疾病检测数据集为什么你的 YOLO 模型在鱼缸里翻车养过金鱼的人都知道鱼生病往往不是突然发生的。白点病、烂鳍、水霉早期症状藏在鳞片和鳍条的纹理里等人眼看出来整缸鱼可能已经交叉感染了。这正是 YOLO 目标检测切入水产场景的价值把「金鱼个体定位」和「疾病区域识别」放在同一个检测头里跑做到早发现、早隔离。但很多人拿公开的鱼类数据集直接训 YOLOmAP 看着还行一放到真实鱼缸就翻车——水面反光、鱼体弯曲、疾病区域只占几十个像素模型根本学不到判别性特征。这篇笔记就围绕「YOLO 金鱼与金鱼疾病检测数据集」这个方向把数据怎么组织、标签怎么定、训练参数怎么调、坑在哪按我实际做过的路径讲清楚。适合做智慧渔业、水族监测、目标检测数据集构建的从业者新手能跟着跑通熟手能看到边界。2. 金鱼疾病检测数据集怎么建从采集到 YOLO 标签的完整链路2.1 先想清楚检测目标个体框和疾病框要不要分开这是整个数据集设计里最先要拍板的事也是最多人做错的地方。金鱼疾病检测和普通目标检测最大的区别在于你要检测的「金鱼」和「疾病」在空间上是包含关系。一条鱼身上可能同时有白点和烂鳍疾病区域又只占鱼体的一小块。常见做法有三种第一种只标金鱼个体框疾病分类交给后续的分类模型。优点是标注简单缺点是丢失了疾病的空间位置没法做「这条鱼哪个部位病了」的定位。第二种只标疾病区域框不标鱼。适合疾病特征明显、鱼体不重要的场景但金鱼游动时疾病区域会变形框不稳定。第三种双类别标注goldfish和disease两个类疾病框独立于鱼体框存在。这是我一般会推荐的方案因为 YOLO 的多类别检测头天然支持这种嵌套标注推理时先拿到鱼的位置再在鱼体范围内过滤疾病框逻辑清晰。选第三种方案时要注意疾病框不要标得比实际病灶大太多。白点病单个白点可能只有 5 到 15 像素如果你按「整片感染区域」标一个大框模型学到的是区域而不是病灶换一条鱼就失效。我的经验是白点病按单个白点或密集白点簇标烂鳍按鳍条缺损边缘标水霉按棉絮状菌丝范围标。2.2 采集与预处理鱼缸场景的四个硬约束金鱼数据集的采集环境和常规目标检测差别很大下面这四个约束直接决定数据集能不能用。约束一水面反光和玻璃折射。俯拍鱼缸时水面会反射顶灯形成大面积高亮区域YOLO 容易把反光当成白点病。解决办法是采集时关掉正上方光源改用侧光或者加偏振镜。如果已经采了带反光的图预处理阶段可以用简单的亮度阈值做掩膜但更稳的是在标注时把反光区域标成ignore区域训练时跳过。约束二鱼体弯曲和遮挡。金鱼游动时身体呈 S 形两条鱼重叠时疾病区域可能被完全挡住。采集时要保证每个疾病类别至少有 30% 的样本是「单鱼、无遮挡、侧身」的清晰图剩下的可以是复杂场景。不要全是复杂场景否则模型连基本特征都学不到。约束三类别不平衡。健康金鱼的图永远比病鱼多白点病又比水霉病多。我的做法是健康鱼图控制在总图量的 40% 以内每个疾病类别至少 200 个标注框。如果某个疾病实在难采用旋转、裁剪、色彩抖动做增强但不要用 GAN 生成金鱼疾病纹理生成出来往往不真实反而引入噪声。约束四图像分辨率。疾病区域小输入分辨率不能太低。YOLO 默认 640但白点病在 640 下可能只剩 2 到 3 个像素。建议采集时用 1080p 以上训练时imgsz设 960 或 1280。代价是显存和速度后面第 4 章会讲怎么权衡。预处理流程我一般写成脚本核心是统一尺寸、去反光、做数据增强。下面是一个基于 OpenCV 的预处理片段import cv2 import numpy as np import os def preprocess_goldfish(img_path, save_path, target_size1280): img cv2.imread(img_path) if img is None: return False # 1. 限制对比度自适应直方图均衡增强鳞片和病灶纹理 lab cv2.cvtColor(img, cv2.COLOR_BGR2LAB) l, a, b cv2.split(lab) clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8, 8)) l clahe.apply(l) img cv2.cvtColor(cv2.merge((l, a, b)), cv2.COLOR_LAB2BGR) # 2. 按长边缩放短边补边保持长宽比避免鱼体变形 h, w img.shape[:2] scale target_size / max(h, w) nh, nw int(h * scale), int(w * scale) img cv2.resize(img, (nw, nh), interpolationcv2.INTER_LINEAR) canvas np.zeros((target_size, target_size, 3), dtypenp.uint8) top (target_size - nh) // 2 left (target_size - nw) // 2 canvas[top:topnh, left:leftnw] img cv2.imwrite(save_path, canvas) return True这段代码做了两件事CLAHE 增强局部对比度让白点和烂鳍边缘更清晰等比缩放加补边避免直接 resize 把鱼拉扁。参数上clipLimit2.0是经验值调高会放大噪声调低增强不明显target_size建议和训练时的imgsz一致省得训练时再缩放一次损失细节。补边用黑色而不是拉伸是因为拉伸会改变疾病区域的形状特征模型学到的框会偏。2.3 标注规范与 YOLO 格式转换标注用 LabelImg 或 CVAT 都行关键是类别名和框的粒度要统一。我一般定三个类goldfish、white_spot、fin_rot。水霉如果样本够加第四个类saprolegnia不够就并到fin_rot里但要在数据集说明里写清楚。YOLO 格式是每行class_id x_center y_center width height全部归一化到 0 到 1。从 VOC 的 XML 转 YOLO 的脚本很常见但金鱼数据集有两个边界坑一是图像补边后原来标注的坐标要跟着平移二是疾病框如果小于 3 像素归一化后宽高接近 0训练时会被 YOLO 的锚框匹配忽略建议标注时就把小于 5 像素的病灶合并或丢弃。import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, classes, img_w, img_h, pad_top0, pad_left0): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) pad_left ymin float(bbox.find(ymin).text) pad_top xmax float(bbox.find(xmax).text) pad_left ymax float(bbox.find(ymax).text) pad_top # 过滤过小病灶框避免归一化后趋近于零 if (xmax - xmin) 5 or (ymax - ymin) 5: continue 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{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) return linespad_top和pad_left是补边偏移量必须和预处理脚本里的补边参数一致否则框会整体偏移。classes列表的顺序要和训练时data.yaml里的names完全一致顺序错了模型会把白点当烂鳍。过滤阈值 5 像素是我踩过坑之后定的低于这个值的框在 640 输入下基本学不到留着只会拉低召回。2.4 数据集划分与 data.yaml 配置划分比例不要用固定的 8:1:1。金鱼疾病样本少验证集和测试集各留 10% 就够但要保证每个疾病类别在三个集合里都有出现。如果某个疾病只有 200 个框按类别分层抽样别随机分否则测试集里可能一个水霉都没有。data.yaml的写法path: ./goldfish_dataset train: images/train val: images/val test: images/test nc: 3 names: [goldfish, white_spot, fin_rot]nc是类别数必须和names长度一致。path用相对路径方便整个数据集打包迁移。如果后面要加疾病类别改nc和names就行但已经训好的权重不能直接复用检测头需要重新训或者只冻结 backbone 微调。3. YOLO 训练参数怎么设小目标疾病检测的调参逻辑3.1 模型选型v8 还是 v11n 还是 s金鱼疾病检测的算力需求不高但小目标多。我的选型逻辑是如果部署在边缘设备Jetson、树莓派加加速棒选 YOLOv8n 或 YOLOv11n输入 960如果服务器端跑选 YOLOv8s 或 v11s输入 1280。n 和 s 的差距主要在 neck 的特征融合能力疾病这种小目标s 的召回通常比 n 高 3 到 5 个点但速度慢一倍左右。不要一上来就上 x 或 l金鱼数据集规模通常几千张大模型直接过拟合验证集 loss 先降后升mAP 卡在 0.5 上不去。我一般先用 n 跑一版 baseline看混淆矩阵里白点和反光有没有混再决定要不要换 s。3.2 关键参数imgsz、batch、学习率和锚框YOLO 训练参数里对金鱼疾病检测影响最大的是这四个参数建议值作用与调整逻辑imgsz960 或 1280小目标检测的核心参数低于 960 白点基本丢batch8 到 16受显存限制batch 太小 BN 统计不稳太大会掉小目标lr00.001 到 0.01从预训练权重微调用 0.001从头训用 0.01anchors自动计算金鱼疾病框偏小建议用 k-means 重新聚类imgsz是最容易省错的地方。很多人为了速度用 640结果白点病 mAP 只有 0.2。调到 1280 后 mAP 能到 0.6 以上但显存翻倍。折中方案是训练用 1280推理用 960精度损失通常在 2 个点以内。学习率方面如果你用的是 COCO 预训练权重lr00.001配合cos_lrTrue比较稳。从头训的话lr00.01但金鱼数据集小从头训基本不现实还是建议用预训练。锚框这块YOLOv8 之后是 anchor-free 的不用手动设 anchors但 v5 和 v7 需要。如果你用的是 v5一定要用kmeans重新聚类默认的 COCO 锚框偏大金鱼疾病的小框匹配不上。3.3 训练命令与断点续训以 Ultralytics 的 YOLOv8 为例训练命令yolo detect train \ data./goldfish_dataset/data.yaml \ modelyolov8s.pt \ imgsz1280 \ epochs200 \ batch8 \ lr00.001 \ cos_lrTrue \ patience30 \ device0 \ projectgoldfish_runs \ nameexp_1280_spatience30是早停验证集 mAP 30 轮不升就停省时间。cos_lrTrue用余弦退火小数据集上比阶梯下降稳。device0指定第一块 GPU多卡用device0,1。断点续训加resumeTrue但要注意如果你改了imgsz或batch不要直接 resume优化器状态对不上会报错或者精度崩。正确做法是加载权重重新训yolo detect train data./goldfish_dataset/data.yaml modelgoldfish_runs/exp_1280_s/weights/last.pt imgsz960 epochs100这样只加载权重不恢复优化器适合换分辨率微调。3.4 训练过程看什么loss 曲线和混淆矩阵训练时别只盯 mAP。金鱼疾病检测要重点看三个东西第一train/box_loss和val/box_loss的差距。如果 train 一直降、val 先降后升是过拟合加数据增强或者减模型。如果两个都降不下去是欠拟合检查标注或者加分辨率。第二混淆矩阵。重点看white_spot和背景的混淆。如果白点大量被预测成背景说明imgsz不够或者白点框太小。如果背景被预测成白点说明反光没处理干净。第三metrics/mAP50-95和mAP50的差距。差距大说明框的位置不准疾病框回归有问题检查标注框是不是太松。4. 金鱼疾病检测的避坑与排查5 个血泪教训4.1 反光被当成白点病现象模型在验证集上白点病 precision 很高但一放到新鱼缸满屏误检全是水面反光。原因训练集里反光样本和白点样本在颜色空间上太接近模型学到了「亮斑白点」的捷径而不是白点的纹理特征。解决采集时加侧光或偏振镜标注时把反光区域标成ignoreYOLO 支持在data.yaml里配ignore类训练时跳过这些区域或者在预处理里用亮度阈值加形态学操作把大面积高亮区域涂黑但注意别把白点也涂掉白点通常是小而密集的亮点反光是大面积连续区域用连通域面积区分。4.2 疾病框太小训练时被忽略现象标注文件里明明有白点框训练日志里instances数量对不上mAP 里白点类一直是 0。原因YOLO 在匹配正样本时如果框的宽高小于 stride 的若干倍会被直接过滤。640 输入下 stride 32 的特征层小于 8 像素的框基本匹配不上。解决提高imgsz到 960 或 1280标注时合并相邻小病灶把多个白点标成一个簇框如果还是不行改 YOLO 的overlap_mask或者用分割任务代替检测但分割标注成本高慎选。4.3 类别不平衡导致水霉病召回为零现象白点病 mAP 0.7烂鳍 0.5水霉 0.05混淆矩阵里水霉全被预测成烂鳍。原因水霉样本只有几十个框模型没学够而且水霉和烂鳍在早期视觉上确实像都是白色絮状。解决先补水霉样本至少 200 个框如果补不到用copy-paste增强把水霉病灶抠出来贴到健康鱼图上但要注意光照和尺度一致训练时用cls权重加权Ultralytics 支持在data.yaml里配class_weights给水霉类 2 到 3 倍权重。4.4 验证集 mAP 高实际部署漏检严重现象验证集 mAP50 0.85部署到鱼缸摄像头鱼一游快就漏检疾病框闪来闪去。原因验证集图片大多是静态清晰图和视频流的运动模糊、光照变化分布不一致。另外YOLO 默认的 NMS 阈值 0.45鱼体密集时疾病框会被互相抑制。解决验证集里加入视频抽帧的模糊图推理时把conf从 0.25 降到 0.15iou从 0.45 提到 0.6减少误抑制如果还不行加跟踪算法ByteTrack做时序平滑疾病框连续几帧出现才输出。4.5 换数据集后类别顺序错乱现象自己训的模型换了一个公开金鱼数据集做测试检测框全乱白点框标到了鱼头上。原因两个数据集的names顺序不一致你的模型输出第 1 类是白点公开数据集第 1 类是金鱼评估脚本没对齐。解决永远以data.yaml里的names顺序为准评估前先打印model.names和数据集names对比写一个映射字典把预测类别 id 映射到统一名称再算指标。这个坑不只在金鱼数据集上出现任何多来源数据集合并都会遇到。5. 从能跑到好用金鱼疾病检测的进阶技巧与验证方法5.1 用切片推理救小目标如果显存不够训不了 1280还有一个技巧训练用 960推理时用 SAHISlicing Aided Hyper Inference切片推理。把 1080p 图切成 4 块 640 的子图分别推理再合并小目标的召回能提升 10 到 15 个点。代价是推理速度慢 3 到 4 倍适合离线分析不适合实时视频流。SAHI 和 YOLO 结合的命令sahi predict \ --model_path goldfish_runs/exp_1280_s/weights/best.pt \ --image_dir ./test_images \ --slice_height 640 \ --slice_width 640 \ --overlap_height_ratio 0.2 \ --overlap_width_ratio 0.2overlap比例 0.2 是经验值太低切边处的鱼会被截断太高重复框多。切片推理后要用 NMS 合并SAHI 内置了但iou阈值建议设 0.5 以上避免把相邻白点合并掉。5.2 验证方法别只看 mAP做场景分层评估mAP 是全局指标金鱼疾病检测更该看分层结果。我一般把测试集分成三组清晰单鱼、复杂多鱼、视频抽帧模糊图分别算 mAP 和召回。如果清晰组 0.8、模糊组 0.3说明模型对运动模糊不鲁棒需要补模糊样本或者加时序平滑。另一个验证方法是「留一鱼缸交叉验证」用 A 鱼缸的图训练B 鱼缸的图测试。如果 mAP 掉超过 20 个点说明模型过拟合了背景比如某个鱼缸的底砂颜色需要加背景随机化增强。5.3 一个具体技巧疾病框的后处理过滤YOLO 输出的疾病框有些会落在鱼体框外面比如白点框标到了背景石头上。加一个后处理只保留中心点落在goldfish框内的white_spot和fin_rot框。这个逻辑很简单但能砍掉大部分背景误检。def filter_disease_boxes(detections, fish_class_id0, disease_class_ids[1, 2]): fish_boxes [d for d in detections if d[class_id] fish_class_id] filtered [] for det in detections: if det[class_id] in disease_class_ids: cx (det[xmin] det[xmax]) / 2 cy (det[ymin] det[ymax]) / 2 for fish in fish_boxes: if fish[xmin] cx fish[xmax] and fish[ymin] cy fish[ymax]: filtered.append(det) break else: filtered.append(det) return filtered这个后处理在鱼体密集时要注意如果两条鱼重叠疾病框可能落在另一条鱼的框里导致误保留。解决办法是加 IoU 判断疾病框和鱼体框的 IoU 大于 0.1 才保留纯中心点判断在重叠场景不够。5.4 我踩过的最大一个坑最后说一个我自己的教训。早期做金鱼疾病检测我花了大量时间调模型结构换 backbone、加注意力mAP 涨了不到 2 个点。后来发现真正卡住精度的是标注质量有 15% 的白点框标大了把周围鳞片也框进去了模型学到的「白点」其实是「白点加鳞片纹理」。重新按病灶边缘标了一遍同样的模型mAP 从 0.52 涨到 0.71。所以如果你也在做这个方向先把标注规范定死再谈模型和参数。数据质量的天花板模型再深也顶不破。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询