RTMPose 实时多人姿态估计实战指南:基于 MMPose 的高性能人体姿态估计框架全解析
【免费下载链接】mmposeOpenMMLab Pose Estimation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmpose
RTMPose 是 OpenMMLab 团队基于 MMPose 构建的高性能实时多人姿态估计框架,本文以其在仓库configs/body_2d_keypoint/rtmpose/下的完整模型库为对象,系统讲解其设计思想、技术架构、训练配置与多数据集实验结果。读完本文,你将掌握 RTMPose t/s/m/l 系列模型的规格差异与性能数据、SimCC 坐标分类编解码与 RTMCCHead 的原理、420 轮两阶段训练策略中优化器、学习率调度、数据增强与 EMA 的完整配置细节,并能够在 MMPose 中直接复现训练与评估。
RTMPose 概述:面向工业场景的实时多人姿态估计框架
二维人体姿态估计(2D pose estimation)在公开基准上已经取得了出色成绩,但落地到工业界时,仍长期受困于"模型参数量大、推理延迟高"两大瓶颈。RTMPose 正是为弥合这一鸿沟而设计:其作者基于 MMPose 对影响多人姿态估计算法性能的五个关键方面展开了实证研究,并在此基础上提出了一个高性能的实时多人姿态估计框架:
- 范式(Paradigm):选择高效的 Top-Down(自上而下,先检测后回归)流程;
- 骨干网络(Backbone Network):复用 RTMDet 的 CSPNeXt 骨干;
- 定位算法(Localization Algorithm):采用 SimCC 坐标分类而非传统热图回归;
- 训练策略(Training Strategy):两阶段训练、EMA 等技巧的组合;
- 部署推理(Deployment Inference):针对 CPU/GPU/移动端做了大量实测与优化。
根据该框架的模型库文档,RTMPose-m 在 COCO 上达到75.8% AP,同时可在 Intel i7-11700 CPU 上以90+ FPS、在 NVIDIA GTX 1660 Ti GPU 上以430+ FPS运行;RTMPose-l 在 COCO-WholeBody 上达到67.0% AP,并以130+ FPS的速度运行,在同时期的开源实现中表现突出。为了进一步验证 RTMPose 在关键实时场景下的能力,作者还专门报告了其部署到移动设备后的性能表现。
RTMPose 技术架构解析
整体范式:Top-Down + SimCC 坐标分类
RTMPose 采用 Top-Down 架构,整体模型在配置文件中由TopdownPoseEstimator定义(见 rtmpose-m_8xb256-420e_coco-256x192.py):
model = dict( type='TopdownPoseEstimator', data_preprocessor=dict( type='PoseDataPreprocessor', mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], bgr_to_rgb=True), backbone=dict( _scope_='mmdet', type='CSPNeXt', arch='P5', expand_ratio=0.5, deepen_factor=0.67, widen_factor=0.75, out_indices=(4, ), channel_attention=True, norm_cfg=dict(type='SyncBN'), act_cfg=dict(type='SiLU'), init_cfg=dict( type='Pretrained', prefix='backbone.', checkpoint='.../cspnext-m_udp-aic-coco_210e-256x192-...pth')), head=dict( type='RTMCCHead', in_channels=768, out_channels=17, input_size=codec['input_size'], in_featuremap_size=tuple([s // 32 for s in codec['input_size']]), simcc_split_ratio=codec['simcc_split_ratio'], final_layer_kernel_size=7, gau_cfg=dict( hidden_dims=256, s=128, expansion_factor=2, dropout_rate=0., drop_path=0., act_fn='SiLU', use_rel_bias=False, pos_enc=False), loss=dict( type='KLDiscretLoss', use_target_weight=True, beta=10., label_softmax=True), decoder=codec), test_cfg=dict(flip_test=True))其中的_scope_='mmdet'表明骨干网络直接复用 MMDetection 中实现的 CSPNeXt;data_preprocessor使用 ImageNet 统计的均值/方差做归一化并完成 BGR 到 RGB 的通道转换。
骨干网络:CSPNeXt(来自 RTMDet)
RTMPose 的骨干网络选用 RTMDet 中的 CSPNeXt,配置为arch='P5'、expand_ratio=0.5,并开启通道注意力(channel_attention=True)、使用 SyncBN 归一化与 SiLU 激活。该骨干先在 AIC+COCO 上以 UDP 策略预训练 210 轮,再通过init_cfg以prefix='backbone.'的方式加载预训练权重,作为后续姿态估计训练的初始化。
RTMCCHead 与 GAU
头部使用专用的RTMCCHead(源码位于 mmpose/models/heads/coord_cls_heads/rtmcc_head.py)。其核心创新是在轻量分类头中引入GAU(Gated Attention Unit)模块,通过gau_cfg配置隐藏维度(hidden_dims=256)、注意力维度(s=128)、扩展系数(expansion_factor=2)等超参,以极低的额外计算量建模关键点坐标间的相关性。头部最终通过final_layer_kernel_size=7的卷积输出每个关键点在 X/Y 两个维度上的 SimCC 分布,配合KLDiscretLoss以 KL 散度监督离散化的坐标分布,其中beta=10.用于软化标签、label_softmax=True使预测与目标以概率分布形式对齐。测试阶段开启flip_test=True,即水平翻转测试 + 结果融合,以进一步提升精度。
SimCCLabel 编解码器
RTMPose 使用的坐标编解码器是SimCCLabel(源码位于 mmpose/codecs/simcc_label.py),其核心思想是:不再像传统方法那样回归一张高斯热图,而是将每个关键点的 X、Y 坐标分别离散化为一维分布,从而在保持亚像素定位精度的同时大幅降低输出通道与计算开销。以 COCO 配置为例:
codec = dict( type='SimCCLabel', input_size=(192, 256), sigma=(4.9, 5.66), simcc_split_ratio=2.0, normalize=False, use_dark=False)input_size=(192, 256):训练输入尺寸(宽 192、高 256);sigma=(4.9, 5.66):生成软标签时 X/Y 方向使用的高斯标准差,需与输入尺寸相匹配,值越大标签越平滑;simcc_split_ratio=2.0:SimCC 分辨率相对输入特征图的放大倍数,该值直接决定一维分布的输出长度(结合in_featuremap_size=tuple([s // 32 for s in codec['input_size']])可知骨干下采样 32 倍,输出坐标分辨率约为 12×16 的 2 倍);normalize=False与use_dark=False:分别表示不额外归一化标签、不启用 DARK 亚像素细化,属于针对实时场景的轻量化选择。
模型系列:RTMPose-t/s/m/l 规格对比
RTMPose 提供 tiny、s、m、l 四种规格,均由 CSPNeXt 骨干 + RTMCCHead 构成,差异集中体现在骨干的深度与宽度因子以及头部输入通道数上(详见 coco 目录 下的四个配置文件):
| 模型 | 配置文件名 | deepen_factor | widen_factor | head in_channels | EMA |
|---|---|---|---|---|---|
| RTMPose-t | rtmpose-t_8xb256-420e_coco-256x192.py | 0.167 | 0.375 | 384 | 关闭(配置注释说明 tiny 模型训练时关闭 EMA) |
| RTMPose-s | rtmpose-s_8xb256-420e_coco-256x192.py | 0.33 | 0.50 | 512 | 开启 |
| RTMPose-m | rtmpose-m_8xb256-420e_coco-256x192.py | 0.67 | 0.75 | 768 | 开启 |
| RTMPose-l | rtmpose-l_8xb256-420e_coco-256x192.py | 1.00 | 1.00 | 1024 | 开启 |
可以看到,规格从 t 到 l,骨干层数与通道数依次放大,精度随之提升、计算量同步增加,便于开发者按算力与精度需求选型。需要特别注意的是,tiny 模型在训练时刻意关闭了 EMA(配置中以注释形式说明 "Turn off EMA while training the tiny model"),其余规格均开启EMAHook。
在 COCO 数据集上的实验结果
模型库文档(rtmpose_coco.md)报告了 COCO val2017 上的结果,评测时使用在 COCO val2017 上人体 AP 为 56.4 的检测器提供人体框。以下为汇总:
256×192 输入尺寸
| 模型 | AP | AP^50 | AP^75 | AR | AR^50 |
|---|---|---|---|---|---|
| RTMPose-t | 0.682 | 0.883 | 0.759 | 0.736 | 0.920 |
| RTMPose-s | 0.716 | 0.892 | 0.789 | 0.768 | 0.929 |
| RTMPose-m | 0.746 | 0.899 | 0.817 | 0.795 | 0.935 |
| RTMPose-l | 0.758 | 0.906 | 0.826 | 0.806 | 0.942 |
| RTMPose-t-aic-coco | 0.685 | 0.880 | 0.761 | 0.738 | 0.918 |
| RTMPose-s-aic-coco | 0.722 | 0.892 | 0.794 | 0.772 | 0.929 |
| RTMPose-m-aic-coco | 0.758 | 0.903 | 0.826 | 0.806 | 0.940 |
| RTMPose-l-aic-coco | 0.765 | 0.906 | 0.835 | 0.813 | 0.942 |
384×288 输入尺寸(AIC+COCO 预训练)
| 模型 | AP | AP^50 | AP^75 | AR | AR^50 |
|---|---|---|---|---|---|
| RTMPose-m-aic-coco | 0.770 | 0.908 | 0.833 | 0.816 | 0.943 |
| RTMPose-l-aic-coco | 0.773 | 0.907 | 0.835 | 0.819 | 0.942 |
对比可见,同样输入尺寸下,使用 AIC+COCO 混合预训练(aic-coco 系列)的模型普遍比单 COCO 训练高约 0.5~1.0 个 AP;而把输入分辨率从 256×192 提升到 384×288 后,RTMPose-m 可再提升约 1.2 个 AP,说明在算力允许时应优先提高输入分辨率。
训练配置深度解析(以 COCO 为例)
RTMPose 的训练配置(rtmpose-m_8xb256-420e_coco-256x192.py)集中体现了其"长训练 + 强正则 + 两阶段"的训练哲学,本节逐块拆解。
训练总览:420 轮、AdamW 与参数分组
# runtime max_epochs = 420 stage2_num_epochs = 30 base_lr = 4e-3 train_cfg = dict(max_epochs=max_epochs, val_interval=10) randomness = dict(seed=21) optim_wrapper = dict( type='OptimWrapper', optimizer=dict(type='AdamW', lr=base_lr, weight_decay=0.05), paramwise_cfg=dict( norm_decay_mult=0, bias_decay_mult=0, bypass_duplicate=True))- 总共训练420 轮,每 10 轮验证一次,随机种子固定为 21;
- 优化器为AdamW,初始学习率
base_lr=4e-3,权重衰减 0.05(tiny/s 配置中 weight_decay 为 0); paramwise_cfg对归一化层与偏置项关闭权重衰减(norm_decay_mult=0, bias_decay_mult=0),这是稳定长训练的标准做法;auto_scale_lr = dict(base_batch_size=1024)表示学习率按总批大小 1024 为基准自动缩放:若实际批大小与 1024 不同,MMPose 会线性调整学习率,保证不同 GPU 数下的训练一致性。
学习率调度:1000 步线性预热 + 后半程余弦退火
param_scheduler = [ dict( type='LinearLR', start_factor=1.0e-5, by_epoch=False, begin=0, end=1000), dict( # use cosine lr from 210 to 420 epoch type='CosineAnnealingLR', eta_min=base_lr * 0.05, begin=max_epochs // 2, end=max_epochs, T_max=max_epochs // 2, by_epoch=True, convert_to_iter_based=True), ]调度分为两段:前 1000 次迭代从1.0e-5线性预热至base_lr(by_epoch=False表示按迭代计数);随后维持恒定学习率到第 210 轮(max_epochs // 2),再从 210 轮开始以余弦退火将学习率降至base_lr * 0.05(即eta_min)。这种"先线性预热 → 保持高位 → 后半程余弦衰减"的组合是 RTMPose 在 420 轮长训练下稳定收敛的关键。
数据增强 Pipeline:两阶段强度差异
训练阶段一的 pipeline(train_pipeline):
train_pipeline = [ dict(type='LoadImage', backend_args=backend_args), dict(type='GetBBoxCenterScale'), dict(type='RandomFlip', direction='horizontal'), dict(type='RandomHalfBody'), dict( type='RandomBBoxTransform', scale_factor=[0.6, 1.4], rotate_factor=80), dict(type='TopdownAffine', input_size=codec['input_size']), dict(type='mmdet.YOLOXHSVRandomAug'), dict( type='Albumentation', transforms=[ dict(type='Blur', p=0.1), dict(type='MedianBlur', p=0.1), dict( type='CoarseDropout', max_holes=1, max_height=0.4, max_width=0.4, min_holes=1, min_height=0.2, min_width=0.2, p=1.), ]), dict(type='GenerateTarget', encoder=codec), dict(type='PackPoseInputs') ]主要增强手段包括:水平随机翻转、RandomHalfBody(随机保留半身关键点训练,强化遮挡鲁棒性)、RandomBBoxTransform(尺度扰动 [0.6, 1.4]、旋转扰动 ±80°)、TopdownAffine仿射对齐、mmdet.YOLOXHSVRandomAug颜色抖动,以及基于 Albumentations 的模糊与随机擦除(CoarseDropout)。
阶段二 pipeline(train_pipeline_stage2)在训练末期(最后 30 轮)通过PipelineSwitchHook切换,增强强度显著降低:尺度扰动收窄为 [0.75, 1.25]、旋转扰动降为 ±60°、CoarseDropout概率由 1.0 降为 0.5,从而让模型在更接近真实分布的干净数据上微调,进一步打磨精度。
EMA 与两阶段切换 Hook
default_hooks = dict( checkpoint=dict(save_best='coco/AP', rule='greater', max_keep_ckpts=1)) custom_hooks = [ dict( type='EMAHook', ema_type='ExpMomentumEMA', momentum=0.0002, update_buffers=True, priority=49), dict( type='mmdet.PipelineSwitchHook', switch_epoch=max_epochs - stage2_num_epochs, switch_pipeline=train_pipeline_stage2) ]EMAHook采用指数滑动平均(ExpMomentumEMA,动量 0.0002)对模型参数做平滑,推理时使用 EMA 权重以获得更稳定的精度;mmdet.PipelineSwitchHook在第max_epochs - 30 = 390轮自动将数据增强 pipeline 切换为阶段二版本;- checkpoint 按验证集
coco/AP保存最优权重(rule='greater'),且最多保留 1 份,节省磁盘。
数据加载与评测
训练使用batch_size=256(8 卡 × 32)、10 个 worker 并开启persistent_workers=True;验证/测试用 COCO 官方CocoMetric(mmpose/evaluation/metrics/coco_metric.py)计算 AP/AR。配置中已将检测框文件注释掉(bbox_file部分),说明模型库报告的数值使用的是 56.4 AP 的外部检测器结果,用户若要在自己的检测框上复现,可取消注释并填入对应检测结果文件。
AIC + COCO 混合数据集训练
带-aic-coco后缀的模型(如 rtmpose-m_8xb256-420e_aic-coco-256x192.py)使用了 AIC(AI Challenger)与 COCO 的混合训练策略,这是 RTMPose 提升精度的另一关键手段:
dataset_coco = dict( type='RepeatDataset', dataset=dict( type=dataset_type, data_root=data_root, data_mode=data_mode, ann_file='coco/annotations/person_keypoints_train2017.json', data_prefix=dict(img='detection/coco/train2017/'), pipeline=[], ), times=3) dataset_aic = dict( type='AicDataset', ... pipeline=[ dict( type='KeypointConverter', num_keypoints=17, mapping=[(0, 6), (1, 8), (2, 10), (3, 5), (4, 7), (5, 9), (6, 12), (7, 14), (8, 16), (9, 11), (10, 13), (11, 15)]), ], ) train_dataloader = dict( ... dataset=dict( type='CombinedDataset', metainfo=dict(from_file='configs/_base_/datasets/coco.py'), datasets=[dataset_coco, dataset_aic], pipeline=train_pipeline, test_mode=False, ))- AIC 数据集中每个人的关键点只有 14 个,需要通过
KeypointConverter与 12 组映射关系转换为 COCO 的 17 点格式; - COCO 数据通过
RepeatDataset重复 3 次以平衡两个数据集的样本量,再经CombinedDataset合并为一个训练流; - 混合训练使模型在更大规模、更多姿态样本上预训练,最终带来约 1 个点的 COCO AP 提升。
更多数据集上的结果
MPII
在 MPII 验证集上,RTMPose-m 使用 256×256 输入,训练 210 轮(配置见 rtmpose-m_8xb64-210e_mpii-256x256.py,基础学习率降为 5e-4、批大小降为 64),结果以 PCKh 指标报告:
| 模型 | 输入尺寸 | PCKh@0.5(含翻转) | PCKh@0.1 | 配置与结果文档 |
|---|---|---|---|---|
| RTMPose-m | 256×256 | 0.907 | 0.348 | rtmpose_mpii.md |
CrowdPose
在密集人群基准 CrowdPose 上,RTMPose-m 以 256×192 输入训练 210 轮(配置见 rtmpose-m_8xb64-210e_crowdpose-256x192.py),评测使用 YOLOv3 人体检测器:
| 模型 | 输入尺寸 | AP | AP^50 | AP^75 | AP(Easy) | AP(Medium) | AP(Hard) |
|---|---|---|---|---|---|---|---|
| RTMPose-m | 256×192 | 0.706 | 0.841 | 0.765 | 0.799 | 0.719 | 0.582 |
其中 AP(Easy/Medium/Hard) 按 CrowdPose 官方标准依据拥挤程度分组评测,可见场景越拥挤精度下降越明显,而 RTMPose 在 Hard 档仍保有 0.582 的 AP。
Human-Art
Human-Art 是一个覆盖自然与人工(绘画、雕塑、卡通等)场景的人体中心数据集。模型库(rtmpose_humanart.md)给出了两类评测:
使用人体 AP 为 56.2 的检测器(Human-Art 验证集):
| 模型 | 输入尺寸 | AP | AR |
|---|---|---|---|
| RTMPose-s | 256×192 | 0.311 | 0.381 |
| RTMPose-m | 256×192 | 0.355 | 0.417 |
| RTMPose-l | 256×192 | 0.378 | 0.442 |
使用 Ground-Truth 边界框(Human-Art 验证集):
| 模型 | 输入尺寸 | AP | AR |
|---|---|---|---|
| RTMPose-s | 256×192 | 0.698 | 0.732 |
| RTMPose-m | 256×192 | 0.728 | 0.759 |
| RTMPose-l | 256×192 | 0.753 | 0.783 |
对照两类结果可以看出,在 Human-Art 这类跨域场景中,检测器质量对最终姿态精度影响极大(GT 框相比检测框 AP 提升约 0.37~0.40),这也是在应用中需要为检测环节预留精度的原因。此外,该文档还对比了仅用 COCO 训练与 Human-Art+COCO 联合训练在同一 COCO 验证集上的表现:联合训练后的 RTMPose-l 在 COCO 上仍可保持约 0.748 的 AP(GT 框 0.770),说明混合训练不会显著损伤原域性能。
训练与测试实操
本仓库提供了完整的训练/测试工具(tools/train.py、tools/test.py 与 tools/dist_train.sh),完整用法可参考 训练与测试指南。以 COCO 的 RTMPose-m 为例:
# 单卡训练 python tools/train.py configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py # 多卡训练(例如 8 卡) bash tools/dist_train.sh configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py 8 # 使用预训练权重测试 python tools/test.py configs/body_2d_keypoint/rtmpose/coco/rtmpose-m_8xb256-420e_coco-256x192.py \ ${CHECKPOINT_FILE} --work-dir work_dirs/rtmpose-m注意事项:
- 训练前需按 数据准备指南 将 COCO 数据放置于
data/coco/目录,data_root = 'data/coco/'与ann_file均以此为基准; - 各模型的权重与训练日志下载地址均记录在对应的结果文档中(如 rtmpose_coco.md),下载 ckpt 后填入
${CHECKPOINT_FILE}即可复现表中指标; - 若实际 GPU 数与配置中的 8 卡批大小不同,
auto_scale_lr会自动完成学习率缩放,无需手工调整。
总结
RTMPose 通过"Top-Down 范式 + CSPNeXt 骨干 + SimCC 坐标分类 + 420 轮两阶段训练 + EMA/混合数据集"的组合拳,在精度与速度之间取得了出色的平衡,并且 t/s/m/l 四种规格覆盖了从移动端到服务端的全场景部署需求。本文所解析的配置均可在 configs/body_2d_keypoint/rtmpose/ 目录中直接查看与复用,你可以据此复现 COCO 75.8 AP、CrowdPose 70.6 AP 等基准结果,也可以参考其中的数据增强与调度策略将其迁移到自定义姿态估计任务中。
【免费下载链接】mmposeOpenMMLab Pose Estimation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmpose
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考