- 人工智能
- 计算机视觉
- 深度学习
【免费下载链接】ViTPose
The official repo for [NeurIPS'22] "ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation" and [TPAMI'23] "ViTPose++: Vision Transformer for Generic Body Pose Estimation"
本篇技术指南围绕 ViTPose 仓库中 simplebaseline3d_mpi-inf-3dhp.md 文档,系统讲解如何在 MPI-INF-3DHP 数据集上使用 SimpleBaseline3D 完成「2D 关键点 → 3D 姿态」的 lifting 任务:包括完整配置解析、数据预处理、训练与测试命令、评估指标(MPJPE / P-MPJPE / 3DPCK / 3DAUC)的源码级实现原理,以及官方记录的模型精度。读完本文,你将掌握在 ViTPose 仓库内复现该实验的全部关键环节。
一、文档与背景:SimpleBaseline3D 在 ViTPose 中的定位
ViTPose 仓库的 pose_lift 目录下提供了「2D 人体关键点 → 3D 人体姿态」的经典基线方案。SimpleBaseline3D 出自论文A simple yet effective baseline for 3d human pose estimation(ICCV'2017),其核心思想是把 3D 姿态估计拆成两个阶段:
- Image → 2D Pose(由成熟的 2D 姿态估计模型完成);
- 2D Pose → 3D Pose(即本配置所实现的 lifting 阶段)。
正如 pose_lift/README.md 所述,作者发现将 Ground Truth(GT)2D 关节位置「提升」到 3D 空间是一个可以用很低误差解决的任务。基于 2D 人体姿态估计的成功经验,该方案直接对 2D 关节坐标进行回归,结构简单但效果扎实。
本文对应的文档给出了在 MPI-INF-3DHP 数据集上、使用 GT 2D 检测结果作为输入的官方实验结果:
| Arch | MPJPE | P-MPJPE | 3DPCK | 3DAUC | ckpt | log |
|---|---|---|---|---|---|---|
| simple_baseline_3d_tcn | 84.3 | 53.2 | 85.0 | 52.0 | ckpt | log |
注:与原论文不同,ViTPose 仓库的实现没有使用
max-norm constraint,因为作者发现去掉该约束后收敛更好、性能更优。该结论在模型结构中表现为 tcn.py 的max_norm参数保持为None。
对应结果同样记录在 simplebaseline3d_mpi-inf-3dhp.yml 中(3DAUC 52.0、3DPCK 85.0、MPJPE 84.3、P-MPJPE 53.2),可直接通过model-index.yml检索。
二、数据集:MPI-INF-3DHP 与 17 关键点定义
MPI-INF-3DHP(3DV'2017)是一个面向 in-the-wild 场景的单目 3D 人体姿态估计数据集,论文为Monocular 3D Human Pose Estimation In The Wild Using Improved CNN Supervision。ViTPose 仓库在 configs/base/datasets/mpi_inf_3dhp.py 中定义了它的关键点信息,共 17 个关键点:
| idx | 名称 | 类型 | swap 对称点 |
|---|---|---|---|
| 0 | head_top | upper | — |
| 1 | neck | upper | — |
| 2 | right_shoulder | upper | left_shoulder |
| 3 | right_elbow | upper | left_elbow |
| 4 | right_wrist | upper | left_wrist |
| 5 | left_shoulder | upper | right_shoulder |
| 6 | left_elbow | upper | right_elbow |
| 7 | left_wrist | upper | right_wrist |
| 8 | right_hip | lower | left_hip |
| 9 | right_knee | lower | left_knee |
| 10 | right_ankle | lower | left_ankle |
| 11 | left_hip | lower | right_hip |
| 12 | left_knee | lower | right_knee |
| 13 | left_ankle | lower | right_ankle |
| 14 | root(pelvis) | lower | — |
| 15 | spine | upper | — |
| 16 | head | upper | — |
数据集实现位于 body3d_mpi_inf_3dhp_dataset.py,其JOINT_NAMES与dataset_info一致。该类支持三种 2D 关节来源(SUPPORTED_JOINT_2D_SRC):
gt:直接读取注解文件中的 2D 标注;detection:从 2D 关键点检测结果文件(npz)中读取;pipeline:在数据流水线中由 2D 检测模型在线生成。
本配置使用joint_2d_src='gt',即文档标题所指的「with ground truth 2D detections」实验设定。2D 关节来源的可选值与加载逻辑可在 body3d_mpi_inf_3dhp_dataset.py 中看到。
2.1 数据预处理
使用仓库提供的预处理脚本 preprocess_mpi_inf_3dhp.py 将原始数据转换为 npz 注解文件:
python tools/dataset/preprocess_mpi_inf_3dhp.py该脚本的核心处理逻辑(可从源码确认)包括:
- 训练集使用 subject 1–8、每个 subject 的 Seq1/Seq2、8 个相机视角(Cam0/1/2/4/5/6/7/8),帧数表见 preprocess_mpi_inf_3dhp.py;
- 测试集使用 TS1–TS6,可输出
mpi_inf_3dhp_test_valid.npz(仅有效帧)或mpi_inf_3dhp_test_all.npz(全部帧),见 preprocess_mpi_inf_3dhp.py; - 从 3D 关节坐标生成 2D 投影,并按可见性规则生成关节权重;
- 计算 2D/3D 关节坐标的 mean/std 统计量(
joint2d_stats.pkl、joint3d_rel_stats.pkl),这些统计量被直接嵌入配置的归一化参数中(详见下文第四节); - 3D 坐标统一乘以
0.001转为米制单位,训练图像尺寸为 2048×2048,测试图像分辨率为 1920×1080(subject 5/6),相机内参通过最小二乘估计,见 preprocess_mpi_inf_3dhp.py。
处理后建议将数据放在data/mpi_inf_3dhp目录下(配置中data_root = 'data/mpi_inf_3dhp'),目录内应包含annotations/(mpi_inf_3dhp_train.npz、mpi_inf_3dhp_test_valid.npz、cameras_train.pkl、cameras_test.pkl、joint3d_rel_stats.pkl、joint2d_stats.pkl)与images/图像目录。
三、模型结构:PoseLifter + TCN + TemporalRegressionHead
本配置的模型定义如下(见 simplebaseline3d_mpi-inf-3dhp.py):
model = dict( type='PoseLifter', pretrained=None, backbone=dict( type='TCN', in_channels=2 * 17, stem_channels=1024, num_blocks=2, kernel_sizes=(1, 1, 1), dropout=0.5), keypoint_head=dict( type='TemporalRegressionHead', in_channels=1024, num_joints=16, # do not predict root joint loss_keypoint=dict(type='MSELoss')), train_cfg=dict(), test_cfg=dict(restore_global_position=True))3.1 PoseLifter:整体检测器框架
PoseLifter 是「把 2D 姿态提升到 3D 姿态」的检测器,内部由 backbone(TCN)、可选的 neck、keypoint_head(TemporalRegressionHead)组成;同时支持可选的traj_backbone/traj_head轨迹模型用于预测绝对根关节位置,并支持loss_semi半监督训练。本配置只使用 pose 模型(无 traj 分支、无半监督分支)。
训练时前向过程为:backbone(input) → keypoint_head(features) → get_loss,回归损失由TemporalRegressionHead计算(见 pose_lifter.py);测试时则通过inference_model与decode恢复归一化前的绝对坐标(见 pose_lifter.py)。
3.2 TCN:时间卷积骨干网络
TCN(Temporal Convolutional Networks)源自 VideoPose3D(CVPR'2019),以 1D 卷积在时间维度上处理关键点序列。本配置的实例化参数含义:
in_channels=2 * 17:输入通道数 = 关键点数 × 每关键点特征维数。由于seq_len=1且每个 2D 关键点只取 x、y 两个坐标(PoseSequenceToTensor把[T,K,C]重排为[K*C, T],见 pose3d_transform.py),故为 34 通道;stem_channels=1024:第一个扩展卷积(expand_conv)输出的特征通道数;num_blocks=2、kernel_sizes=(1, 1, 1):一个 1×1 扩展卷积 + 2 个BasicTemporalBlock。由于核大小全为 1,网络退化为纯逐帧映射(无时间上下文),这正是单帧 lifting 的配置;dropout=0.5:每个卷积块后施加 dropout;max_norm=None:不施加权重范数裁剪,这是本实现相对原论文的关键差异。
从 tcn.py 可以看到assert num_blocks == len(kernel_sizes) - 1,且所有核大小必须为奇数;BasicTemporalBlock由conv1(mid_channels=1024)→ dropout → conv2(1×1)→ dropout → 残差连接构成,dilation逐块累积(见 tcn.py)。
3.3 TemporalRegressionHead:回归头与 loss 计算
TemporalRegressionHead 是 VideoPose3D 的回归头:用num_joints * 3个输出通道的 1×1 卷积把 TCN 特征映射为每个关节的 (x, y, z),最终 reshape 为[N, num_joints, 3](见 temporal_regression_head.py)。
num_joints=16:由于 root 关节(idx=14)在数据流水线中被移除(remove_root=True),head 只回归 16 个非根关节;loss_keypoint=dict(type='MSELoss'):回归损失采用均方误差,训练时在get_loss中输出键名为reg_loss(见 temporal_regression_head.py);test_cfg=dict(restore_global_position=True):推理/评测时把预测的根相对坐标加上根关节位置恢复为全局坐标,并通过root_position_index把根关节插回第 14 位,见_restore_global_position实现(temporal_regression_head.py)。
四、数据流水线:根中心化、归一化与张量化
训练/验证/测试共用同一套 pipeline(见 simplebaseline3d_mpi-inf-3dhp.py),其背后是 pose3d_transform.py 中注册的三个变换类:
train_pipeline = [ dict( type='GetRootCenteredPose', item='target', visible_item='target_visible', root_index=14, root_name='root_position', remove_root=True), dict( type='NormalizeJointCoordinate', item='target', mean=joint_3d_normalize_param['mean'], std=joint_3d_normalize_param['std']), dict( type='NormalizeJointCoordinate', item='input_2d', mean=joint_2d_normalize_param['mean'], std=joint_2d_normalize_param['std']), dict(type='PoseSequenceToTensor', item='input_2d'), dict( type='Collect', keys=[('input_2d', 'input'), 'target'], meta_name='metas', meta_keys=[ 'target_image_path', 'flip_pairs', 'root_position', 'root_position_index', 'target_mean', 'target_std' ]) ]各步骤的源码级原理:
- GetRootCenteredPose(pose3d_transform.py):把 3D 目标姿态以
root_index=14(root/pelvis)为原点做零中心化,root_position保存根关节的全局坐标,remove_root=True时删除根关节并把root_position_index=14存入 meta,供推理时恢复全局坐标; - NormalizeJointCoordinate × 2(pose3d_transform.py):分别对 3D 目标与 2D 输入做
(x - mean) / std标准化,mean/std 来自预处理脚本生成的统计量 pkl,并被硬编码在配置中(joint_3d_normalize_param形状为 [16,3],因为根关节已被移除;joint_2d_normalize_param形状为 [17,2])。变换还会把{item}_mean、{item}_std存入结果,供 head 在get_accuracy/decode阶段反归一化(见 temporal_regression_head.py); - PoseSequenceToTensor(pose3d_transform.py):把
[T, K, C]的 2D 序列重排为[K*C, T],匹配 TCN 的 1D 卷积输入格式;seq_len=1时即[34, 1]; - Collect:打包模型输入(
input)、回归目标(target)与 meta 信息。
值得说明的是,GetRootCenteredPose会提示删除根关节后关节索引不再与flip_pairs、num_joints等注解信息对齐(pose3d_transform.py),因此head.num_joints=16与 17 关节的 dataset_info 存在刻意差异,这是设计使然而非配置错误。
五、训练配置细节
5.1 优化器与学习率
optimizer = dict(type='Adam', lr=1e-3) optimizer_config = dict(grad_clip=None) lr_config = dict( policy='step', by_epoch=False, step=100000, gamma=0.96, ) total_epochs = 200- 优化器为 Adam,初始学习率 1e-3,不做梯度裁剪;
- 学习率调度为按 iteration 衰减的 step 策略:训练到第 100000 个 iteration 时学习率乘以 0.96;
- 共训练 200 个 epoch。该部分与 Human3.6M 的 SimpleBaseline3D 配置(simplebaseline3d_h36m.py)完全一致。
5.2 评估配置
evaluation = dict( interval=10, metric=['mpjpe', 'p-mpjpe', '3dpck', '3dauc'], key_indicator='MPJPE')每 10 个 epoch 在验证集上评估一次,同时计算 4 个指标,并以 MPJPE 作为选择最优 checkpoints 的关键指标。
5.3 数据加载
data = dict( samples_per_gpu=64, workers_per_gpu=2, val_dataloader=dict(samples_per_gpu=64), test_dataloader=dict(samples_per_gpu=64), train=dict( type='Body3DMpiInf3dhpDataset', ann_file=f'{data_root}/annotations/mpi_inf_3dhp_train.npz', img_prefix=f'{data_root}/images/', data_cfg=train_data_cfg, ...), val=dict( type='Body3DMpiInf3dhpDataset', ann_file=f'{data_root}/annotations/mpi_inf_3dhp_test_valid.npz', ...), test=dict(..., ann_file=f'{data_root}/annotations/mpi_inf_3dhp_test_valid.npz', ...))train_data_cfg/test_data_cfg中与本实验直接相关的字段(定义见 Kpt3dSviewKpt2dDataset):
seq_len=1:每个样本只取 1 帧,对应核大小为 1 的 TCN;seq_frame_interval=1:相邻帧间隔;causal=True:causal 模式下目标帧为序列最右帧(此处即唯一帧);joint_2d_src='gt':2D 输入使用 GT 标注(本实验的前提条件);need_camera_param=False:本实验不需要相机参数;camera_param_file:指向cameras_train.pkl/cameras_test.pkl,仅在need_camera_param=True时加载(见 body3d_mpi_inf_3dhp_dataset.py)。
六、训练、测试与推理实战
6.1 单卡训练
python tools/train.py configs/body/3d_kpt_sview_rgb_img/pose_lift/mpi_inf_3dhp/simplebaseline3d_mpi-inf-3dhp.py常用可选参数(由 tools/train.py 定义):
--work-dir:指定日志与 checkpoint 保存目录;--resume-from:从指定 checkpoint 恢复训练;--no-validate:训练期间不进行验证;--gpu-id/--gpus:指定 GPU。
6.2 多卡分布式训练
bash tools/dist_train.sh configs/body/3d_kpt_sview_rgb_img/pose_lift/mpi_inf_3dhp/simplebaseline3d_mpi-inf-3dhp.py 8tools/dist_train.sh的第一个参数为配置文件路径,第二个参数为 GPU 数量。若使用 Slurm 集群,可改用tools/slurm_train.sh。
6.3 测试与评估
python tools/test.py configs/body/3d_kpt_sview_rgb_img/pose_lift/mpi_inf_3dhp/simplebaseline3d_mpi-inf-3dhp.py \ https://download.openmmlab.com/mmpose/body3d/simplebaseline3d/simplebaseline3d_mpi-inf-3dhp-b75546f6_20210603.pth常用可选参数(由 tools/test.py 定义):
--eval {mpjpe, p-mpjpe, 3dpck, 3dauc}:指定要计算的指标,与配置中evaluation.metric对应;--out:输出结果文件路径;--fuse-conv-bn:融合 conv 与 bn 层以略微提升推理速度。
6.4 推理脚本
对于通用 3D 人体姿态两阶段推理,可参考 body3d_two_stage_img_demo.py(图片)与 body3d_two_stage_video_demo.py(视频):第一阶段用 2D 姿态估计模型(如 topdown_heatmap 系列的 HRNet)得到 2D 关键点,第二阶段用 PoseLifter 类模型把 2D 关键点提升为 3D 姿态。两阶段使用说明可查阅 3d_human_pose_demo.md。
七、评估指标源码级解析
MPI-INF-3DHP 数据集的评估在 body3d_mpi_inf_3dhp_dataset.py 中实现,支持的指标包括mpjpe、p-mpjpe、3dpck、p-3dpck、3dauc、p-3dauc(见ALLOWED_METRICS)。底层计算函数位于 pose3d_eval.py:
- MPJPE(Mean Per Joint Position Error):所有关节预测与 GT 的欧氏距离均值,不做任何对齐(
alignment='none'),实现见 pose3d_eval.py; - P-MPJPE:先通过相似变换(Procrustes alignment:尺度 + 旋转 + 平移)把预测对齐到 GT 后再计算 MPJPE,对齐由 mesh_eval.py 的
compute_similarity_transform求解正交 Procrustes 问题完成; - 3DPCK(Percentage of Correct Keypoints):预测与 GT 的 L2 距离小于阈值(默认 0.15 米)的关节占比 ×100,见 pose3d_eval.py;
- 3DAUC(Area Under the Curve):在一系列 3DPCK 阈值上计算得到的曲线下面积,实现派生自 MPI-INF-3DHP 官方测试数据发布中的
mpii_compute_3d_pck.m(见 pose3d_eval.py)。
此外,TemporalRegressionHead.get_accuracy在训练/验证过程中也会计算 MPJPE 与 P-MPJPE:它会先根据 meta 中的target_mean/target_std反归一化预测与目标,再依据restore_global_position恢复全局坐标,最后用compute_similarity_transform计算两种误差(见 temporal_regression_head.py)。
八、常见问题与注意事项
- 数据目录结构:配置硬编码
data_root = 'data/mpi_inf_3dhp',若目录结构不同需要同步修改配置中的data_root及相关文件路径。 joint_2d_src的含义:本实验结果基于 GT 2D 检测('gt')。若要验证 2D 检测误差对 3D 提升结果的影响,可将joint_2d_src改为'detection'并指定joint_2d_det_file指向 2D 检测结果 npz(检测结果形状需与joints_3d对齐且最后一维为 3,见 body3d_mpi_inf_3dhp_dataset.py)。- 17 vs 16 关节:root 关节在 pipeline 中被移除,因此 head 输出 16 个关节;推理时通过
restore_global_position与root_position_index将根关节插回,最终输出仍为 17 关节的完整 3D 姿态。 - 单帧 vs 时序:本配置为
seq_len=1、kernel_sizes=(1,1,1)的单帧模型;若需要利用时序信息,可参考同目录下 video_pose_lift 的 videopose3d_mpi-inf-3dhp 配置,其中 TCN 使用更大的核大小与更长的序列。 - checkpoint 下载:官方预训练权重与训练日志的下载地址见文档表格(simplebaseline3d_mpi-inf-3dhp.md)与 simplebaseline3d_mpi-inf-3dhp.yml;模型权重与日志由 OpenMMLab 官方托管,属于仓库文档中明确给出的资源。
通过上述配置、数据与源码层面的完整梳理,你可以在 ViTPose 仓库中直接复现 SimpleBaseline3D 在 MPI-INF-3DHP 上的 84.3 MPJPE / 85.0 3DPCK 基线结果,并进一步替换 2D 检测来源、扩展为时序模型或迁移到其他 3D 人体姿态数据集。
- 人工智能
- 计算机视觉
- 深度学习
【免费下载链接】ViTPose
The official repo for [NeurIPS'22] "ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation" and [TPAMI'23] "ViTPose++: Vision Transformer for Generic Body Pose Estimation"
相关推荐
ViTPose 仓库实战:VideoPose3D 在 MPI-INF-3DHP 数据集上的 2D→3D 姿态提升(时序卷积)配置与训练指南
ViTPose 仓库实战:VideoPose3D 在 MPI INF 3DHP 数据集上的 2D→3D 姿态提升(时序卷积)配置与训练指南 本篇文章聚焦 ViT
人工智能计算机视觉深度学习HRNet 在 CrowdPose 上的 Top-Down 姿态估计:配置文件、训练评估与实现解析(ViTPose 仓库)
HRNet 在 CrowdPose 上的 Top Down 姿态估计:配置文件、训练评估与实现解析(ViTPose 仓库) 本文以 hrnet_crowdpos
人工智能计算机视觉深度学习ViTPose 仓库 CrowdPose 人体姿态估计实战:基于 ResNet + SimpleBaseline 的 Top-Down 配置解析与训练评估指南
ViTPose 仓库 CrowdPose 人体姿态估计实战:基于 ResNet + SimpleBaseline 的 Top Down 配置解析与训练评估指南
人工智能计算机视觉深度学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考