基于YOLOv9实现人体姿态估计:从检测头改造到OKS调优实战
简介本资源面向计算机视觉方向的研究者、算法工程师与高校学生提供一套基于YOLOv9实现的人体姿态估计完整项目源码可用于安全监控、体育分析、人机交互、游戏娱乐及虚拟现实等场景下的关键点检测与动作理解。压缩包共188个文件约58.75MB以141个Python脚本为核心配合33个YAML配置、6张示例图片、3个Shell脚本、2份Markdown说明以及TOML、Dockerfile和预训练权重文件覆盖算法实现、参数配置、数据处理与部署流程。目前已有214人学习关注。项目不仅给出可运行的关键点定位代码还包含测试脚本与数据组织方式便于读者深入理解YOLOv9在姿态估计中的运作机制并在此基础上进行二次开发与改进兼顾理论先进性与实际场景中的健壮性、易用性和扩展性。1. 人体姿态估计遇上 YOLOv9为什么这套组合值得你花一个周末跑通姿态估计这件事很多人第一次接触是在健身房动作纠正、工业质检里的工人操作规范检测或者体育训练里的动作打分。传统做法是先用目标检测把人框出来再在框里跑一遍关键点回归两阶段串行延迟高、部署烦。YOLOv9 出来之后一个很自然的想法是能不能把关键点直接挂到检测头上一次前向就出人框和骨架答案是能而且这套「基于 YOLOv9 实现的人体姿态估计」的思路正是当前工业落地里性价比很高的一条路。它解决的核心问题是在保证实时性的前提下同时输出人体边界框和 17 个 COCO 关键点。适合谁适合已经跑通过 YOLO 系列检测、想往关键点方向延伸的算法工程师也适合需要做跌倒检测、手势交互、运动分析的产品团队。你不需要从零搭 backbone也不用去啃 HRNet 那种高分辨率网络的显存开销改检测头就能拿到可用的骨架输出。下面我把选型理由、数据准备、模型改造、训练调参和踩坑记录按顺序讲清楚你照着能复现。2. 从检测到关键点YOLOv9 姿态头的结构改造与选型理由2.1 为什么选 YOLOv9 而不是 YOLOv8-poseYOLOv8 已经自带 pose 分支为什么还要折腾 YOLOv9我当时的判断基于三点。第一YOLOv9 的 PGIProgrammable Gradient Information和 GELAN 结构在浅层特征保留上更稳关键点回归对浅层空间信息依赖很重尤其是手腕、脚踝这种小目标。第二YOLOv9 的辅助可逆分支在训练时能缓解深层网络的梯度消失关键点热图回归的收敛速度比直接改 YOLOv8 快一截。第三如果你手上已经有 YOLOv9 的检测权重迁移到姿态任务只需要替换检测头backbone 和 neck 可以直接复用省掉大量预训练时间。常见做法是backbone 用 YOLOv9-C 或 YOLOv9-Eneck 保持 PAN 结构把原来的检测头换成「检测头 关键点头」的双分支。检测头负责输出 person 类别的框关键点头在框内回归 17 个点的 (x, y, visibility)。这里有个细节关键点头不要直接回归绝对坐标而是回归相对于框中心的偏移量再乘以框的宽高还原这样对不同尺度的人体更鲁棒。2.2 关键点头的三种接法对比接法一在检测头旁边并联一个关键点分支共享 neck 输出。优点是结构简单训练时两个 loss 一起回传缺点是关键点分支和检测分支会抢特征小目标关键点容易抖。接法二先出框再用 ROIAlign 把框内特征抠出来送进一个小型关键点网络。这是两阶段思路精度高但速度掉得明显实时场景不推荐。接法三在检测头的每个 anchor 上直接预测关键点偏移类似 YOLO-Pose 的做法。优点是端到端、速度快缺点是对 anchor 匹配策略敏感正样本不够时关键点学不动。我一般会选接法三但在 loss 上加一个关键点可见性权重让遮挡点的梯度不要主导训练。下面是一个关键点头的最小实现片段基于 PyTorch 风格写你可以直接嵌到自己的 YOLOv9 检测头里。import torch import torch.nn as nn class PoseHead(nn.Module): def __init__(self, in_channels256, num_kpts17, num_classes1): super().__init__() # 检测分支输出框回归 类别 self.det_conv nn.Conv2d(in_channels, 4 num_classes, 1) # 关键点分支每个点预测 x偏移, y偏移, 可见性 self.kpt_conv nn.Conv2d(in_channels, num_kpts * 3, 1) self.num_kpts num_kpts def forward(self, x): det_out self.det_conv(x) # [B, 5, H, W] kpt_out self.kpt_conv(x) # [B, 51, H, W] B, _, H, W kpt_out.shape # 重排成 [B, num_kpts, 3, H, W] kpt_out kpt_out.view(B, self.num_kpts, 3, H, W) return det_out, kpt_out逻辑说明det_conv用 1x1 卷积把通道压到 54 个框参数 1 个 person 类别kpt_conv压到 5117 点 × 3 参数。关键点参数里的 x、y 是相对于当前 grid cell 的偏移visibility 过 sigmoid 变成 0 到 1 的置信度。参数上in_channels要和你 neck 最后一层输出对齐YOLOv9-C 通常是 256num_kpts按 COCO 标准是 17如果你做手部关键点就改成 21。2.3 数据准备COCO 转 YOLO-Pose 格式的四个边界坑COCO 的 keypoints 标注里每个点有 x、y、v 三个值v0 表示未标注v1 表示标注但遮挡v2 表示可见。转成 YOLO-Pose 训练格式时需要把绝对坐标归一化到 0 到 1并且把 v0 的点也保留在标签里但 loss 里要 mask 掉。坑一图像 resize 后关键点没同步缩放。很多人只改了框忘了点结果训练 loss 一直不降。坑二框的宽高为 0 时除零。COCO 里偶尔有退化框转换时要过滤。坑三关键点超出图像边界。归一化后可能出现负数或大于 1要 clip 到 0 到 1。坑四多人场景下关键点和框的对应关系错乱。COCO 的 annotation 是按人组织的转换时要保证每个框和它自己的 17 个点绑定。def coco_to_yolo_pose(img_w, img_h, bbox, keypoints): # bbox: [x, y, w, h] 绝对坐标 # keypoints: [x1,y1,v1, x2,y2,v2, ...] 共 51 个数 x, y, w, h bbox if w 0 or h 0: return None cx (x w / 2) / img_w cy (y h / 2) / img_h nw w / img_w nh h / img_h kpts_norm [] for i in range(0, len(keypoints), 3): kx, ky, kv keypoints[i], keypoints[i1], keypoints[i2] if kv 0: kpts_norm.extend([0.0, 0.0, 0.0]) else: kx min(max(kx / img_w, 0.0), 1.0) ky min(max(ky / img_h, 0.0), 1.0) kpts_norm.extend([kx, ky, 1.0]) return [cx, cy, nw, nh] kpts_norm这段转换函数里kv 0的点写成 0,0,0训练时通过第三位的 0 来 mask。min(max(...))是防止越界。返回的列表前 4 位是框后 51 位是点直接写进 YOLO 的 txt 标签即可。3. 训练配置与调参让关键点 loss 真正降下来的实操参数3.1 损失函数组合与权重设置姿态估计的 loss 一般由三部分组成框回归 lossCIoU 或 DFL、关键点坐标 lossL1 或 Wing Loss、关键点可见性 lossBCE。我常用的权重是框 loss 权重 1.0关键点坐标 loss 权重 0.05可见性 loss 权重 0.5。为什么坐标 loss 权重这么低因为关键点坐标的数值范围是 0 到 1而框的 CIoU 本身也在 0 到 1 附近如果不压低坐标 loss它会主导梯度导致框回归变差。Wing Loss 在小误差区间比 L1 更平滑适合关键点这种对精度敏感的任务。如果你用 L1手腕和脚踝的抖动会明显一些。可见性 loss 用 BCEWithLogitsLoss正样本是 v2 的点负样本是 v0 的点v1 的点忽略。import torch.nn.functional as F def pose_loss(pred_kpt, target_kpt, target_vis): # pred_kpt: [N, 17, 2] 预测坐标 # target_kpt: [N, 17, 2] 真实坐标 # target_vis: [N, 17] 可见性 0/1 coord_loss F.smooth_l1_loss(pred_kpt, target_kpt, reductionnone) coord_loss (coord_loss * target_vis.unsqueeze(-1)).sum() / (target_vis.sum() 1e-6) vis_loss F.binary_cross_entropy_with_logits(pred_vis, target_vis) return 0.05 * coord_loss 0.5 * vis_loss参数说明target_vis为 0 的点不参与坐标 loss 计算避免未标注点污染梯度。1e-6是防止除零。实际训练时框 loss 单独算最后加权求和。3.2 学习率与数据增强的配合YOLOv9 姿态训练我一般用 SGD初始学习率 0.01warmup 3 个 epochcosine 衰减到 0.0001。batch size 根据显存来单卡 24G 用 16 左右。数据增强方面Mosaic 和 MixUp 对检测有帮助但对关键点要小心Mosaic 拼接后关键点坐标要重新映射如果实现不对点会跑到别的图上。我的做法是前 10 个 epoch 开 Mosaic后面关掉让关键点回归在干净数据上收敛。另外随机缩放和旋转要同步作用于框和点。水平翻转时左右关键点要交换索引比如左肩和右肩对调。这个映射表在 COCO 的 17 点里是固定的鼻子不变左眼和右眼交换左耳和右耳交换左肩和右肩交换左肘和右肘交换左手腕和右手腕交换左髋和右髋交换左膝和右膝交换左脚踝和右脚踝交换。3.3 验证指标OKS 怎么算、多少算能用OKSObject Keypoint Similarity是姿态估计的标准指标类似检测里的 IoU。它根据每个关键点的标注方差和预测距离算相似度最后对所有点取平均。COCO 的 OKS 阈值从 0.5 到 0.95步长 0.05算 AP。工业场景里如果 OKS AP 能到 0.65 以上基本可用到 0.75 以上算不错。计算 OKS 时要注意预测点和真实点都要在同一个坐标系下通常是原图坐标。如果你在训练时用了归一化坐标验证时要还原回去。另外visibility 为 0 的点不参与 OKS 计算。import numpy as np def compute_oks(pred, gt, vis, sigmas): # pred, gt: [17, 2] # vis: [17] # sigmas: COCO 17 点的标准差 if vis.sum() 0: return 0.0 d np.linalg.norm(pred - gt, axis1) e d / (sigmas * 2) oks np.exp(-e ** 2) oks (oks * vis).sum() / vis.sum() return okssigmas是 COCO 官方给的 17 个值鼻子 0.026眼睛 0.025耳朵 0.035肩膀 0.079手肘 0.072手腕 0.062髋 0.107膝 0.087脚踝 0.089。这些值越大表示该点越难预测OKS 对误差的容忍度越高。4. 避坑与排查姿态估计训练里最常见的五类翻车4.1 关键点 loss 不降框 loss 正常现象训练几个 epoch 后框的 loss 稳定下降但关键点坐标 loss 一直在高位震荡。原因通常是关键点头的学习率太大或者正样本匹配时关键点分支没拿到足够的正样本。解决把关键点头的初始学习率设为检测头的 0.1 倍或者在 loss 里给关键点分支加一个 warmup前 5 个 epoch 只训练检测头之后再联合训练。4.2 预测的骨架整体偏移现象可视化时发现所有关键点都往一个方向偏比如统一往右下角偏。原因是坐标回归的基准点搞错了。如果你回归的是相对于 grid cell 左上角的偏移但还原时用了 cell 中心就会整体偏移半个 cell。解决统一基准要么都用左上角要么都用中心并且在 decode 时保持一致。4.3 遮挡点预测置信度异常高现象被遮挡的手腕模型给出的 visibility 接近 1但坐标完全不对。原因是训练时 v1 的点被当成正样本训练了可见性。解决可见性 loss 只把 v2 当正样本v1 和 v0 都当负样本或者 v1 直接忽略。我一般选择忽略 v1让模型只学「确定可见」和「确定不可见」。4.4 多人场景关键点串人现象两个人挨得近时A 的手腕点跑到了 B 的身上。原因是关键点分支没有和检测框绑定decode 时按全局 argmax 取点。解决关键点 decode 必须在每个框内部做先通过框的置信度筛选出人再在框对应的特征区域内取关键点。如果用的是 anchor-free 接法要确保每个 grid cell 只负责一个目标。4.5 导出 ONNX 后关键点输出维度对不上现象PyTorch 里推理正常导出 ONNX 后关键点输出变成一维或者维度错乱。原因是关键点头的 view 操作在 ONNX 里不支持动态 shape。解决把 view 换成 reshape并且在导出时固定 batch size 和输入尺寸。如果还是不行把关键点头的输出在 forward 里就整理成 [B, 17, 3] 的格式不要留到后处理。5. 进阶技巧用热图辅助回归把 OKS 再提两个点如果你已经把上面的流程跑通OKS 卡在 0.7 左右想再往上走可以试试热图辅助回归。具体做法是关键点头除了输出坐标偏移再额外输出 17 个热图每个热图是高斯峰值在真实点位置。训练时热图用 MSE loss推理时取热图峰值作为粗略位置再用偏移量做精细修正。这样做的好处是热图提供了空间上的软监督对遮挡和模糊更鲁棒。实现上热图分支可以用几层转置卷积把特征图上采样到输入尺寸的 1/4然后对每个关键点出一个通道。热图 loss 权重我一般设 1.0坐标 loss 权重降到 0.02。推理时先对热图做 sigmoid然后找每个通道的最大值位置再加上该位置的偏移预测得到最终坐标。class PoseHeadWithHeatmap(nn.Module): def __init__(self, in_channels256, num_kpts17): super().__init__() self.kpt_conv nn.Conv2d(in_channels, num_kpts * 3, 1) self.heatmap nn.Sequential( nn.ConvTranspose2d(in_channels, 128, 4, stride2, padding1), nn.ReLU(), nn.ConvTranspose2d(128, num_kpts, 4, stride2, padding1) ) self.num_kpts num_kpts def forward(self, x): kpt_out self.kpt_conv(x) hm_out self.heatmap(x) return kpt_out, hm_out热图分支的转置卷积把特征图放大 4 倍最终热图尺寸是输入的四分之一。训练时真实热图用高斯核生成sigma 取 2 个像素。推理时热图峰值位置乘以 4 得到原图坐标再加上偏移修正。验证这个方法是否有效可以固定其他参数只切换热图分支开和关跑两次验证集看 OKS AP 的变化。我自己的经验是在 COCO val2017 上加熱图后 AP 能提 1.5 到 2.5 个点但推理速度会掉 10% 左右。如果你的场景对帧率要求极高比如 60 FPS 以上这个技巧要慎重。最后说个习惯我每次改完关键点头都会先用一张固定图片跑一遍可视化把骨架画在原图上肉眼确认没有整体偏移和串人再开始大规模训练。这个动作花不了两分钟但能帮你省掉几个小时的无效训练。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

RFSoC RFDC配置实战:ADC混频NCO频率计算与QMC镜像校准

RFSoC RFDC配置实战:ADC混频NCO频率计算与QMC镜像校准

做Zynq UltraScale RFSoC的RF Data Converter IP配置,很多兄弟最头疼的就是两件事:ADC混频器(NCO)的频率字到底怎么算,QMC校准怎么调镜像都压不下去。这两个问题背后,其实是大家对RFDC内部数据通路和配置模…

2026/10/7 23:04:22 阅读更多 →
RFSoC射频直采:RF Data Converter IP配置与QMC校准

RFSoC射频直采:RF Data Converter IP配置与QMC校准

做射频接收链路有一阵子了,之前接触的方案都是外挂高速ADC加FPGA,布线麻烦不算,还要调一堆差分时钟、同步信号。后来换了Zynq UltraScale RFSoC平台,第一感觉是“集成度真高”——RF-ADC、RF-DAC、DDC/DUC、混频器、QMC全部塞进一…

2026/10/7 23:04:22 阅读更多 →
源码编译 Git 2.39.0 实战:从依赖配置到多版本共存与避坑指南

源码编译 Git 2.39.0 实战:从依赖配置到多版本共存与避坑指南

简介:本资源为 Git 2.39.0 官方源码压缩包,面向需要编译安装、研究版本控制底层实现或进行二次开发的开发者与运维人员。包内共约 2000 个文件,以 1192 个 sh 脚本、845 个 txt 文档、565 个 c 源文件与 283 个 h 头文件为主,另含…

2026/10/9 0:41:44 阅读更多 →

最新新闻

Java+JSP+MySQL教材管理系统实战:库存扣减与分页导出

Java+JSP+MySQL教材管理系统实战:库存扣减与分页导出

简介:这份资源是面向Java Web初学者与课程设计开发者的学校教材管理系统完整项目源码,基于Java、JSP与MySQL技术栈构建,运行于Tomcat环境,适合作为毕业设计、课程作业或Web开发练手参考。压缩包共81个文件,约3.91MB&am…

2026/10/9 0:43:31 阅读更多 →
javaWeb+servlet购物车项目:从零跑通核心链路

javaWeb+servlet购物车项目:从零跑通核心链路

简介:一套基于JavaWeb与Servlet的简易购物车系统源码,面向JavaWeb初学者与课程设计人群,演示如何通过Servlet接收商品添加请求、记录选购信息与数量,并跳转至另一个Servlet以表格形式展示购物车内容。工程基于Eclipse构建&#xf…

2026/10/9 0:43:31 阅读更多 →
Spring Boot单商户商城源码拆解:部署、调试与核心链路

Spring Boot单商户商城源码拆解:部署、调试与核心链路

简介:microapp-linjiashop-master 是一套基于 Java 的轻量级单商户商城系统源码,面向中小企业和想深入电商开发的 Java 开发者。项目以 Spring Boot 为核心,整合 MyBatis、Thymeleaf、Redis 与 Maven,体现微服务拆分思想&#xff…

2026/10/9 0:43:31 阅读更多 →
text-to-cad 实战:从自然语言到参数化 CAD 模型的完整链路

text-to-cad 实战:从自然语言到参数化 CAD 模型的完整链路

1. 从一段文字到三维实体:text-to-cad 到底在解决什么问题第一次听到 "text-to-cad" 这个说法,很多人脑子里浮现的画面是:对着电脑敲一句"给我画一个法兰盘",然后屏幕上就自动长出一个带螺栓孔的三维模型。这…

2026/10/9 0:43:30 阅读更多 →
大模型上下文模式详解:从滑动窗口到摘要压缩的工程实践

大模型上下文模式详解:从滑动窗口到摘要压缩的工程实践

上周有个朋友跑来跟我吐槽,他做的AI客服机器人聊到第20轮就开始“装失忆”,用户在前面确认过的订单编号、收货地址,到后面全都不记得,用户气得直说“你是鱼吗,只有七秒记忆”。我瞄了一眼他的代码,发现每次…

2026/10/9 0:43:30 阅读更多 →
C# WinForm药品管理系统实战部署指南

C# WinForm药品管理系统实战部署指南

简介:这是一套基于C# WinForm框架与SQL Server数据库开发的医院药品管理系统源码,面向计算机专业本科生课程设计、毕业设计及医疗信息化初学者,解决医院场景下药品入库出库、申领审核、库存预警、用户与病人信息管理等核心业务数字化需求。资…

2026/10/9 0:42:30 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/7 13:34:55 阅读更多 →