MMPose 基于 RTMPose 的 COCO-WholeBody-Face 人脸关键点检测配置解析与实战指南
【免费下载链接】mmposeOpenMMLab Pose Estimation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmpose
本文以 MMPose 仓库中 rtmpose_coco_wholebody_face.md 对应的官方模型页面为核心骨架,系统讲解 RTMPose-m 在 COCO-WholeBody-Face 数据集上训练 68 点人脸关键点检测模型的完整配置、核心组件原理与训练/评估流程。读完本文,你将能够读懂该模型卡中的所有字段,掌握 SimCC 坐标分类编解码、RTMCCHead 头部结构、两阶段训练策略与 NME 评估指标在真实配置中的落地方式,并能在本仓库中直接复现该模型的训练与测试。
模型卡速览:官方已发布的结果与文件
该模型卡的原始内容围绕一张结果表展开,先完整还原它(表格中的配置文件与权重文件均存在于当前仓库或由模型卡/模型库 yml 声明):
| Arch | Input Size | NME | 配置文件 | 权重与日志 |
|---|---|---|---|---|
| RTMPose-m | 256x256 | 0.0466 | rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py | 权重文件rtmpose-m_simcc-coco-wholebody-face_pt-aic-coco_60e-256x256-62026ef2_20230228.pth及对应训练日志(下载地址见 rtmpose_coco_wholebody_face.yml 中的Weights字段) |
结果表同时引用了两个工作:骨干/框架相关的 RTMDet 论文(RTMDet: An Empirical Study of Designing Real-Time Object Detectors,ArXiv 2022)与数据集来源论文 Whole-Body Human Pose Estimation in the Wild(ECCV 2020)。这两篇文献在文档中以 bibtex 形式给出,分别对应 RTMPose 所依赖的实时检测/主干设计与 COCO-WholeBody 数据集的标注协议。
在仓库的整体目录中,该模型被收录于 configs/face_2d_keypoint/rtmpose/README.md 的 "COCO-WholeBody-Face Dataset" 小节,与 WFLW(NME 4.01)、LaPa(NME 1.29)等其他 RTMPose 人脸模型并列。此外,configs/face_2d_keypoint/rtmpose/README.md 还给出了 RTMPose 的整体设计动机:现有 2D 姿态估计方法在公开基准上表现优秀,但工业落地仍受制于模型参数大、延迟高的问题,RTMPose 从范式、骨干网络、定位算法、训练策略与部署推理五个方面进行经验性改进,构建了高性能实时多人姿态估计框架。
训练配置文件逐段拆解
本模型的完整训练配置位于 rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py,下面按逻辑段逐一解读。
训练周期、随机性与优化器
_base_ = ['../../../_base_/default_runtime.py'] max_epochs = 60 stage2_num_epochs = 10 base_lr = 4e-3 train_cfg = dict(max_epochs=max_epochs, val_interval=1) 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))- 配置通过
_base_继承 configs/base/default_runtime.py,该文件提供了日志、Checkpoint、可视化、分布式环境、日志处理器等通用运行设置(例如默认LoggerHook每 50 次迭代打点、CheckpointHook每 10 个 epoch 保存)。 - 训练共60 个 epoch,其中最后10 个 epoch为第二阶段(
stage2_num_epochs),由后面的PipelineSwitchHook触发管线切换。 - 优化器采用AdamW,初始学习率
4e-3,权重衰减0.05;norm_decay_mult=0与bias_decay_mult=0表示 BatchNorm 与偏置项不参与权重衰减,bypass_duplicate=True用于避免参数分组重复。
学习率调度:线性预热 + 余弦退火
param_scheduler = [ dict( type='LinearLR', start_factor=1.0e-5, by_epoch=False, begin=0, end=1000), dict( 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), ] auto_scale_lr = dict(base_batch_size=512)- 前 1000 次迭代执行从
1e-5倍基准学习率开始的线性预热(by_epoch=False,即按迭代计算); - 自第 30 个 epoch 起执行CosineAnnealingLR,最低学习率降至
base_lr * 0.05,T_max=30与begin/end对应后半段 30 个 epoch; auto_scale_lr = dict(base_batch_size=512)声明该配置的基准批大小为 512,当实际总 batch size 变化时,MMPose 会自动按比例缩放学习率,保证大批量训练时的收敛行为一致。
编解码器:SimCC 坐标分类
codec = dict( type='SimCCLabel', input_size=(256, 256), sigma=(5.66, 5.66), simcc_split_ratio=2.0, normalize=False, use_dark=False)SimCCLabel是 mmpose/codecs/simcc_label.py 中注册的SimCCLabel类,其核心思想来自论文SimCC: a Simple Coordinate Classification Perspective for Human Pose Estimation:不再像热图方法那样预测 2D 空间热图,而是把关键点定位拆成x、y 两个一维坐标分类任务,每个坐标用一个长度等于输入尺寸 × simcc_split_ratio的一维标签向量表示。
对照源码中的关键参数行为(mmpose/codecs/simcc_label.py):
input_size=(256, 256):编码与解码都在该图像尺寸空间内进行;simcc_split_ratio=2.0:标签分辨率是输入尺寸的 2 倍,即每个轴的标签长度W = 256 * 2 = 512,这是坐标分类精度的关键因子;sigma=(5.66, 5.66):高斯标签的方差,编码时按3-sigma 规则生成高斯分布目标(见_generate_gaussian,mmpose/codecs/simcc_label.py),sigma同时影响 DARK 后处理的模糊核尺寸;normalize=False:关闭标签归一化,直接使用exp(-(x-mu)^2 / (2*sigma^2))形式的高斯值;use_dark=False:解码时不启用 DARK 亚像素细化。若开启,decode会调用refine_simcc_dark对峰值位置做二次多项式拟合(mmpose/codecs/simcc_label.py),并配合sigma计算模糊核int((sigma*20-7)//3)。
模型结构:TopdownPoseEstimator + CSPNeXt + RTMCCHead
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='https://download.openmmlab.com/mmpose/v1/projects/' 'rtmposev1/cspnext-m_udp-aic-coco_210e-256x192-f2f7d6f6_20230130.pth' )), head=dict( type='RTMCCHead', in_channels=768, out_channels=68, 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, ))- 整体范式:
TopdownPoseEstimator即自顶向下(top-down)姿态估计,先由外部检测器给出人脸框,再在裁剪框内做单人 68 点关键点回归; - 数据预处理:
PoseDataPreprocessor使用 ImageNet 统计均值/方差做归一化,bgr_to_rgb=True表示输入图像按 BGR 读取后转为 RGB 再送入网络; - 骨干网络:
CSPNeXt从 mmdet 作用域引入,arch='P5'表示五阶段结构,deepen_factor=0.67与widen_factor=0.75对应 RTMPose-m 的深度/宽度缩放,out_indices=(4,)只取最高层特征;channel_attention=True启用通道注意力。骨干采用在 AIC+COCO 上预训练的权重初始化(init_cfg中的checkpoint字段,prefix='backbone.'保证只加载骨干参数); - 检测头:
RTMCCHead的实现位于 mmpose/models/heads/coord_cls_heads/rtmcc_head.py,其结构为大核卷积(final_layer,kernel_size=7)→ 展平 → 全连接层(MLP)→ Gated Attention Unit(GAU)→ 输出 SimCC 一维坐标分布。out_channels=68对应 68 个面部关键点;in_featuremap_size=tuple([s // 32 for s in codec['input_size']])即(8, 8),由 256 输入经骨干 32 倍下采样得到。GAU 配置中hidden_dims=256、s=128控制注意力通道维数,expansion_factor=2为 FFN 扩展倍数,act_fn='SiLU'; - 损失函数:
KLDiscretLoss,beta=10.用于平滑软标签分布,label_softmax=True在计算前对预测做 softmax,use_target_weight=True按关键点可见性加权; - 测试策略:
test_cfg=dict(flip_test=True)启用水平翻转测试融合,利用人脸左右对称的swap关系(见下文数据集定义)提升精度。
测试增强说明
flip_test=True的翻转融合会依据数据集定义的keypoint_info中每个点的swap字段交换左右对称点对。在 configs/base/datasets/coco_wholebody_face.py 中可以看到,例如face-0与face-16互为一对(swap='face-16'/swap='face-0'),眼睑、眉毛、嘴唇等对称点均有对应关系,而鼻尖face-27/28/29/30、下巴face-57、鼻梁face-33、上唇中心face-51、下唇中心face-62、鼻根face-66等中轴点swap=''为空。
数据集与数据管线
数据集类与 68 点标注
数据集类型为CocoWholeBodyFaceDataset,实现位于 mmpose/datasets/datasets/face/coco_wholebody_face_dataset.py。它继承BaseCocoStyleDataset,其METAINFO从 configs/base/datasets/coco_wholebody_face.py 读取,该文件定义了完整的 68 点语义:轮廓点face-0~face-16、左右眉face-17~face-26、鼻部face-27~face-36、左右眼face-36~face-47、外唇face-48~face-59、内唇face-60~face-67,并附带sigmas(每点 OKS 用的归一化方差)与joint_weights(全 1.0)。
关键解析逻辑在parse_data_info(coco_wholebody_face_dataset.py):
- 通过
ann['face_valid']与max(ann['face_kpts']) > 0过滤无效人脸实例; - 使用
ann['face_box'](xywh 格式)裁剪人脸框,并将坐标裁剪到图像范围内,得到[1, 4]的 bbox; - 关键点从
ann['face_kpts']读取,[..., :2]为坐标,[..., 2]经np.minimum(1, ...)得到可见性标记; - 可见关键点数量
num_keypoints用于数据过滤。
数据加载配置
dataset_type = 'CocoWholeBodyFaceDataset' data_mode = 'topdown' data_root = 'data/coco/' backend_args = dict(backend='local')训练与验证均使用 COCO 目录下的官方标注:训练用annotations/coco_wholebody_train_v1.0.json+train2017/图像,验证用annotations/coco_wholebody_val_v1.0.json+val2017/图像。backend_args默认本地文件系统,配置中保留的 petrel/S3 块为可选的远端存储写法(被注释掉)。数据加载器统一为batch_size=32、num_workers=10、persistent_workers=True,训练侧DefaultSampler(shuffle=True),验证侧关闭 shuffle 并设置test_mode=True。
训练/验证管线
train_pipeline = [ dict(type='LoadImage', backend_args=backend_args), dict(type='GetBBoxCenterScale'), dict(type='RandomFlip', direction='horizontal'), 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='GenerateTarget', encoder=codec), dict(type='PackPoseInputs') ] val_pipeline = [ dict(type='LoadImage', backend_args=backend_args), dict(type='GetBBoxCenterScale'), dict(type='TopdownAffine', input_size=codec['input_size']), dict(type='PackPoseInputs') ]训练侧依次执行:图像加载 → 由 bbox 计算中心与尺度 → 水平随机翻转 → 随机 bbox 变换(尺度缩放 0.6~1.4、旋转 ±80°)→ 仿射变换到 256x256 → HSV 颜色增强(来自 mmdet 的YOLOXHSVRandomAug)→ Albumentations 增强(Blur与MedianBlur各 0.1 概率,CoarseDropout随机挖空)→ 用 SimCC codec 生成训练目标 → 打包。验证管线只保留加载、仿射对齐与打包,不做任何随机增强。
两阶段训练策略(PipelineSwitchHook)
train_pipeline_stage2 = [ ... dict(type='RandomBBoxTransform', shift_factor=0., scale_factor=[0.75, 1.25], rotate_factor=60), ... ]配置文件通过custom_hooks中的mmdet.PipelineSwitchHook在max_epochs - stage2_num_epochs = 50个 epoch 处切换到第二训练管线(配置文件的 hooks 段)。第二阶段的核心差异是弱化数据增强:尺度范围收窄为[0.75, 1.25]、旋转角收窄为 ±60°、CoarseDropout概率从 1.0 降到 0.5,并在进入该阶段后配合 EMA 模型使网络从"探索"过渡到"精细收敛",这是 RTMPose 系列稳定精度的关键训练技巧之一。
EMA 与模型保存
default_hooks = dict( checkpoint=dict( save_best='NME', rule='less', max_keep_ckpts=1, interval=1)) custom_hooks = [ dict( type='EMAHook', ema_type='ExpMomentumEMA', momentum=0.0002, update_buffers=True, priority=49), ... ]训练全程维护Exponential Moving Average(EMA)参数副本(momentum=0.0002),验证与保存均基于 EMA 模型;Checkpoint 以验证集 NME 为监控指标(rule='less'),仅保留最优权重一份,每 1 个 epoch 评估一次。
评估指标:NME
val_evaluator = dict( type='NME', norm_mode='keypoint_distance', )该模型使用NME(Normalized Mean Error,归一化平均误差)作为评测指标,评测器NME实现在 mmpose/evaluation/metrics/keypoint_2d_metrics.py。NME 定义为预测关键点与真值之间的平均欧氏距离除以一个归一化因子;norm_mode='keypoint_distance'表示以人脸框对角线长度(即"关键点距离")作为归一化分母,这与 COCO-WholeBody 官方评估协议一致。NME 值越小精度越高,官方报告的本模型验证集 NME 为0.0466。
训练与推理实操
单卡/多卡训练
按照 MMPose 的标准训练方式,在安装好依赖并下载 COCO-WholeBody 数据集(标注放入data/coco/annotations/,图像放入data/coco/train2017/与data/coco/val2017/)后,可基于 tools/train.py 与 tools/dist_train.sh 启动训练:
# 单机 8 卡训练 bash tools/dist_train.sh configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py 8 # 单卡训练 python tools/train.py configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py训练日志默认输出到work_dirs/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256/,最优模型(EMA)会按 NME 最优自动保存。当实际使用的总 batch size 与配置的base_batch_size=512不一致时,auto_scale_lr机制会自动修正学习率;如需关闭可加--no-auto-scale-lr。
测试与权重获取
使用 tools/test.py 评估:
python tools/test.py configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py \ /path/to/rtmpose-m_simcc-coco-wholebody-face_pt-aic-coco_60e-256x256-62026ef2_20230228.pth官方预训练权重的文件名与下载地址可在 rtmpose_coco_wholebody_face.yml 的Weights字段查到,该 yml 同时声明了模型架构(RTMPose)、训练数据(COCO-WholeBody-Face)、任务类型(Face 2D Keypoint)与 NME 结果,是模型库索引与自动下载(如mim download mmpose --config rtmpose-m_8xb32-60e_coco-wholebody-face-256x256)的元数据来源。
推理接入
人脸 68 点关键点检测属于自顶向下流程,正式使用时需先做人脸检测再送入本模型。仓库提供两条可参考的推理路径:
- 通用推理脚本 demo/inferencer_demo.py(基于
Pose2DInferencer,见 mmpose/apis/inferencers/pose2d_inferencer.py),可配合 mmdet 的人脸检测模型组合调用; - 纯检测+关键点串联示例 demo/topdown_demo_with_mmdet.py,其中
--det-cat-id 0等参数用于控制检测类别。仓库还提供了现成的人脸检测器配置,例如 demo/mmdetection_cfg/yolox-s_8xb8-300e_coco-face.py。
小结
COCO-WholeBody-Face 上的 RTMPose-m 配置是一个高度工程化的"标准答案",它集中体现了 RTMPose 系列的几大设计要素:以 SimCC 一维坐标分类替代二维热图(mmpose/codecs/simcc_label.py)、以 CSPNeXt + RTMCCHead(大核卷积 + GAU)构成轻量高精度主干与头部(mmpose/models/heads/coord_cls_heads/rtmcc_head.py)、以预热 + 余弦退火 + 自动学习率缩放 + EMA + 两阶段弱增强管线的组合训练策略,并以 NME(norm_mode='keypoint_distance')作为与官方协议一致的评测口径。如果你需要在其他面部数据集(如 WFLW、LaPa)或自建人脸数据上复刻这套方案,只需替换dataset_type、标注路径、关键点元信息(configs/base/datasets/coco_wholebody_face.py 中keypoint_info的 68 点定义与swap/sigmas)以及codec的输入尺寸,即可复用本文拆解的全部训练机制。
【免费下载链接】mmposeOpenMMLab Pose Estimation Toolbox and Benchmark.项目地址: https://gitcode.com/GitHub_Trending/mm/mmpose
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考