YOLOv5实战:超声波肾脏结石检测数据集训练与调优全流程

发布时间:2026/8/27 1:32:02
YOLOv5实战:超声波肾脏结石检测数据集训练与调优全流程 简介目标检测是计算机视觉中应用最广泛的技术之一其核心在于同时完成目标定位与分类。YOLOv5作为经典的一阶段检测框架凭借推理速度快、部署灵活的特点在工业与医学影像分析中备受青睐。医疗影像数据具有灰度单一、噪声高、目标尺度小等特殊性直接使用通用训练流程往往无法获得理想效果。本文从超声波肾脏结石检测场景出发系统梳理了基于YOLOv5的数据集校验、YAML配置、超参数调整、模型训练与验证指标解读的完整实践路径。重点讨论超声图像黑色扇形区域干扰、小目标漏检、类别不平衡等实际工程问题并给出基于mAP、recall等指标的效果优化策略。无论你是刚接触目标检测的初学者还是正在开展医学图像分析的研究者都能从中获得可复用的工程经验。 做医疗影像目标检测我一直觉得数据比模型更重要。一个超声波肾脏结石检测的YOLOv5数据集2个类别训练集验证集都给好了看着省事但真正跑起来还是有不少门道。这篇文章我就把自己从拿到数据集到训练验证完的整个过程梳理一遍包含数据怎么检查、YAML怎么写、超参数怎么调、验证结果怎么看以及超声影像这种特殊数据会遇到的坑。不管你是刚接触YOLOv5的初学者还是已经在做医学图像检测的同行这篇文章应该都能给你一些参考。1. 超声波肾脏结石检测任务的整体拆解1.1 2类别到底指什么拿到数据集第一件事不是急着训练而是先搞清楚类别定义。标题里写的是2类别结合超声波肾脏结石检测这个场景比较常见的标注方案是两类目标一类是肾脏kidney一类是结石stone或者一类是结石另一类是正常肾脏组织。我接触过的类似医疗超声数据集大多数时候类别是kidney和stone。为什么要这样设因为这就是一个检测任务模型需要先在图像里定位肾脏区域再在肾脏内部或周围找到结石如果只标注结石一类模型容易把其他强回声结构误判成结石增加一个肾脏类别相当于给了模型一个上下文约束。还有一种情况是类别名称为stone和normal后者代表没有结石的肾脏图像或区域。这种设置适合做分类辅助检测但YOLOv5是目标检测框架如果用normal做类别意味着需要标注大量正常区域作为负样本反而降低了训练效率。我的建议是拿到数据集后先打开类别文件确认名字再决定是直接用还是稍微调整一下标注策略。1.2 训练集与验证集划分背后的逻辑这个数据集已经帮你分好了训练集和验证集省了一步但我要提醒一点划分方式比划分比例更关键。医疗影像数据和自然图像不一样一个患者可能有多张超声图像如果划分时不按患者分组同一个人的图像可能一部分进了训练集一部分进了验证集。这样训练的时候模型已经见过这个患者验证时再遇到自然表现得很好指标虚高但真正部署到新患者身上效果就会大打折扣。一般常见做法是训练集、验证集按7:2或8:1:1的比例划分。但如果数据集是严格按患者或者按病例视频帧来组织的我更建议人工复查一下划分结果。怎么复查把验证集的图片路径和训练集的图片路径做一次交叉比对看看有没有文件名前缀相同的情况如果有说明划分不够严谨。你也可以通过读取文件名中的患者ID字段重新生成一个按ID划分的train.txt和val.txt这是最稳妥的做法。2. 数据集的构成、标注细节与质量检查2.1 超声波影像数据集的核心特征超声图像和普通相机拍的照片完全是两回事模型在这类数据上的表现很大程度上取决于你怎么理解它的特性。第一超声图像是灰度图虽然文件可能是三通道的PNG或JPG但实际上颜色信息基本没用。YOLOv5在加载图像时会做归一化但三通道彩色图和单通道灰度图的处理效率还是有差别所以如果你有能力可以先把图像统一转成灰度再复制到三个通道或者直接在加载时用cv2.imread(..., 0)处理。第二图像里存在大量黑色区域。B超探头扫描出来的区域通常是扇形画面四周是纯黑的无效区域。这些黑色区域对检测没有帮助但会占用计算资源也会让模型的注意力被分散。我看到不少人直接把整张图喂进去训练结果模型学到的特征里混入了黑色背景判断这种奇怪的东西。合理的做法是先用掩膜把扇形区域外的部分置为固定值比如0或128或者直接在读取后裁剪出有效区域。第三超声图像噪声大、对比度低。结石在超声图像里通常表现为强回声伴后方声影边界往往不清晰所以标注框的大小和位置在不同标注者之间可能差异很大。这个数据集的标注是否准确直接决定了最终模型的上限。2.2 标注格式与数据校验要点YOLOv5使用的标注格式是txt文件每行对应一个目标框格式为class_id x_center y_center width height其中坐标值是相对于图像宽高的归一化值范围0~1。比如图像宽度是800像素某个框的中心点x坐标是400像素那么x_center就是0.5。我在拿到数据集后第一件事就是写脚本检查标注是否越界、是否出现负数、是否有多余空行。常见的错误包括坐标数值超过了1.0宽度或高度为0类别ID超出了类别总数文件名与图像名对不上等。YOLOv5训练时遇到这些错误通常不会直接报错退出而是会跳过或产生奇怪的loss曲线排查起来很费劲。另外要检查的是类别平衡情况。用脚本统计每个类别在训练集和验证集中的标注框数量如果两类数量悬殊比如stone有3000个框kidney只有800个框模型训练时会更倾向预测数量多的那个类别。YOLOv5本身有类别损失权重调整但数据分布不均的时候还是建议手动调整cls_pw超参数或者做针对性增强。2.3 数据量分布与预处理的实操建议假设这个数据集训练集有几百到上千张图像验证集占20%左右。这个规模在医学影像领域并不算大所以数据增强策略就显得特别重要。YOLOv5内置的增强是比较完善的默认开启了马赛克、随机仿射、HSV扰动、水平翻转等。但对于超声图像我会做两个调整第一关闭或降低颜色扰动因为超声图像的灰度分布是诊断信息的一部分过度改变色调反而会让模型学到虚假特征第二适当提高mosaic的启用概率因为超声图像背景相对单一马赛克增强能让模型在多个目标组合场景下更鲁棒。至于图像分辨率超声原图一般是640x480或者800x600左右YOLOv5默认输入是640x640基本够用。如果检测的结石比较小可以试试把输入尺寸提到960或1280但要注意显存开销会成倍增加。3. YOLOv5训练配置与完整实操流程3.1 环境准备与依赖安装YOLOv5的环境安装其实不复杂核心就两个东西PyTorch和YOLOv5仓库的依赖。建议用Python 3.8以上、PyTorch 1.12或2.x版本CUDA版本根据显卡驱动选即可。git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt如果国内网络下载太慢可以把requirements.txt里的torch和torchvision单独安装或者用镜像源。我个人习惯是先装好PyTorch再装其他依赖避免pip自动装一个不匹配的CPU版本。安装完成后可以快速跑一下python detect.py --weights yolov5s.pt --source data/images/bus.jpg能正常输出检测结果就说明环境没问题。这一步很值得做不然训练到一半发现CUDA不可用再排查环境问题会很被动。3.2 数据集YAML配置与超参数选择YOLOv5训练时需要指定一个数据集配置文件格式是YAML。这个文件路径不对后面全白搭。# kidney_stone.yaml train: /data/kidney_stone/images/train val: /data/kidney_stone/images/val nc: 2 names: 0: kidney 1: stone注意三点第一train和val指的是图片所在目录YOLOv5会自动在同级目录下找对应的labels文件夹第二nc一定要和names的数量一致类别ID从0开始第三路径建议用绝对路径如果相对路径写错了训练会报错AssertionError: train: ... does not exist。超参数方面YOLOv5提供了数据增强、损失权重等参数全部存在data/hyps/hyp.scratch-low.yaml和hyp.scratch-high.yaml里。低增强版本适合小数据集高增强版本适合大数据集。小规模医疗影像我一般用hyp.scratch-low.yaml再手动改一两个参数比如把hsv_h从0.015改成0减少颜色扰动对超声图像的影响。3.3 训练命令与关键启动参数训练命令如下python train.py \ --data kidney_stone.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0 \ --name kidney_stone_run参数含义不复杂但有几个值得展开说。--weights yolov5s.pt用的是COCO预训练权重。你可能会问COCO和超声图像差这么远迁移学习有用吗实测下来还是有点用的尤其是骨干网络对边缘、纹理的基础特征提取能力可以帮你节省不少训练时间。如果训练过程中发现loss降不下去可以试试--weights 从头训练对比一下效果。--batch的大小取决于显存。12GB显存跑yolov5s配--img 640--batch 16基本没问题如果只有6GB显存就得降到--batch 8甚至--batch 4。推荐在训练时开启--cache参数把数据提前缓存到内存里能明显缩短每个epoch的数据加载时间。如果你的机器内存不够大就忽略这个参数。--epochs设100是为了让模型充分收敛。医疗小数据集在100轮的时候可能会开始过拟合所以我还习惯在命令行里加--patience 20让模型在20轮内没有提升就自动早停省时省力。3.4 训练过程的实时监控训练启动以后控制台会打印每个epoch的损失、精度、召回率、mAP同时会在runs/train/kidney_stone_run/下生成训练曲线图。我一般重点看两个东西Box_loss和Objectness_loss是否在稳定下降。如果这两个loss在训练集上下降但验证集上反而上升基本就是过拟合了这时候不是继续加大epoch而是应该增加数据增强、减小模型复杂度或者减少训练轮数。另一个值得看的是results.png里每个类别的mAP0.5曲线。如果两个类别的mAP差距大比如kidney已经跑到0.95但stone只有0.6说明模型对结石的检测能力不足。结石在超声图像里本身就是小目标形状又多变这种情况非常常见后面我会单独讲优化思路。4. 验证集评估与模型效果分析4.1 验证结果核心指标解读训练结束后YOLOv5会自动在验证集上评估模型输出precision、recall、mAP0.5和mAP0.5:0.95。这四个指标对医疗影像任务来说优先级不太一样。mAP0.5代表IoU阈值0.5时的平均精度是一个基础指标。如果这个值低于0.8说明模型整体检测能力还没起来需要检查数据标签、训练策略。mAP0.5:0.95代表多个IoU阈值下的平均精度对目标定位的准确性要求更高医疗场景中这个指标如果能到0.5以上就已经不错了。但在医疗应用中我更关注的是recall也就是查全率因为漏检一个结石在临床上比误检严重得多。YOLOv5的recall是在默认置信度阈值0.25下计算的如果你发现recall不高可以修改conf_thres在推理时降低到0.1提高检出能力容忍一些误检再交给人工复核。4.2 模型推理与后处理建议验证完成后用训练好的权重跑一张超声图像python detect.py \ --weights runs/train/kidney_stone_run/weights/best.pt \ --source /data/kidney_stone/images/val/xxx.jpg \ --conf-thres 0.1 \ --iou-thres 0.45 \ --save-txt其中--conf-thres 0.1是置信度阈值--iou-thres 0.45是NMS去重的IoU阈值。对超声图像置信度阈值可以比通用目标检测低一些因为超声影像对比度低模型天然的置信度普遍不如自然图像高。--save-txt会把检测结果保存成txt文件里面是class_id x_center y_center width height conf的格式。拿到坐标后如果你是做辅助诊断工具建议加一个过滤逻辑只保留stone类别且在kidney框内部的结石这样能有效减少肾脏外部强回声结构造成的误检。4.3 验证集badcase分析只看指标是不够的我每次训练完都会从验证集里挑出漏检和误检的图片一张张看。YOLOv5会把预测结果可视化到runs/val/exp/val_batch0_pred.jpg这些图上通常能直接看出问题所在。漏检的图片往往集中在结石较小或与周围组织对比度低的样本上。误检则经常出现在肾脏周围的骨骼、气体、钙化灶等强回声结构上。针对这些badcase有两种处理路径一是补数据专门收集这些难例二是调后处理比如用空间约束过滤掉肾脏区域以外的检测框。我个人经验是后者见效更快。5. 常见问题与踩坑实录5.1 训练集loss正常但验证集mAP上不去这个问题我遇到不止一次。训练集上loss一路下降曲线看起来很漂亮但验证集mAP一直徘徊在0.3到0.5之间。这种情况最常见的原因是标注噪声太大尤其是超声图像里结石边界本身就模糊不同人标出来的框差异很大。怎么验证把训练集中loss最高的那批图像可视化出来看标注框和图像内容是否对得上。如果发现部分框标偏了或者漏标了优先修数据而不是调模型。我见过有人为了追mAP反复调超参数最后发现是标签里混了几个类别标反的样本修完之后mAP直接涨了0.2。5.2 超声图像小目标漏检怎么办这是超声检测的经典难题。结石在图像里可能只占几十个像素特征又弱模型很容易漏。第一个方法是增大输入尺寸把--img从640改成960或1280相当于把小目标放大给模型看。这个方法简单直接代价是训练时间变长。第二个方法是做TTA测试时增强推理时对图像做多尺度变换然后合并预测结果python detect.py --weights best.pt --source xxx.jpg --img 960 --augment第三个方法是用SAHI这类切图推理工具把大图切成小图分别检测再拼接。超声图像长宽比接近1:1切图效果还行但要注意重叠区域的框去重问题。5.3 类别不平衡导致的结果偏移如果数据集中stone的框数量远少于kidney模型可能会倾向于把不确定的区域预测成kidney。YOLOv5在处理类别不平衡时可以通过--cls-pw参数调整类别损失的权重但更简单的做法是在后处理阶段单独调每类的置信度阈值。在detect.py里有一个conf_thres参数是全类别统一的。如果你想要kidney用0.25、stone用0.1可以在后处理代码里自己按类别分开判断。我自己写推理脚本时通常会读取txt结果再按类别设置不同的阈值这样比反复训练调参高效得多。5.4 扇形B超图像的黑色区域干扰开头提过超声图像有大量黑色无效区域。YOLOv5在做马赛克增强的时候会把四张图拼接在一起黑色区域会被当成正常图像内容混进来导致模型学到一些奇怪的背景特征。解决方法有两种。一是预处理时把扇形区域外的像素直接置为0并且保证所有图像在做归一化时黑色区域的值是一致的二是在数据增强阶段保留原始探头掩膜在训练时让模型只关注有效区域。对于常规的YOLOv5流程第一种更简单效果也立竿见影。不过要记住推理阶段同样需要做相同的预处理否则训练和推理的图像分布不一致性能会打折扣。5.5 训练集和验证集划分不合理有的数据集虽然给你分好了训练集和验证集但训练集里可能混入了同一患者的多张连续帧导致验证集和训练集之间存在高相似度的图像。前面说了这种情况会让验证指标虚高。如果遇到这种问题最稳妥的办法是重新划分。按照文件名里的患者ID把同一个患者的图像全部放到同一个集合。假设没有患者ID就按时间戳或视频序列来分。如果文件命名完全没有规律可以用图像感知哈希做去重把相似度超过阈值的图像只保留一张。这个方法在超声视频帧数据里特别实用。6. 实操心得与一点建议6.1 数据检查的重要性如果你只从这篇文章里记住一点我希望是拿到数据集后先花时间检查数据不要直接开训。我见过太多人上来就train.py最后模型效果不好回过头来才发现标签文件已经损坏了一大半。建议把下面这个检查流程固化成脚本检查每张图像是否有对应的txt文件检查每个txt文件的第一列类别ID是否在有效范围内检查所有框坐标能否在原图上画出来并把一部分样本可视化输出到目录里人工抽查。这些步骤加起来只需要几分钟但能帮你省下几个小时的排查时间。6.2 小模型的优势对于超声波肾脏结石检测这种相对单一的任务yolov5s基本够用yolov5n也值得一试。小模型训练速度快部署方便更重要的是在数据量不大的时候小模型不容易过拟合。我在一个几十个类别的工业项目里用过yolov5x效果反而不如yolov5m原因就是数据量撑不起那么大的模型容量。所以在医疗这种样本量普遍偏小的领域别迷信大模型。6.3 后续扩展思路这个数据集本身已经是一个完整的检测任务了后续可以做的扩展不少。比如换用YOLOv8或YOLOv11测试新框架的Anchor-Free机制在超声小目标上是否有提升也可以用TensorRT对训练好的模型做量化加速部署到床边超声设备上做实时辅助诊断。更深一层如果拿到的是连续视频帧还可以加上时序信息比如用跟踪算法或者轻量的时序模型把单帧检测结果在时间维度上平滑减少超声图像中伪影和噪声导致的闪烁误检。这个方向在临床落地时价值很大因为B超是动态检查医生看的是实时影像单帧检测的稳定性再高也不如多帧融合的效果自然。我在实际训练这个数据集时最大的感触是医疗影像和自然图像之间的鸿沟远远不止图像内容不一样这么简单。超声图像的信噪比低、目标尺度跨度大、标注标准很难统一这些都会潜移默化地影响训练过程。如果你已经准备好训练自己的肾脏结石检测模型建议从今天提到的数据检查、超声预处理、类别权重调整这几个方向入手每一步都做扎实了最后的模型效果一定不会差。最后分享一个小技巧训练结束后别急着删验证集图片周末没事的时候把预测结果翻出来再仔细看看很多时候你会从那些错误检测框里发现一个比调参更管用的突破点。本文还有配套的精品资源点击获取