news 2026/10/15 1:53:34

ViTPose 中的 DARK 分布感知坐标表示:无偏热图编码与解码的源码级解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ViTPose 中的 DARK 分布感知坐标表示:无偏热图编码与解码的源码级解析
  • 人工智能
  • 计算机视觉
  • 深度学习

【免费下载链接】ViTPose

The official repo for [NeurIPS'22] "ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation" and [TPAMI'23] "ViTPose++: Vision Transformer for Generic Body Pose Estimation"

项目地址:https://gitcode.com/gh_mirrors/vi/ViTPose
点击查看免费下载

导读

DARK(Distribution-Aware coordinate Representation of Keypoints)是 CVPR 2020 提出的一种模型无关的姿态估计后处理/前处理增强方法,其核心发现是:热图(heatmap)从预测到最终关节坐标的解码过程对精度影响远超预期。本文以 ViTPose 仓库中的算法文档 docs/en/papers/algorithms/dark.md 为主体,结合仓库中TopDownGenerateTarget的无偏编码实现、keypoints_from_heatmaps的分布感知解码实现以及 ResNet/HRNet 的 dark 系列训练配置,完整拆解 DARK 的数学原理、代码调用链与实际配置方法,帮助你在自己的姿态估计模型上直接落地这套“即插即用”的精度提升方案。


一、DARK 方法概述:从论文摘要看核心主张

在人体姿态估计领域,热图长期是关节坐标表示的事实标准(de facto standard),但很少有工作深入剖析热图本身的设计。DARK 论文(Zhang et al.,Distribution-aware coordinate representation for human pose estimation, CVPR 2020)首次指出两个此前被忽视的环节:

  1. 解码环节至关重要:将预测热图解码回原始图像空间中的最终关节坐标这一过程,对最终性能的影响“惊人地显著”(surprisingly significant)。标准坐标解码方法(取最大值并做固定偏移)存在系统性偏差。
  2. 编码环节可以更准:将真实坐标转换为热图(ground-truth coordinates → heatmaps)的过程也可以改进,通过生成无偏/更精确的热图来消除量化误差。

论文将这两部分统一为一个完整方法——分布感知的关键点坐标表示(DARK)。作为模型无关的即插即用模块(model-agnostic plug-in),DARK 能为现有姿态估计模型带来显著性能提升,论文报告其在 MPII 与 COCO 两个常见基准上取得当时的最佳结果,并斩获 ICCV 2019 COCO Keypoints Challenge 第二名(以上结论均出自论文摘要原文)。

在 ViTPose 仓库中,DARK 并非一个独立模型,而是以训练管线配置 + 评测后处理函数的形式存在:编码端由数据管线TopDownGenerateTarget的unbiased_encoding开关控制,解码端由keypoints_from_heatmaps的post_process='unbiased'分支驱动。


二、编码端:如何生成无偏的热图标签

2.1 标准编码的问题:量化取整引入偏差

在 mmpose/datasets/pipelines/top_down_transform.py 中,TopDownGenerateTarget支持三种编码方案(encoding参数:MSRA、Megvii、UDP),并通过布尔开关unbiased_encoding决定是否采用 DARK 的无偏编码。默认配置为encoding='MSRA'、unbiased_encoding=False。

标准的 MSRA 编码流程(unbiased_encoding=False分支)为:

feat_stride = image_size / [W, H] mu_x = int(joints_3d[joint_id][0] / feat_stride[0] + 0.5) mu_y = int(joints_3d[joint_id][1] / feat_stride[1] + 0.5)

这里将连续的真实坐标映射到热图网格时使用了int(... + 0.5)的四舍五入取整,高斯分布的中心被强制对齐到整数像素,从而引入最多 ±0.5 像素的量化误差。这个误差在把热图解码回原图时会以特征步长(feat_stride)倍数放大。

2.2 DARK 无偏编码:保留亚像素位置

当unbiased_encoding=True时(对应源码 L325-L348),代码不再取整,而是直接在浮点中心上放置高斯分布:

feat_stride = image_size / [W, H] mu_x = joints_3d[joint_id][0] / feat_stride[0] mu_y = joints_3d[joint_id][1] / feat_stride[1] ... target[joint_id] = np.exp(-((x - mu_x)**2 + (y - mu_y)**2) / (2 * sigma**2))

此时mu_x、mu_y是亚像素精度的浮点数,每个热图像素的值按照其与真实中心的连续距离计算,高斯分布的中心得以“落”在真实位置,从而消除取整带来的系统偏差。这就是论文中“生成无偏/精确热图”(unbiased/accurate heatmaps)的仓库实现。

值得注意的实现细节:无偏编码分支用全图逐点计算高斯(x = np.arange(0, W, 1)),而标准分支只在一个2*tmp_size+1的局部窗口内生成高斯并切片写入(L362-L379)。无偏分支同样遵循 3-sigma 规则(tmp_size = sigma * 3)做边界检查,越界关节会被置为不可见。

2.3 在训练配置中的开启方式

在仓库的 dark 系列配置中,训练管线里即开启了无偏编码。以 res50_coco_256x192_dark.py 为例:

dict(type='TopDownGenerateTarget', sigma=2, unbiased_encoding=True),

其中sigma=2控制训练热图中高斯分布的尺度,它与解码端的调制核(modulate_kernel)存在严格的对应关系(见下文)。


三、解码端:分布感知的坐标解码

3.1 解码入口与调用链

推理时,TopDown检测器在 top_down.py 中调用keypoint_head.decode(),该方法定义于 topdown_heatmap_base_head.py,最终进入评测核心函数keypoints_from_heatmaps(定义于 mmpose/core/evaluation/top_down_eval.py):

preds, maxvals = keypoints_from_heatmaps( output, c, s, unbiased=self.test_cfg.get('unbiased_decoding', False), post_process=self.test_cfg.get('post_process', 'default'), kernel=self.test_cfg.get('modulate_kernel', 11), ... )

关键参数均来自test_cfg:post_process='unbiased'触发 DARK 解码;modulate_kernel控制高斯调制核大小(默认 11)。需要注意的是,源码中还保留了一个已废弃的unbiased布尔参数,若设置unbiased=True会发出弃用警告并自动归一化为post_process='unbiased'(L555-L560),因此新配置一律直接使用post_process='unbiased'。

3.2 标准解码 vs DARK 解码

keypoints_from_heatmaps中非 UDP 分支的解码逻辑(L589-L612)清晰地对比了三种后处理:

  • post_process='default'(标准方法):先取热图最大值_get_max_preds,然后根据最大值两侧邻居的差分符号施加固定的±0.25 像素偏移。这个经验性偏移是启发式的,当真实分布不对称时会产生系统性偏差——这正是 DARK 论文批评的对象。
  • post_process='unbiased'(DARK):同样先取最大值定位初值,但随后对热图执行高斯调制 + 对数变换 +泰勒展开亚像素修正(_taylor)。
  • post_process='megvii':仅对热图做高斯模糊(_gaussian_blur),并施加 +0.5 偏移与特殊分数归一化(maxvals = maxvals / 255.0 + 0.5)。

DARK 解码的核心流程(L591-L597):

if post_process == 'unbiased': # alleviate biased coordinate # apply Gaussian distribution modulation. heatmaps = np.log(np.maximum(_gaussian_blur(heatmaps, kernel), 1e-10)) for n in range(N): for k in range(K): preds[n][k] = _taylor(heatmaps[n][k], preds[n][k])

三步依次是:

  1. 高斯分布调制:用_gaussian_blur(L399-L438)对预测热图做核大小为modulate_kernel的高斯模糊,同时归一化回原始峰值(heatmaps[i, j] *= origin_max / np.max(...)),使热图分布更接近训练时的高斯形态;
  2. 对数变换:np.log将热图从响应值域转换为对数域,便于后续泰勒展开直接拟合对数高斯(即二次型)曲面;
  3. 泰勒展开修正:_taylor(L298-L332)在初值点计算一阶导数(梯度)与二阶导数(海森矩阵),按牛顿法一步求亚像素偏移:
dx = 0.5 * (heatmap[py][px + 1] - heatmap[py][px - 1]) dy = 0.5 * (heatmap[py + 1][px] - heatmap[py - 1][px]) dxx = 0.25 * (heatmap[py][px + 2] - 2 * heatmap[py][px] + heatmap[py][px - 2]) dxy = 0.25 * (heatmap[py + 1][px + 1] - heatmap[py - 1][px + 1] - heatmap[py + 1][px - 1] + heatmap[py - 1][px - 1]) dyy = 0.25 * (heatmap[py + 2][px] - 2 * heatmap[py][px] + heatmap[py - 2][px]) derivative = np.array([[dx], [dy]]) hessian = np.array([[dxx, dxy], [dxy, dyy]]) if dxx * dyy - dxy**2 != 0: hessianinv = np.linalg.inv(hessian) offset = -hessianinv @ derivative coord += offset

其数学本质:假设预测响应在对数域近似为高斯(二次型),则最优亚像素位置即梯度为零的点,coord_new = coord - H⁻¹·∇f。注意_taylor要求初值位于热图内(1 < px < W-2 and 1 < py < H-2),靠近边界时直接返回原始坐标。

3.3 调制核与训练 sigma 的配套原则

_gaussian_blur与keypoints_from_heatmaps的文档字符串均明确给出对应关系:核大小必须与训练热图的 sigma 匹配——K=17对应sigma=3,K=11对应sigma=2。因此 dark 配置中训练侧TopDownGenerateTarget(sigma=2, unbiased_encoding=True)与推理侧modulate_kernel=11成对出现,切勿随意改动其中一侧。

3.4 与 UDP 的关系:post_dark_udp

仓库还提供了post_dark_udp(L335-L396),它是 DARK 解码在 UDP(The Devil is in the Details, CVPR 2020)数据流程下的向量化实现:对热图先做高斯模糊,再np.clip(0.001, 50)后取对数,随后通过预填充(np.pad(..., mode='edge'))与平铺索引一次性完成全 batch 的导数/海森矩阵计算,最后用np.linalg.inv(hessian + eps * eye(2))求逆并做np.einsum修正。它在keypoints_from_heatmaps的use_udp=True分支中被调用(L567-L570),同时在 bottom-up 范式的人群分组后处理(mmpose/core/post_processing/group.py)中也被复用,是 DARK 思想在仓库内二次扩散的体现。


四、ViTPose 仓库中的 DARK 配置实践

4.1 完整的 dark 配置范式

将编码端与解码端合起来,一个标准的 dark 训练配置(以 hrnet_w32_coco_256x192_dark.py 为例)包含三个关键位置:

# 训练侧:无偏编码,sigma=2 dict(type='TopDownGenerateTarget', sigma=2, unbiased_encoding=True), # 推理侧:DARK 解码,调制核与 sigma 配套 test_cfg=dict( flip_test=True, post_process='unbiased', shift_heatmap=True, modulate_kernel=11)

配套的还有data_cfg中的输入输出尺寸(image_size=[192, 256]、heatmap_size=[48, 64],即 4 倍下采样)以及标准优化配置(Adam、lr=5e-4、step 学习率策略、210 epochs)。对比同尺寸的普通配置可以发现,dark 版本与 baseline 的唯一区别正是上述编码开关与后处理模式,充分体现了 DARK “模型无关插件”的定位。

4.2 仓库提供的 dark 模型家族

ViTPose 仓库在 COCO 与 MPII 上提供了完整的 dark 配置与权重发布记录:

  • COCO(ResNet 骨干):resnet_dark_coco.md 收录 ResNet-50/101/152 在 256x192 与 384x288 两种分辨率下的 6 个 dark 模型,例如res50_coco_256x192_dark(AP 0.724)与res152_coco_384x288_dark(AP 0.757);
  • COCO(HRNet 骨干):hrnet_dark_coco.md 收录 HRNet-W32/W48 的 4 个 dark 模型,最佳为hrnet_w48_coco_384x288_dark(AP 0.772,AP75 0.836);
  • MPII(HRNet 骨干):hrnet_dark_mpii.md 收录 2 个 dark 模型,hrnet_w48_mpii_256x256_dark达到 PCKh@0.5 = 0.905、Mean@0.1 = 0.360。

各配置对应的.py文件与预训练权重下载记录统一维护在同目录的.yml文件(如 hrnet_dark_coco.yml)中,模型名规范为topdown_heatmap_<backbone>_coco_<input_size>_dark。这些指标仅作为仓库内配置复现结果供参考,实际以自行训练/评测为准。

4.3 在 ViT 骨干上复用的思路

从源码结构看,DARK 完全作用于数据标签生成与热图后处理两层,与骨干网络解耦:TopDownGenerateTarget属于数据管线,keypoints_from_heatmaps属于头部解码,二者均不感知 backbone 类型。因此对于 ViTPose 的 Vision Transformer 骨干(如 mmpose/models/backbones/vit.py),只需沿用相同的unbiased_encoding=True与post_process='unbiased'组合即可获得同等收益,无需修改网络结构——这正是 DARK 作为“即插即用”插件的设计意图。


五、测试验证:从单元测试看 DARK 的行为约束

仓库在 tests/test_evaluation/test_top_down_eval.py 中为 DARK 解码提供了直接的单测覆盖,可据此验证实现行为:

preds, maxvals = keypoints_from_heatmaps( heatmaps, center, scale, post_process='unbiased') assert_array_almost_equal(preds, np.array([[[126, 126]]]), decimal=4)

测试构造一个64x64全 1、峰值(2.0)位于(31, 31)的对称热图,post_process='unbiased'解码后仍应得到对称结果(126, 126)——对于对称分布,泰勒修正偏移为零,验证了 DARK 在无偏输入下不会引入额外偏差。同时测试还断言post_process='unbiased'时kernel=0会触发断言错误(AssertionError),印证了 DARK 解码必须携带合法的调制核大小这一约束(源码 L531-L532)。


六、总结与使用建议

DARK 之所以能成为姿态估计工具箱中的常青技巧,在于它用极小代价(两个开关、一个后处理函数)修正了热图流程两端最容易被忽视的系统偏差:

环节标准做法DARK 做法仓库实现位置
编码坐标取整到整数像素放置高斯浮点中心放置高斯(无偏编码)top_down_transform.py L325-L348
解码最大值 + 固定 ±0.25 偏移高斯调制 + 对数域泰勒展开求亚像素偏移top_down_eval.py L589-L597、L298-L332
配置——unbiased_encoding=True+post_process='unbiased'+modulate_kernel=11hrnet_w32_coco_256x192_dark.py

在实际项目中启用 DARK 时,请务必遵守三条配套原则:训练 sigma 与调制核必须匹配(sigma=2 ↔ kernel=11,sigma=3 ↔ kernel=17);编码与解码必须同时开启(仅开一端会因训练/推理分布不一致而效果打折);注意输入分辨率与热图下采样倍率,它们共同决定亚像素修正折算回原图后的实际位移量。参考仓库中的 resnet_dark_coco.yml 等元数据文件,可以快速复现并在此基础上做增量实验。

  • 人工智能
  • 计算机视觉
  • 深度学习

【免费下载链接】ViTPose

The official repo for [NeurIPS'22] "ViTPose: Simple Vision Transformer Baselines for Human Pose Estimation" and [TPAMI'23] "ViTPose++: Vision Transformer for Generic Body Pose Estimation"

项目地址:https://gitcode.com/gh_mirrors/vi/ViTPose
点击查看免费下载

相关推荐

上一篇:3分钟快速上手Exo:打造本地AI集群的终极指南 🚀
下一篇:gsd-core ADR 1866 解读:agent_skills 双重注入契约(编排侧注入 + Agent 侧自加载)

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 1:52:25

REFramework 上手指南:10 分钟跑通你的第一个 RE 引擎 Mod

REFramework 上手指南&#xff1a;10 分钟跑通你的第一个 RE 引擎 Mod 【免费下载链接】REFramework Mod loader, scripting platform, and VR support for all RE Engine games 项目地址: https://gitcode.com/GitHub_Trending/re/REFramework REFramework 是覆盖 RE 引…

作者头像 李华
网站建设 2026/10/15 1:50:03

图像复原本质:退化建模、噪声辨识与逆问题求解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/15 1:48:26

2026年安全员C证(专职安全员)题库带答案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/15 1:48:13

手写RPC核心:Netty传输与通用序列化接口实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华