MMPose Top-down 回归式 2D 人体姿态估计:从 Deeppose/RLE 原理、官方配置到源码实现的全链路实践
MMPose Top-down 回归式 2D 人体姿态估计从 Deeppose/RLE 原理、官方配置到源码实现的全链路实践【免费下载链接】mmposeOpenMMLab Pose Estimation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmpose本文围绕 MMPose 仓库中configs/body_2d_keypoint/topdown_regression/目录下的官方文档展开系统讲解 Top-down 回归范式Deeppose 与 RLE的算法原理、COCO/MPII 数据集上的官方模型清单与精度指标、对应的训练配置写法以及RegressionLabel编解码器、RegressionHead/RLEHead、RLELoss等核心源码的实现细节。读完本文后你将能够独立读懂并复现仓库中全部 9 份 topdown regression 配置文件理解直接回归关键点坐标这一范式在 MMPose 框架中的完整数据流。一、什么是 Top-down 回归式姿态估计官方文档topdown_regression/README.md对这一范式给出了如下定义Top-down 方法将姿态估计任务拆分为两个阶段第一阶段是目标检测object detection第二阶段是在给定目标检测框bounding box的条件下对单个人体实例做姿态估计。在第二阶段回归式方法regression-based methods直接从检测框区域内的特征中回归出关键点坐标该范式源自 DeepposeHuman pose estimation via deep neural networks, CVPR 2014。与 Top-down 热力图范式如 HRNet、RTMPose 输出的 heatmap不同回归式方法不预测中间的空间分布场而是把关键点在哪里作为回归目标直接输出Deeppose 范式骨干网络提取全局特征后经全连接层直接输出每个关键点的 (x, y) 坐标RLEResidual Log-Likelihood Estimation, ICCV 2021范式在坐标之外同时回归一个表示不确定性的 sigma方差并用基于 Normalizing Flow 的残差对数似然损失训练从而让网络学会对误差分布建模。MMPose 用统一的TopdownPoseEstimator框架承载这两种方法差异只体现在 head、loss 与 codec 配置上这也是本文源码分析的主线。二、官方模型库COCO 与 MPII 的精度与配置对照2.1 COCO 数据集结果官方 README 给出的 COCO val2017 结果检测器在 val2017 上 human AP 为 56.4如下ModelInput SizeAPAR详情与权重ResNet-152RLE256x1920.7310.805resnet_rle_coco.mdResNet-101RLE256x1920.7220.768resnet_rle_coco.mdResNet-50RLE256x1920.7060.768resnet_rle_coco.mdMobileNet-v2RLE256x1920.5930.644mobilenetv2_rle_coco.mdResNet-152256x1920.5840.688resnet_coco.mdResNet-101256x1920.5620.670resnet_coco.mdResNet-50256x1920.5280.639resnet_coco.md更细粒度的指标含 AP50、AP75、AR50 及配置文件名记录在模型库详情页中例如 resnet_rle_coco.mdArch配置文件Input SizeAPAP50AP75ARAR50td-reg_res50_rle-8xb64-210e_coco-256x192.py256x1920.7060.8880.7760.7530.924td-reg_res50_rle-pretrained-8xb64-210e_coco-256x192.py256x1920.7190.8910.7880.7640.925td-reg_res101_rle-8xb64-210e_coco-256x192.py256x1920.7220.8940.7940.7680.930td-reg_res152_rle-8xb64-210e_coco-256x192.py256x1920.7310.8970.8050.7770.933td-reg_res152_rle-8xb64-210e_coco-384x288.py384x2880.7490.9010.8150.7930.935从表格可以得出两个符合直觉的规律同骨干下 RLE 版本比纯 Deeppose 回归版本 AP 高约 0.12~0.15如 ResNet-500.706 vs 0.528骨干增大与输入尺寸增大均带来稳定增益ResNet-152 RLE 从 256x192 的 0.731 提升到 384x288 的 0.749。2.2 MPII 数据集结果ModelInput SizePCKh0.5PCKh0.1详情与权重ResNet-50RLE256x2560.8610.277resnet_rle_mpii.mdResNet-152256x2560.8500.208resnet_mpii.mdResNet-101256x2560.8410.200resnet_mpii.mdResNet-50256x2560.8260.180resnet_mpii.mdMPII 的评估指标是 PCKh以头部直径归一化的 PCK 准确率对应配置中的MpiiPCKAccuracy评估器与 COCO 的 AP 指标体系完全不同后文第 6 节会展开。三、整体架构TopdownPoseEstimator 如何组装回归模型以 RLE 版 COCO 配置 td-reg_res50_rle-8xb64-210e_coco-256x192.py 为例模型部分的核心结构是model dict( typeTopdownPoseEstimator, data_preprocessordict( typePoseDataPreprocessor, mean[123.675, 116.28, 103.53], std[58.395, 57.12, 57.375], bgr_to_rgbTrue), backbonedict( typeResNet, depth50, init_cfgdict(typePretrained, checkpointtorchvision://resnet50)), neckdict(typeGlobalAveragePooling), headdict( typeRLEHead, in_channels2048, num_joints17, lossdict(typeRLELoss, use_target_weightTrue), decodercodec), test_cfgdict( flip_testTrue, shift_coordsTrue))从源码结构看这条链路各组件的职责是TopdownPoseEstimatorMMPose 的 Top-down 任务统一估计器负责把 backbone → neck → head 的前向结果在训练期走loss()、测试期走predict()GlobalAveragePoolingneck回归式方法不需要空间分辨率直接把骨干输出的特征图ResNet-50 末层通道数为 2048故in_channels2048全局池化成一个向量head把向量经全连接层映射到关键点坐标Deeppose或坐标sigmaRLEdecodercodec把网络输出的归一化坐标解码回输入图像坐标系再经仿射变换还原到原图。这个骨干 GAP 全连接的极简结构正是 Deeppose 原始设计的忠实实现——它也是这类模型推理速度极快的原因前向路径上没有任何上采样或反卷积模块。四、RegressionLabel 编解码器坐标的归一化与还原回归方法的 codec 实现在 mmpose/codecs/regression_label.py 的RegressionLabel类中配置里对应codec dict(typeRegressionLabel, input_size(192, 256))4.1 encode把 GT 关键点变成回归标签encode()在训练 pipeline 的GenerateTarget阶段被调用核心逻辑是w, h self.input_size valid ((keypoints 0) (keypoints [w - 1, h - 1])).all(axis-1) ( keypoints_visible 0.5) keypoint_labels (keypoints / np.array([w, h])).astype(np.float32) keypoint_weights np.where(valid, 1., 0.).astype(np.float32)三个要点归一化经过TopdownAffine变换后的关键点坐标位于input_size定义的裁剪框坐标系内被除以(w, h)压缩到 [0, 1] 区间。这就是为什么网络输出的目标范围是固定的与裁剪框大小无关有效性掩码只有落在输入区域内且可见度keypoints_visible 0.5的关键点权重为 1其余为 0避免对被裁剪掉的不可见点强监督输出两个张量keypoint_labelsN, K, 2与keypoint_weightsN, K分别送入 head 的loss()作为回归目标和逐关键点权重。4.2 decode把网络输出还原为像素坐标decode()的分支逻辑体现了对两种 head 的兼容if encoded.shape[-1] 2: # Deeppose 范式纯坐标输出 normalized_coords encoded.copy() scores np.ones((N, K), dtypenp.float32) elif encoded.shape[-1] 4: # RLE 范式前 2 维是坐标后 2 维是 sigma normalized_coords encoded[..., :2].copy() output_sigma encoded[..., 2:4].copy() scores (1 - output_sigma).mean(axis-1)Deeppose 分支输出 (x, y) 两个值坐标乘回(w, h)得到像素坐标关键点置信度统一记 1RLE 分支输出 (x, y, σx, σy) 四个值decode会用scores (1 - σ).mean(-1)把不确定性直接换算成关键点置信度——sigma 越大的点得分越低这使得下游按关键点得分过滤的逻辑可以自然沿用是回归方法补齐 heatmap 方法天然带置信度优势的关键设计。五、两种回归 Head 的源码解析5.1 RegressionHeadDeeppose实现在 mmpose/models/heads/regression_heads/regression_head.py# 全连接层直接输出 K 个点的 2 维坐标 self.fc nn.Linear(in_channels, self.num_joints * 2) def forward(self, feats): x feats[-1] x torch.flatten(x, 1) x self.fc(x) return x.reshape(-1, self.num_joints, 2)前向输出形状 (B, K, 2)。loss()阶段默认使用SmoothL1Loss(use_target_weightTrue)逐关键点加权训练日志中额外计算acc_pose阈值 0.05 的 PCK 精度便于监控收敛。5.2 RLEHead坐标 sigma 的联合回归实现在 mmpose/models/heads/regression_heads/rle_head.py与RegressionHead的三处关键差异输出维度self.fc nn.Linear(in_channels, self.num_joints * 4)前 2 维回归坐标、后 2 维回归 sigmasigma 的约束在predict()与 TTA 分支中都有batch_coords[..., 2:] batch_coords[..., 2:].sigmoid()把 sigma 压到 (0, 1) 区间保证RLELoss中error (pred - target) / (sigma 1e-9)的数值稳定TTATest Time Augmentation当test_cfg中flip_testTrue时head 会同时前向原图与水平翻转图翻转分支的输出经flip_coordinates(..., shift_coordstest_cfg.get(shift_coords, True), ...)做左右对称点映射与 0.5 像素坐标偏移后与原始预测做平均_batch_coords_flip flip_coordinates( self.forward(_feats_flip), flip_indicesflip_indices, shift_coordstest_cfg.get(shift_coords, True), input_sizeinput_size) batch_coords (_batch_coords _batch_coords_flip) * 0.5这就是配置中test_cfgdict(flip_testTrue, shift_coordsTrue)的底层含义所有官方 RLE 模型的 AP 数字都是在翻转 TTA 下测得的复现时务必保留这两项。此外RLEHead注册了_load_state_dict_pre_hook可自动把 MMPose v1.0 之前旧版DeepposeRegressionHead的 state dict键名loss.*→loss_module.*转换为当前格式保证历史权重的兼容性。5.3 RLELoss残差对数似然损失实现在 mmpose/models/losses/regression_loss.py 的RLELoss类。它把回归误差error (pred - target) / sigma送入一个RealNVPNormalizing Flow核心公式为sigma sigma.sigmoid() error (pred - target) / (sigma 1e-9) log_phi self.flow_model.log_prob(error.reshape(-1, 2)) # Flow 归一化项 log_sigma torch.log(sigma).reshape(...) nf_loss log_sigma - log_phi # 流匹配项 if self.residual: # 默认 True if self.q_distribution laplace: # 默认 laplace loss_q torch.log(sigma * 2) torch.abs(error) else: # gaussian loss_q torch.log(sigma * math.sqrt(2 * math.pi)) 0.5 * error**2 loss nf_loss loss_q if self.use_target_weight: loss * target_weight从源码结构看损失由两部分构成nf_loss让网络学习误差的分布形状flow 的 log 概率loss_q是一个显式的拉普拉斯或高斯对数似然残差项二者相加再按use_target_weightTrue逐关键点加权。use_target_weight直接消费第 4 节RegressionLabel.encode生成的keypoint_weights即不可见关键点不参与梯度。配置中lossdict(typeRLELoss, use_target_weightTrue)只显式传了权重开关residualTrue、q_distributionlaplace均走默认值。六、配置文件逐项解读COCO 与 MPII6.1 训练超参COCO 配置为例td-reg_res50_rle-8xb64-210e_coco-256x192.py 的运行期部分train_cfg dict(max_epochs210, val_interval10) optim_wrapper dict(optimizerdict(typeAdam, lr1e-3)) param_scheduler [ dict(typeLinearLR, begin0, end500, start_factor0.001, by_epochFalse), dict(typeMultiStepLR, begin0, endtrain_cfg[max_epochs], milestones[170, 200], gamma0.1, by_epochTrue) ] auto_scale_lr dict(base_batch_size512)总训练 210 epoch每 10 epoch 验证一次RLE 版本 Adam 学习率为1e-3而纯 Deeppose 版td-reg_res50_8xb64-210e_coco-256x192.py是5e-4——这是两个配置最重要的超参差异前 500 个 step 线性 warmup起始因子 0.001之后在第 170、200 epoch 把 LR 乘 0.1auto_scale_lr以 512 为基准 batch 自动缩放学习率配置名义 batch 为 8 卡 × 64 512与文件名8xb64对应。6.2 数据增强与 pipelineCOCO 训练 pipelinetrain_pipeline [ dict(typeLoadImage), dict(typeGetBBoxCenterScale), dict(typeRandomFlip, directionhorizontal), dict(typeRandomHalfBody), dict(typeRandomBBoxTransform), dict(typeTopdownAffine, input_sizecodec[input_size]), dict(typeGenerateTarget, encodercodec), dict(typePackPoseInputs) ]关键点在于GetBBoxCenterScale从预生成的检测框bbox_file计算裁剪中心与缩放TopdownAffine把人体区域仿射变换到input_size192×256格式为 [w, h]GenerateTarget调用RegressionLabel.encode产生归一化标签与权重。RandomHalfBody是 topdown 回归配置中保留的半身裁剪增强对回归类模型尤为重要因为它强迫网络在部分身体可见时仍给出合理的全局坐标。验证/测试 pipeline 只保留LoadImage → GetBBoxCenterScale → TopdownAffine → PackPoseInputs四步无增强、无GenerateTarget测试时的检测框来自person_detection_results/COCO_val2017_detections_AP_H_56_person.json——这正是 README 中detector having human AP of 56.4约束的落地方式。6.3 评估器与最佳模型保存COCO 配置default_hooks dict(checkpointdict(save_bestcoco/AP, rulegreater)) val_evaluator dict(typeCocoMetric, ann_file..., score_modebbox_rle)注意score_modebbox_rle这是 RLE 模型专属的评分模式COCO 评分时以检测框置信度作为人-关键点匹配依据保证 AP 与官方结果口径一致。6.4 MPII 配置的关键差异td-reg_res50_rle-8xb64-210e_mpii-256x256.py 与 COCO 配置相比有四处不同dataset_type MpiiDataset输入尺寸 256×256num_joints16MPII 为 16 关键点COCO 为 17训练 pipeline 中RandomBBoxTransform显式设了shift_prob0且没有RandomHalfBody验证时不需要检测框而是用 GT 头部框文件headbox_file{data_root}/annotations/mpii_gt_val.mat构造裁剪区域——这也是 PCKh 指标头部直径归一化能计算的前提评估器换成MpiiPCKAccuracy最佳模型保存键为PCKdefault_hooks dict(checkpointdict(save_bestPCK, rulegreater)) val_evaluator dict(typeMpiiPCKAccuracy)七、动手实践训练、评测与推理在准备好 COCO 数据data/coco/含annotations/person_keypoints_train2017.json与官方检测框结果文件后训练 RLE 模型python tools/train.py configs/body_2d_keypoint/topdown_regression/coco/td-reg_res50_rle-8xb64-210e_coco-256x192.py分布式训练使用仓库提供的脚本 dist_train.sh评测使用 test.pypython tools/test.py configs/body_2d_keypoint/topdown_regression/coco/td-reg_res50_rle-8xb64-210e_coco-256x192.py \ checkpoint.pth --out results.pkl由于配置中flip_testTrue评测会自动执行翻转 TTA。推理侧仓库的 demo/inferencer_demo.py 展示了基于 MMPoseInferencer 的图像推理入口可直接加载上述配置/权重做单图关键点回归预测。八、选型建议与适用边界结合官方模型库数据与源码结构可以给出如下实践结论精度优先选 RLE 系列。同骨干下 AP 比 Deeppose 纯回归高 0.12~0.15ResNet-152RLE 0.731 256x1920.749 384x288 为仓库记录的最高回归结果且 sigma 提供了可解释的关键点置信度计算受限MobileNet-v2RLE0.593 256x192见 mobilenetv2_rle_coco.md是轻量选择骨干可替换为配置中的mobilenetv2需要关键点置信度参与下游任务如过滤低质量点、加权融合时应使用 RLE 版本因为RegressionLabel.decode会把 sigma 换算成 scores而纯 Deeppose 输出的 scores 恒为 1数据集差异COCO 用检测框 AP 评估MPII 用 GT 头框 PCKh 评估两套配置不可直接混用切换时需同时修改dataset_type、num_joints、codec[input_size]与评估器四项。回归式方法的固有局限也值得注意它把姿态估计压缩为全局特征 → 单向量 → 坐标空间定位能力依赖骨干的卷积感受野。这也是为什么在 MMPose 模型库中Heatmap 系HRNet、RTMPose在同等骨干下精度更高回归系的价值在于推理链路上的极简性与 RLE 带来的不确定性建模。理解本文的 codec、head、loss 三层实现后若需扩展新的回归头例如输出 3D 坐标或增加辅助分支参照 rle_head.py 的注册方式MODELS.register_module()在mmpose/models/heads/regression_heads/下新增模块即可接入现有训练框架。【免费下载链接】mmposeOpenMMLab Pose Estimation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmpose创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考