MMPose 实时人脸关键点检测实战:RTMPose 在 COCO-WholeBody-Face、WFLW 与 LaPa 数据集上的配置、训练与原理解析
2026/9/17 16:44:12 网站建设 项目流程

MMPose 实时人脸关键点检测实战:RTMPose 在 COCO-WholeBody-Face、WFLW 与 LaPa 数据集上的配置、训练与原理解析

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

本文以 configs/face_2d_keypoint/rtmpose/README.md 为骨架,系统讲解 OpenMMLab MMPose 中 RTMPose 人脸 2D 关键点检测的模型库、配置文件逐段解析、训练/测试/推理全流程,以及 SimCC 编码、RTMCCHead 头部与 NME 评估的源码级原理。读完本文,你将能够独立复现 RTMPose-m 在三个经典人脸对齐基准上的结果,并掌握将 68/98/106 点标注统一迁移到实时人脸关键点模型上的完整方法论。

RTMPose 与实时人脸关键点检测

传统 2D 姿态估计在公开基准上表现优异,但在工业落地中长期受困于模型参数过大、推理延迟过高。RTMPose 正是为弥合这一差距而提出的高性能实时多人姿态估计框架——它基于 MMPose,从范式(paradigm)、骨干网络(backbone)、定位算法(localization algorithm)、训练策略(training strategy)与部署推理(deployment inference)五个维度系统研究了影响多人姿态估计算法性能的因素。

原文档给出的核心性能数据(来源 configs/face_2d_keypoint/rtmpose/README.md):

  • 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% AP130+ FPS
  • 作者还在移动端部署场景下进一步验证了 RTMPose 在关键实时应用中的能力。

人脸的 2D 关键点检测(人脸对齐)本质上是一个单物体、高精度、强实时性要求的关键点回归任务,天然适合 RTMPose 的轻量高吞吐特性。在本仓库中,RTMPose 人脸模型共覆盖三个经典基准数据集,并在 face6 方案中实现了六大数据集联合训练。

模型库与基准结果

COCO-WholeBody-Face 数据集

COCO-WholeBody-Face 是 COCO-WholeBody(ECCV'2020)中人脸部分的关键点子集,评测指标为 NME(归一化平均误差),数值越小越好。在 val 集上的结果如下:

模型输入尺寸NME详情与下载
RTMPose-m256x2560.0466rtmpose_coco_wholebody_face.md

对应的完整结果(含 ckpt 与训练 log 下载地址)见 configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose_coco_wholebody_face.md:

ArchInput SizeNMEckptlog
pose_rtmpose_m256x2560.0466ckptlog

该模型输出68 个人脸关键点,在 COCO-WholeBody 训练集上训练 60 epoch,并以前缀pt-aic-coco的预训练权重初始化骨干。

WFLW 数据集

WFLW(CVPR'2018)是含 98 个关键点的野外人脸对齐基准,包含姿态、表情、光照、遮挡等 7 个子集,难度较高。模型在 WFLW train 上训练,评测结果如下:

模型输入尺寸NME详情与下载
RTMPose-m256x2564.01rtmpose_wflw.md

完整结果(含 ckpt 与 log)见 configs/face_2d_keypoint/rtmpose/wflw/rtmpose_wflw.md:

ArchInput SizeNMEckptlog
pose_rtmpose_m256x2564.01ckptlog

LaPa 数据集

LaPa(AAAI'2020)是面向人脸解析(face parsing)标注的大规模人脸数据集,其关键点标注含 106 个点。RTMPose-m 在 LaPa val 集上的结果如下:

模型输入尺寸NME详情与下载
RTMPose-m256x2561.29rtmpose_lapa.md

完整结果见 configs/face_2d_keypoint/rtmpose/lapa/rtmpose_lapa.md:

ArchInput SizeNMEckptlog
pose_rtmpose_m256x2561.29ckptlog

配置文件深度解析:以 COCO-WholeBody-Face 为例

以 rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py 为例,逐步拆解 RTMPose 人脸配置的每一层。WFLW 与 LaPa 配置结构完全一致,仅在数据集、关键点数量、训练轮数上不同,可对照阅读。

运行时与优化器

_base_ = ['../../../_base_/default_runtime.py'] # runtime 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) # optimizer 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))

要点:

  • 优化器采用AdamW,基础学习率4e-3,权重衰减0.05norm_decay_mult=0bias_decay_mult=0表示归一化层与偏置不做权重衰减,这是大规模训练中稳定 BN/偏置的常见做法;
  • 随机种子固定为 21,保证实验可复现;
  • LaPa 配置将max_epochs调整为 120(见 rtmpose-m_8xb64-120e_lapa-256x256.py)。

学习率调度与自动缩放

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), ] # automatically scaling LR based on the actual training batch size auto_scale_lr = dict(base_batch_size=512)
  • 前 1000 次迭代用LinearLR 线性预热(从1e-5起步),随后切换为CosineAnnealingLR余弦退火至base_lr * 0.05
  • auto_scale_lr = dict(base_batch_size=512):当你的实际 batch size 与 512 不同时,MMPose 会自动按线性缩放学习率,无需手动调参。

SimCC 编码器(codec)

codec = dict( type='SimCCLabel', input_size=(256, 256), sigma=(5.66, 5.66), simcc_split_ratio=2.0, normalize=False, use_dark=False)

RTMPose 不再输出二维热图,而是采用SimCC(Simple Coordinate Classification)方案,把人脸关键点定位转换为两个一维坐标分类问题。对应源码见 mmpose/codecs/simcc_label.py:

  • input_size:模型输入尺寸(w, h) = (256, 256)
  • simcc_split_ratio=2.0:标签分辨率是输入分辨率的 2 倍,即 x/y 方向各生成256*2=512长的分类向量;
  • sigma=(5.66, 5.66):一维高斯标签的方差(源码默认 6.0,此处为 RTMPose 人脸任务调优值)。注意:由于normalize=False,编码时不除以sigma * sqrt(2π)做归一化;
  • use_dark=False:不使用 DARK 亚像素细化(源码中decode()refine_simcc_dark分支被跳过);
  • smoothing_type默认为'gaussian',即对每个关键点在 x/y 轴分别生成一维高斯分布标签(见_generate_gaussian),标签形状为(N, K, W)(N, K, H),其中W = w * simcc_split_ratio
  • 解码时通过get_simcc_maximum取最大值位置,再除以simcc_split_ratio还原到输入图像空间。

模型结构: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, ))

逐项说明:

  • Backbone:CSPNeXt(来自 RTMDet),通过_scope_='mmdet'复用 MMDetection 注册的实现。deepen_factor=0.67widen_factor=0.75对应m 规格arch='P5'指 P5 层级结构,out_indices=(4,)只取最后一层特征,输入 256x256 图像经过 32 倍下采样得到 8x8 特征图;
  • 预训练init_cfg加载 AIC+COCO 上训练 210 epoch 的cspnext-m_udp-aic-coco骨干权重(prefix='backbone.')。WFLW、LaPa 配置使用同一预训练权重;而 face6 配置改用 ImageNet-1K RSB 预训练权重cspnext-m_8xb256-rsb-a1-600e_in1k(见 rtmpose-m_8xb256-120e_face6-256x256.py);
  • Head:RTMCCHead(源码见 mmpose/models/heads/coord_cls_heads/rtmcc_head.py),由**大核卷积层 + 全连接层 + 门控注意力单元(Gated Attention Unit, GAU)**组成,从低分辨率特征图生成一维 SimCC 表示。关键参数:
    • in_channels=768:CSPNeXt-m 最后一层输出通道数;
    • out_channels关键点数量,COCO-WholeBody-Face 为 68,WFLW 为 98,LaPa/face6 为 106;
    • final_layer_kernel_size=7:大核卷积用于扩大感受野;
    • gau_cfg:GAU 模块配置,hidden_dims=256s=128(分割维度)、expansion_factor=2、激活SiLU
    • loss=KLDiscretLoss:KL 散度离散回归损失,beta=10.label_softmax=True
    • decoder=codec:解码器即前面定义的 SimCCLabel;
  • test_cfg=dict(flip_test=True):测试时启用水平翻转 TTA,对原图与翻转图的结果取平均,可稳定提升精度。

数据管道:两阶段训练策略

训练管道(阶段一):

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.0), ]), dict(type='GenerateTarget', encoder=codec), dict(type='PackPoseInputs') ]

数据增强要点:

  • RandomBBoxTransform:尺度扰动scale_factor=[0.6, 1.4]、旋转扰动rotate_factor=80°(LaPa 配置放宽到[0.5, 1.5]并开启RandomHalfBody);
  • YOLOXHSVRandomAug:HSV 色彩空间增强;
  • Albumentation:Blur/MedianBlur 轻度模糊(p=0.1)与 CoarseDropout 随机块遮挡(用于提升遮挡鲁棒性);
  • GenerateTarget:利用 codec 将关键点坐标编码为 SimCC 标签;face6 配置额外传入use_dataset_keypoint_weights=True

验证管道则只保留必要的仿射变换,不做任何增强:

val_pipeline = [ dict(type='LoadImage', backend_args=backend_args), dict(type='GetBBoxCenterScale'), dict(type='TopdownAffine', input_size=codec['input_size']), dict(type='PackPoseInputs') ]

两阶段训练策略是 RTMPose 的核心技巧之一:配置通过mmdet.PipelineSwitchHook在最后stage2_num_epochs=10个 epoch 切换到更强的阶段二管道train_pipeline_stage2——该阶段收紧尺度扰动为[0.75, 1.25]、旋转角为 60°、CoarseDropout 概率降为 0.5,模拟接近测试时的分布,帮助模型"精修":

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) ]

同时配置EMA(指数移动平均)ExpMomentumEMAmomentum=0.0002update_buffers=True,用滑动平均权重提升收敛稳定性与最终精度。

数据加载与评测

train_dataloader = dict( batch_size=32, num_workers=10, persistent_workers=True, sampler=dict(type='DefaultSampler', shuffle=True), dataset=dict( type=dataset_type, # 'CocoWholeBodyFaceDataset' data_root=data_root, # 'data/coco/' data_mode='topdown', ann_file='annotations/coco_wholebody_train_v1.0.json', data_prefix=dict(img='train2017/'), pipeline=train_pipeline, ))
  • 训练 batch_size 为 32(WFLW 为 64,face6 为 256);data_mode='topdown'表明使用自顶向下范式,需要检测器提供人脸框;
  • 对应数据集类源码见 mmpose/datasets/datasets/face/coco_wholebody_face_dataset.py、mmpose/datasets/datasets/face/wflw_dataset.py、mmpose/datasets/datasets/face/lapa_dataset.py;
  • 评测器使用NME 指标(源码见 mmpose/evaluation/metrics/keypoint_2d_metrics.py 中的NME类):
val_evaluator = dict( type='NME', norm_mode='keypoint_distance', ) test_evaluator = val_evaluator

norm_mode='keypoint_distance'表示用**两眼瞳孔间距(inter-ocular distance)**作为归一化因子——NME类内置的DEFAULT_KEYPOINT_INDICES中,coco_wholebody_face[36, 45]wflw[60, 72](均为最左/最右眼关键点);LaPa 同理。checkpoint hook 以save_best='NME', rule='less'保存最佳权重,NME 越小越好。

训练、测试与推理实战

准备数据与安装

按 docs/zh_cn/user_guides/prepare_datasets.md 与 docs/zh_cn/installation.md 准备数据集(COCO-WholeBody 需按data/coco/布局放置 annotations 与图片,WFLW 需转换为 COCO 格式,转换脚本见 tools/dataset_converters/wflw2coco.py)并安装 MMPose 及其依赖。

训练

python tools/train.py configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py

WFLW 与 LaPa 对应命令:

python tools/train.py configs/face_2d_keypoint/rtmpose/wflw/rtmpose-m_8xb64-60e_wflw-256x256.py python tools/train.py configs/face_2d_keypoint/rtmpose/lapa/rtmpose-m_8xb64-120e_lapa-256x256.py

训练入口为 tools/train.py。多卡分布式训练可改用 tools/dist_train.sh:

bash tools/dist_train.sh <CONFIG> <GPU_NUM>

单卡训练可用--cfg-options覆盖配置,例如调整 batch size 以适配显存:

python tools/train.py <CONFIG> --cfg-options train_dataloader.batch_size=16

测试

使用 tools/test.py 评测已训练模型,--out保存结果文件,--work-dir指定工作目录:

python tools/test.py <CONFIG> <CHECKPOINT> --out <RESULT_FILE> --work-dir <WORK_DIR>

例如:

python tools/test.py configs/face_2d_keypoint/rtmpose/coco_wholebody_face/rtmpose-m_8xb32-60e_coco-wholebody-face-256x256.py \ <CHECKPOINT_PATH> --out results.pkl

推理与可视化

对于单张人脸图片的 top-down 推理,可直接使用 demo/topdown_demo_with_mmdet.py,其通过 MMDetection 检测器提供人脸框、MMPose 模型完成关键点定位:

python demo/topdown_demo_with_mmdet.py \ <MMDET_CONFIG> <MMDET_CKPT> \ <POSE_CONFIG> <POSE_CKPT> \ --input <IMAGE_OR_VIDEO> \ --output-root <OUTPUT_DIR> \ --draw-heatmap

检测器配置可复用 demo/mmdetection_cfg 中的人脸检测配置。若已有人脸框标注,也可用 demo/image_demo.py 直接推理。

face6:六大数据集联合训练的统一 106 点人脸关键点模型

除了三个单数据集模型,仓库还提供了face6方案(见 configs/face_2d_keypoint/rtmpose/face6/rtmpose_face6.md),在一个统一的 106 关键点定义下联合训练:

  • COCO-Wholebody-Face
  • WFLW
  • 300W
  • COFW
  • Halpe
  • LaPa
ConfigInput SizeNME(LaPa)FLOPS(G)Download
RTMPose-t*256x2561.670.652Model
RTMPose-s*256x2561.591.119Model
RTMPose-m*256x2561.442.852Model

其中Face6*表示模型在 6 个公开数据集上联合训练,三个规格(t/s/m)的 FLOPS 分别为 0.652/1.119/2.852 G,LaPa 上的 NME 依次为 1.67/1.59/1.44。模型元数据见 configs/face_2d_keypoint/rtmpose/face6/rtmpose_face6.yml,其中 RTMPose-m 还带有Alias: face,可直接通过mmpose工具链的别名引用。

face6 的训练配置是理解"多数据集统一"的关键,其核心机制:

  1. 关键点统一(KeypointConverter):6 个数据集的标注点数各不相同(WFLW 98 点、COFW 29 点、Halpe/300W/COCO-WholeBody-Face 68 点等),配置中通过KeypointConverter与手工定义的映射表(如kpt_68_to_106mapping_wflwmapping_halpemapping_cofw)将各类标注映射到统一的106 点定义。例如mapping_cofw(0, 33)表示 COFW 第 0 号点对应 106 点定义中的第 33 号点;
  2. 多源拼接(CombinedDataset):训练时用CombinedDatasetdataset_lapadataset_cocodataset_wflwdataset_300wdataset_cofwdataset_halpe六个子数据集拼接,metainfo以 configs/base/datasets/lapa.py 为准,且各子数据集pipeline=[],数据增强统一由外层train_pipeline施加;
  3. 测试集组合:测试阶段同样通过CombinedDataset组合 6 个 val 子集,在统一的 106 点空间上评估;
  4. 更深的调度eta_min=base_lr * 0.005,余弦退火在 epoch 30 后开始;增加clip_grad=dict(max_norm=35, norm_type=2)梯度裁剪以稳定大 batch(256)训练;骨干改用 ImageNet-1K RSB 预训练权重。

源码级原理小结

结合仓库源码,RTMPose 人脸关键点链路可以概括为三条主线:

  1. 编码:SimCCLabel 将 2D 关键点拆解为 x/y 两个一维高斯分类标签,标签长度 = 输入尺寸 ×simcc_split_ratio_generate_gaussian按 3-sigma 规则截断高斯范围并跳过不可见点(keypoints_visible < 0.5);
  2. 网络:RTMCCHead 在 CSPNeXt 输出的 8×8 低分辨率特征上,用大核卷积 + FC + GAU 直接回归两组一维向量,配合KLDiscretLossbeta=10.label_softmax=True)训练,解码时经get_simcc_maximum取 argmax 还原坐标;
  3. 评估:NME 以两眼间距(keypoint_distance归一化模式,内置各数据集的默认眼关键点索引)为归一化因子,对人脸任务比 AP 类指标更贴合对齐精度的工程语义。

这种"一维分类替代二维热图 + 低分辨率特征 + 轻量头部"的组合,正是 RTMPose 在保证精度的同时获得极高推理吞吐的关键,也让其成为实时人脸关键点(美颜、人脸特效、姿态辅助)场景的高性价比选择。

参考资源

  • 模型库总览:configs/face_2d_keypoint/rtmpose/README.md
  • 各数据集详情:COCO-WholeBody-Face / WFLW / LaPa / Face6 的 md 与 py 配置文件(见上文各节链接)
  • 训练与测试入口:tools/train.py、tools/test.py
  • 数据集准备与安装:docs/zh_cn/user_guides/prepare_datasets.md、docs/zh_cn/installation.md
  • 相关源码:mmpose/codecs/simcc_label.py、mmpose/models/heads/coord_cls_heads/rtmcc_head.py、mmpose/evaluation/metrics/keypoint_2d_metrics.py

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

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

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

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

立即咨询