MMPose 手部姿态估计实战:MobileNetV2 骨干网络在 RHD 数据集上的 Top-Down Heatmap 配置全解析
2026/9/17 2:09:25 网站建设 项目流程

MMPose 手部姿态估计实战:MobileNetV2 骨干网络在 RHD 数据集上的 Top-Down Heatmap 配置全解析

【免费下载链接】mmposeOpenMMLab Pose Estimation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmpose

MMPose(OpenMMLab Pose Estimation Toolbox)在configs/hand_2d_keypoint/topdown_heatmap/rhd2d/目录下提供了基于 Rendered Handpose Dataset(RHD)的 2D 手部关键点估计完整方案。本文以其中 MobileNetV2 骨干网络配置 td-hm_mobilenetv2_8xb64-210e_rhd2d-256x256.py 为核心,逐段拆解其训练配置、数据管线、编解码器与评估指标,并结合仓库源码解释底层实现原理。读完本文,你将掌握如何在 MMPose 中复现并运行这套手部关键点方案,理解 MobileNetV2 轻量骨干与 MSRAHeatmap 热图编解码的组合方式,并学会如何用 PCK、AUC、EPE 指标评估手部姿态估计模型。

方案总览:MobileNetV2 骨干 + RHD 数据集的组合

该配置对应的模型卡片 mobilenetv2_rhd2d.md 明确标注了两篇核心工作:

  • MobileNetV2(CVPR'2018):由 Sandler 等人提出的轻量骨干网络,核心思想是Inverted Residuals(倒残差结构)与 Linear Bottlenecks(线性瓶颈),在保持精度的同时显著降低计算量,适合对模型体积和推理速度敏感的场景。
  • RHD(Rendered Handpose Dataset)(ICCV'2017):Zimmermann 与 Brox 在论文Learning to Estimate 3D Hand Pose from Single RGB Images中提出的合成渲染手部数据集,提供 2D 与 3D 手部关键点标注,是手部姿态估计领域广泛使用的基准之一。

该模型在RHD test set上的官方基准结果为:

模型架构输入尺寸PCK@0.2AUCEPE权重文件训练日志
pose_mobilenet_v2256x2560.9850.8832.79由 OpenMMLab 模型库提供(见原始模型卡片)由 OpenMMLab 模型库提供(见原始模型卡片)

说明:权重(ckpt)与训练日志(log)的下载链接记录在原始模型卡片中,由 OpenMMLab 官方模型库托管。本文重点聚焦配置解读与复现路径。

在 rhd2d 目录下,MMPose 还提供了 ResNet50、HRNetv2-W18、HRNetv2-Dark、HRNetv2-UDP 等骨干的同类配置,MobileNetV2 是其中计算量最小的轻量选项,可用于对部署资源敏感的移动端或边缘端手部姿态估计场景。

模型配置文件逐段解析

整个训练流程由 td-hm_mobilenetv2_8xb64-210e_rhd2d-256x256.py 一个文件驱动。文件名本身即编码了关键信息:td-hm(top-down heatmap 范式)、mobilenetv2(骨干网络)、8xb64(8 卡 × batch size 64)、210e(210 个 epoch)、rhd2d(数据集)、256x256(输入图像尺寸)。

训练运行时与优化策略

_base_ = ['../../../_base_/default_runtime.py'] # runtime train_cfg = dict(max_epochs=210, val_interval=10) # optimizer optim_wrapper = dict(optimizer=dict( type='Adam', lr=5e-4, )) # learning policy param_scheduler = [ dict( type='LinearLR', begin=0, end=500, start_factor=0.001, by_epoch=False), # warm-up dict( type='MultiStepLR', begin=0, end=210, milestones=[170, 200], gamma=0.1, by_epoch=True) ] # automatically scaling LR based on the actual training batch size auto_scale_lr = dict(base_batch_size=512) # hooks default_hooks = dict(checkpoint=dict(save_best='AUC', rule='greater'))

各字段的作用如下:

  • train_cfg:最多训练 210 个 epoch,每 10 个 epoch 在验证集上评估一次。
  • optim_wrapper:采用Adam优化器,初始学习率lr=5e-4。相比 SGD 系优化器,Adam 在姿态估计这类稠密回归任务上收敛更稳定。
  • param_scheduler:两段式学习率调度:
    • 500 次迭代执行线性 warm-up(LinearLRstart_factor=0.001,即从 0.1% 的学习率线性升温到目标值,by_epoch=False表示按迭代计);
    • 之后按 epoch 执行MultiStepLR,在epoch 170 和 200处将学习率乘以gamma=0.1
  • auto_scale_lr:声明base_batch_size=512(即 8 卡 × 64)。当实际训练 batch size 与此不同时,MMEngine 会自动按比例缩放学习率,保证跨硬件配置下的训练行为一致。
  • default_hooks:checkpoint 保存策略以验证集AUC 最高为最优模型判定标准(save_best='AUC'rule='greater')。这也说明 AUC 是本任务的核心监控指标。

模型结构与 Heatmap Codec

# codec settings codec = dict( type='MSRAHeatmap', input_size=(256, 256), heatmap_size=(64, 64), sigma=2) # model settings 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( type='MobileNetV2', widen_factor=1., out_indices=(7, ), init_cfg=dict( type='Pretrained', checkpoint='mmcls://mobilenet_v2', )), head=dict( type='HeatmapHead', in_channels=1280, out_channels=21, loss=dict(type='KeypointMSELoss', use_target_weight=True), decoder=codec), test_cfg=dict( flip_test=True, flip_mode='heatmap', shift_heatmap=True, ))

这一段的要点:

  • codec:使用MSRAHeatmap编解码器(源自Simple Baselines for Human Pose Estimation and Tracking, ECCV'2018),输入图像 256×256,输出热图 64×64,高斯核sigma=2。即热图空间分辨率是输入图像的 1/4。
  • data_preprocessor:使用 ImageNet 统计量(mean/std)归一化,bgr_to_rgb=True处理 OpenCV 读取的 BGR 图像。
  • backbone:MobileNetV2,widen_factor=1.(通道宽度不缩放),out_indices=(7,)取第 7 个输出(即最后的conv21×1 卷积层输出,1280 通道);init_cfg使用mmcls://mobilenet_v2的 ImageNet 预训练权重初始化。
  • headHeatmapHead,输入 1280 通道特征,输出 21 通道热图(对应 RHD 的 21 个手部关键点),损失函数为带关键点权重加权的 MSE(KeypointMSELoss, use_target_weight=True)。
  • test_cfg:测试时启用水平翻转测试增强flip_test=True),翻转模式为热图级(flip_mode='heatmap'),并对翻转后的热图进行像素偏移补偿(shift_heatmap=True),可进一步提升关键点定位精度。

数据管线(Pipeline)

dataset_type = 'Rhd2DDataset' data_mode = 'topdown' data_root = 'data/rhd/' train_pipeline = [ dict(type='LoadImage'), dict(type='GetBBoxCenterScale'), dict(type='RandomFlip', direction='horizontal'), dict( type='RandomBBoxTransform', rotate_factor=180, scale_factor=(0.7, 1.3)), dict(type='TopdownAffine', input_size=codec['input_size']), dict(type='GenerateTarget', encoder=codec), dict(type='PackPoseInputs') ] val_pipeline = [ dict(type='LoadImage'), dict(type='GetBBoxCenterScale'), dict(type='TopdownAffine', input_size=codec['input_size']), dict(type='PackPoseInputs') ]

训练管线与验证管线的差异体现了 top-down 数据增强的核心思路:

  • LoadImage加载图像;GetBBoxCenterScale从标注框计算中心点与尺度。
  • 训练阶段的随机增强组合:
    • RandomFlip:水平随机翻转;
    • RandomBBoxTransform:旋转范围高达 ±180°(手部可任意朝向),尺度缩放范围 0.7~1.3。
  • TopdownAffine将裁剪区域仿射变换到 256×256;GenerateTarget调用codec.encode把关键点坐标编码为高斯热图;PackPoseInputs统一打包输入。
  • 验证阶段不做任何随机增强,只做仿射归一化,保证评估稳定性。

数据加载器与评估器

train_dataloader = dict( batch_size=64, num_workers=2, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), dataset=dict( type=dataset_type, data_root=data_root, data_mode=data_mode, ann_file='annotations/rhd_train.json', data_prefix=dict(img=''), pipeline=train_pipeline, )) val_dataloader = dict( batch_size=32, num_workers=2, persistent_workers=True, drop_last=False, sampler=dict(type='DefaultSampler', shuffle=False, round_up=False), dataset=dict( type=dataset_type, data_root=data_root, data_mode=data_mode, ann_file='annotations/rhd_test.json', data_prefix=dict(img=''), test_mode=True, pipeline=val_pipeline, )) test_dataloader = val_dataloader # evaluators val_evaluator = [ dict(type='PCKAccuracy', thr=0.2), dict(type='AUC'), dict(type='EPE'), ] test_evaluator = val_evaluator
  • 训练集标注文件为annotations/rhd_train.json,验证/测试集为annotations/rhd_test.json(RHD 官方不设独立验证集,MMPose 直接用官方 test set 作为验证与测试集)。
  • 训练 batch size 64、验证 batch size 32,num_workers=2
  • 评估器同时启用PCK@0.2、AUC、EPE三个指标,这是 RHD 基准的官方评估协议。

MobileNetV2 骨干网络源码解析

在 mmpose/models/backbones/mobilenet_v2.py 中,MobileNetV2 以BaseBackbone子类实现,核心是InvertedResidual模块:

  • 倒残差结构:先经 1×1 卷积升维(expand_ratio=6时隐藏层通道为输入的 6 倍),再经 3×3 深度可分离卷积(groups=hidden_dim),最后用 1×1 卷积降维回输出通道,且末尾不使用激活函数act_cfg=None),这正是论文中的 "Linear Bottlenecks" 设计。
  • 残差连接条件:仅当stride == 1in_channels == out_channels时才启用恒等残差(use_res_connect),见源码第 54 行附近。
  • 网络结构表arch_settings定义了 7 个倒残差阶段:[[1, 16, 1, 1], [6, 24, 2, 2], [6, 32, 3, 2], [6, 64, 4, 2], [6, 96, 3, 1], [6, 160, 3, 2], [6, 320, 1, 1]],每项依次为 expand_ratio、通道数、块数、首块 stride。
  • 第 8 个输出是conv2的 1×1 卷积层,输出固定为 1280 通道(widen_factor > 1.0时按比例放大)。配置中的out_indices=(7,)即取该最终输出,这也是HeatmapHeadin_channels=1280的来源。
  • 可选frozen_stages冻结前若干阶段参数、norm_eval冻结 BN 统计量等训练技巧在该类中均有实现。

RHD 数据集详解与关键点顺序陷阱

RHD 数据集在 MMPose 中由 Rhd2DDataset 类实现,它继承BaseCocoStyleDataset,数据元信息(关键点定义、骨架、颜色)声明在 configs/base/datasets/rhd2d.py 中。

RHD 共 21 个关键点,顺序为:

索引名称索引名称
0wrist(手腕)11middle_finger2
1thumb412middle_finger1
2thumb313ring_finger4
3thumb214ring_finger3
4thumb115ring_finger2
5forefinger416ring_finger1
6forefinger317pinky_finger4
7forefinger218pinky_finger3
8forefinger119pinky_finger2
9middle_finger420pinky_finger1
10middle_finger3

关键点顺序陷阱(务必注意):configs/base/datasets/rhd2d.py 的注释明确说明:在 RHD 中,每根手指的编号1~4 是从指尖到掌根排列(thumb4 最靠近指尖);而在 COCO-WholeBody-Hand、FreiHand、CMU Panoptic HandDB 等数据集中顺序恰好相反。因此,如果希望将 RHD 与其他手部数据集混合训练同一个模型,必须先统一关键点顺序。同时,keypoint_info不会直接改变数据集内关键点的实际排列顺序,它主要用于可视化与记录flip_pairs等翻转配对信息。

单元测试 test_rhd2d_dataset.py 使用tests/data/rhd下的测试标注验证了数据集在topdownbottomup两种data_mode下返回的data_info字段类型,可用于快速了解该数据集的对外接口。

数据准备目录结构

按照 docs/en/dataset_zoo/2d_hand_keypoint.md 的说明,下载 RHD 官方数据与 OpenMMLab 提供的标注文件(rhd_annotations.zip)后,解压到仓库根目录的data/下,目录应组织为:

data/rhd/ ├── annotations │ ├── rhd_train.json │ └── rhd_test.json ├── training │ ├── color/ # 训练集 RGB 图像 │ ├── depth/ # 训练集深度图 │ └── mask/ # 训练集掩码 └── evaluation ├── color/ # 测试集 RGB 图像 ├── depth/ └── mask/

MSRAHeatmap 编解码器:关键点与热图之间的双向转换

Mmmpose/codecs/msra_heatmap.py 实现了本配置使用的MSRAHeatmap,其核心机制如下:

  • 编码(encode):将 256×256 输入空间中的关键点坐标除以scale_factorinput_size / heatmap_size = 4)映射到 64×64 热图空间,再以sigma=2生成高斯峰(generate_gaussian_heatmaps),同时输出关键点权重keypoint_weights。源码第 74~75 行计算scale_factor,第 110 行调用高斯热图生成函数。此外该类还内置了unbiased=True的 DarkPose 变体支持(generate_unbiased_gaussian_heatmaps+refine_keypoints_dark)。
  • 解码(decode):从预测热图取最大值位置(get_heatmap_maximum)获得粗略坐标,再经refine_keypoints进行亚像素细化,最后乘回scale_factor还原到输入图像空间。这一解码逻辑挂在HeatmapHeaddecoder字段上,训练与推理共用。

HeatmapHead 与 KeypointMSELoss

Hmmpose/models/heads/heatmap_heads/heatmap_head.py 中的HeatmapHead源自Simple Baselines论文,结构为:若干反卷积层(deconv)+ 中间卷积层 + 最终 1×1 卷积。本配置未显式指定反卷积参数,因此使用默认值:3 层反卷积,输出通道(256, 256, 256),核大小(4, 4, 4),最后接 1×1 卷积输出 21 通道热图。1280 通道的低分辨率特征经三层反卷积上采样后,正好匹配 64×64 的热图尺寸。

损失函数 KeypointMSELoss 采用均方误差衡量预测热图与高斯目标热图的差异;use_target_weight=True时按关键点权重加权——RHD 中所有 21 个关键点的权重均为 1.0(见joint_weights=[1.] * 21),该机制主要为处理含遮挡/缺失关键点的场景预留。

评估指标:PCK、AUC 与 EPE

三个指标全部实现在 mmpose/evaluation/metrics/keypoint_2d_metrics.py 中:

  • PCK(Percentage of Correct Keypoints)PCKAccuracy计算预测关键点与真值距离在归一化阈值内的比例。thr=0.2表示距离阈值为人手检测框尺寸的 20%,norm_item='bbox'(默认)以 bbox 尺寸归一化,即常说的 PCK@0.2。
  • AUC(Area Under Curve)AUC通过遍历不同 PCK 阈值绘制曲线并计算面积,norm_factor=30(像素)、num_thrs=20为默认设置,用于综合评价定位精度曲线。
  • EPE(End-Point Error)EPE直接计算所有预测关键点与真值的平均端点像素误差,数值越小越好。三者的互补关系:PCK 反映阈值内的命中率,AUC 反映精度曲线的整体水平,EPE 反映绝对像素误差。

训练与测试命令

数据准备就绪后,按 docs/en/user_guides/train_and_test.md 的说明即可训练。单卡训练:

python tools/train.py configs/hand_2d_keypoint/topdown_heatmap/rhd2d/td-hm_mobilenetv2_8xb64-210e_rhd2d-256x256.py

多卡分布式训练(以 8 卡为例):

bash tools/dist_train.sh configs/hand_2d_keypoint/topdown_heatmap/rhd2d/td-hm_mobilenetv2_8xb64-210e_rhd2d-256x256.py 8

测试评估:

python tools/test.py configs/hand_2d_keypoint/topdown_heatmap/rhd2d/td-hm_mobilenetv2_8xb64-210e_rhd2d-256x256.py <checkpoint路径>

训练期间 checkpoint 会依据验证集 AUC 自动保存最优权重,测试输出即 PCK@0.2、AUC、EPE 三项指标。

与其他骨干网络的基准对比

在同一数据集与训练协议(8×batch size 64、210 epoch、256×256 输入)下,rhd2d 目录中的模型卡片记录了对齐的对比结果:

骨干网络PCK@0.2AUCEPE对应配置
MobileNetV20.9850.8832.79td-hm_mobilenetv2_8xb64-210e_rhd2d-256x256.py
ResNet500.9910.8982.32td-hm_res50_8xb64-210e_rhd2d-256x256.py
HRNetv2-W180.9920.9022.21td-hm_hrnetv2-w18_8xb64-210e_rhd2d-256x256.py

可以看到,MobileNetV2 在精度上略低于 ResNet50 与 HRNetv2-W18,但其计算量与参数量显著更小,属于精度/效率权衡下的轻量选项。同目录还提供了 HRNetv2-Dark 与 HRNetv2-UDP 等进阶解码策略的配置,可作为精度优先场景的参考。读者可根据实际算力与部署约束选择合适的骨干。

总结

本文围绕 MMPose 中 MobileNetV2 + RHD 的 Top-Down Heatmap 手部关键点方案,完成了从模型卡片到源码实现的全链路解读:训练配置中的优化器、学习率调度、数据增强与评估协议,MobileNetV2 的倒残差结构,RHD 数据集的 21 关键点定义及其与主流手部数据集的顺序差异,MSRAHeatmap 的编解码机制,以及 PCK/AUC/EPE 三项指标的计算方式。这套方案可直接复现运行,也可作为在 MMPose 中搭建其他 top-down 手部姿态估计任务的模板——只需替换骨干网络、数据集标注与关键点数量即可快速迁移。

【免费下载链接】mmposeOpenMMLab Pose Estimation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmpose

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询