mmpose 实战:SCNet 自校准卷积在 COCO-WholeBody-Face 面部关键点检测中的应用与配置全解析
2026/9/17 14:32:12 网站建设 项目流程

mmpose 实战:SCNet 自校准卷积在 COCO-WholeBody-Face 面部关键点检测中的应用与配置全解析

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

导读:本文围绕 configs/face_2d_keypoint/topdown_heatmap/coco_wholebody_face/scnet_coco_wholebody_face.md 展开,深入讲解如何在 OpenMMLab 姿态估计工具箱 mmpose 中,使用 CVPR 2020 提出的 SCNet(Self-Calibrated Convolutions)在 COCO-WholeBody-Face 数据集上完成 68 点面部关键点检测。读完本文,你将掌握该模型完整配置文件的每一处参数含义、SCNet 自校准卷积的源码级实现原理、COCO-WholeBody-Face 数据集标注的解析方式,以及如何复现 NME 0.0567 的评测结果并执行训练与测试。

一、任务背景:面部关键点检测的两个核心组件

本模型配置由两个关键组件构成,二者在原文档中分别以算法与数据集的引用信息给出:

1.1 算法:SCNet(CVPR'2020)

SCNet 全称为 "Improving Convolutional Networks with Self-Calibrated Convolutions",由 Liu Jiang-Jiang 等人发表于 CVPR 2020。其核心思想是用自校准卷积(Self-Calibrated Convolution, SCConv)替代普通卷积,在不显著增加参数量的前提下扩大每个卷积层的感受野,从而让网络能够利用更大范围的上下文信息——这对面部关键点这类需要对局部特征(眼睛、嘴角等)与全局结构(脸型轮廓)同时建模的任务尤为有价值。

原文档给出的 BibTeX 引用如下:

@inproceedings{liu2020improving, title={Improving Convolutional Networks with Self-Calibrated Convolutions}, author={Liu, Jiang-Jiang and Hou, Qibin and Cheng, Ming-Ming and Wang, Changhu and Feng, Jiashi}, booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition}, pages={10096--10105}, year={2020} }

1.2 数据集:COCO-WholeBody-Face(ECCV'2020)

COCO-WholeBody 是 "Whole-Body Human Pose Estimation in the Wild" 工作中提出的大规模人体姿态数据集,在 COCO 的基础上补充了脚部、面部和手部的关键点标注。其中面部关键点采用 68 点标记方案(mark-up),对应数据集子任务 COCO-WholeBody-Face。mmpose 中以独立的CocoWholeBodyFaceDataset类封装该子集,用于面部关键点定位任务。

原文档给出的 BibTeX 引用如下:

@inproceedings{jin2020whole, title={Whole-Body Human Pose Estimation in the Wild}, author={Jin, Sheng and Xu, Lumin and Xu, Jin and Wang, Can and Liu, Wentao and Qian, Chen and Ouyang, Wanli and Luo, Ping}, booktitle={Proceedings of the European Conference on Computer Vision (ECCV)}, year={2020} }

二、模型结果与权重

原文档的核心结论是 SCNet-50 在 COCO-WholeBody-Face 验证集上的评测结果。mmpose 对 2D 面部关键点任务使用NME(Normalized Mean Error,归一化平均误差)作为评估指标:

ArchInput SizeNMEckptlog
pose_scnet_50256x2560.0567已发布权重(见 model-index.yml 与 scnet_coco_wholebody_face.yml)训练日志已随模型发布

其中:

  • Input Size 256x256:输入到网络的图像分辨率;
  • NME 0.0567:归一化平均误差,数值越小精度越高;
  • 模型权重与训练日志托管于 OpenMMLab 官方模型库,元数据登记在 scnet_coco_wholebody_face.yml 中,训练数据为 COCO-WholeBody-Face,任务分类为 Face 2D Keypoint。

三、配置文件逐段精读

完整的训练配置文件位于 td-hm_scnet50_8xb32-60e_coco-wholebody-face-256x256.py,文件名本身即概括了核心信息:td-hm(Top-Down Heatmap,自顶向下热图范式)、scnet50(SCNet-50 骨干)、8xb32(8 卡 × 每卡 batch 32)、60e(60 epoch)、输入 256×256。下面按模块逐段拆解。

3.1 运行时配置(runtime)

_base_ = ['../../../_base_/default_runtime.py'] # runtime train_cfg = dict(max_epochs=60, val_interval=1)
  • 继承 default_runtime.py 中的通用运行配置(日志、随机种子、环境等);
  • max_epochs=60:共训练 60 个 epoch;
  • val_interval=1:每个 epoch 结束后执行一次验证。

3.2 优化器与学习率调度(optimizer & scheduler)

# optimizer optim_wrapper = dict(optimizer=dict( type='Adam', lr=2e-3, )) # 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=[40, 55], gamma=0.1, by_epoch=True) ] # automatically scaling LR based on the actual training batch size auto_scale_lr = dict(base_batch_size=256)
  • 使用Adam优化器,初始学习率2e-3
  • 两段式学习率调度
    • 先执行 500 iteration 的线性 warm-upstart_factor=0.001,即从 1e-3 × 1e-3 起步线性爬升),by_epoch=False表示按 iteration 计;
    • 再切换到MultiStepLR,在 epoch 40 和 55 处将学习率乘以gamma=0.1衰减(注意该调度器的end=210大于max_epochs=60,实际以训练长度为准);
  • auto_scale_lr声明了基准 batch size 为 256,mmengine 会根据实际使用的总 batch size 自动缩放学习率。

3.3 模型结构(backbone + head)

# 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='SCNet', depth=50, init_cfg=dict( type='Pretrained', checkpoint='https://download.openmmlab.com/mmpose/' 'pretrain_models/scnet50-7ef0a199.pth')), head=dict( type='HeatmapHead', in_channels=2048, out_channels=68, loss=dict(type='KeypointMSELoss', use_target_weight=True), decoder=codec), test_cfg=dict( flip_test=True, flip_mode='heatmap', shift_heatmap=True, ))

逐项说明:

  • MSRAHeatmapcodec:采用 MSRA 方案(即 "Simple Baselines for Human Pose Estimation and Tracking" 中的做法)将关键点编码为高斯热图。input_size=(256, 256)为输入图像尺寸,heatmap_size=(64, 64)为热图尺寸(即 4 倍下采样),sigma=2为高斯核标准差。codec 同时承担编码(训练时由GenerateTarget调用生成热图标签)与解码(测试时从热图回归关键点坐标)两项职责,具体实现在 mmpose/codecs/msra_heatmap.py;
  • TopdownPoseEstimator:mmpose 的通用自顶向下姿态估计器,负责串联 preprocessor → backbone → head 的完整前向流程;
  • PoseDataPreprocessor:图像归一化,使用 ImageNet 统计量mean/std,并设置bgr_to_rgb=True适配 OpenCV 读取的 BGR 图像;
  • SCNet骨干depth=50,并加载 OpenMMLab 预训练的 scnet50 ImageNet 权重(scnet50-7ef0a199.pth)进行初始化;
  • HeatmapHead:简单热图回归头,in_channels=2048对应 SCNet-50 最后一层输出通道,out_channels=68对应 68 个面部关键点,损失函数为带关键点权重(use_target_weight=True)的 MSE 损失KeypointMSELoss
  • test_cfg:测试阶段启用水平翻转测试(flip_test),翻转模式为heatmap(对热图进行翻转融合),并shift_heatmap=True对翻转后的热图做像素偏移修正,这是经典的自顶向下方法提升精度的标准技巧。

3.4 数据流水线(pipeline)

# pipelines train_pipeline = [ dict(type='LoadImage'), dict(type='GetBBoxCenterScale'), dict(type='RandomFlip', direction='horizontal'), dict( type='RandomBBoxTransform', rotate_factor=60, scale_factor=(0.75, 1.25)), 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') ]
  • 训练流水线LoadImage加载图像 →GetBBoxCenterScale从标注框提取中心与尺度 →RandomFlip随机水平翻转 →RandomBBoxTransform做数据增强(旋转 ±60°,尺度缩放 0.75~1.25)→TopdownAffine将人脸区域仿射裁剪到 256×256 →GenerateTarget用 MSRAHeatmap codec 生成 64×64 高斯热图标签 →PackPoseInputs打包;
  • 验证流水线:去除翻转与增强,仅保留仿射对齐与打包,保证评测一致性。

3.5 数据加载(data loaders)

dataset_type = 'CocoWholeBodyFaceDataset' data_mode = 'topdown' data_root = 'data/coco/' train_dataloader = dict( batch_size=32, 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/coco_wholebody_train_v1.0.json', data_prefix=dict(img='train2017/'), 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/coco_wholebody_val_v1.0.json', data_prefix=dict(img='val2017/'), test_mode=True, pipeline=val_pipeline, )) test_dataloader = val_dataloader
  • 训练与验证分别读取coco_wholebody_train_v1.0.jsoncoco_wholebody_val_v1.0.json标注,图像分别位于 COCO 的train2017/val2017/目录;
  • data_mode='topdown'表示单实例样本模式(每个样本包含一张人脸图像区域);
  • 训练 batch size 32、shuffle;验证不 shuffle、drop_last=Falsetest_dataloader直接复用val_dataloader

3.6 评估指标(evaluator)

val_evaluator = dict( type='NME', norm_mode='keypoint_distance', ) test_evaluator = val_evaluator

NME 评估器定义于 mmpose/evaluation/metrics/keypoint_2d_metrics.py,其norm_mode支持'use_norm_item''keypoint_distance'两种归一化模式:前者读取标注中预先给出的归一化距离,后者则根据标注中的关键点距离计算归一化因子。本配置使用'keypoint_distance'模式,即利用面部几何尺度(如两瞳孔距离)对误差进行归一化,得到无量纲的 NME 值。

四、SCNet 源码级原理剖析

SCNet 骨干网络实现在 mmpose/models/backbones/scnet.py,它继承自 ResNet,通过替换残差瓶颈块引入自校准卷积。

4.1 SCConv:自校准卷积的核心算子

SCConv是自校准机制的最小实现单元(scnet.py),其前向计算可概括为:

out = torch.sigmoid( torch.add(identity, F.interpolate(self.k2(x), identity.size()[2:]))) out = torch.mul(self.k3(x), out) out = self.k4(out)

四个子模块分工如下:

子模块作用
k2对输入做AvgPool2d(kernel_size=pooling_r, stride=pooling_r)下采样以扩大感受野,再经 3×3 卷积、BN 提取上下文特征,最后通过F.interpolate上采样回原尺寸
k33×3 卷积提取原始尺度的局部特征
门控sigmoid(identity + k2输出)生成 0~1 的软注意力权重,对k3的输出做逐元素加权,实现"用大感受野信息校准局部特征"
k43×3 卷积(stride 由外部传入)聚合校准后的特征并输出

其中pooling_r默认取 4(类属性SCBottleneck.pooling_r = 4),即下采样 4 倍后提取上下文。这种"下采样扩感受野 → 上采样 → sigmoid 门控"的结构正是"自校准"一词的来源:卷积核的权重被输入本身的全局结构所调制。

4.2 SCBottleneck:通道分流式残差块

SCBottleneck(scnet.py)在标准 ResNet Bottleneck 基础上做了通道分流:输入先经两个并行的 1×1 卷积(conv1conv2)分别得到mid_channels的两种特征,其中

  • 一路out_a走普通 3×3 卷积(k1);
  • 另一路out_b走上述 SCConv 自校准路径;

两路结果沿通道拼接后经conv3(1×1 卷积)投影回out_channels,再与残差identity相加、ReLU 输出。这种设计将传统 Bottleneck 的"串行 1×1-3×3-1×1"改造为"并行双分支 + 自校准",使模型能以接近原 ResNet 的计算量获得更丰富的多尺度表征。

4.3 SCNet-50 的整体结构

SCNet类(scnet.py)仅需指定depth,其结构表为:

arch_settings = { 50: (SCBottleneck, [3, 4, 6, 3]), 101: (SCBottleneck, [3, 4, 23, 3]) }

即仅支持 50 层与 101 层两种深度,其余超参(base_channelsstridesdilationsfrozen_stageswith_cp等)均继承自ResNet。SCNet-50 的四阶段输出通道为 256/512/1024/2048(与 ResNet-50 一致),这正是配置中HeatmapHead.in_channels=2048的由来。其正确性由单元测试 tests/test_models/test_backbones/test_scnet.py 覆盖,包括:

  • 非法深度(如SCNet(20))会抛出KeyError
  • out_indices组合下的前向输出形状正确;
  • frozen_stages冻结、with_cp梯度检查点、zero_init_residual等 ResNet 继承特性均可用。

五、COCO-WholeBody-Face 数据集的工程化处理

5.1 数据集类与标注解析

CocoWholeBodyFaceDataset定义于 mmpose/datasets/datasets/face/coco_wholebody_face_dataset.py,继承自BaseCocoStyleDataset,其parse_data_info方法负责将 COCO 风格 JSON 转成 mmpose 内部样本格式,关键逻辑包括:

  • 实例过滤:仅当ann['face_valid']为真且max(ann['face_kpts']) > 0时保留该人脸实例;
  • 人脸框提取:从ann['face_box'](xywh 格式)计算人脸包围框,并裁剪到图像边界内,输出为[1, 4]的 xyxy 框;
  • 关键点转换face_kpts原始形状为(68, 3)(x, y, 可见性),reshape 为(1, 68, 3)后拆分出坐标keypoints与可见性keypoints_visible(取min(1, 可见性),将 0/1/2 三类标注统一为是否可见)。

5.2 68 点语义与元信息

数据集的 68 点语义定义在 configs/base/datasets/coco_wholebody_face.py:

  • 0~16:面部轮廓(chin/face oval);
  • 17~26:眉毛(eyebrows);
  • 27~35:鼻梁与鼻尖(nose);
  • 36~47:眼睛(eyes);
  • 48~67:嘴唇外沿与内沿(mouth)。

该文件同时为每个关键点配置了swap映射(如face-0face-16),用于水平翻转时左右对称关键点的标签交换;joint_weights=[1.] * 68为全部关键点等权;sigmas数组给出各关键点的归一化标准差,供 NME/OKS 类指标使用。

六、训练、测试与推理实战

6.1 数据准备

使用默认配置时,需将 COCO-WholeBody 数据按以下布局放置(data_root = 'data/coco/'):

data/coco/ ├── annotations/ │ ├── coco_wholebody_train_v1.0.json │ └── coco_wholebody_val_v1.0.json ├── train2017/ └── val2017/

数据集下载与整理的完整说明可参考 prepare_datasets.md。

6.2 训练

单卡训练:

python tools/train.py configs/face_2d_keypoint/topdown_heatmap/coco_wholebody_face/td-hm_scnet50_8xb32-60e_coco-wholebody-face-256x256.py

多卡分布式训练(8 卡):

bash tools/dist_train.sh configs/face_2d_keypoint/topdown_heatmap/coco_wholebody_face/td-hm_scnet50_8xb32-60e_coco-wholebody-face-256x256.py 8

8xb32即 8 卡 × batch 32 = 256 总 batch size,与auto_scale_lr.base_batch_size=256对应,因此单卡训练时学习率会被自动缩小以保持训练动力学一致。训练细节与参数含义可参考 train_and_test.md。

6.3 测试与评测

python tools/test.py configs/face_2d_keypoint/topdown_heatmap/coco_wholebody_face/td-hm_scnet50_8xb32-60e_coco-wholebody-face-256x256.py ${CHECKPOINT_FILE}

其中${CHECKPOINT_FILE}为模型权重路径。测试阶段会自动应用test_cfg中的翻转测试策略,并输出 NME 指标——官方发布的 SCNet-50 权重在验证集上的 NME 为0.0567。训练过程中的最佳模型保存策略由default_hooks中的save_best='NME', rule='less'决定,即始终保留 NME 最低的检查点。

6.4 推理

mmpose 也提供了统一的 Inferencer 接口进行快速推理,可直接加载该配置对应的模型进行单张图片的关键点预测与可视化,具体用法见 inference.md 与 demo/image_demo.py。

七、总结

SCNet-50 + COCO-WholeBody-Face 配置是 mmpose 面部 2D 关键点检测体系中"强骨干 + 标准热图范式"的代表性方案:

  • 算法层面:SCNet 通过 SCConv 自校准机制(下采样扩感受野 + sigmoid 门控加权)在几乎不增加参数的前提下提升骨干网络的上下文建模能力,其实现可直接在 mmpose/models/backbones/scnet.py 中完整阅读;
  • 工程层面:该配置集中体现了 mmpose 自顶向下热图任务的完整范式——MSRAHeatmap codec 负责热图编解码、TopdownPoseEstimator串联骨干与回归头、RandomBBoxTransform做框级增强、NME评估器做归一化误差评测;
  • 复现层面:NME 0.0567 的结果可通过 td-hm_scnet50_8xb32-60e_coco-wholebody-face-256x256.py 一键复现,权重元数据登记于 scnet_coco_wholebody_face.yml。

对于希望在精度与速度之间取得平衡、或希望基于该骨干做迁移学习的开发者,建议进一步对比同目录下的 resnet_coco_wholebody_face.md(ResNet-50 基线)与 hrnetv2_coco_wholebody_face.md(HRNet 高分辨率表示)等配置,结合自身任务需求选择骨干网络。

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

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

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

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

立即咨询