基于PyTorch时空图卷积ST-GCN的骨骼动作识别毕设全攻略
发布时间:2026/9/1 18:12:11 作者:尧图编辑部 阅读量:1,286

简介这是一份面向计算机专业本科生的高质量毕业设计资源聚焦基于PyTorch实现的时空图卷积网络ST-GCN骨骼动作识别系统适用于毕业设计、课程设计及期末大作业等实践场景尤其适合具备Python基础但尚未深入图神经网络的新手开发者快速上手。压缩包共90个文件含29个核心Python源码涵盖数据预处理、双流ST-GCN模型构建、离线/实时推理demo、13个YAML配置文件定义训练超参与数据路径、3个预训练模型.pt格式含NTU与Kinetics数据集适配版本、11个GIF演示动图及9个说明文档整体52.61MB结构清晰、模块解耦明确。目前已有306人学习下载项目为作者手打实现获导师高度认可代码逐行注释详尽配套README与文档说明完整部署仅需安装依赖并运行main.py即可完成端到端识别流程。 毕设选题年年有动作识别相关的项目这几年几乎霸占了人工智能方向的半壁江山。如果你手里正好拿到一套“基于PyTorch时空图卷积ST-GCN的骨骼动作识别源码模型”那么恭喜你这个题目选得不算冷门但想把它做成一个能过答辩、能讲清楚、甚至能拿出来找工作的项目光把代码跑通远远不够。这篇东西我就从选题价值、原理拆解、环境配置、源码结构、训练调参到答辩话术按我一个带过不少这类项目的经验给你捋一遍。1. 毕设选型ST-GCN到底值不值得做1.1 这个项目能做什么先把这个项目用一句话说清楚输入一段视频里人体的骨骼关键点序列输出一个动作类别。比如你对着摄像头挥挥手它能识别出你在“挥手”你原地跳一下它能识别出“跳”。它不依赖RGB的图像信息而是靠人体骨架点比如肩膀、手肘、手腕、膝盖这些关节点在时间序列上的位置变化来判断动作。和传统的图像分类、目标检测相比骨骼动作识别有几个很明显的好处数据量小不涉及几十万张图片的大规模训练对背景变化不敏感换了个环境、换了个衣服识别效果基本不受影响模型结构清晰甚至可以在CPU上做推理做演示很方便。所以它特别适合作为本科毕设或者研究生入门项目。不像目标检测那种又要调anchor又要处理NMS的项目ST-GCN的代码量适中PyTorch框架又读起来友好理解空间卷积、时间卷积这些基础概念还能支撑你后续面试时聊深度学习。1.2 这个项目适合谁做我接触过的准备做这个题目的学生大概有三类第一类是已经上过深度学习课、会用Python、能看懂简单的PyTorch代码这类学生做这个项目基本不会卡在代码层面更多需要的是理解原理和找到改进点。第二类是只学过Python基础、深度学习还停留在“听说过”的阶段这类学生跑通代码一般没问题但如果让他从头解释一遍LSTM、CNN、GCN的区别就会露馅。这类学生必须认认真真把原理啃下来否则答辩大概率被问懵。第三类是纯粹冲着“源码模型”来的想改个名字和数据集就交差。我劝你不要走这条路本科毕业论文没有那么严但答辩老师随便问一句“你的数据预处理做了什么”就能把你问住。1.3 拿到源码和模型后第一步应该做什么别急着跑。先把源码目录结构看一遍找到模型定义文件、数据加载文件、训练脚本、配置文件这几类关键模块。然后用模型做一个快速推理测试随便丢一段测试视频或者一组骨骼数据进去看能不能正确输出类别。这一步通过了再考虑环境、训练、指标分析这些事。如果代码一跑就报错说明你缺依赖或者环境不对这时候再逐个排查。后面我会专门列一个踩坑清单。2. ST-GCN原理拆解时空图卷积在识别什么2.1 人体骨架怎么变成一张图这是ST-GCN最核心的idea。以前的动作识别方法比如CNN-based方法是把骨架序列转换成一张伪图像然后用常规的2D卷积去处理。这样处理有一个问题人体骨架的天然结构是图不是一个规则的矩形网格。肩关节和肘关节、手腕之间有着明确的物理连接关系但这种连接关系在伪图像里是表达不出来的。ST-GCN的做法是把人体的每个关节当作图的一个节点把关节之间的骨骼连接当作图的边这样就构建了一张空间图。传统卷积是在规则网格上滑动的而图卷积是在这张由人体结构定义的图上做的。节点之间通过图的边互相传递信息每个节点聚合它邻居节点的特征从而学会“当手腕和肩膀的y坐标差变大的时候可能是在举手”这一类规律。一个值得注意的细节是ST-GCN的邻接矩阵设计。作者不仅使用了人体物理连接定义的邻接矩阵A还加入了自连接的矩阵I这样每个节点在更新时能保留自身的信息。公式层面简单说就是对特征做一次归一化后的邻接矩阵乘法再乘一个可学习的权重矩阵。2.2 空间图卷积怎么聚合特征图卷积的一个关键操作是邻接矩阵的归一化。如果不做归一化多个邻居节点的特征求和后可能会让数值越来越大导致训练不稳定。ST-GCN的做法是使用对称归一化即对邻接矩阵的行和列同时做归一化处理。从实现角度来说这一步在PyTorch里可能只是一个矩阵乘法加上一个标准化处理但理解它背后的意义很重要。每个节点更新时它汇聚了邻接节点的特征经过一个线性变换和激活函数得到新的特征表示。你可以把它理解成每个人体关节不仅“知道”自己的位置还“听取”了相邻关节的信息这样某个关节的置信度低也不至于丢掉这个关节的动作信息。值得留意的还有ST-GCN会通过一个可学习的注意力向量来给每一层图卷积的边分配不同的权值而不是对所有邻接节点一视同仁。这个设计让模型能够关注更重要的连接关系比如手部和头部的连接可能比背部中段的连接更能区分某些动作。2.3 时间维度的建模TCN在干啥空间图卷积解决的是“每一帧里关节之间的关系”但动作本质上是一个时间过程。你挥手这个动作从开始抬臂到落下中间有一整个时间序列的变化。为此ST-GCN在每一层空间图卷积之后接了一个时间卷积层通常是一个普通的一维卷积用卷积核在时间维上滑动捕捉相邻帧之间的关节运动模式。这里有一个初学者容易混淆的点空间图卷积处理的是“同一帧内节点间的关系”时间卷积处理的是“同一个节点在不同帧间的关系”。两者组合起来才构成了“时空”图卷积。时间卷积核的大小通常取9意思是每一帧的节点特征会结合前后各4帧的信息来进行更新。核大的优势是感受野大能覆盖更长时间范围的运动但也会增加参数量。如果用更大的核通常需要配合更深的网络来避免过拟合。2.4 网络整体结构和残差连接ST-GCN的主干由9个时空图卷积块组成通道数从64开始之后增加到128、256和常规CNN一样遵循“浅层通道少、深层通道多”的设计逻辑。每一层之间还带有残差连接Residual Connection确保深层网络的梯度可以顺利回传避免网络加深后出现退化问题。最后一层输出会在时间维和空间维上做全局平均池化把特征压缩成一个向量然后接一个全连接层输出动作类别的置信度分数。整体结构不算复杂很适合在论文中画出清晰的示意图。如果想更深入一点你可以研究下ST-GCN的两个变体AGCN和2S-AGCN。AGCN引入了自适应邻接矩阵让图结构不再是固定不变的2S-AGCN增加了骨骼的长度和方向信息用双流结构做融合。这些改进点都可以作为毕设里“创新之处”的来源。3. 环境与数据准备跑通项目前最容易被卡住的环节3.1 PyTorch环境搭建的版本问题这个项目网上流传的版本很多有的基于PyTorch 1.x写的你如果用PyTorch 2.6直接跑大概率会遇到接口不兼容的情况。比如热词里频繁出现的“pytorch 2.6中torch.load的weights_only参数默认值变化”在PyTorch 2.6版本之后torch.load的默认行为改为weights_onlyTrue很多旧项目加载预训练权重时会报“Weights only load failed”之类的错误。解决办法很简单加载权重时显式指定weights_onlyFalse或者用torch.load(path, map_locationcpu)并加上weights_onlyFalse参数。如果你拿到的是老版本代码还要注意torch.utils.data.DataLoader的pin_memory、num_workers这些参数在新版本里的行为基本没变但旧代码里一些已经废弃的API要替换成新版写法。搭建环境时我建议直接创建独立的conda环境Python选3.8到3.10之间PyTorch选2.0以上。如果机器有NVIDIA显卡装CUDA版本对应的PyTorch如果没显卡用CPU版本也能跑通推理和少量epoch的训练毕设演示足够。3.2 选择数据集NTU RGBD还是自采数据ST-GCN最早发布的版本是在Kinetics-Skeleton和NTU RGBD上做的实验。NTU RGBD有两个规模NTU-60包含60类动作NTU-120包含120类动作每类都有几百到上千个样本。Kinetics-Skeleton是视频数据集经过2D姿态估计后抽取的骨架数据节点数为18NTU RGBD是25个节点。对毕设来说完整下载NTU数据集有点大而且下载前要申请授权。我更推荐的做法是先用数据集的子集做实验比如每个类别挑出几十个训练样本。这样训练时间短模型迭代快也足够你完成完整的训练流程。等实验结果稳定了再考虑是否扩展到全量数据。如果学校条件允许你也可以自己录制若干段动作视频然后用OpenPose或MediaPipe提取骨骼关键点做成自己的小数据集。用自己采集的数据做demo答辩时很有说服力因为这是完全独立于开源数据集的测试结果。3.3 骨骼数据格式和预处理细节很多人在这上面栽跟头。ST-GCN的数据输入张量形状一般是(N, C, T, V, M)其中N是batch sizeC是特征通道数通常是3分别是关键点的x坐标、y坐标和置信度。有些数据集的通道不只3个比如加入z坐标深度信息后就是4个T是时间帧数也就是一个动作持续了多少帧V是每帧的关节数NTU数据集是25Kinetics-Skeleton是18M是人数一般取2因为一个视频里可能有多个人同时在做动作。预处理阶段最常见的操作是均匀采样也就是把不等长的骨骼序列调整成固定的时间长度。如果原始视频是300帧而你要的是150帧那每隔一帧取一次即可。直接截断或者最简单的插值都行具体取决于代码里的实现。我在看学生代码时经常发现一个问题他们把数据读进来之后没有检查节点的索引顺序。不同工具输出的关节点顺序可能不同有的从鼻子开始编号有的从骨盆开始编号如果模型是按特定顺序定义邻接矩阵的数据顺序错了训练出来的模型效果会非常差而且很难排查。4. 核心源码阅读模型的骨架和训练逻辑4.1 项目目录里这些文件都是干什么的一般ST-GCN项目的目录结构大概长这样st-gcn/ ├── config/ # 训练参数配置可修改的yaml或py文件 ├── models/ # 模型定义 │ └── st_gcn.py ├── processors/ # 训练、测试入口 ├── datasets/ # 数据加载与预处理 ├── tools/ # 一些辅助脚本 └── weights/ # 预训练模型文件关键是先看models/st_gcn.py这是模型的骨架。然后看datasets下的数据处理脚本清楚数据是怎么被读入、怎么格式化为(N, C, T, V, M)的。再看processors下的train.py和test.py了解训练流程和测试流程。配置文件里的batch_size、base_lr、step、num_epoch这些参数决定了模型训练的基本设置。4.2 图卷积层到底怎么写我摘一个典型的图卷积核心实现让你有个直观印象。代码不长但理解它比背代码有用。import torch import torch.nn as nn class SpatialGraphConvolution(nn.Module): def __init__(self, in_channels, out_channels, num_nodes): super().__init__() # 可学习的邻接矩阵掩码用于调整每条边的权重 self.conv nn.Conv2d(in_channels, out_channels, kernel_size1) self.attention nn.Parameter(torch.ones(num_nodes, num_nodes)) self.relu nn.ReLU() def forward(self, x, adj): # x shape: (N, C, T, V) N, C, T, V x.shape # 对时间维做1x1卷积相当于只对特征通道做变换 x self.conv(x) # - (N, out_channels, T, V) # 应用邻接矩阵和注意力权重 adj adj * self.attention # 图卷积的核心矩阵乘法把节点特征按边关系聚合 x torch.einsum(nctv,vw-nctw, x, adj) return self.relu(x)这只是示意图实际工程里还会涉及归一化、批量归一化层、残差连接等。但核心就是einsum这一步把每个节点t的特征与邻接矩阵相乘实现邻居特征的聚合。弄清楚这一步你就掌握了GCN的精髓。4.3 训练配置里的那些超参数ST-GCN训练时的常用超参数配置大同小异。以NTU-60交叉视角cross-view协议为例常见配置是参数数值说明batch_size64显存不够就降到32或16base_lr0.1初始学习率Adam可以用0.001optimizerSGDmomentum0.9weight_decay0.0001num_epoch80数据集大时可以适当增加step30, 60每30个epoch学习率乘0.1SGD配合momentum在这类任务上效果一般比Adam稳定。你也可以试Adam但学习率要调低很多。这些参数不是死规矩一定要根据自己的数据量和硬件情况来调整。4.4 加载预训练模型做推理拿到“源码模型”的好处就是可以先实现推理演示。加载模型时有几个容易踩的坑检查模型的类别数是否和你的数据集一致。如果你要识别10类动作但预训练模型是在60类上训练的你需要修改最后一层全连接的输出维度并只迁移前面层参数。注意torch.load的map_location参数。你用CPU加载GPU训练的模型时不加map_locationcpu会报错。权重文件的key和模型定义的key必须一一对应。如果预训练模型是用不同版本代码保存的键名可能不同需要写脚本做键的映射。推理阶段模型的输入同样是一段骨骼序列输出的每个类别的logits取最高的那个作为预测结果。这里要纠正一个常见误区模型不是直接读视频的它读的是骨骼点坐标序列所以在demo时需要先用姿态估计工具把视频帧转成骨骼点数据再喂给ST-GCN。如果你的项目源码里自带了一个端到端的demo脚本通常它内部已经串好了这部分流程。5. 训练效果与调优从复现到改进5.1 怎么判断训练有没有正常进行很多初学者看到loss在下降就以为万事大吉其实不一定。你还要关注top-1准确率、loss每一轮的分布、测试集上的表现避免过拟合。训练过程中我一般会盯这三件事第一个epoch结束时的loss值。如果loss几乎不变化说明学习率可能太小或者模型的权重初始化有问题训练集和验证集的准确率差距。如果训练集90%但验证集只有60%基本可以确定过拟合某些动作类别准确率特别低的时候要去看是不是数据样本太少或者类别本身不好区分比如“坐下”和“蹲下”骨骼点很容易混淆。5.2 过拟合的几种处理办法毕设数据量通常不大过拟合几乎是必然遇到的事。通用做法有这么几个。第一个是数据增强。骨骼数据最常见的增强方式包括随机旋转、随机缩放、随机裁剪时间片段、随机遮掩部分关节等。最简单有效的是时间片段随机裁剪相当于让模型见识到动作的不同起止位置提高泛化能力。第二个是加大权重衰减。weight_decay从0.0001调到0.001通常能缓解过拟合。第三个是提前停止。训练到验证集准确率不再提升时直接保存最优模型。千万不要等到训练完80个epoch再取模型中间那个验证集最优的checkpoint往往才是最好的。5.3 改进ST-GCN的几个方向如果只是复现源码答辩时很容易被追问“你的创新点在哪里”。改进方向可以从这几个角度考虑。一是双流结构。在原有的关节流基础上增加一条骨骼流分支输入不再是关节点的坐标而是相邻关节之间的骨骼向量包括方向和长度最后把两条流的预测分数融合。这个思路有公开论文支撑代码改造也不复杂。二是自适应邻接矩阵。让模型自动学习图的拓扑结构而不是完全依赖人工定义的连接关系。对某些复杂动作自适应图结构的效果会更好。三是增加注意力机制。比如在时间维上引入通道注意力让模型更关注关键帧。这个改动相对独立不影响原有主体结构论文里也好解释。四是在时间卷积中引入空洞卷积dilation在不增加参数量的前提下扩大时序感受野。这些方向不一定每个都带来大幅提升但每一个都可以作为你论文里的一章来写。毕设要的不是顶会级别的创新而是逻辑闭环、实践完整性和工作量。5.4 训练时的硬件问题没有GPU的机器也不是不能训练但一个epoch可能要跑很久这时候有两个选择一是用Google Colab免费GPU缺点是免费额度有限二是自己买云GPU按需付费一次训练也就几十块钱。如果你在本地CPU上训练最好把数据量减小、训练epoch也减到10个以内先把流程跑通再上强资源训练完整模型。我在实习期间就遇到过学生把完整NTU-60数据丢到自己笔记本上训练跑了一晚上才2个epoch第二天发现学习率设置错了白白浪费一晚上。6. 答辩与论文怎样把项目讲出深度6.1 答辩老师通常问什么答辩时老师一般不会拿特别偏的细节为难你但基础原理问题一定要答上来。我列几个高频问题图和普通图像的区别是什么为什么用图而不是用2D卷积邻接矩阵在ST-GCN里起什么作用不归一化会怎样时间卷积和空间卷积分别在处理什么信息为什么选择ST-GCN而不是LSTMLSTM做动作识别有什么缺陷你的模型在哪些类别上出错最多为什么你的模型对遮挡、多人交互场景鲁棒吗最后一个问题很容易被问到。ST-GCN的一个明显局限是它对遮挡比较敏感如果节点缺失太多识别准确率会下降。你可以坦率承认这个局限性并说明你做了哪些处理或者提出未来能怎么改进比如加入RGB分支去补充信息。6.2 论文架构怎么搭论文结构可以分五章绪论、相关工作、ST-GCN原理与网络设计、实验与结果分析、总结与展望。相关工作中要提到基于RNN/LSTM的方法、基于CNN的方法、基于GCN的方法三类把它们的关系和演进过程讲清楚。实验部分除了准确率对比最好再附上混淆矩阵和几个典型样本的可视化结果。把图表做规范比文字写得长更重要。模型结构图、训练曲线、混淆矩阵、错误案例图这几张图放上去论文的专业度会提升一个档次。6.3 怎么把“源码模型”变成你自己的东西最有力的做法是做一个自定义数据集上的小实验。哪怕只是采集几个动作、每个动作几十个样本用预训练模型做微调然后展示它在你自己的demo里工作。这比直接说“我复现了开源代码”要有说服力得多。另一个做法是写一份详细的项目README把你对代码每个模块的理解记录下来包括数据流程、模型结构、训练过程分析。这份README既是你的复习资料答辩时也可以主动展示给老师看证明你的工作量。7. 最终踩坑清单环境、数据、训练一条龙下面是我根据自己碰过的、还有学生反复问过的问题整理出来的高频坑你跑代码前先过一遍能省很多时间。7.1 环境类坑PyTorch版本导致的torch.load报错按前面说的加weights_onlyFalse解决CUDA能用但PyTorch检测不到GPU时检查安装的是不是CPU版本用torch.cuda.is_available()验证numpy版本太高导致某些旧代码报错时降到1.23左右基本能解num_workers设置过大在Windows上可能引发多进程报错直接设为0最省心。7.2 数据类坑节点顺序错乱是影响最大的隐性bug模型给出的节点索引顺序和数据集的节点索引必须对应不匹配时准确率会断崖式下跌部分视频的骨骼序列为空要在数据加载阶段过滤掉否则损失函数会算出NaN多人场景下骨架数据可能不止一个人模型通常只取前两人前处理时宁缺毋滥不要把空的张量塞进去。7.3 训练类坑loss为NaN时优先检查学习率和数据是否归一化测试准确率远低于训练准确率时先用单个batch拟合测试如果单batch loss降不下去多半是模型实现或数据张量形状有问题保存模型时最好保存state_dict而不是整个模型方便跨代码版本加载如果你改动了模型的类别数记得同时修改配置文件和模型初始化的参数。7.4 一个特殊的坑骨架数据质量骨骼动作识别的效果上限其实是由姿态估计模型决定的。如果你的demo端用的是MediaPipe低光照、大动作幅度、遮挡严重时提取出的骨架点会有很多噪声。ST-GCN作为一个分类模型对输入数据的质量非常敏感。我的建议是demo时选择光线均匀、动作幅度适中、背景干净的场景这样识别效果看起来最稳定。做消融实验时最好也记录一下不同场景下的准确率差异这部分内容写进论文里反而是加分项。7.5 关于“源码模型”的底线建议最后再说一句实在话。开源代码和预训练模型是很好的起点但你不能只做一个“搬运工”。拿到项目后的正确姿势是先复现结果再拆解代码再提出一个小的改进点最后用自己的表达把整个过程写进论文和答辩PPT。哪怕那个改进点只是把数据增强加进去或者换了个优化器它也是你亲自做出来的东西答辩时底气完全是两回事。骨骼动作识别这个方向未来几年还会有持续热度智能安防、人机交互、运动分析、康复医疗都有落地场景。如果你把这个项目吃透了不仅毕业没问题也为自己积累了图神经网络实战、时序建模、姿态估计生态这套完整的技术栈。动手跑起来吧跑通了第一段代码后面的事情都比你想的简单。本文还有配套的精品资源点击获取