ARTICLE DETAIL

资讯详情

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

超声波肾脏结石检测:YOLOv5数据集训练与避坑指南

超声波肾脏结石检测:YOLOv5数据集训练与避坑指南 简介超声波肾脏结石检测YOLOv5数据集涵盖训练集与验证集标注面向医学影像目标检测开发者和研究者适用于基于超声图像的肾脏与结石识别场景。压缩包为rar格式约19.73MB共2000个文件其中包含1999个YOLO格式的txt标注文件与1个py可视化脚本标注类别为结石和正常肾脏并附有类别文本信息。数据集按照YOLOv5目录结构整理训练集对应2564张超声图像的标注验证集对应183张超声图像的标注图像均为250x250分辨率的RGB超声图片边界框标注清晰无需额外格式转换即可用于目标检测模型的训练与验证。包内提供的show.py可视化脚本无需修改即可运行传入任意一张图片即可绘制并保存边界框便于快速检查标注质量。目前已有454人学习下载适合需要现成医学超声检测数据集的入门与进阶用户。1. 超声波肾脏结石检测为什么这个数据集比通用目标检测集更难跑做过超声影像的工程师都知道肾脏结石检测这件事难点压根不在模型结构而在数据本身。B 超图像天生噪声大、边界模糊结石在声像图里往往只是几毫米到十几毫米的强回声团后面还拖着一道声影伪影搞不好连医生都要反复扫查才能确认想让模型第一次训练就抓住这个特征靠通用 COCO 数据集那套思路基本行不通。这份 YOLOv5 超声波肾脏结石检测数据集就是冲着这个场景来的两个类别、配好了训练集和验证集标签直接是 YOLO 格式下载解压之后不需要重新标注改一下配置就能喂给 YOLOv5 训练。适合正在做医学图像目标检测落地的工程师、做超声辅助筛查相关课题的学生以及想快速跑通 YOLOv5 完整流程但手上没有医学图像素材的人。2. 目录结构与标注格式先摸清数据集的底细再动手拿到数据集的第一件事不是急着训练而是把目录结构和标注格式核对一遍。YOLOv5 对数据摆放方式有固定约定数据集的根目录组织结构通常会按照 images 和 labels 两部分展开这两个目录各自再分 train 和 val。下面是一份典型的超声波肾脏结石数据集布局绝大多数公开整理的 YOLO 数据集都遵循这个套路。2.1 images 与 labels训练集和验证集各就各位kidney_stone_dataset/ ├── images/ │ ├── train/ │ │ ├── patient01_frame001.png │ │ ├── patient01_frame002.png │ │ └── ... │ └── val/ │ ├── patient09_frame001.png │ └── ... ├── labels/ │ ├── train/ │ │ ├── patient01_frame001.txt │ │ └── ... │ └── val/ │ └── ... └── data.yaml这套结构里images 和 labels 下方都带 train 与 val 子目录一张 PNG 图像对应一个同名 TXT 标签文件。拿到数据集后我一般先跑一个核对脚本确认每张图都有对应标签、标签行数不等于零免得训练到一半才发现某个文件名对不上。2.2 两个类别到底指什么标题里写的是“2 类别”落到具体任务上通常指的是 stone结石和 kidney肾脏区域前者是你要检测的目标后者是器官上下文帮助模型理解结石位于肾脏内部而不是别的脏器。不同数据集在类别定义上可能略有差异常见的另一套定义是把“含结石肾脏”和“正常肾脏”作为两类所以动手前一定要打开标签文件看一眼类别 ID 对应的实际含义。# 查看一个标签文件的内容 cat labels/train/patient01_frame001.txt一个典型文件内容长这样0 0.514843 0.323437 0.076563 0.051562 1 0.487500 0.543750 0.310938 0.265625每一行的五个数字分别代表类别 ID、归一化中心点 x、归一化中心点 y、归一化宽度、归一化高度。像素坐标都要除以图像宽高归一化到 0~1 区间这是 YOLO 系列约定俗成的格式。如果看到某行数字大于 1 或者小于 0说明标签在整理时出了问题训练前必须清理不然 loss 直接飞掉。2.3 先做一次标签分布统计再决定训练策略超声波图像里的结石通常是小目标但到底小到什么程度不能靠猜要靠统计。我习惯在训练前写一段脚本把所有训练集标签的框宽高和类别分布过一遍生成柱状图这个操作能帮你判断后面对 anchor 和输入尺寸该做什么调整。import os import numpy as np label_dir labels/train class_names [stone, kidney] class_counts {} box_sizes [] for file in os.listdir(label_dir): if not file.endswith(.txt): continue with open(os.path.join(label_dir, file), r) as f: lines f.readlines() for line in lines: parts line.strip().split() cls_id int(parts[0]) w float(parts[3]) h float(parts[4]) class_counts[cls_id] class_counts.get(cls_id, 0) 1 box_sizes.append((w, h)) for cls_id, count in class_counts.items(): print(fClass {cls_id} ({class_names[cls_id]}): {count} instances) box_sizes np.array(box_sizes) print(fBox width - mean: {box_sizes[:, 0].mean():.4f}, fmin: {box_sizes[:, 0].min():.4f}, max: {box_sizes[:, 0].max():.4f})这段脚本做了三件事按类别统计样本数量计算所有标注框的归一化宽高最后输出宽高的均值、最小值和最大值。输出结果直接决定后面的超参数方向。比如最小框宽只有 0.02 的话意味着在 640×640 的输入下这个框大约只有 13 个像素这种尺寸的结石必须靠高分辨率输入或者调整 anchor 才能抓住按默认配置硬练大概率漏检。3. 接入 YOLOv5 训练data.yaml、超参数与第一次训练数据集结构确认无误后下一步就是把它接到 YOLOv5 的训练流程里。这一章把从编写 data.yaml 到跑通 train.py 的完整路径走一遍重点说清楚哪些参数在医学超声场景下需要额外留意。3.1 data.yaml让 YOLOv5 认识你的数据集YOLOv5 靠一个 YAML 文件描述数据集路径和类别信息训练脚本不关心数据集放在哪只认这个文件。针对这份肾脏结石数据集data.yaml 的内容如下train: ../kidney_stone_dataset/images/train val: ../kidney_stone_dataset/images/val nc: 2 names: [stone, kidney]train 和 val 指向的是图像目录不是标签目录YOLOv5 会自动把路径里的 images 替换成 labels 去读取标签文件。如果解压后的目录名跟上面不一致务必改成实际路径。nc 是类别数量2 个类别就写 2names 列表顺序必须和标签文件里的类别 ID 一一对应tag 里 ID 为 0 的类对应 names 第一个元素ID 为 1 对应第二个顺序反了训练不会报错但测试结果会完全错乱。3.2 超参数怎么设从 imgsz 到 anchor 的选择超声波结石是小目标检测输入分辨率直接决定模型能看到多小的结石。YOLOv5 默认 imgsz640对于一般场景够用但在超声图像上结石的像素尺寸往往只有十几个像素我第一轮通常直接用 640 起步先把基线跑出来再考虑要不要提到 960 或 1280。anchor 是另一个关键点。YOLOv5 支持自动学习 anchor训练命令里加--noautoanchor会禁用这个功能不加则会基于你的数据集重新聚类 anchor。对于这种框尺寸跨度大的医学数据集建议第一次训练时先不加--noautoanchor让 YOLOv5 在训练前用 k-means 对标签框做聚类生成更适合结石尺度的初始 anchor。python train.py \ --data data/kidney_stone.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --project runs/kidney_stone \ --name exp_baseline命令里值得解释的是--weights yolov5s.pt。这里用的是 COCO 预训练权重做迁移学习虽然 COCO 里没有超声图像但浅层特征提取能力是可以迁移的能让模型在较少训练数据下更快收敛。如果你的图量比较少用 yolov5s 比 yolov5l 更稳参数量小不容易过拟合。batch 大小主要看显存16 这个值在 12GB 显存下配合 640 分辨率基本安全显存紧张就降到 8没必要硬撑。3.3 训练过程的检查节点训练跑起来之后重点盯三个指标train/box_loss是否在稳步下降、val/obj_loss是否有明显波动、以及每个 epoch 之后的验证集 mAP。超声图像噪声大box_loss 在最初的 20 个 epoch 里振荡是正常的不要看到曲线上下跳就急着调参。# 训练结束后查看结果 ls runs/kidney_stone/exp_baseline/训练完成后这个目录下会生成 weights 文件夹里面是 best.pt 和 last.pt以及一系列结果曲线图。best.pt 是验证集表现最好的权重后续推理优先用这个。如果训练到一半发现 loss 不降先别调模型回去检查标签文件里有没有异常的框——比如宽度为 0 或者超出图像边界的标注这类脏数据在医学数据集里相当常见。4. 针对超声图像的预处理与增强策略灰度一致性、mosaic 与尺度取舍超声波图像和自然图像在特征分布上有本质差别直接把 YOLOv5 默认的数据增强套上去短期看不出问题等模型上线面对真实超声设备时就会露馅。这一章说三个必须调整的点。4.1 灰度图的通道处理别让模型学到伪彩色特征超声原始图像是单通道灰度图数据集里存储的 PNG 可能是三通道的也可能是单通道的。如果训练集里混了两种通道数模型会学到“图像的 RGB 通道分布”这种无关特征换一台超声设备就失效。最简单的做法是统一转成三通道灰度再做归一化。import cv2 import os def normalize_grayscale(src_dir, dst_dir): os.makedirs(dst_dir, exist_okTrue) for filename in os.listdir(src_dir): if not filename.lower().endswith((.png, .jpg, .jpeg)): continue img cv2.imread(os.path.join(src_dir, filename), cv2.IMREAD_GRAYSCALE) # 将单通道灰度图复制为三通道保持维度兼容 img_3c cv2.merge([img, img, img]) cv2.imwrite(os.path.join(dst_dir, filename), img_3c) print(fProcessed: {filename} - shape {img_3c.shape}) # 示例对训练集做灰度归一化 normalize_grayscale(kidney_stone_dataset/images/train, kidney_stone_dataset/images/train_3c)这段代码把图像按灰度读取再复制成三通道明确告诉模型“颜色信息不存在三个通道只是兼容性填充”。对超声数据来说色调和饱和度没有物理意义而灰度图像的纹理和亮度梯度才是关键特征与其依赖 YOLOv5 自带的 HSV 增强引入无意义的颜色扰动不如从源头统一通道数。4.2 mosaic 增强要降低概率肝脏能拼结石不能切YOLOv5 默认开启 mosaic 数据增强每张训练图由四张图拼接而成。这个策略对自然场景很有效能增加目标上下文多样性但放到超声肾脏结石检测上反而有害结石的位置信息强烈依赖器官解剖结构mosaic 把四张超声图拼接后一个肾脏的上半截和另一个肾脏的下半截拼在一起模型学到的解剖上下文是扭曲的。我在训练这类医学小目标数据集时会单独降 mosaic 概率让模型在多数 epoch 里看到完整的原始图像。# hyp.kidney_stone.yaml 片段 mosaic: 0.3 hsv_h: 0.0 hsv_s: 0.0 hsv_v: 0.0 fliplr: 0.5上面这份超参数文件里mosaic 从默认的 1.0 降到 0.3同时把三个 HSV 增强全部置零。fliplr 的水平翻转可以保留因为肾脏左右对称翻转不破坏语义。垂直翻转不建议开超声扫查方向固定上下翻转后的图像在真实临床场景中不会出现开了只会增加无效的分布偏移。4.3 输入分辨率的选择640 起步1280 看显存超声波结石检测对输入分辨率很敏感因为结石是典型的强回声小目标。640 分辨率下一个直径 8mm 的结石如果占图像宽度 1/20对应的像素宽度只有 32 像素属于中等偏小目标YOLOv5s 勉强能处理如果你发现统计脚本算出的框均宽低于 0.03也就是 640 下不足 20 像素就要把 imgsz 提到 960 或 1280。分辨率提升带来两个问题显存占用翻倍训练速度明显下降。一个折中做法是先用 640 把迁移学习做扎实再用 960 微调 20 到 30 个 epoch这样既稳住了收敛曲线又保住了小目标的细节信息。微调阶段记得把学习率降低 10 倍否则容易震荡。5. 避坑与常见问题数据泄漏、标签漂移、mAP 虚高这几道坎医学图像数据集训练翻车往往不在模型而在数据本身。下面这几条是我反复踩过的坑每一条都按现象、原因、解决三步说明训练前对照着排查一遍能省很多无谓的时间。5.1 验证集 mAP 高达 0.95换一台超声设备直接失灵现象训练集的验证 mAP 接近 0.9模型在测试集上表现惊艳可一旦在真实超声设备的新扫查画面上跑漏检和误报同时飙升。原因超声数据集的典型问题是同一病人的连续帧同时混入了训练集和验证集。扫查时保存的几十帧图像只有轻微的运动差异在模型眼里几乎是同一张图这等于把测试答案提前塞进了训练集属于数据泄漏。解决检查数据集中是否存在同一病人编号的图像同时出现在 train 和 val 目录。我一般会写一个脚本从文件名提取病人编号统计编号分布发现重叠就手动把整个病人的图像整体挪到训练集或验证集保证验证集中不会出现训练集见过的病人。医学数据按病人划分而不是按帧划分这条规则要刻在脑子里。5.2 训练到一半 loss 出现 NaNloss 直接崩溃现象前几十个 epoch 训练正常突然某个 epoch 的 box_loss 跳成 NaN之后指标全部归零。原因超声图像中偶尔会有极端标注——比如标注框宽度为 0、或者框超出图像边界。YOLOv5 在计算 GIoU loss 时遇到这种非法框梯度就会变成 NaN。另一个高发原因是某个标签文件里混入了类别 ID 超出范围的数字比如类别数是 2标签里却出现了 ID 5。解决训练前强制清一遍标签。检查每个 TXT 文件中坐标是否在 0~1 之间、宽高是否大于 0、类别 ID 是否小于 nc。遇到异常行直接删除并记录文件名训练结束后可以人工复查这些被清洗掉的样本。def clean_labels(label_dir, num_classes2): issue_count 0 for filename in os.listdir(label_dir): if not filename.endswith(.txt): continue filepath os.path.join(label_dir, filename) with open(filepath, r) as f: lines f.readlines() valid_lines [] for line in lines: parts line.strip().split() cls_id int(float(parts[0])) cx, cy, w, h map(float, parts[1:]) if cls_id num_classes or w 0 or h 0: issue_count 1 continue if not (0 cx 1 and 0 cy 1): issue_count 1 continue valid_lines.append(line.strip()) with open(filepath, w) as f: f.write(\n.join(valid_lines)) print(fCleaned {issue_count} invalid annotations in {label_dir}) clean_labels(labels/train)这个脚本会自动剔除非法标注行保留有效数据。清洗后再跑同样的训练NaN 问题基本不会出现标签的脏数据是超声数据集里最常见也最容易忽略的根因。5.3 验证集 mAP 不低Recall 却只有 0.5 左右现象训练结束打印的 mAP0.5 有 0.85看起来能用但查看 Recall 指标只有 0.5 上下大量结石样本根本没被模型召回。原因mAP 的数值同时受 Precision 和 Recall 影响如果类别不平衡——比如 kidney 类样本数量远多于 stone 类——模型会在多数类上学得很好少数类则倾向于保守预测宁可漏掉也不敢错检导致 Recall 偏低。解决训练时给少数类加大 loss 权重或者用过采样策略。在 YOLOv5 中可以直接修改损失函数的类别权重参数让 stone 类的正样本贡献更大的梯度。更省事的做法是先用当前模型跑一遍验证集把漏检的图像挑出来看如果漏检集中在小尺寸结石上优先提升输入分辨率而不是调权重。5.4 显存不足OOM 反复出现batch 降到 4 还是崩溃现象训练命令执行后爆出 CUDA out of memory把 batch 降到 4 依然报错。原因超声图像分辨率偏高如果数据集原图是 1024×1024 而你没有在训练时强制 resizeYOLOv5 会按--img参数缩放这个一般不占显存。真正吃显存的是默认开启的 cache 选项和 mosaic 拼接。另外如果同时跑着 TensorBoard 或者其他模型显存分配也可能不足。解决训练命令加--cache改成不缓存或者直接不加。检查后台是否有其他进程占用 GPUnvidia-smi看一下显存分配情况。如果确认没有别的进程抢显存就把 batch 设为 8同时把--workers降到 4减少数据加载线程的内存开销。6. 验证技巧用混淆矩阵和 PR 曲线决定阈值训练结束不代表项目结束医学图像模型上线的关键在于找到合适的置信度阈值而这个阈值不应该拍脑袋定。跑完验证集后YOLOv5 会在结果目录下生成 confusion_matrix.png 和 PR 曲线图这两张图就是定阈值的依据。python val.py \ --data data/kidney_stone.yaml \ --weights runs/kidney_stone/exp_baseline/weights/best.pt \ --img 640 \ --conf 0.25val.py 会遍历验证集按置信度从高到低排列预测结果得到完整 PR 曲线。我一般先看一下类别各自的 Recall 在什么置信度下开始急剧下降然后选择曲线膝盖位置对应的 conf 阈值——既能保证不漏检又不会让误报满天飞。对于超声结石检测我的习惯是把置信度阈值压到 0.15 到 0.2宁可多几个人工复核的框也不放过小结石医学场景漏检的代价远大于多余框的代价。定完阈值后再做一次批量可视化推理把预测框画到原图上几张图拼成一张大图。超声图像灰度背景下的可视化效果很直观框能叠在强回声团上说明模型确实学到了声学特征而不是在瞎猜。我过去有一个项目就是靠这批可视化图说服医生复核标注数据的——把结石的框和真实声影位置比一比哪些标注偏了哪些框压在伪影上一眼就能看出来。从那以后我拿到任何超声类数据集都会强制走一遍按病人划分训练验证集、清洗标签坐标、统计框分布、可视化抽查预测结果四步做完才允许自己动训练命令。这套流程救过我很多次希望也能帮到你。本文还有配套的精品资源点击获取
返回列表