尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

YOLOv5骨龄检测实战:从数据预处理到部署避坑全解析

发布时间:2026/9/28 16:40:16

资讯中心
01
ARTICLE

YOLOv5骨龄检测实战:从数据预处理到部署避坑全解析

YOLOv5骨龄检测实战:从数据预处理到部署避坑全解析
简介一套基于Python和YOLOv5实现的骨龄检测项目资料面向毕业设计、课程设计及项目开发场景适合有一定深度学习基础、希望快速掌握目标检测在医疗影像中如何落地的读者。压缩包共25个文件其中20个为Python源码涵盖模型结构定义、训练流程、单图预测、数据加载、数据增强、损失计算、评估指标与可视化等模块另有Markdown项目说明、依赖清单、Git忽略规则及YAML/TOML类配置文件用于环境配置与运行参数调整整体体积仅95KB结构紧凑便于快速定位关键脚本。项目沿用YOLOv5标准工程组织方式models、utils等目录职责明确预测脚本与训练流程相互独立使用者可根据随附md文档指引获取数据模型、数据集与预训练权重完成骨龄检测的训练或推理验证。源码已经过严格测试可直接作为毕业设计或课程设计的起点也适合在此基础上做改进和延伸。目前已有107人浏览学习对于需要从零搭建YOLOv5医疗识别流程的开发者而言是一份实用的参考资源。1. 骨龄检测没有想象中那么玄一个 YOLOv5 资源包就能起跑手骨 X 光片的骨龄检测过去是放射科医生的专属活计一张左手腕正位片要对着图谱逐块比对骨化中心的发育程度费眼不说不同医生之间的判读偏差能到一到两岁。换用目标检测的思路之后事情就拆成了两步先用 YOLOv5 把关键骨骼区域或骨化中心定位出来再在检测结果上做回归映射把「定位」和「年龄」分开解决。这套基于 Python YOLOv5 的骨龄检测资源包把数据组织、预处理、训练、权重文件与可视化串成了一条完整流水线源码经过测试可以直接跑通。正在选毕业设计或课程设计题目的学生以及想快速上手医学影像检测的从业者都适合先跑通这套再改造成自己的任务。2. 为什么用 YOLOv5 做骨龄检测选型理由与资源包文件解剖2.1 为什么是 YOLOv5生态成熟度压倒一切做骨龄检测可选的路线其实不少。早年间有人用传统图像处理对 X 光片做边缘检测、形态学开闭运算再数骨化中心的数量这种方案对拍摄角度和曝光条件极其敏感换一批图就失效调参基本靠玄学很难当成一个稳定的课程设计交上去。后来分类网络流行很多人直接把整张 X 光片丢进 ResNet 回归骨龄好处是端到端坏处是模型完全是个黑匣子你看不到它到底在关注哪个区域出错了也没法解释放到毕设答辩里很容易被评委追问「你的模型依据是什么」。检测网络在这两条路之间取了一个折中先把目标区域框出来再做后续判断中间结果可解释。YOLOv5 被选作检测骨架最核心的理由不是精度指标多好看而是生态成熟度。相比 YOLOv8 和 YOLOv11v5 的训练、推理、转 ONNX、部署资料全网最多遇到问题搜一下就有对应的踩坑记录这对时间有限的毕设和课设来说是实打实的后悔药。它的显存占用也比较友好单张消费级显卡就能把上百轮的训练跑完不需要去借昂贵的算力。此外YOLOv5 的工程结构非常规整train.py、detect.py、export.py 这些入口都是现成的资源包里的 utils 和 models 目录可以直接复用项目特有的部分只要集中在预处理和数据集组织上改动面很小。当然选型也要看边界。YOLOv5 本质是一个目标检测器它输出的是一堆框、类别和置信度并不会直接给一个连续的年龄数值所以「骨龄」这个回归问题必须放在检测结果之上再做一层处理。这一点是整个资源包真正的技术含量所在也是后文第 4 章要展开的内容。先把这个定位搞明白再动代码思路才不会乱。2.2 资源包解剖哪些文件要改、哪些可以直接躺平拿到压缩包解压后不要急着运行先花十分钟对着文件结构过一遍。Bone_Age_Predict-main 表面上是标准 YOLOv5 工程的骨架实际上只有少数几个文件是为骨龄检测定制的认清楚哪些是官方通用件、哪些是项目特有件能省下大把瞎折腾的时间。整个包可以分成四类。第一类是官方 YOLOv5 的基础设施集中在 utils 和 models 目录下。utils 里有 loss.py、metrics.py、autoanchor.py、dataloaders.py、augmentations.py 这一批文件分别管损失计算、评估指标、anchor 重算、数据加载和数据增强。这些文件在训练和推理时被主脚本自动调用基本不用碰。models 下是网络结构定义common.py 放基础模块yolo.py 放 Detect 检测头如果你要把类别数改成自己的骨化中心类别数改数据集配置就行结构文件不需要动。第二类是项目特有的预处理入口 Bone-pre.py这是整个资源包里最值得读的脚本之一。原始 X 光片不可能直接送进 YOLOv5 训练需要统一尺寸、归一化、划分训练集和验证集还要把标注转成 YOLO 要求的 txt 格式Bone-pre.py 干的就是这件事。毕设里如果要换自己的数据集这个文件就是主要修改对象。第三类是可视化配置 .streamlit/config.toml说明作者预留了 Streamlit 网页展示的配置入口这也是答辩时能拿出来演示的部分。剩下的 .github/workflows、requirements.txt、README.md 和 .gitignore 属于通用件README 和 requirements 先读其他知道存在即可。下面这张表把各部分角色和需要动手的程度标一下照着这个顺序读文件效率最高。文件/目录在项目里的角色需要动的程度Bone-pre.py数据预处理与数据集划分换数据集时常改utils/ 下脚本训练与推理基础设施默认不动models/ 下脚本网络结构定义通常不动.streamlit/config.toml网页演示服务配置按需调整requirements.txt依赖清单按环境微调README.md / 项目文档运行说明与技术细节先通读2.3 跑通之前先理解数据流向从数据流的角度看这套工程链条是这样的原始 X 光片经过 Bone-pre.py 处理后变成 images 和 labels 配对的训练目录train.py 读取 data 配置里指定的 yaml加载图片和标注开始训练训练过程中 utils/metrics.py 计算每一轮的 mAPutils/autoanchor.py 在训练启动前会重算适合当前数据集的 anchor训练结束后在 runs/train/exp 下得到 best.pt 权重最后 detect.py 或者 Streamlit 界面加载权重做推理展示。理解了这条主线后面每一步操作就只是在把对应环节跑起来出了问题也能顺着数据流快速定位到具体环节。值得注意的一点是这个资源包没有对官方 YOLOv5 的入口脚本做二次封装train.py 和 detect.py 用的就是原版命令。这样做的最大好处是网上搜到的 YOLOv5 教程里的命令、参数、报错解决方案都能直接套用不需要为项目特有写法额外换算。坏处也很明显如果只看 README 就动手很容易忽略 Bone-pre.py 这个数据入口直接从训练命令开始跑结果就是数据集格式不对训练立刻报错。所以拿到资源包第一步永远是先跑预处理脚本而不是先跑训练。3. 把环境跑通conda 配置、预处理脚本与第一张推理图3.1 conda 环境与 requirements.txt 的正确打开方式python 环境的坑往往不在 Python 本身而在 torch 与 CUDA 的版本搭配上。常见做法是先用 conda 建一个独立环境避免把系统 Python 搞乱然后进项目目录按 requirements.txt 安装依赖。推荐创建 Python 3.8 的环境这个版本对 YOLOv5 和旧版 torch 的兼容性最好升到 3.10 以上容易遇到某些算子编译不过的问题。conda create -n boneage python3.8 -y conda activate boneage cd Bone_Age_Predict-main pip install -r requirements.txt解释一下每行干了什么conda create 是新建一个名为 boneage 的隔离环境python3.8 指定解释器版本-y 表示跳过确认直接创建conda activate 进入这个环境后续所有包都装在这里不会影响其他项目cd 进入项目根目录pip install -r requirements.txt 按清单一次性装齐依赖。装完后先别急着跑训练用 python -c import torch; print(torch.cuda.is_available()) 检查一下 CUDA 是否可用如果输出 False说明 pip 装到了 CPU 版 torch训练速度会慢一个数量级。如果遇到这个问题常规做法是把 torch 和 torchvision 换成对应 CUDA 版本的安装包。这里给一个常用的安装方式CUDA 11.8 及以上的显卡驱动一般都能覆盖pip uninstall torch torchvision -y pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118这个命令先用 pip uninstall 把 CPU 版 torch 和 torchvision 卸载干净再通过 --index-url 参数指定 PyTorch 官方 CUDA 11.8 的 wheel 仓库安装 GPU 版。需要注意的是cu118 指的是 CUDA 11.8 运行时只要显卡驱动版本够新就能用不需要你单独装一套 CUDA 工具包这也是对新手最省事的方式。装完再执行一次上面那条 CUDA 检查命令确认输出为 True 再继续。3.2 预处理脚本 Bone-pre.py 做了什么环境就绪后的第一件事不是训练而是跑 Bone-pre.py。这个脚本负责把原始 X 光片整理成 YOLOv5 能直接消费的数据集结构包括统一图像尺寸、处理像素范围、按比例划分 train/val以及把标注信息转成 YOLO 格式的 txt 文件。如果你用的是资源包自带的数据集和权重这一步可以跳过直接做推理但如果你打算换自己的 X 光片数据这里就是第一个要改的脚本。python Bone-pre.py \ --data_dir ./datasets/raw \ --out_dir ./datasets/processed \ --split 0.8三个参数需要说明一下。--data_dir 是原始图像所在目录脚本会扫描这个目录下的所有图片--out_dir 是处理后数据的输出目录训练和推理时指向的就是这里--split 表示训练集划分比例0.8 意味着 80% 的图片进 train、20% 进 val。实际使用时如果你的数据量很小建议把 split 调到 0.9多留一点训练样本但要注意验证集的代表性如果数据量大0.8 就够。跑完之后去 out_dir 检查一下目录结构是否生成了 images 和 labels 两个分支train 和 val 是否都有内容不要急着往下走。这里有一个判断预处理是否正常的土办法随便打开 out_dir 里的一张训练图再看同名的 txt 标注内容。如果图片上能明显看到骨骼结构、txt 里每行是「类别 x_center y_center width height」五个数字且都在 0 到 1 之间说明预处理没问题如果图片一片黑或者 txt 内容为空说明读图或标注转换出了问题先修这里再往下走否则训练出来也是一个无效模型。3.3 用自带权重跑一次推理预处理验证完毕就可以用资源包自带的权重跑一次完整推理目的是验证整个链路是通的也顺便看看模型预测骨化中心的效果。detect.py 是 YOLOv5 官方入口脚本直接复用即可。python detect.py --weights best.pt --source ./datasets/processed/val/ --imgsz 640 --conf-thres 0.25 --save-txt --save-conf逐项拆解--weights 指定权重文件路径best.pt 通常是训练过程中验证集表现最好的那一轮权重放在 runs/train/exp/weights 目录下--source 指定输入来源可以是一个图片文件、一个目录也可以是摄像头设备号这里直接用验证集目录一次跑一批--imgsz 是推理时的输入尺寸640 是 YOLOv5 的常用配置X 光片分辨率高的话可以提到 960 试试代价是推理变慢--conf-thres 是置信度阈值0.25 表示只保留置信度大于 25% 的框--save-txt 和 --save-conf 分别表示把检测结果存成 txt 文件并在里面附带置信度后面做后处理时会用到。跑完去 runs/detect/exp 目录看结果里面会生成带检测框的标注图。这时要看的是三个东西第一框是否准确套在骨骼区域上而不是满屏乱框第二置信度普遍有多高如果大部分低于 0.3说明权重与数据风格不匹配需要重新训练第三检测到的区域是否覆盖了你关心的骨化中心位置。如果这三项都正常说明资源包在自带数据上完全可用接下来就可以考虑用自己的数据训练了。4. 训练自己的骨龄数据集目录组织、超参数与回归衔接4.1 数据集怎么组织images、labels 与 train/val 划分YOLOv5 对数据集的目录结构有硬性要求images 和 labels 必须平行存在训练图和标注 txt 一一对应常见的组织方式如下datasets/processed/ ├── images/ │ ├── train/ │ ├── val/ ├── labels/ │ ├── train/ │ ├── val/labels 目录下的每个 txt 与 images 下的图片同名一行对应一个目标框格式是「class_id x_center y_center width height」五个值全部归一化到 0 到 1 之间。class_id 从 0 开始计数对应你在 yaml 里定义的类别顺序。骨龄检测场景里类别一般不是年龄而是不同的骨化中心或骨骼区域编号比如 0 表示桡骨远端、1 表示尺骨远端、2 开始是各块腕骨。很多人第一次做会误把年龄直接当类别这是概念上的偏差YOLOv5 的分类头只能区分目标种类不能输出连续数值年龄要在检测之后单独算。数据配置需要单独写一个 yaml 文件常见做法是在项目根目录下建一个 bone.yaml内容类似这样path: ./datasets/processed train: images/train val: images/val nc: 6 names: [radius, ulna, carpal1, carpal2, carpal3, carpal4]path 是数据集根目录train 和 val 是相对这个根目录的图片路径nc 是类别总数必须和 names 列表长度一致names 是类别名顺序要与标注 txt 里的 class_id 对应。这个文件是 train.py 唯一的数据入口改数据集时先核对这三项再核对你标注里的 class_id配错的后果是训练不报错但 mAP 永远上不去这是最容易翻车又最难排查的问题之一。4.2 训练命令与超参数怎么设数据配好后训练命令本身并不复杂复杂的是超参数怎么选。对于骨龄检测这种医学影像任务目标区域在整张图里占比较大、背景相对干净和 COCO 数据集的小目标场景完全不同所以超参数不能照搬默认值。python train.py --data bone.yaml --weights yolov5s.pt --epochs 100 --batch-size 16 --imgsz 640 --device 0这个命令里--data 指向刚写好的 bone.yaml--weights 用官方预训练权重 yolov5s.pt 做迁移学习初始化而不是从零训练能显著加快收敛--epochs 100 是训练轮数--batch-size 16 和 --imgsz 640 是显存占用的两个大头--device 0 表示用第一块 GPU。如果你是第一次跑这个数据集我强烈建议先把 epochs 改成 10 跑一个小实验确认 loss 在下降、mAP 在上涨再回来跑全量这是性价比最高的验证方式能避免在错误的数据配置上浪费几十个小时。显存有限的情况下优先保 imgsz 而不是 batch-size。医学影像的骨骼结构比较大缩到 320 会丢失细节影响精度但 batch-size 从 16 降到 8 对最终精度影响很小。所以遇到显存不够先把 batch-size 减半实在不行再降 imgsz。下面给一组不同显存下的参考配置显存batch-sizeimgsz说明6 GB4640训练慢但可接受8 GB8640毕业设计常用配置12 GB16640收敛更平稳24 GB16960高分辨率微调可选另外一个常见误区是盲目加大训练轮数。骨龄检测数据集通常不会特别大几十轮之后 mAP 就可能进入平台期继续训练反而过拟合。判断标准很简单观察训练日志里 val 的 mAP 是否连续 20 轮不再上涨如果是就可以停了不用硬跑满配置的轮数。这也解释了为什么资源包强调「源码经过测试」因为训练这件事有一半时间花在等待上先用小实验跑通流程比一上来就拉满参数要稳妥得多。4.3 从检测框到骨龄YOLOv5 之外的那一步YOLOv5 训练完你手里有一个能框出骨化中心的检测器但骨龄这个最终输出还没算出来。常见的做法是两阶段处理第一阶段用训练好的权重检测骨骼区域把每个框对应的区域裁剪出来第二阶段把这些区域作为输入交给一个回归模型或者查表逻辑输出骨龄数值。下面这段示意代码演示了第一阶段的结果如何保存和整理为回归做准备import cv2, glob, numpy as np # 遍历检测结果 txt读取每个框的坐标 for txt_path in glob.glob(runs/detect/exp/labels/*.txt): img_path txt_path.replace(labels, images).replace(.txt, .jpg) image cv2.imread(img_path) h, w image.shape[:2] with open(txt_path, r) as f: for line in f: cls, xc, yc, bw, bh map(float, line.split()) # 归一化坐标换算回像素坐标 x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) roi image[y1:y2, x1:x2] # 统一尺寸后送入骨龄回归网络或查表模块 roi_resized cv2.resize(roi, (112, 112)) cv2.imwrite(froi/{cls}_{x1}_{y1}.jpg, roi_resized)这段代码的逻辑是读取 detect.py 保存的推理结果 txt从归一化坐标换算出像素级的框位置裁剪出每个骨化中心区域并统一缩放到 112×112。注意归一化到像素的换算要乘以图片宽高这里的 h、w 来自原图读出后的实际尺寸不能写死。裁剪出的 roi 就是第二阶段回归模型的输入。如果数据量小第二阶段完全可以用一个简单的线性回归或小 CNN 实现把骨龄输出当作连续值拟合训练成本很低却是整个项目里最能体现「你理解这个任务」的部分答辩时值得多讲几句。5. 避坑记录跑骨龄检测时最容易翻车的五个现场5.1 训练一半 OOMbatch-size 与 imgsz 的取舍现象train.py 跑到第二个 epoch 就报 RuntimeError: CUDA out of memory进程直接死掉前面几轮白跑了。原因batch-size 和 imgsz 的乘积超出了显存上限X 光片本身分辨率高不像自然图像那样在加载时自动缩小。解决先用 nvidia-smi 确认显存大小把 batch-size 降到 8 甚至 4imgsz 从 640 降到 480。骨龄检测的目标区域占比大480 输入也够用精度损失很小。另外跑训练前把浏览器、IDE 这类吃显存的应用关掉能省出几百 MB 显存。5.2 权重加载报错missing keys 与 unexpected keys现象训练启动时日志里出现大量 missing keys 或 unexpected keys甚至直接 KeyError 中断推理时加载权重报错。原因官方预训练权重是在 COCO 80 类上训练的而你改了类别数检测头的权重形状不匹配另一个常见原因是 torch 版本升级后旧格式权重序列化方式不兼容。解决训练时用 --weights yolov5s.pt 做迁移学习官方代码会自动裁剪掉不匹配的检测头推理时优先用资源包自带的 best.pt不要随手从网上下个权重就拿来用。如果旧权重在 torch 2.x 下加载报错检查一下 torchvision 版本是否配套通常统一升级或统一降级就能解决。5.3 mAP 一直上不去标注规范与 anchor 玄学现象训练几十轮mAP50 停在 0.3 以下val loss 不降反升但训练集 loss 一直在降。原因最常见的是标注 txt 里的 class_id 和 bone.yaml 里 names 的顺序对不上模型学了半天在学错误映射其次是骨化中心区域小、框标注不精准导致正样本质量差。解决先用可视化脚本把标注框画到图上逐个检查确认每个框是否贴合目标然后跑一次 utils/autoanchor.py 让 YOLOv5 根据你的标注重新计算 anchor而不是沿用 COCO 的默认值最后检查 data 配置里 nc 是否正确。这三步做完mAP 一般会有明显改善。5.4 预处理后图片发黑BGR 与 RGB 的通道刺客现象Bone-pre.py 处理完的图像整体发黑或者颜色怪异偏绿推理时框的位置大致对但置信度很低。原因X 光原图可能是 16 位灰度 PNG 或 DICOM 格式直接用 cv2.imread 按 8 位读会把高动态范围截断导致大部分像素落在暗部另一个坑是 OpenCV 读入顺序是 BGR而 PyTorch 训练时用的是 RGB通道顺序不一致会让模型感知到异常的颜色分布。解决读图后先把像素用 np.clip 截断到 0 到 255 再转 uint8必要时做窗宽窗位调节增强对比度图像送入模型前统一用 cv2.cvtColor 转成 RGB可视化保存结果时再转回 BGR。5.5 Streamlit 页面起不来端口占用与 config.toml现象streamlit run 命令执行后终端没有报错但浏览器一直转圈或白屏换一台电脑又正常。原因.streamlit/config.toml 里固定了端口这个端口被其他进程占用Streamlit 启动失败但提示不明显。解决先看终端输出里的端口号然后用 lsof -i:8501 或 netstat 查占用情况临时绕过配置直接启动时指定端口streamlit run app.py --server.port 8502这样会用命令行参数临时覆盖 config.toml 里的设置不修改原文件。如果你的自定义 config.toml 里配了 theme 或 headless 之类的选项仔细检查一下语法TOML 文件对格式要求严格多一个逗号都会导致整个配置失效。6. 把结果变成答辩素材Streamlit demo 与 ONNX 导出做了这么多训练和调参最终还是要落到「能拿出来演示」这一步。资源包里的 .streamlit/config.toml 已经预留了 Streamlit 的服务配置顺着这个入口做一个简单的可视化界面答辩时现场上传一张手骨 X 光片几秒内看到检测框和骨龄结果比甩一张训练曲线图直观得多。Streamlit 的启动不复杂核心是把检测逻辑封装成一个函数再用 st.file_uploader 接收图片生成结果后显示出来。config.toml 里配好的主题和端口能让整个界面看起来更正式省去现场调样式的尴尬。另一个值得做的准备是导出 ONNX 模型。YOLOv5 的 export.py 就是干这个的一条命令就能把 PyTorch 权重转成通用的 ONNX 格式python export.py --weights best.pt --include onnx --opset 11--opset 11 是兼容性比较好的算子版本选择ONNX 模型可以用 onnxruntime 在 CPU 上推理也可以进一步转成 TensorRT 做 GPU 加速。这对接下来的部署工作是一个很好的铺垫也让项目的技术栈显得更完整。有了 ONNX 模型即使答辩环境没有 GPU也可以用 CPU 跑出可接受的推理效果这是最实在的保底方案。整个项目走到这一步你会发现真正麻烦的从来不是模型本身而是数据怎么组织、预处理怎么写、踩坑怎么绕过。我每次拿到一个新的骨龄数据集都会强制自己走一遍先用最小轮数跑通流程再可视化检查标注分布最后才拉长训练时间这个习惯帮我避开了不少无效训练和深夜返工希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。