TT Lab
博客

한국어 English 日本語 中文

开始
博客

博客

人体姿态 2:ViTPose、RTMPose 的 SimCC 与 RTMO —— 在实时性与准确率之间抉择

状态:草稿 (2026-10-13)。 论文数据均已打开原文并结合条件进行了核对。亲自尝试过的是笔记本 CPU 上的 numpy 示例(code/08_simcc.py,少于 1 秒)。TT Score 实际使用 RTMPose·MediaPipe 的结果引用自《TT Score 模型解剖》第 4 篇,ViTPose 与 RTMO 未进行运行测试(未实测)。 系列「阅读视觉模型 2」第 8 篇。上一篇: 人体姿态 1. RTMPose 的解码代码和我们的使用场景在 TT Score 第 4 篇中已有详细探讨,因此本篇重点关注「为什么这样训练」。

人体姿态 2:实时性与准确率之间

目录

1. 直觉:一边做大,一边做减法

回顾第 7 篇末尾的表格,2019–2020 年的强者们采用的是 HRNet 这类精细网络搭配精细解码的结构。此后,道路分成了两支。

관절 하나의 출력: 2D 지도 대 1D 벡터 두 개 히트맵(¼ 해상도, 48×64) 칸 하나 = 입력 4화소 값 3,072개 손실: 칸마다 제곱 오차 SimCC(나누기 배율 k=2) x: 384칸(192 × 2), 칸 하나 = ½ 화소 … y: 512칸(256 × 2) … 값 896개 정답 = 가우시안으로 번진 분포 손실 = 분포 사이의 KL 발산 디코딩 = argmax 두 번 RTMPose 사람 상자(검출기) → CSPNeXt 몸통 → SimCC 두 분류기 RTMO 검출기 없이 한 번에: 상자 안에 칸을 펼친 1D 분류
图:2D 热力图与 SimCC 的两个 1D 向量、RTMPose 与 RTMO 的结构

2. ViTPose:几乎不需要解码器

ViTPose (2022) 将普通的 ViT 作为主干网络(图中 1/16 分辨率的特征),并在其上堆叠一个极其简单的解码器。它通过单一的「放大 4 倍(双线性插值)→ ReLU → 3×3 卷积」来输出热力图。训练时采用与第 7 篇相同的热力图均方误差。

对比不同主干网络是否行得通这个简单的解码器,结果非常有趣(COCO val)。在 ResNet 主干中,换成简单解码器后下降了约 18 个点(ResNet-50 从 71.8 跌至 53.1),而在 ViT 主干中,差距在 0.3 点以内(ViT-B 从 75.8 降至 75.5)。 由于注意力层已经融合了广泛的上下文信息,解码器几乎没有什么事情可做(论文原意)。

准确率随着主干网络体量的增大而提升。在 256×192 输入下,ViTPose-B 为 75.8、-L 为 78.3、-H 为 79.1,并且它甚至将 COCO test-dev 推到了 10 亿参数级别的主干网络规模 80.9(单模型,576×432,引入外部数据)(论文)。速度也并非想象中那么差。ViTPose-B 为每秒 944 张,HRNet-W32 为 916 张(数据中心级 GPU,batch 64,论文)。

关于预训练数据也有相关实验。如果用 COCO 和 AI Challenger 的 50 万张人体裁剪图像代替 ImageNet 进行 MAE 预训练,结果同样是 75.8;仅使用 COCO 时则为 74.5(论文)。这说明仅靠姿态数据也相当可行,这也呼应了第 2 篇和第 3 篇中关于「无标签的我们自己的视频」的讨论。

ViTPose 还使用了第 4 篇中的蒸馏方法。在冻结大模型 (L) 的同时,仅训练一个可学习的「知识令牌(Knowledge Token)」,并将该令牌插入小模型 (B) 中。仅通过令牌就提升了 +0.2,结合输出蒸馏则提升了 +0.8(从 75.8 升至 76.6)(论文)。

3. SimCC:坐标转为两个分类

思考

热力图存在两个问题(第 7 篇):必须为每个关节绘制 2D 图,代价高昂,且精度受限于地图分辨率。SimCC (2022) 改变了提问方式。它将「x 坐标属于第几个格子」和「y 坐标属于第几个格子」 分别作为分类问题来解决。

无需放大地图,也能获得比像素更精细分辨率。

标签与损失

如果使用仅正确格子为 1 的独热标签(one-hot),那么隔壁格子或十个格子之外的格子都会同样被判定为「错误」。SimCC 采用了将概率分配到正确答案周围的 标签平滑(label smoothing) ,并将预测分布与真实分布之间的 KL 散度作为损失函数。在平滑方式的对比中(ResNet-50, 384×288),不平滑为 71.3,均匀分配为 73.0, 高斯分布为 73.4,拉普拉斯分布为 73.0(论文)。离得越近视为误差越小的高斯分布效果最好。

亲自上手尝试

code/08_simcc.py 的输出结果(code/08_simcc.out.txt).

[1] x 정답 101.3px → 칸 202.6/384, 정답 분포의 최대 칸 203, 폭(σ) 6.0칸
[2] τ=1.0: 예측 분포 최댓값 0.012, KL(정답‖예측) 1.420, 디코딩 105.5px
[2] τ=0.1: 예측 분포 최댓값 0.171, KL(정답‖예측) 0.499, 디코딩 105.5px

[2] 展示了温度的作用。网络产生的 logits 通常数值范围较窄。如果直接(τ=1)应用 softmax,分布会比较平缓,从而距离真实分布较远(KL 为 1.42);而如果除以 τ=0.1,分布就会变尖锐,从而更接近(KL 为 0.50)。RTMPose 将该温度设为 0.1,使得 COCO val 达到了 72.7(下表中的步骤)。并且 温度不会改变 argmax(两种情况下都是 105.5px)。温度是调整训练梯度的把手,而不是改变解码结果的把手。此示例中出现的 4px 误差是由于故意引入了噪声。

我们在 x 单轴上对比了量化误差(完美预测,2 万个随机位置)。

输出 格子大小 平均误差
SimCC k=1 1 像素 0.249px
SimCC k=2 ½ 像素 0.125px
SimCC k=3 ⅓ 像素 0.084px
2D 热力图 ¼ 分辨率,argmax 4 像素 1.012px

如果在 logits 中混入噪声(1 千次),k=1、2、3 的平均误差分别为 2.97、2.54、2.37px,细分格子的收益被噪声掩盖而变小了。SimCC 论文也测试了 1–4 的 k 值,并得出 2–3 最好的结论。如果分割得太细,每个格子的训练信号就会变薄。

输出尺寸(每个关节的值的数量)如下:

2D 히트맵 ¼ 해상도 48×64 = 3,072  → 17관절 52,224
SimCC k=2: 384 + 512 = 896 → 17관절 15,232

在低分辨率下尤为强大

SimCC 的收益在输入较小时更为显著(论文,COCO val,HRNet-W48)。

输入 热力图 + ¼ 像素偏移 SimCC
64×64 48.5 59.7
128×128 68.9 72.0
256×192 75.1 75.9

这与第 7 篇的结论一致。格子越粗糙,解码的量化问题就越严重,而 SimCC 从输出结构上去掉了这种量化。

4. RTMPose:逐步累积训练技巧

RTMPose (2023) 采用自顶向下(top-down)的方式。由人体检测器(RTMDet)寻找检测框,通过 CSPNeXt 主干网络 → 大卷积(7×7) → 关节特征 → 注意力层(GAU) → SimCC 两个分类器来寻找关节。这篇论文的价值不在于结构,而在于 逐个叠加训练技巧并详细记录其效果的表格(COCO val,RTMPose-m)。

步骤 AP
起点 69.7
先用热力图(UDP)训练主干网络 70.3
+ 指数移动平均(EMA)权重 70.4
+ 学习率调度(先平坦后余弦) 70.7
+ 两阶段数据增强(强增强 180 epochs → 弱增强 30 epochs)等 …
+ 注意力层(GAU) 71.9
+ 温度 τ=0.1 72.7
+ x·y 分别使用 σ 72.8
+ 7×7 卷积 73.3
+ 420 epochs 73.7
+ 补充数据(AI Challenger) 75.3

标签形式为施加了「由高斯距离生成的分布的 softmax」,在预测和标签两端都应用了温度(论文)。强增强的程度大约为:缩放 0.6–1.4 倍、旋转 80 度、持续应用局部擦除(Cutout)。由于存在训练数据条件不同的多个版本(仅 COCO / 附加 AI Challenger / 包含翻转测试),在引用诸如 75.8 这样的数字时,必须确认具体是哪个版本。

速度(论文,RTMPose-m):桌面端 CPU (ONNX Runtime) 11.06 ms,桌面级 GPU (TensorRT) 2.29 ms,在手机 SoC 上超过 35 fps。小版本 RTMPose-s 在手机 SoC 上耗时 13.89 ms(超过 70 fps),AP 为 72.2。无需在每一帧都运行人体检测器,而是每隔几帧运行一次,在此期间利用上一帧的姿态来生成检测框。

5. RTMO:去掉人体检测器

自顶向下(top-down)方法的弱点在于耗时与人数成正比,且单独运行检测器的负担较重。RTMO (CVPR 2024) 类似于目标检测器(YOLO 系列),将图像划分为网格,在每个格子中一次性输出「这里有人吗?如果有,检测框和关节分别是什么?」

关节坐标像 SimCC 一样通过 1D 分类输出,但格子的范围不是针对整张图像,而是 仅在该格子预测的人体检测框(扩大 1.25 倍)内 展开(动态坐标分类器,DCC)。无论人是大还是小,都在检测框内划分为 x 192 格和 y 256 格,因此分辨率会根据人体大小进行调整。

损失函数也进行了更改。不再使用与真实分布之间的 KL 散度,而是最大化「从预测位置周围的高斯分布中产生成果的似然度」,同时 让网络一同学习分布的宽度(不确定性) (最大似然估计,MLE)。在相同的 RTMO-s 中,KL 为 64.4,坐标回归(OKS 损失)为 65.6,MLE 为 67.6 (COCO val,论文)。正如第 5 篇中的 SEA-RAFT 一样,这是一个对原本模棱两可的情况惩罚较轻的损失函数取胜的例子。

项目 数值(论文)
COCO val(仅训练 COCO) RTMO-s 67.6 · -m 71.2 · -l 72.5
摘要中的代表性数值 RTMO-l val 74.8,单张数据中心级 GPU 上达到 141fps(摘要中未说明训练数据与执行器条件)
COCO test-dev s 66.9 · m 70.1 · l 71.6(添加外部数据时为 67.7 · 71.5 · 73.3)
CrowdPose(拥挤场景) RTMO-l 73.2(仅训练 CrowdPose)
相比自顶向下(RTMPose) 当人数在 4 人左右时,RTMO 更快(ONNX Runtime)。即使人数从 1 人增加到 10 人以上,延迟增加也仅约 0.1ms

6. 局限性

7. 与我们项目的联系

TT 的总结。 将坐标转化为“属于第几个格子?”的分类问题后,原本用于绘制地图的 3,072 个格子缩减到了 896 个。并且,我们还通过直接计算确认了“温度并不是用来改变正确答案,而是用来改变学习方式的控制旋钮”。

参考文献

登录后即可点赞

评论

还没有评论。

登录后即可发表评论