PaddleDetection 关键点检测配置完全指南:以 tinypose_256x192.yml 为例解析 Top-Down 姿态估计全流程
PaddleDetection 关键点检测配置完全指南:以 tinypose_256x192.yml 为例解析 Top-Down 姿态估计全流程
导读
本文是 PaddleDetection 关键点检测(KeyPoint Detection)配置体系的实战指南,以仓库中 configs/keypoint/tiny_pose/tinypose_256x192.yml 这一真实配置文件为蓝本,逐段讲解 Top-Down 姿态估计任务的完整 YAML 配置——从全局训练参数、模型结构、优化器,到数据集定义与数据增强流水线。读完本文,你将掌握 PaddleDetection 关键点模型每个配置项的语义、取值边界与底层实现原理,能够独立读懂、修改并上手训练(如 PP-TinyPose 系列)关键点检测模型。
一、配置文件的整体骨架
PaddleDetection 采用"约定式配置 + 注册机制"的设计:YAML 文件描述模型的组装方式与训练流程,ppdet/core/workspace.py 负责解析,各模块通过 @register 装饰器向全局注册表登记,配置中的字符串类名(如 TopDownHRNet、LiteHRNet、KeyPointMSELoss)会被动态实例化为真实对象。
一份关键点配置文件通常由以下五个部分组成,这与通用检测配置(可参考 configs/runtime.yml)保持一致:
# 1. 全局训练参数(use_gpu / epoch / weights / save_dir 等)
# 2. model 模型结构(architecture + backbone + head + loss + post_process)
# 3. optimizer 优化器(LearningRate 调度 + OptimizerBuilder)
# 4. data 数据部分(TrainDataset / EvalDataset / TestDataset + 三个 Reader)
# 5. 其他公共定义(worker_num、global_mean、global_std 等)
其中大量参数通过 YAML 锚点(&name)与引用(*name)复用,例如 num_joints: &num_joints 17 定义一次,后续在模型、数据集、损失中统一引用,避免多处维护导致不一致。理解这一点是读懂本配置的关键。
二、全局训练参数详解
2.1 训练控制类参数
| 配置项 | 示例值 | 含义与说明 |
|---|---|---|
use_gpu |
true |
是否使用 GPU 训练 |
log_iter |
5 |
每 5 个 iter 打印一次日志 |
save_dir |
output |
模型保存目录 |
snapshot_epoch |
10 |
每训练 10 个 epoch 保存一次快照 |
weights |
output/tinypose_256x192/model_final |
加载的权重路径,不含 .pdparams 后缀;用于断点续训或评估 |
epoch |
420 |
总训练轮数 |
2.2 任务核心语义参数
num_joints: &num_joints 17 # 关键点数量(COCO 人体 17 点)
pixel_std: &pixel_std 200 # 标准化像素长度,用于由 bbox 计算尺度
metric: KeyPointTopDownCOCOEval # 评估指标
num_classes: 1 # 类别数(检测任务字段,关键点任务不使用)
train_height: &train_height 256 # 模型输入高度
train_width: &train_width 192 # 模型输入宽度
trainsize: &trainsize [*train_width, *train_height] # 输入尺寸 [w, h]
hmsize: &hmsize [48, 64] # 输出热图尺寸 [w, h]
flip_perm: &flip_perm [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16]]
逐一说明:
num_joints:决定输出通道数。COCO 人体关键点共 17 个,其索引定义可参见 ppdet/data/source/keypoint_coco.py 中的注释:0鼻子、1/2左右眼、3/4左右耳、5/6左右肩、7/8左右肘、9/10左右腕、11/12左右髋、13/14左右膝、15/16左右踝。pixel_std:文档注释为"don't care",实际它在数据加载中承担重要作用——KeypointTopDownCocoDataset._box2cs用scale = [w / pixel_std, h / pixel_std]将 bbox 尺度归一化到模型坐标系(见下文数据集章节),因此应保持默认值 200 并与其他模块保持一致。hmsize:输出热图尺寸,通常为输入尺寸的 1/4(256×192 输入 → 64×48 热图)。注意trainsize是[w, h](即[192, 256]),而hmsize是[48, 64]——前者宽在前,后者高在前,是两个维度顺序约定不同的列表,配置时切勿混淆。flip_perm:左右对称关键点配对表。进行水平翻转数据增强或 flip-test 时,左腕(id=9)会变成右腕,因此需要将左右对应的关键点互换;<a href="https://link.gitcode.com/i/81c2f226733015db21a63a4c2c7b59a5" target="_blank">1,2]表示左眼(1)与右眼(2)成对。该配对在 [ppdet/modeling/architectures/keypoint_hrnet.py 的flip_back方法中被用于把翻转后的热图映射回原坐标系。
三、model 模型模块
3.1 TopDownHRNet 架构
architecture: TopDownHRNet # 模型架构
TopDownHRNet:
backbone: LiteHRNet # 骨干网络
post_process: HRNetPostProcess
flip_perm: *flip_perm # 引用全局 flip_perm
num_joints: *num_joints # 关键点数(即输出通道数)
width: &width 40 # backbone 输出通道数
loss: KeyPointMSELoss # 损失函数
use_dark: true # 后处理是否使用 DarkPose 坐标解码
TopDownHRNet 的完整实现位于 ppdet/modeling/architectures/keypoint_hrnet.py,核心前向逻辑为:
backbone(self.inputs)提取特征feats;- 通过
final_conv = L.Conv2d(width, num_joints, 1, 1, 0, bias=True)(1×1 卷积)将width通道映射为num_joints个通道,即生成每张热图; - 训练阶段直接返回热图交给
KeyPointMSELoss计算损失; - 推理阶段若
flip=True,将图像水平翻转再前向一次,用flip_back还原左右关键点并做shift_heatmap平移修正,最后与原热图取平均(即 flip-test 测试时增强); - 后处理由
HRNetPostProcess完成,将热图坐标映射回原图坐标系。
use_dark: true 对应 HRNetPostProcess(use_dark),即采用 DARK(Distribution-Aware coordinate Representation of KeyPoints,CVPR 2020)坐标解码:先对热图做高斯模糊、取对数,再对峰值附近做二阶泰勒展开修正坐标,得到亚像素精度的关键点位置。该逻辑在 keypoint_hrnet.py 的 dark_parse / dark_postprocess / get_final_preds 中实现;若关闭 DARK,则退化为"峰值 + 0.25 像素偏移"的常规解码。在低分辨率热图(如本配置 64×48)下,DARK 能显著提升精度。
3.2 LiteHRNet 骨干网络
LiteHRNet:
network_type: wider_naive # 网络类型
freeze_at: -1 # 冻结分支:-1 表示不冻结
freeze_norm: false # 是否冻结归一化层权重
return_idx: [0] # 取第 0 个分支的特征
LiteHRNet 源码在 ppdet/modeling/backbones/lite_hrnet.py:
network_type可选["lite_18", "lite_30", "naive", "wider_naive"]。wider_naive将 naive 结构各 stage 通道加宽为[40,80] / [40,80,160] / [40,80,160,320],是 PP-TinyPose 为移动端优化的轻量选择;freeze_at:冻结指定阶段不参与反向传播,-1表示全部参与训练;freeze_norm:是否冻结 BN 等归一化层参数(迁移学习冷启动时常用);return_idx:返回哪个 stage 的特征给检测头。配置为[0],即只取第一级输出,对应TopDownHRNet._forward中的feats[0]。
3.3 损失函数
KeyPointMSELoss:
use_target_weight: true # 是否使用目标权重(按关键点可见性加权)
loss_scale: 1.0 # 损失缩放系数,final_loss = loss * loss_scale
KeyPointMSELoss 实现在 ppdet/modeling/losses/keypoint_loss.py:底层为 nn.MSELoss(reduction='mean')。use_target_weight=True 时,热图损失按每个关键点的可见性权重(由 ToHeatmapsTopDown_DARK 生成的 target_weight)进行加权,遮挡/未标注的关键点不参与梯度贡献。
四、optimizer 优化器模块
4.1 学习率调度
LearningRate:
base_lr: 0.002 # 基础学习率
schedulers:
- !PiecewiseDecay # 分段衰减
milestones: [380, 410] # 衰减发生的 epoch
gamma: 0.1 # 衰减系数,new_lr = lr * gamma
- !LinearWarmup # 线性预热
start_factor: 0.001 # 起始学习率为 base_lr 的 0.001 倍
steps: 500 # 预热持续 500 个 iter
epoch: 420 与 milestones: [380, 410] 配合:训练前 380 个 epoch 保持 base_lr,380 与 410 处各衰减为原来的 0.1 倍,即学习率路径为 0.002 → 0.0002 → 0.00002,后段用小学习率精细收敛。LinearWarmup 在前 500 个 iter 将学习率从 0.002 × 0.001 线性升至 0.002,避免训练初期梯度震荡。
4.2 优化器构建
OptimizerBuilder:
optimizer:
type: Adam # 优化器类型
regularizer:
factor: 0.0 # 正则化权重
type: L2 # 正则化类型 L2 / L1
关键点任务通常使用 Adam + 无权重衰减(factor: 0.0)。需要提醒的是:若修改 GPU 数量或 batch size,应根据 configs/keypoint/tiny_pose/README_en.md 中 Model Zoo 的说明参考 docs/tutorials/FAQ/README.md 按线性缩放规则调整 base_lr。
五、data 数据模块
5.1 三个数据集的定义
TrainDataset:
!KeypointTopDownCocoDataset
image_dir: "" # 图片目录(相对 dataset_dir)
anno_path: aic_coco_train_cocoformat.json # 训练标注(COCO 格式,相对 dataset_dir)
dataset_dir: dataset # 数据集根目录
num_joints: *num_joints
trainsize: *trainsize
pixel_std: *pixel_std
use_gt_bbox: True # 是否使用 GT bbox
EvalDataset:
!KeypointTopDownCocoDataset
image_dir: val2017
anno_path: annotations/person_keypoints_val2017.json
dataset_dir: dataset/coco
num_joints: *num_joints
trainsize: *trainsize
pixel_std: *pixel_std
use_gt_bbox: True
image_thre: 0.5 # 检测框置信度阈值(use_gt_bbox=False 时生效)
TestDataset:
!ImageFolder
anno_path: dataset/coco/keypoint_imagelist.txt # 图片列表文件
要点解析:
KeypointTopDownCocoDataset是 Top-Down 关键点数据集加载器,实现在 ppdet/data/source/keypoint_coco.py。Top-Down 范式是"先检测人框、再对每人体关键点":数据集中每条样本对应"一张图片中的一个人框 + 该人的关键点标注"。use_gt_bbox: True时,调用_load_coco_keypoint_annotations()直接从标注解析 bbox 并计算 center/scale;use_gt_bbox: False时调用_load_coco_person_detection_results()从bbox_file(检测器输出的 JSON)读取人框,此时image_thre用于过滤低置信度框,模拟真实部署时"检测器+关键点"级联的评测场景。文档注释"commonly used in eval"即指后者。_box2cs(keypoint_coco.py)是 Top-Down 的关键预处理:由 bbox 中心得到center,并按trainsize宽高比修正后除以pixel_std得到scale,再统一乘以 1.25 留出裁剪余量,确保姿态不会贴边被截断。- 训练标注
aic_coco_train_cocoformat.json是 COCO 与 AI Challenger 数据集的合并标注(统一为 COCO 格式),这一对齐细节与训练命令可参见 configs/keypoint/tiny_pose/README_en.md 的 Model Training 章节。 TestDataset使用ImageFolder:无标注推理时仅通过图片列表文件加载图像。
5.2 训练数据增强流水线(TrainReader)
worker_num: 2 # 数据加载进程数
global_mean: &global_mean [0.485, 0.456, 0.406] # 归一化均值
global_std: &global_std [0.229, 0.224, 0.225] # 归一化标准差
TrainReader:
sample_transforms:
- RandomFlipHalfBodyTransform: # 随机翻转 + 随机半身变换
scale: 0.25 # 尺寸缩放幅度上限
rot: 30 # 最大旋转角度
num_joints_half_body: 8 # 可见关键点少于该值时跳过半身变换
prob_half_body: 0.3 # 半身变换概率
pixel_std: *pixel_std
trainsize: *trainsize
upper_body_ids: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # 上半身关键点 id
flip_pairs: *flip_perm # 左右配对(翻转时交换)
- AugmentationbyInformantionDropping: # AID 信息丢弃增强
prob_cutout: 0.5 # 执行 cutout 的概率
offset_factor: 0.05 # 遮挡中心抖动偏移(相对输入宽的百分比)
num_patch: 1 # 遮挡区域数量
trainsize: *trainsize
- TopDownAffine: # 仿射变换到模型输入尺寸
trainsize: *trainsize
use_udp: true # 是否使用 UDP 无偏数据处理
- ToHeatmapsTopDown_DARK: # 生成 GT 高斯热图
hmsize: *hmsize
sigma: 2 # 高斯核标准差
batch_transforms:
- NormalizeImage:
mean: *global_mean
std: *global_std
is_scale: true # 像素值从 [0,255] 缩放到 [0,1]
- Permute: {} # 通道 HWC → CHW
batch_size: 128 # 训练 batch size
shuffle: true
drop_last: false # 是否丢弃不足一个 batch 的尾部数据
各增强算子的底层实现位于 ppdet/data/transform/keypoint_operators.py:
RandomFlipHalfBodyTransform(L511-L629):综合了随机缩放、随机旋转(rot_prob=0.6概率触发)、随机水平翻转与半身变换。半身变换在可见关键点总数 >num_joints_half_body且概率命中prob_half_body时,以upper_body_ids划分上下半身,随机选取一半身体重新计算 center/scale 并放大 1.5 倍,模拟只拍到半身的场景;翻转时按flip_pairs交换左右关键点(flip_joints)。AugmentationbyInformantionDropping(AID,L633-L688):以prob_cutout概率随机选中一个可见关键点,在其周围(位置叠加offset_factor比例的随机抖动)以num_patch个圆形区域进行像素置零,模拟关键点被遮挡的情况,提升模型对遮挡的鲁棒性。TopDownAffine(L820 起):根据center、scale、旋转角计算仿射变换矩阵(UDP 模式下使用get_warp_matrix无偏版本),将人体裁剪区变换到trainsize。use_udp: true采用 UDP(Unbiased Data Processing)编码,避免传统仿射变换因整数取整引入的坐标偏差,配合 flip-test 使用。ToHeatmapsTopDown_DARK(L1149 起):将关键点坐标按sigma=2的高斯核散布到hmsize热图上生成训练目标,同时产出target_weight可见性权重供KeyPointMSELoss使用。NormalizeImage/Permute为批处理变换:前者按global_mean/global_std归一化(is_scale=true时先除以 255),实现见 ppdet/data/transform/operators.py;后者将图像从 HWC 变为 CHW。
5.3 评估与测试 Reader
EvalReader:
sample_transforms:
- TopDownAffine: # 评估仅做仿射变换,无随机增强
trainsize: *trainsize
use_udp: true
batch_transforms:
- NormalizeImage: # 均值/方差必须与 TrainReader 一致
mean: *global_mean
std: *global_std
is_scale: true
- Permute: {}
batch_size: 16
TestReader:
inputs_def:
image_shape: [3, *train_height, *train_width] # 模型输入维度 CHW
sample_transforms:
- Decode: {} # 加载并解码图片
- TopDownEvalAffine: # 评估用仿射变换(center 取图像中心)
trainsize: *trainsize
- NormalizeImage:
mean: *global_mean
std: *global_std
is_scale: true
- Permute: {}
batch_size: 1
fuse_normalize: false # 导出模型时是否将归一化融合进模型
- EvalReader 与 TrainReader 的差别:去掉随机增强,仅保留仿射变换与归一化,且
batch_size较小(16)。 - TestReader 面向无 GT 的部署推理:
Decode负责解码图片(实现在 ppdet/data/transform/operators.py);TopDownEvalAffine(keypoint_operators.py)以整图中心为center、整图尺寸为scale做仿射,适用于检测器已给出人框、或整图单人推理场景。 fuse_normalize: false:导出模型时若置为true,归一化算子会被融合进模型内部,推理时省去预处理中的归一化计算以加速——PP-TinyPose 移动端部署文档明确建议导出时开启(见 configs/keypoint/tiny_pose/README_en.md 的 Deployment 章节)。
六、评估指标与验证闭环
配置中的 metric: KeyPointTopDownCOCOEval 对应 ppdet/metrics/keypoint_metrics.py 中的 KeyPointTopDownCOCOEval:评估时收集每张图的预测关键点 <a href="https://link.gitcode.com/i/82a522736dfe2372209d240def1393ad" target="_blank">x, y, score]、center、scale 与 im_id,写入 keypoints_results.json,最终调用 pycocotools 的 COCOeval(iou_type='keypoints')按 OKS(Object Keypoint Similarity)指标计算 AP/AR。其中 oks_thre=0.9、in_vis_thre=0.2 为默认评估阈值,相关后处理工具(oks_nms 等)定义于 [ppdet/modeling/keypoint_utils.py。
七、从配置到训练:完整使用流程
基于本配置启动训练(多卡)与评估:
# 训练(-c 指定配置文件)
python3 -m paddle.distributed.launch tools/train.py -c configs/keypoint/tiny_pose/tinypose_256x192.yml
# 评估(-o 覆盖配置,加载训练好的权重)
python3 tools/eval.py -c configs/keypoint/tiny_pose/tinypose_256x192.yml \
-o weights=output/tinypose_256x192/model_final
# 导出部署模型
python3 tools/export_model.py -c configs/keypoint/tiny_pose/tinypose_256x192.yml \
--output_dir=output_inference -o weights=output/tinypose_256x192/model_final \
TestReader.fuse_normalize=true
训练数据需准备 dataset/ 目录下的图片与 aic_coco_train_cocoformat.json 合并标注、dataset/coco/annotations/person_keypoints_val2017.json 验证标注,布局与配置中的 dataset_dir/image_dir/anno_path 对应。若在移动端部署,还需配合 Paddle-Lite 将导出的模型转换为 .nb 格式,完整流程见 deploy/lite/README.md。
八、快速修改指南
- 换输入分辨率:同时修改
train_height/train_width、trainsize、hmsize(约为输入 1/4)三处锚点定义,其余引用自动跟随;参考同目录 tinypose_128x96.yml 的做法。 - 换数据集:将
TrainDataset/EvalDataset的dataset_dir、image_dir、anno_path指向自有数据(需转为 COCO 格式,可参考 tools/x2coco.py),并将num_joints改为实际关键点数,同时更新flip_perm左右配对与upper_body_ids上半身 id 列表。 - 换骨干网络:将
backbone改为其他已注册骨干(如HRNet),并同步调整width输出通道。 - 调整精度/速度权衡:关闭
use_dark(更快)、调小输入分辨率(更快)、减小hmsize或sigma(影响热图精度),各参数取舍可对照 configs/keypoint/KeypointBenchmark.md 的评测数据判断。
结语
PaddleDetection 的关键点配置文件以 YAML 锚点体系实现了"一次定义、全局复用",本文从 tinypose_256x192.yml 出发,逐层拆解了全局参数、模型、优化器、数据加载与增强流水线,并下钻到 TopDownHRNet 前向逻辑、DARK 解码、UDP 仿射、AID 增强等源码实现。掌握这份配置的语义,你便能举一反三地读懂 configs/keypoint 下 HRNet、Lite-HRNet、HigherHRNet、ViTPose 等全部关键点模型的配置,并据此定制自己的姿态估计方案。