
1. 这篇论文到底解决了什么问题1.1 姿态估计从单人走向多人的那道坎先聊个背景。OpenPose 这篇论文的完整标题是Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields它当年在 CVPR 2017 发表至今仍是人体姿态估计领域绕不开的基石。我第一次读它的时候感受是这玩意儿把“多人姿态估计”从一个看起来很别扭的问题做成了工程上真正能落地的方案。为什么说别扭单人姿态估计其实相对好办——输入一张图里面只有一个人检测关键点就行模型只需要关注“这个人的肩膀在哪、手肘在哪”。但现实中的场景摄像头拍到的画面几乎不会只有一个人。一旦画面里出现多个人问题就变了你要先知道图里有几个人、每个人在哪然后把每一个关键点分给对应的人。错误的分组会直接导致姿态结构完全错乱——比如把 A 的手肘接到了 B 的肩膀上。早期做法通常分两步先做人检测再对每个检测框做单人姿态估计。听起来合理但实际跑起来很脆。检测框一旦重叠、遮挡、人物交互紧密单人姿态估计的结果就会互相干扰而且两步串联导致误差累积检测框稍微偏一点姿态也跟着歪。OpenPose 的思路是端到端地同时预测关键点位置和关键点之间的连接关系然后用图匹配把人体骨架拼出来。这篇论文最核心的贡献就是提出了 Part Affinity FieldsPAF部件亲和场专门解决“关键点之间的关联”这个问题。如果你刚接触姿态估计可以把 OpenPose 理解成“一种既能找关键点、又能正确地连接骨架的深度学习方案”。它不只是给出一堆点还能告诉你这些点应该怎么连成一个人。这听着简单里面的数学设计和网络结构设计却非常讲究今天这篇就是想把这套设计的来龙去脉讲清楚包括不少论文里没细写、但复现和工程落地时一定会踩的坑。1.2 PAF 到底在做什么用“方向”代替“连接”的思路要理解 PAF先想想一个更朴素的办法既然要判断关键点之间是否属于同一个人那能不能直接让网络预测两个关键点之间“是否连接”如果把所有可能的连接都当成二分类问题每张图里的关键点数量一多计算量就爆炸而且这种全局二分类很容易模棱两可。PAF 的核心思路换了个赛道——不直接预测“是否连接”而是预测“连接的走向”。具体来说对于两个相邻的关键点比如手肘和手腕PAF 在两者的连线路径上为图像中的每个像素位置都输出一个二维单位向量用来表示该位置处于“从手肘到手碗”的哪个方向。当网络在多个位置都输出了方向一致、且与真实骨骼方向吻合的向量场时就说明这里大概率存在一条真实的肢体连接。我的理解是PAF 把“连接关系”这种离散问题做成了“稠密方向场回归”这种连续问题。这样做的好处是网络不需要显式思考“这两个点是不是同一个人的”只需要学习“如果这里是手臂的位置方向应该指向哪里”。这在监督信号上舒服很多因为方向场是稠密的——每个像素都有监督信息不像二分类那样只有稀疏的点级监督。另一方面PAF 用向量场同时表达位置和方向信息后期做匹配时非常高效。OpenPose 的后期只用了一个贪心匹配算法就能在多人场景里把关键点组装成完整姿态而且速度足够快这也是它能做到实时的一个重要原因。2. 网络结构设计与核心创新点拆解2.1 双分支多阶段从 VGG 前身到精炼模块OpenPose 的网络结构最初分成两个分支一个分支预测关键点的置信度图confidence map每一个关键点类型对应一张热力图另一个分支预测 PAF对于每一条骨骼连接输出两个通道的向量场。这两个分支共享底层的特征提取网络底层用的是 VGG-19 的前 10 层做初步特征提取后再分别送入两个分支的后续网络。这里最值得拆解的设计是“多阶段精炼”。OpenPose 不是一锤子买卖——第一个阶段输出的结果相对粗糙但从第二个阶段开始每个阶段都会把上一阶段两个分支的输出和原始特征图拼起来重新处理这种重复式的精炼有点像人在看一张混乱的图时先大概扫一眼再反复盯着细节确认。论文里管这种机制叫“sequential refinement”。我在实际训练的时候体会特别深如果你只跑一个阶段模型在简单场景下能出结果但没有精炼过程后续阶段的监督 loss 对整体训练的提升非常明显。多阶段设计的另一个好处是它可以利用中层的语义信息。底层的 VGG 特征提供的是纹理和边缘信息这是定位关键点的基础上层的语义信息给的是“人体结构”的先验比如“有左手大概就有右手”。两个分支的中间结果 cross 来 cross 去等于让位置信息和关联信息互相校验最终的效果就是姿态骨架的整体一致性更强。论文里有几种不同的网络配置一种是两个分支独立跑、中间不互相融合另一种是分支之间在阶段之间用 concat 连接起来。实验也验证了跨分支融合的效果会更好原因也不难理解——关联信息PAF会反过来帮助关键点定位比如当某个关键点模糊不清时如果周围的 PAF 已经给出了肢体的大致走向定位置信度也会更集中。2.2 PAF 真值怎么生成向量场与关节点匹配的关系论文里最难啃的数学部分就是 PAF 真值ground truth的生成。当时我看这部分看了整整一个晚上才想明白。直接说结论对于一条特定的肢体比如左肘到左腕对于真正的骨骼连接区域中的任意一个像素位置 pPAF 真值是一个单位向量方向是从肘部指向腕部。注意这里的“区域”不是一整条粗线段而是基于两个关键点连线距离阈值算出来的“细长条区域”。数学上对于位置 pPAF 的定义是如果 p 在线段上即 p 到两端点连线的垂直距离小于阈值且 p 在线段范围内PAF 真值就是单位向量 (x2 - x1) / ||x2 - x1||其中 x1、x2 分别是两个关键点坐标。如果 p 不在区域内则 PAF 真值为零向量。这样处理的好处是网络在训练时只在有意义的位置获得方向监督其他位置输出零向量即可。后期做匹配时我们不会对整张图的每个像素都做积分而是只对“候选关键点之间连线经过的位置”做方向向量的积分积分结果越大说明实际预测出来的 PAF 越支持这一对关键点相连。这种设计初看有点绕但把它想成一个模板匹配就很好懂了。比如你要判断两个点是不是手臂的两端你沿着这两点的连线方向去看如果沿途的 PAF 一直都在“指向同一个方向”而且这个方向恰好是从这一点到另一点的方向那就说明网络认为这里有一条“从肘到腕”的骨骼。如果沿途的 PAF 杂乱无章那这大概率是两个不同人的关键点被凑到了一起。训练时每张图的 loss 是每个阶段的置信度图和 PAF 的 L2 loss 的总和。这里论文里有个细节容易被忽略——不同关键点类型在造成遮挡或未标注时对应位置的 loss 会被 mask 掉否则模型会被标注噪声带偏。这一点我们在后面实操章节里还会再展开。3. 训练与推理的实操细节3.1 数据、损失与训练配置从 COCO 到自定义数据集的迁移OpenPose 论文里用的数据集主要是 COCO 和 MPII。COCO 定义了 17 个关键点包括鼻子、双眼、双耳等五官和身体躯干的关键点而 MPII 是 16 个关键点两者在骨架连接的定义上略有区别。如果用 OpenPose 做自己的项目最需要注意的就是骨架连接的定义要和数据标注一致。我见过不少人把 COCO 的标注直接喂给 MPII 的骨架定义结果训练出来的模型关键点全乱了——不是模型不行是骨骼连接的索引对不上。训练配置方面论文里给了不少可复现的参数优化器选 Adam初始学习率设置得比较激进论文里甚至提到 0.01 甚至更高配合 Schedule 逐步下降 batch size 在没有大显存显卡的时代普遍比较小。实际复现时我建议一开始把输入图片缩放成固定分辨率比如 368x368 或 656x368配合随机旋转、缩放、翻转做数据增强。输入太大训练慢输入太小关键点定位精度会下降368 这个值是论文经过权衡后给出来的经验值直接照抄问题不大。loss 部分需要重点说一下 mask 机制。COCO 数据集里对某些关键点标注了“不可见”比如被遮挡或不在图内OpenPose 处理时不是直接忽略这些关键点而是把这部分区域的 loss 乘了一个权重为 0 的 mask。这个细节非常重要因为如果你不管遮挡模型会被“明明标了关键点但实际看不见”的样本严重误导尤其是手肘、手腕这些容易出现遮挡的关节。我在复现时一开始没加 mask结果模型在遮挡场景下经常在背景上输出一个假的关键点热力图后来确认就是 mask 没做对。3.2 推理流程与后处理匹配算法推理阶段OpenPose 的流程可以分为三步前向网络推理得到关键点热力图和 PAF从热力图中提取候选关键点利用 PAF 和候选关键点做二分图匹配并组装骨架。关键点提取这一步通常做法是对每个通道的热力图做非极大值抑制NMS。简单说就是把热力图上局部最大的位置当作候选关键点。实际操作时有一个参数需要注意热力图的阈值。阈值设太高容易漏检设太低会出现很多假关键点后续匹配的计算量也会增大。论文里用的默认阈值大概是 0.1 左右但实际使用要看场景如果画面里人特别小可以适当降低阈值。匹配这一步才是 OpenPose 的真正精华所在。对于每一类骨骼连接比如“左肘-左腕”假设有 m 个肘部候选点和 n 个腕部候选点我们要从 m x n 个组合中找出最优匹配。OpenPose 的做法是对每一对可能的候选点沿着它们连线做 PAF 的线积分把积分值作为“这对点相连”的置信度然后把这个问题定义成一个最大权重的二分图匹配问题再用贪心算法快速求解。很多人看到这里会问为什么不直接用匈牙利算法做全局最优论文里给出的答案是为了速度。贪心匹配在精度上略逊但速度有很大优势而且在大多数实际场景下贪心的结果和全局最优非常接近。我在工程中验证过在人员密集的场景下贪心匹配确实会出现少量误连但整体的姿态结构还是可用的如果真的对精度有极高要求可以改成匈牙利算法但推理时间可能会增加一倍以上。4. 复现与实战中踩过的坑4.1 数据预处理与关键点标注的坑首先说说数据。跟我一样想用自定义数据集的读者要注意OpenPose 训练数据的关键点标注有固定的顺序从 0 到 16或 15分别对应鼻子、脖子、右肩……一旦你改变了顺序在计算 PAF 真值时也会跟着错。所以强烈建议直接沿用 COCO 的标注格式不要自创顺序白白浪费时间排查。第二个坑是图像的尺度问题。我在训练自定义数据集时一开始直接用原始尺寸喂网络发现两个问题一是训练显存暴涨二是小目标人物比如远处的人的关键点定位全乱。后来才知道OpenPose 训练时会把输入图缩放到固定尺寸但数据集里人的尺寸分布千差万别直接缩放会让小目标变得更小。解决方法有两个方向一是像论文里说的那样在训练时做多尺度随机裁剪二是在推理时做多尺度测试并对结果做平均。工程上如果对速度有要求多尺度推理会显得笨重我更倾向把输入分辨率适当调大一点并用一个专门的小目标检测增强策略来处理远处的人。还有一个特别容易被忽略的坑是翻转增强。左右翻转对姿态估计来说是常见的增强手段但如果你直接翻转图片后训练ground truth 里的关键点索引也要跟着交换。比如左肘变右肘左腕变右腕。忘记做索引交换的话模型会学到一种很诡异的左右混淆而且训练 loss 会迟迟降不下去。我当时就栽在这个坑里排查了一整天才发现是翻转增强时索引映射写错了。4.2 loss 不收敛与定位漂移的排查训练 OpenPose 时最常见的两个问题一个是 loss 不收敛一个是关键点定位在局部区域内漂移看起来热力图模糊、峰值不够尖锐。先说 loss 不收敛。OpenPose 的多阶段设计天然堆叠了很多个 loss 相加如果某个阶段的 loss 权重设置得不合理比如中间阶段权重太高网络会花大量精力去优化早期阶段反而忽略了最终阶段的输出。论文里各个阶段默认权重是均等的但我在实际训练中发现后期阶段尤其是最后一两个阶段的 loss 权重可以适当调高一点让网络更聚焦于精炼输出收敛速度会更快。再说定位漂移。这个问题大多出在输入分辨率与感受野的匹配上。因为 OpenPose 的主干是基于 VGG 的结构下采样倍数比较高如果输入分辨率太低一个像素在原始图像上对应的区域就会变大热力图的峰值自然就模糊了。解决方法是适当提高输入分辨率但要考虑显存或者在损失函数中加入热力图峰值约束。我试过一个比较绕但有效的方法在训练时对关键点的热力图额外施加一个高斯峰值的二元交叉熵惩罚让网络输出的峰值更加尖锐这样虽然训练时间变长了一点但关键点定位精度明显提升。4.3 部署加速与长尾场景的取舍OpenPose 虽然号称实时但那是相对当时的硬件条件而言的。真正部署到嵌入式设备上比如 Jetson 或者手机端不做模型轻量化基本跑不起来。实际工程中几个经验可以分享一个是用 TensorRT 或 ONNX Runtime 做推理加速。OpenPose 网络结构不算复杂但多阶段堆叠导致中间层计算量较大TensorRT 做 FP16 量化之后推理速度可以提升一倍以上精度损失在可控范围内。另一个是裁剪不必要的阶段。如果你对精度的要求没那么极致只保留前两到三个阶段推理速度会有明显提升。我测试过阶段数从 6 个砍到 3 个定位精度在简单场景下只下降了不到 2%但速度几乎翻倍。长尾场景的取舍则更多体现在算法设计上。比如在多人密集场景里OpenPose 的贪心匹配偶尔会把人连错简单的规避方法是结合目标检测的结果做约束——先检测人框在匹配时只允许同一个框内的关键点互相连接。虽然这会降低一定召回率但误连率会显著下降。对于画面边缘被截断的人物也可以先把关键点裁剪到一个缓冲区域再做匹配能有效提升鲁棒性。常见现象可能原因建议排查方向loss 一直不降数据标注顺序错、翻转增强索引未交换检查骨骼连接定义和标注顺序关键点定位模糊输入分辨率太低提高输入分辨率或加大热力图输出尺寸多人场景误连贪心匹配质量下降引入检测框约束或改用匈牙利匹配小目标人物漏检缩放后尺寸过小多尺度训练或提升输入分辨率遮挡部位假峰值mask 未生效或阈值不合理检查训练 mask调节推理阈值5. 论文之外可扩展的方向与后续思考OpenPose 发布多年它的影响远不止二维姿态估计本身。原本被设计成二维关键点的 PAF后来被推广到了三维姿态估计、动物姿态估计、甚至物体部件关联等领域。我自己在做一些相关项目时常常会想如果当时没有把“关联”建模成向量场后续很多工作可能都不会这么顺畅地展开。PAF 提供的本质是一种“结构先验的表达方式”这个思路的价值甚至超过了 OpenPose 网络本身的精度。另外即便现在涌现出了各种更强的新网络比如基于 Transformer 的 TokenPose、基于热力图的 HRNetOpenPose 的 PAF 思想在工程中依然有很强的生命力。很多实时应用依旧直接跑 OpenPose 的权重或者基于它的后处理逻辑做二次开发。理解这篇论文其实不只是在学一个模型的结构而是在理解“如何把一个复杂且模糊的关联问题工程化地拆解成可以让深度网络学习和推理的范式”。最后再分享一个小技巧。如果你只是想把 OpenPose 用在具体业务里而不是从头训练直接用官方预训练权重解决大部分常规场景的人体姿态估计是够用的但遇到特殊角度比如俯拍、仰拍或者特殊服装宽松长袍、厚重外套时最好还是在少量这类数据上做一下微调。微调时不要贪心保持小学习率、冻结前面几十层参数只更新后面阶段效果会稳定很多。这套思路不只对 OpenPose 适用几乎所有姿态估计模型都适用。