1. 这个方向到底在研究什么——先把概念拆清楚
搞计算机视觉的人应该都遇到过这种尴尬:甲方说“我要一个人体动作跟踪系统”,你以为是要做目标跟踪,结果对方要的是动作识别;你说“检测关键点”,对方以为你要输出动作标签。这类项目在学术界一般归到pose estimation、action recognition、multi-person tracking这几个圈子,但落到实际研究标题里,经常就统称为“基于卷积神经网络的人体动作跟踪研究”。写这篇的目的,就是把这个大帽子底下的核心内容、关键路径和实操坑位一次讲透。
先说结论:人体动作跟踪不是一个单一模型能搞定的事,它一般拆成“空间姿态估计 + 时序动作识别 + 跨帧身份关联”三个子问题。卷积神经网络在其中最大的作用是解决第一个子问题和第二个子问题的空间特征提取,也就是理解“人长什么样、关节在什么位置、身体局部长什么样”。至于时序上的动作变化,通常还要再套一层时间维度上的建模,比如时序卷积、光流、循环结构,或者干脆用3D卷积直接把时空一块学了。
适合看这篇的人,主要是准备做毕设或者做工程预研的学生,也包括刚入门视觉方向、想找一个可落地方向的开发者。如果你有OpenCV基础,yolov系列跑过,但对姿态估计还是懵的,这篇文章能帮你把从数据准备到模型训练再到推理优化的整条链路理顺。如果你只是想搜个模型调包,我建议你也花十分钟过一遍,因为真正磨人的地方往往不在网络结构,而在数据处理和训练细节上。
1.1 人体动作跟踪到底在“跟”什么
人体动作跟踪,从输出角度看有两层含义。第一层是关节位置跟踪:给定一帧图像或一段视频,输出人体关键点坐标,比如头、肩、肘、腕、髋、膝、踝这17个或25个点,并把相邻帧里同一个人的关键点关联起来。第二层是动作类别跟踪:把“挥手”“走路”“下蹲”“跑步”这些语义标签,按时间顺序标到视频片段上,甚至再细分到每个动作的开始帧和结束帧。两者可以独立做,也可以串起来做——先用关键点网络得到骨架,再把骨架序列送入分类网络输出动作标签,这就是非常经典的“两阶段方案”。
我们经常看到论文里出现ST-GCN、PoseC3D这类模型,它们吃的输入就是骨架序列而不是原始图像。这类方法看起来摆脱了CNN对图像的直接依赖,但骨架本身是从哪来的?绝大多数时候还是CNN姿态估计网络产出的。也就是说,哪怕你最后用了图卷积、Transformer,整个系统的最底层特征提取依然绕不开CNN。这也是为什么这个方向的核心研究点,通常都落在CNN姿态估计网络上,而不是直接落在动作分类网络上。
1.2 用生活化的方式理解CNN在干什么
卷积神经网络在这条链路里的角色,可以理解为一条流水线上的检测员。第一层检测员只认“边缘”和“色块”,比如衣服边缘、皮肤色块;第二层把边缘和色块拼成“胳膊”“腿”这样的零件;再往后几层,网络就能根据零件的组合方式,推断出“这是一个手肘”“这是一个膝盖”。这些检测员不是人写的规则,而是通过大量标注数据自己总结出来的模式匹配器。
关键点检测最常见的做法,不是让网络直接回归一个坐标数字,而是让网络输出一张“热力图”。热力图上的每个像素值表示“关键点有多大概率出现在这里”,峰值位置就是关键点坐标。这样做的好处是空间泛化能力强,预测目标从“某一个精确值”变成了“一片概率区域”,网络更容易学。你如果自己写损失函数,大概率也会选热力图监督而不是坐标回归,前者的收敛稳定性和最终的定位精度都要好不少。
2. 方案选型:三种主流技术路线怎么取舍
“基于CNN的人体动作跟踪”具体怎么落地,业内大致有几种范式。不同范式的精度、延迟、标注成本和部署难度差异很大。我建议不要一上来就看最前沿的论文,先搞清楚自己的资源边界,再选一条路线做深做透。
2.1 路线一:2D姿态估计加动作分类
这是最经典、最适合入门和研究验证的方案。先用一个CNN姿态估计模型,比如经典的HRNet或者OpenPose,从视频每一帧中提取人体关键点坐标;然后把这些坐标序列整理成固定长度的窗口,送入一个轻量分类网络,比如一维卷积网络、LSTM或者简单的多层感知机,输出动作类别。
这个路线的优点非常明显:
- 公开权重多,开源实现完善,调试门槛低。
- 关键点数据是结构化数据,预处理方便,可以做大量的数据增强和归一化。
- 模型分阶段可解释性强,出了错知道是姿态估计的锅还是分类器的锅。
缺点在于2D关键点丢失了深度信息,侧身、遮挡、俯视场景下误差会放大,动作分类的鲁棒性比较受限。对于正面拍摄、单人或少量人的场景,这条路线完全够用。
2.2 路线二:3D姿态估计和骨架序列识别
3D路线在2D基础上多预测一个深度值,输出关节的三维坐标。代表性做法如VideoPose3D,用2D关键点序列通过时域卷积提升到3D坐标。也有直接从图像回归3D模型参数的方案,比如某些参数化人体模型方法。3D骨架天然包含动作的立体信息,对“弯腰”“举手”这类动作的区分能力远强于2D。
代价是数据和标注不好搞。真实世界的3D标注需要专业动捕设备,现有3D数据集的多样性和规模远不如2D数据集。自己采集制作3D数据的成本更是高得离谱。要在这个方向上做实验,通常的做法是在公开3D数据上预训练,再用视频数据做迁移学习,或者退而求其次,在2D关键点序列上用网络预测一个相对深度,获得效果不错的伪3D骨架。
2.3 路线三:端到端时空卷积网络
第三种路线直接把连续视频帧堆成一个5D张量(批次、通道、帧数、高度、宽度),喂给3D卷积网络或2D卷积加时间维度的混合网络,直接输出动作类别。经典代表有SlowFast、TSM、C3D这些名字,核心思想是用卷积同时建模空间和时间。
好处是流程最短,不用单独维护姿态估计环节,性能上限高。缺点是对训练数据量的要求极其苛刻,视频分类数据动辄需要几十万甚至上百万个标注片段。对大多数个人研究或小型团队来说,数据规模就是最大的瓶颈,光靠ImageNet预训练权重支撑一个自定义动作分类任务,效果通常不太理想。
2.4 为什么多数研究仍然围绕CNN展开
这几年Transformer在视觉领域势头很猛,很多论文用ViT做姿态估计效果也不错。但实际做项目时,我依然建议优先考虑CNN。一是CNN算子部署生态成熟,多数边缘设备和推理框架对CNN支持最完善;二是CNN在小数据集上的收敛速度明显优于Transformer;三是训练技巧成熟,不需要考虑patch化序列长度这类额外超参。等你的基线系统完全跑通,再考虑替换主干网络做消融对比,才是比较稳妥的研究路径。
3. 核心环节详解:数据、结构、训练一个都不能少
选定路线之后,接下来就是工程实现阶段。这个阶段的坑最多,很多刚入门的开发者喜欢把时间花在调整模型结构上,结果最后发现瓶颈根本不在网络,而在数据清洗和训练流程上。
3.1 数据集准备和标注格式
如果你做2D姿态估计,常用公开数据集的格式是COCO风格:一张图像、一个人体实例的标注框、以及一组关键点坐标和可见性标志。每个关键点通常定义为“可见、被遮挡、不可见”三种状态,训练的时候不可见的关键点不参与损失计算。
自己做数据标注时,有几个细节需要注意。第一,关键点编号顺序必须固定,比如0号是鼻子,1号是左眼,2号是右眼,一旦顺序乱了,前面的训练就白费了。第二,标注时建议把“被遮挡但可推测位置”的点定为可见性1,把“完全看不到”的点定位可见性2,这样模型在遮挡场景下不至于学出离谱的位置。第三,图像坐标系建议归一化到[-1, 1]区间,以人体框的中心和尺度做归一化,去掉绝对像素值的影响,训练更稳定。
3.2 热力图监督与网络结构要点
热力图监督的细节值得多说几句。给每个关键点生成监督信号时,通常在高斯中心画一个二维高斯分布,标准差一般取2到3个像素。太小的话网络学不动,太大则关键点定位精度变差。不同数据集上最合适的sigma不太一样,我倾向于通过小范围网格搜索确定,比如2、2.5、3三个值都跑一遍,对比验证集上的平均关键点误差。
网络结构方面,姿态估计主流的思路是“高分辨率表示”,也就是网络全程尽量保持高分辨率的特征图,而不是像分类网络那样不断降采样到低分辨率。HRNet就是这种设计的典型代表,它并行维护多条不同分辨率的分支,并在各阶段反复融合,最终输出的热力图既保留全局语义又保留局部细节。如果你是在基础研究上做改进,可以从增大最后一层热力图分辨率、改进特征融合方式、增加跨层连接这几个方向入手。
3.3 训练超参与迁移学习策略
训练姿态估计模型,一开始不要从头训练。哪怕是同一个数据集,从头训练一个深层CNN在单卡环境下也可能要一两个星期,很多人根本等不起。标准做法是用ImageNet分类预训练权重初始化主干网络,然后把自己的检测头换掉,微调整个网络。我实测下来,这种做法可以把收敛时间压缩到原来的三分之一以下。
优化器和学习率方面:Adam是常用选择,初始学习率建议设在1e-4左右,配合余弦退火或者阶梯式下降。批次大小设置取决于显存,如果输入是256x192分辨率,单卡batch size大概能到32甚至更高;再大的batch size配合同步批归一化,对精度有提升但也有一定调参成本。损失函数一般用均方误差计算预测热力图与高斯标签的差值,如果想更关注关键点定位精度,可以在主损失之外加一个局部坐标细化分支的辅助监督。
数据增强环节,随机旋转、随机缩放、随机水平翻转、随机遮挡都值得加。旋转角度控制在±30度以内,缩放比例在0.7到1.3之间,翻转时要配对左右关键点编号。对于动作识别任务,还可以在时序维度上做随机裁剪和帧间隔采样,增强对动作速度变化的鲁棒性。
3.4 推理阶段的后处理与关联匹配
模型训练完成后,推理阶段还有一个很容易被忽略的环节就是后处理。热力图输出后要经过argmax找到峰值位置,如果要达到亚像素精度,可以在峰值附近做高斯拟合,求出浮点坐标。多人的场景下还要做关键点分组,判断哪些关键点属于同一个人,经典的做法是计算关键点之间的部件亲和度向量场,再用图匹配算法装配成完整骨架。
动作跟踪的跨帧关联,本质上是解决一个匹配问题。简单做法是计算相邻帧骨架框之间的IoU,大于阈值就认为同一人,这是Tracking-by-Detection的套路。更平滑的做法是加一个卡尔曼滤波预测下一帧位置,再用匈牙利算法做最优匹配。注意一个问题:如果姿态估计模型本身帧间抖动明显,匹配结果再好,看起来还是很飘,这时候在输出端加一个指数滑动平均,能显著改善视觉体验。
4. 实操记录:一个模拟项目的完整落地过程
理论上的东西说多了容易飘,我拿一个实际做过的模拟项目X来复盘一遍完整流程。项目需求不复杂:单目摄像头前,一个人做深蹲、行走、举手三个动作,系统输出当前动作类别,并标注骨架可视化结果。这个项目我用的是2D姿态估计加骨架分类的两阶段路线。
4.1 数据采集与预处理
没有现成的动作数据集,我决定自己拍摄采集。找一段空白墙壁背景,用手机固定拍摄,让一个人分别做三个动作视频,每个动作大概2分钟。然后把视频按帧抽出来,再人工标注关键点。这个过程相当枯燥,大概标注了800帧之后我放弃了全部手标,改用开源的2D姿态估计模型先自动标注,再人工修正明显错误的帧,效率提高不少,但要注意自动标注行为可能在最终模型上引入一些系统性偏差,比如侧身位关键点位置整体偏移。
数据量最终为1200帧左右,按8比1比1划分训练、验证和测试集。因为是同一个人的数据,划分前我把同一条视频片段放进同一侧,避免帧与帧之间的强相关性造成评估结果虚高。
4.2 模型搭建与训练过程
姿态估计部分直接加载了预训练权重,冻结前40层参数,只微调最后几个阶段。输入尺寸选256x256,热力图分辨率64x64,输出17个关键点。分类器部分,我把每帧的17个关键点坐标按统一骨架结构归一化后,构造成一个窗口长度为16帧的序列,先简单接入一个两层的Conv1D网络,再接全局池化和全连接层,输出3个类别的概率。分类模块的训练采用交叉熵损失。
第一版训练结果差强人意,验证集动作分类准确率约87%,但深蹲和行走经常混淆。排查后发现一个明显问题:数据不均衡。深蹲动作中膝盖弯曲时人在画面里变得更矮,产生的关键点坐标分布和行走动作有部分重叠。我采取了三步改进:对深蹲样本做随机时序插值扩充,把分类窗口从16帧改成24帧,在分类器输入端加入髋关节和膝关节的夹角特征,和关键点坐标拼在一起。改进后准确率提升到96%左右。
4.3 前后端联调的几个细节
模型训练完,项目还剩最后一步:把模型接到实时视频流上。这一步的麻烦程度不亚于训练。比如摄像头输入的图片色彩空间必须做匹配,否则推理结果会明显变差;又比如视频帧率不固定时,动作分类窗口按帧数滑动的策略会导致动作判定时间轴不准,最终我改成按时间戳滑动窗口来做。
推理延迟方面,姿态估计模型和分类模型两段式串联,在普通显卡上能做到20帧左右,但视频流是25帧每秒,稍微有些吃紧。优化方案是把分类模型从Conv1D换成更轻的GRU,同时在姿态估计模型输出端把关键点从float32改为float16存储,整体延迟降低了约15%。这个经验也提醒我,研究阶段评估的FPS数据如果脱离了完整系统管道,意义其实不大。
5. 常见问题速查表与避坑建议
实操中遇到的所有问题里,有一半以上是可以提前预判的。我把高频问题整理成了一张速查表,方便你在调进程的时候快速定位。
| 现象 | 可能原因 | 排查思路 | 解决方向 |
|---|---|---|---|
| 训练loss始终不降 | 学习率过大或过小、数据标签错误 | 先固定一个epoch画出loss曲线,检查标签图片 | 调学习率、降低batch、清洗错误标注 |
| 关键点预测到画面外 | 热力图分辨率过低、高斯sigma太小 | 可视化热力图峰值,检查网络最后一层尺寸 | 增大热力图分辨率、增加上采样模块 |
| 多人场景骨架互相串 | NMS阈值过低、分组策略简单 | 打印分组置信度,分析相邻人IoU分布 | 调高NMS阈值、添加部件亲和力字段 |
| 动作分类在时间上有滞后 | 滑动窗口太长、模型依赖未来帧 | 分析单个动作窗口的时序特征 | 缩短窗口、使用因果卷积或单侧GRU |
| 训练时GPU占用高 | 网络过宽、输入图过大 | 用nvidia-smi查看显存占用瓶颈 | 降低输入尺寸、使用梯度累积 |
| 推理结果抖动明显 | 后处理缺少时序平滑 | 比较相邻帧的坐标变化幅度 | 加卡尔曼滤波或指数滑动平均 |
5.1 关于训练稳定性的三件小事
第一件事是固定随机种子。姿态估计的训练过程中包含很多随机因素,数据打乱顺序、增强参数、权重初始化、Dropout位置都会影响最终结果。你不固定种子的话,跑两次结果差1%都很难判断是改动带来的还是随机波动,这在对比实验里是硬伤。第二件事是自动保存最佳模型。按验证集损失最小的时刻保存权重,而不是按最后一个epoch保存,防止过拟合尾巴影响最终模型。第三件事是记录所有超参实验到一张表里。我见过太多人改了学习率之后不记录,几天后忘了哪组参数对应哪个结果,只能重跑实验。
5.2 数据集不均衡的实战解法
动作识别任务里数据不均衡几乎是必然的。各种动作的出现频率天然不同,深蹲占比20%、行走占比60%、举手占比20%的分布已经很常见。解决时我建议优先尝试损失函数加权,给样本少的类别大权重;如果还不够,再进行数据扩充。扩充的时候注意不要只做复制粘贴,而是做坐标系的轻微扰动、时序窗口的随机截取、关节点的小幅抖动,让网络看到更多真实世界的差异性。用SMOTE这类合成样本的方式我之前也试过,在关键点序列上效果一般,因为合成的动作坐标可能不符合人体运动学约束,产生不自然的骨架。
5.3 多人场景与遮挡场景的进阶提醒
如果你的场景是多人甚至密集人群,2D姿态估计的误差会急剧增加,原因是自遮挡和人与人遮挡造成关键点可见性很低。这时候有几个升级方向:一是加入追踪网络来建模遮挡期间的运动状态,把短暂丢失的骨架从历史轨迹中推断出来;二是引入光流信息辅助关键点传播;三是切换成带有显式遮挡建模的模型结构,增加关键点可见性预测分支。任何一个方向展开都可以变成一篇论文的核心创新点,但也意味着工作量成倍增加,需要在项目初始就评估好时间预算。
6. 一些个人体会和改善建议
整个项目做完之后,我对“基于卷积神经网络的人体动作跟踪研究”这句话的理解比刚开始深刻得多。这类选题表面上是一个模型问题,实际做下来会发现数据工程、训练策略、系统联调这些环节所占的时间远超模型结构设计。作为研究入门,我建议你把主体精力放到“热力图监督的姿态估计”上,把动作分类作为一个简单验证应用,这样才能在有限的时间里抓住核心矛盾。
最后分享一个小技巧:在做消融实验或对比实验时,可以把姿态估计模型输出的中间热力图保存下来,做成视频可视化。热力图比最后的骨架画线包含更多信息,哪怕网络最终输出错了,热力图往往也能告诉你模型是“哪里看错了”。有一次我通过热力图发现模型总是把深蹲动作中的膝盖和背景椅子边缘混淆,后来调整训练数据中椅子的出现频率,模型立刻就稳定了很多。这类细节,光看最终骨架图是永远发现不了的。
这个方向后续可以扩展的地方还有很多:比如引入多视角信息来解决遮挡问题,把骨架序列接上Transformer提高动作分类的时序建模能力,或者把整个流程封装成支持多人的实时推理服务。只要先把CNN姿态估计这个底座打扎实,往哪个方向延伸都不会太吃力。