☰
级联金字塔网络CPN:多人姿态估计难关键点挖掘与复现指南
2026/10/15 7:10:43 网站建设 项目流程

1. 从单人到多人:为什么级联金字塔网络值得反复读

多人姿态估计这个方向,如果你做过一段时间,就会知道它有一个非常折磨人的特点:图片里的人数一多,遮挡、尺度变化、关键点模糊这三件事就会同时爆发。单人姿态估计里那些表现很好的方法,一旦放到多人场景,精度掉得让人怀疑人生。CVPR 2018 那篇《Cascaded Pyramid Network for Multi-Person Pose Estimation》之所以到现在还值得反复读,就是因为它把"难关键点"这个问题单独拎出来,用一个两阶段的级联结构去专门对付它。

这篇论文的核心贡献,说白了就两件事:第一,用一个叫 GlobalNet 的骨干网络先把容易的关键点(眼睛、肩膀、髋部这些)搞定;第二,用一个叫 RefineNet 的细化网络,专门去啃那些被遮挡、被遮挡后又被误判的"hard keypoints"(手腕、手肘、膝盖、脚踝)。整个结构是级联的,也就是前一级的输出会喂给后一级,逐级把误差压下去。这个思路在当年是很超前的,因为大部分人的做法是堆一个更深的网络或者加更强的后处理,而它选择了"分而治之"。

我写这篇笔记的目的,不是把论文翻译一遍——那种东西你去看原文就好。我想做的是把这篇论文里真正影响工程落地的设计决策拆开,讲清楚每个模块为什么这么设计、参数怎么来的、如果我自己复现会怎么搭、踩过哪些坑。适合的读者是:做过或者正在做姿态估计的算法工程师、想入门多人姿态估计的研究生、以及任何对"级联结构"这个通用范式感兴趣的人。哪怕你之前没接触过姿态估计,我也会把基础概念用生活化的方式讲清楚,保证你能跟上。

关键词先摆出来,方便你建立索引:多人姿态估计、级联金字塔网络、GlobalNet、RefineNet、难关键点挖掘、在线难例挖掘、特征金字塔、人体关键点检测。这几个词基本覆盖了这篇论文的全部技术骨架,后面每一节我都会围绕它们展开。

2. 整体设计思路:为什么要做级联,而不是一步到位

2.1 多人姿态估计的两条技术路线之争

在讲这篇论文之前,得先把多人姿态估计的两条主流路线说清楚,不然你理解不了它的定位。第一条是自顶向下(top-down):先用一个人体检测器把图里每个人框出来,然后对每个框单独做单人姿态估计。第二条是自底向上(bottom-up):先把图里所有的关键点都检测出来,再想办法把这些点拼成一个个完整的人。

这两条路线各有各的痛点。自顶向下的问题在于,它的精度高度依赖检测框的质量,而且人数一多,推理时间就线性增长,因为你要对每个框跑一遍网络。自底向上的问题在于"拼人"这一步特别容易出错,尤其是两个人挨得很近的时候,左腿的关键点可能被拼到右腿上去。

这篇论文走的是自顶向下的路线。它的逻辑是:既然检测框已经给了,那每个人的区域是确定的,我就可以把全部精力放在"怎么把这个人的关键点估准"上。这个选择在当时是合理的,因为自顶向下的方法在精度上确实更容易做高,而这篇论文的目标就是刷精度。

提示:选择自顶向下还是自底向上,本质上是在"精度上限"和"推理效率"之间做权衡。如果你的场景是单人或者人数很少(比如健身动作分析),自顶向下几乎是无脑选择;如果是密集人群(比如车站监控),自底向上的效率优势才会体现出来。

2.2 级联结构的核心动机:难关键点需要被单独对待

论文里有一个观察非常关键:在 COCO 数据集上,不同关键点的检测难度差异巨大。像眼睛、鼻子、肩膀这些关键点,因为通常不会被遮挡,而且外观特征明显,所以大部分方法都能检测得不错。但手腕、手肘、膝盖、脚踝这些点,经常被身体其他部位遮挡,或者因为运动模糊而变得模糊不清,检测精度就明显偏低。

传统的做法是让一个网络同时学所有关键点,但这样会有一个问题:网络会把大部分容量分配给那些容易的关键点,因为它们在损失函数里贡献的梯度更多、更容易被优化。难关键点的梯度信号被淹没了。

这篇论文的解法很直接:分两阶段,第一阶段让 GlobalNet 学所有关键点,第二阶段让 RefineNet 专门学难关键点。RefineNet 的输入是 GlobalNet 输出的特征金字塔,它的监督信号只来自那些被判定为"难"的关键点。这样一来,网络的容量就被强制分配给了难关键点。

这个思路其实和 boosting 的思想很像:先学一个弱分类器,然后针对它分错的样本再学一个。区别在于这里是端到端训练的,而且用的是特征金字塔而不是简单的样本加权。

2.3 特征金字塔为什么是必要的

人体在图片里的尺度变化非常大。同一个人,离镜头近的时候可能占满整张图,离镜头远的时候可能只有几十个像素高。如果只用单一尺度的特征图,网络很难同时处理好这两种情况。

特征金字塔(Feature Pyramid)的作用就是提供多尺度的特征。浅层的特征图分辨率高,适合检测小尺度的关键点;深层的特征图分辨率低但语义信息强,适合检测大尺度的关键点。GlobalNet 和 RefineNet 都用了金字塔结构,这样无论人体大小,都能找到合适尺度的特征来响应。

论文里 GlobalNet 的金字塔是基于 ResNet 的 backbone 构建的,从 C2 到 C5 四个阶段分别输出特征,然后通过上采样和相加的方式融合。RefineNet 则是在 GlobalNet 的金字塔基础上再做一次级联细化。这个设计在当年是很标准的做法,但论文的贡献在于把它和"难关键点挖掘"结合起来了。

3. GlobalNet 与 RefineNet 的细节拆解

3.1 GlobalNet:先把容易的点拿下

GlobalNet 的 backbone 用的是 ResNet-50 或者 ResNet-101,这个选择在当时是很常规的。它的输出是一个特征金字塔,从 stage 2 到 stage 5 分别对应不同的分辨率。论文里对每个 stage 的输出都做了一次 3x3 卷积,然后通过上采样和 element-wise sum 的方式融合。

这里有一个细节值得注意:论文并没有用 FPN 那种 lateral connection 的方式,而是用了更简单的"上采样后相加"。这个选择的原因我推测是为了减少参数量和计算量,因为后面还有一个 RefineNet 要跑,整体计算预算有限。

GlobalNet 的损失函数是标准的 MSE,对所有关键点一视同仁。也就是说,在这个阶段,网络并不知道哪些点是难的,它只是尽力把每个点都估准。这个阶段的输出会作为 RefineNet 的输入之一。

注意:GlobalNet 的输出不是最终结果,它只是一个"粗估"。如果你在复现的时候发现 GlobalNet 单独跑出来的精度不够,不要慌,这是正常的,RefineNet 才是真正拉精度的地方。

3.2 RefineNet:难关键点的专项攻坚

RefineNet 的结构比 GlobalNet 复杂一些。它的输入是 GlobalNet 输出的特征金字塔,然后通过一系列 bottleneck block 和上采样操作,逐步把特征图的分辨率恢复到输入图像的 1/4。这个过程中,它会融合不同尺度的特征,最终输出每个关键点的热力图。

RefineNet 最关键的设计是在线难例挖掘(Online Hard Keypoints Mining)。具体做法是:在每次前向传播后,计算每个关键点的损失,然后只选择损失最大的那 K 个关键点进行反向传播。论文里 K 取的是 8,也就是每次只回传 8 个最难的关键点的梯度。

这个设计的精妙之处在于,它让网络始终聚焦在那些还没学好的关键点上。如果某个关键点已经被学得很好了,它的损失很小,就不会被选中,网络就不会在它身上浪费容量。反过来,那些一直学不好的关键点,会持续获得梯度信号,直到它们也被学好。

K 的取值是一个超参数。取太小,梯度信号不足,训练不稳定;取太大,就退化成普通的全关键点训练。论文里通过实验发现 8 是一个比较平衡的值。这个数字和 COCO 数据集的 17 个关键点有关,8 大约是总数的一半,既能保证足够的梯度,又能过滤掉容易的点。

3.3 两个阶段的衔接:级联是怎么实现的

GlobalNet 和 RefineNet 是端到端联合训练的,不是分开训练的。这一点很重要,因为如果分开训练,GlobalNet 的输出分布和 RefineNet 的输入分布可能不匹配,导致 RefineNet 学不好。

联合训练的方式是:GlobalNet 的输出特征直接喂给 RefineNet,然后两个网络的损失加在一起做反向传播。论文里的损失函数是 GlobalNet 的损失加上 RefineNet 的损失,两者权重相同。这样 GlobalNet 在学习的时候,会考虑到 RefineNet 的需求,而不是只顾自己。

这个设计和后来的很多级联方法是一致的,比如 Cascade R-CNN 也是类似的思路。核心思想就是:后一级的网络会"告诉"前一级的网络,你需要给我什么样的特征,我才能把难例学好。

4. 实操复现:从数据准备到训练调参

4.1 数据准备与预处理的关键细节

如果你要复现这篇论文,数据准备是第一步,也是最容易踩坑的一步。COCO 数据集的标注格式是 JSON,里面包含了每个人的关键点坐标和可见性标记(visible、occluded、not labeled)。预处理的时候,你需要把每个人裁剪出来,然后缩放到固定尺寸(论文里用的是 256x192)。

裁剪的时候有一个细节:不是简单地按检测框裁剪,而是要把检测框扩展一定的比例,通常是 1.25 倍,然后再裁剪。这样做是为了保证人体的完整关键点都在裁剪区域内,尤其是手和脚这些容易超出检测框的部位。

数据增强方面,论文用了随机旋转(±30度)、随机缩放(0.75 到 1.25 倍)、随机翻转。这些增强手段在姿态估计里是标配,因为人体姿态对旋转和缩放很敏感,增强可以显著提升模型的泛化能力。

提示:翻转增强的时候要注意左右关键点的索引要交换。COCO 的关键点索引里,左眼和右眼、左肩和右肩这些是成对的,翻转后如果不交换索引,网络会学到错误的对应关系。

4.2 网络搭建:backbone 和 head 的具体配置

GlobalNet 的 backbone 用 ResNet-50 的话,输出特征图的通道数分别是 256、512、1024、2048(对应 stage 2 到 stage 5)。论文里对每个 stage 的输出都做了一次 3x3 卷积,把通道数统一到 256,然后再做上采样和相加。

RefineNet 的输入是 GlobalNet 输出的融合特征,通道数是 256。它内部用了 4 个 bottleneck block,每个 block 包含 3 个卷积层,通道数分别是 128、256、512、1024。最后通过一个 1x1 卷积输出 17 个通道的热力图,对应 17 个关键点。

热力图的尺寸是输入图像的 1/4,也就是 64x48。这个分辨率是精度和计算量的折中。如果做到 1/2 分辨率,精度会更高,但计算量会翻倍;如果做到 1/8,计算量小但精度会掉。

4.3 训练策略:学习率、优化器和损失函数

论文用的是 Adam 优化器,初始学习率是 1e-3,在第 180 个 epoch 降到 1e-4,第 220 个 epoch 降到 1e-5。总共训练 250 个 epoch。batch size 是 32。

损失函数是 MSE,但 RefineNet 的损失只计算难关键点的部分。具体实现的时候,你需要先计算所有关键点的损失,然后排序,取前 K 个的损失求和,再除以 K。这个操作在 PyTorch 里可以用torch.topk实现。

训练的时候有一个技巧:先用 GlobalNet 单独训练几个 epoch,等它稳定了再联合训练。这样做可以避免一开始 RefineNet 的梯度太大,把 GlobalNet 带偏。论文里没有明确说这一点,但我在复现的时候发现这样做收敛更稳定。

4.4 推理阶段:从热力图到坐标

推理的时候,网络输出的是 17 个热力图,每个热力图对应一个关键点。你需要从热力图中找到最大值的位置,然后通过一个从热力图坐标到原图坐标的变换,得到最终的关键点坐标。

这个变换需要考虑裁剪和缩放的因素。具体来说,如果裁剪的时候把检测框扩展了 1.25 倍,然后缩放到 256x192,那么从热力图坐标反推原图坐标的时候,需要先除以缩放比例,再乘以扩展比例,最后加上裁剪框的左上角坐标。

有一个细节容易被忽略:热力图的最大值位置是整数坐标,但真实的关键点坐标可能是小数。为了提高精度,可以用二次插值的方式,在最大值附近拟合一个抛物线,取抛物线的顶点作为最终坐标。这个技巧在论文里没有提,但在实际工程中很常用,可以提升 0.5 到 1 个 AP。

5. 常见问题与排查技巧实录

5.1 训练不收敛或者精度远低于论文

这是复现时最常见的问题。可能的原因有几个:第一,学习率太大,导致损失震荡。可以尝试把初始学习率降到 5e-4 或者 1e-4。第二,数据增强太强,导致网络学不到有效的特征。可以先把增强关掉,看看能不能过拟合一个小数据集,如果能过拟合,说明网络结构没问题,问题出在增强或者正则化上。第三,难关键点挖掘的 K 值设置不当。如果 K 太小,梯度信号不足;如果 K 太大,退化成普通训练。可以尝试 K=8 到 K=12 之间的值。

5.2 难关键点的精度提升不明显

如果 RefineNet 没有带来明显的精度提升,可能是以下几个原因:第一,GlobalNet 的输出质量太差,RefineNet 拿到的输入本身就是错的,它也很难纠正。可以先把 GlobalNet 训练得更充分一些。第二,难关键点的判定标准有问题。论文里是按损失排序取前 K 个,但如果你用的是其他标准(比如按可见性),可能效果不好。第三,RefineNet 的容量不够。可以尝试增加 bottleneck block 的数量或者通道数。

5.3 推理速度太慢

自顶向下的方法推理速度本来就慢,因为要对每个检测框跑一遍网络。如果速度不能满足要求,可以考虑以下几个优化:第一,用更轻量的 backbone,比如 ResNet-18 或者 MobileNet。第二,减少 RefineNet 的 bottleneck block 数量。第三,用 TensorRT 或者 ONNX Runtime 做推理加速。第四,如果场景里人数不多,可以只对置信度高的检测框做姿态估计,忽略那些置信度低的框。

5.4 常见问题速查表

问题现象可能原因排查方法解决方案
损失震荡不下降学习率太大打印每步损失降低学习率到 1e-4
精度远低于论文数据预处理错误可视化裁剪后的图片检查裁剪比例和缩放
难关键点无提升GlobalNet 输出太差单独评估 GlobalNet先充分训练 GlobalNet
推理速度慢网络太重测各模块耗时换轻量 backbone 或剪枝
热力图峰值不明显损失函数权重问题可视化热力图调整损失权重或加正则

注意:复现论文的时候,不要一上来就追求完全复现论文的精度。先把 pipeline 跑通,确保数据流是正确的,然后再逐步调参。很多人的问题不是调参调不好,而是数据流本身就是错的,调参只是在错误的基础上瞎调。

6. 这篇论文对后续工作的影响与个人思考

这篇论文发表之后,级联结构在姿态估计领域被广泛采用。后来的很多工作,比如 HRNet,虽然在网络结构上做了很大的改进,但"难关键点需要被单独对待"这个思想是一直被继承的。HRNet 通过并行多分辨率的架构,让高分辨率特征和低分辨率特征始终保持交互,本质上也是在解决"不同尺度的关键点需要不同处理"这个问题。

从工程落地的角度看,这篇论文的实用性在于它的结构相对简单,容易复现和修改。GlobalNet 和 RefineNet 都是标准的卷积网络,没有特别复杂的算子,部署的时候不会有太多兼容性问题。这一点在工业界很重要,因为很多花哨的结构在实验室里跑得好,一到部署就各种问题。

我个人在实际操作中的体会是,难关键点挖掘这个技巧不仅可以用在姿态估计上,还可以迁移到其他关键点检测任务,比如人脸关键点、手部关键点。核心思想是一样的:让网络把容量集中在那些还没学好的点上。如果你正在做类似的任务,不妨试试这个思路,改动量不大,但效果往往很明显。

最后再分享一个小技巧:在训练 RefineNet 的时候,可以给难关键点的损失加一个权重系数,比如 1.5 或者 2.0,这样可以让网络更加关注这些点。论文里没有用这个技巧,但我在实践中发现它可以帮助网络更快地收敛到难关键点上。当然,权重也不能太大,否则会导致容易的关键点精度下降,需要根据具体任务做平衡。

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

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

立即咨询