ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

机器学习人体动作识别实战:骨骼关键点与LSTM工程解析

机器学习人体动作识别实战:骨骼关键点与LSTM工程解析 简介面向机器学习、深度学习方向毕业设计或课程设计的人群压缩包提供了一个完整的人体动作识别项目涵盖从数据预处理、特征工程到模型训练与评估的流程。包内共7个文件包含Jupyter Notebook主程序、Matlab调参脚本、数据集及Markdown说明文档等总大小2.28MB结构紧凑便于快速上手。项目利用随机森林、AdaBoost、逻辑回归、SVM等多种算法对比实验并通过参数穷举搜索优化模型性能数据集文件夹提供整理并标注后的动作样本说明文档与主程序则详细记录实现思路与实验结论。已有41人学习适合希望完整复现动作识别实验、理解机器学习算法实际落地流程的开发者与研究者。对于智能监控、人机交互等应用场景亦有参考价值。1. 机器学习人体动作识别这个压缩包里装了什么能直接交作业吗解压这个基于机器学习的人体动作识别.zip第一眼的感觉是“麻雀虽小五脏俱全”。它不是一个论文空壳而是一套能直接跑通的课程设计/毕设工程视频读取、骨骼关键点提取、时序模型训练、实时推理脚本全部都有你只需要补齐自己的数据集路径和标签就能出结果。换句话说如果你正愁机器学习或深度学习期末大作业没方向这个包相当于把从“摄像头画面”到“动作类别输出”的主链路给你铺好了剩下的活是把参数调明白、把坑踩平。适合两类人一是想快速交差的同学二是想弄懂“人体动作识别到底怎么做”的入门者。我拆完这套工程后最大的感受是——它真正的价值不在模型多新而在于把数据采集、标注、训练、部署这一整套流程讲清楚了。2. 动作识别的技术选型为什么是骨骼关键点加 LSTM而不是直接怼 CNN2.1 两个主流方案的本质区别人体动作识别在课程设计级别有两个常见路线一个是基于原始 RGB 帧的 CNN 或 3D-CNN另一个是基于骨骼关键点的时序模型。这个压缩包选的是后者也就是“先提取骨骼点再用 LSTM 做分类”。我第一次做的时候也纠结过要不要直接上 CNN后来发现骨骼点方案在三个维度上更适合作业场景。第一是计算量。CNN 直接吃 224x224x3 的连续帧显存和 CPU 占用都很难看在普通笔记本上训练一轮要等到怀疑人生。而骨骼关键点只需要 33 个点的 x、y、z 坐标输入维度只有几十LSTM 训练一轮快一个数量级。第二是数据量需求。深度模型要喂海量帧才能收敛而骨骼点序列本质上是低维时序数据几百个样本就能把动作分清楚。第三是可解释性。骨骼点可视化之后你能直接看到模型到底在“看”哪些关节的运动答辩时老师问起来你也能讲明白。那为啥用 LSTM 而不是 Transformer因为这是一个典型的“够用就好”的场景。LSTM 在时序建模上虽然老但对 30 帧左右的短序列动作识别非常稳定而且 Keras 里几行就能搭好调试成本低。Transformer 在长序列和跨模态上有优势但在这个任务里属于杀鸡用牛刀而且训练不稳定、调参玄学多。你交作业用 LSTM 完全说得通如果后续想冲高分再换 Transformer 也有现成的接口。2.2 资源包内的模型结构与文件清单这个包里的模型结构是典型的“骨骼点序列 - LSTM - 全连接分类”。我把它拆开看角色分工大概是这样的文件/目录作用关键点pose_extract.py用 MediaPipe 提取骨骼关键点输出 33 个点的 xyz 坐标dataset_builder.py把视频帧序列转成训练数组统一序列长度存成 npytrain_lstm.py训练 LSTM 分类模型三层 LSTM Dropout Softmaxpredict_cam.py摄像头实时推理加载 h5 模型逐帧预测action_labels.txt类别标签文件顺序对应模型输出requirements.txt依赖清单Python 3.8 到 3.10 可用这里核心的是train_lstm.py里的网络定义。我去掉注释之后核心代码大致长这样model Sequential([ LSTM(64, return_sequencesTrue, input_shape(seq_len, feat_dim)), Dropout(0.5), LSTM(128, return_sequencesFalse), Dropout(0.3), Dense(64, activationrelu), Dense(num_classes, activationsoftmax) ]) model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy])逻辑说明第一层 LSTM 用return_sequencesTrue是因为还要把完整的时序信息传给第二层 LSTM第二层输出最后一个时间步的隐藏状态只保留最终特征。两个 Dropout 分别压制过拟合训练集小的时候尤其管用。参数说明seq_len是每个动作采样多少帧包里的默认值是 30对应 1 秒左右的动作时长feat_dim是每帧的特征数MediaPipe Pose 输出 33 个点乘以 3 个坐标等于 99如果你的数据集只保留部分关节点这个值要同步改。num_classes改成你实际的动作类别数。我一般会先用这个结构跑通再把第一层 LSTM 的 units 从 64 改成 32 试试观察验证集准确率变化。注意input_shape必须和dataset_builder.py里生成的数组维度严格一致否则第一个model.fit就直接报错这是新手最容易翻车的地方。2.3 数据采集与标注流程别指望网上直接下现成数据集包里的数据采集脚本是用 OpenCV 调摄像头按帧提取骨骼点后保存为 npy 数组。我复现时是这么操作每个动作录 50 个样本每个样本录 3 秒脚本自动截取序列。想提高模型泛化能力就换不同的人、不同的背景、不同的摄像头角度各录一批。标注的格式是一行一个动作类别比如0 挥手、1 下蹲、2 走路。类别顺序必须和action_labels.txt里一致不然预测结果全是错位的。我自己吃过亏先录了 3 个类别的数据后来加了一类但标签文件没改模型训练正常推理却永远输出不到新类别最后发现是标签列表没同步。这个流程里数据质量比模型结构重要得多宁可样本少一点也要保证动作干净、背景不过度杂乱。3. 把工程跑起来环境配置、训练命令与参数调试全记录3.1 环境搭建版本卡死才能少踩坑这个包对版本是有隐性要求的。我在 Windows 11 和 Ubuntu 22.04 上都跑过最容易翻车的不是模型代码而是 MediaPipe 和 TensorFlow 的版本搭配。MediaPipe 0.10.x 搭配 TensorFlow 2.10 是稳定的组合如果直接pip install mediapipe tensorflow装上最新版很可能遇到.so文件加载失败或者 GPU 版本不匹配的问题。conda create -n action_recognition python3.9 -y conda activate action_recognition pip install mediapipe0.10.14 tensorflow2.13.1 opencv-python4.10.0.84 numpy1.24.3逻辑说明Python 3.9 是兼容性最好的版本3.11 以上有些预编译包会缺。TensorFlow 2.13.1 是 CPU 版本也能跑的训练版本MediaPipe 0.10.14 对应的是较稳定的 Pose 接口。参数说明opencv-python版本不需要太纠结但要确保是 4.x因为 3.x 的VideoCapture接口读取摄像头时色彩空间处理不太一样。装完之后用一个命令验证python -c import mediapipe as mp; print(mp.__version__); import tensorflow as tf; print(tf.__version__)如果能打印版本号环境就算过了。这里有个血泪经验不要用 Python 3.12 或 3.11 去创建环境MediaPipe 的依赖包protobuf在 Python 3.12 上有兼容性坑你会在导入阶段遇到各种莫名其妙的报错然后陷入疯狂的版本回退中。环境问题占整个复现时间的三分之一版本老老实实按 requirements 走能省很多事。3.2 从摄像头到模型训练三个脚本的顺序不能乱整个流程分三步采集、训练、推理。包里的脚本本身写得比较直白但执行顺序和数据格式是有讲究的。以我踩过坑的经验正确顺序是先跑pose_extract.py转骨骼数据再跑dataset_builder.py构建训练集最后train_lstm.py出模型。如果你的数据集是别人提供的视频而不是自己录的跳过第一步直接构建 npy 也一样。python pose_extract.py --data_dir ./videos/squat --output ./npy/squat --label 0 python dataset_builder.py --npy_dir ./npy --output ./dataset/action.npz python train_lstm.py --dataset ./dataset/action.npz --epochs 100 --batch_size 16逻辑说明pose_extract.py这个文件的作用是把每个视频裁成固定帧数的序列逐帧丢给 MediaPipe输出一个(样本数, 帧数, 99)的数组。为什么是 99前面提过33 个关键点乘 3 个坐标轴。dataset_builder.py负责把多个动作类别的 npy 文件拼到一起同时做标签的 one-hot 编码最后压缩成一个 npz 文件这样train_lstm.py加载起来就很快。参数说明--epochs 100是看数据量决定的如果你每个类别只录了 30 个样本100 个 epoch 必过拟合这时候看训练集准确率可能 100%但验证集只有 60%。我一般会在 50 到 100 之间调同时加一个ModelCheckpoint回调保存最佳模型而不是最后一轮的模型。3.3 模型训练的输出与评估盯着三条曲线看训练跑起来之后不要傻等。我习惯把 Keras 的History存下来画出 loss 曲线、准确率曲线再决定要不要停。这个包默认是训练完直接输出测试集报告但我会额外加一段sklearn.metrics.classification_report它能给出每个类别的精确率、召回率、F1-score比单一准确率有用得多。from sklearn.metrics import classification_report import numpy as np y_pred np.argmax(model.predict(X_val), axis1) y_true np.argmax(y_val, axis1) print(classification_report(y_true, y_pred, target_names[squat, wave, walk]))逻辑说明np.argmax的作用是把 softmax 输出的概率分布转成类别索引因为 Keras 的categorical_crossentropy需要 one-hot 标签而评估指标要的是具体类别。classification_report会按类别输出 P/R/F1你能一眼看出哪两个动作经常被搞混。参数说明target_names要和action_labels.txt严格对应顺序不能乱否则报告上的类别名全是错的。我在跑完一遍后习惯把识别的类别数控制在 5 个以内超过 5 个混淆率会明显上升因为有些动作的骨骼序列高度相似。比如“挥手”和“招手”在关键点上就是手腕轨迹的差异LSTM 很容易糊。3.4 实时摄像头推理验证模型能不能用训练完的模型最终要接到摄像头上看效果。predict_cam.py里面是一个标准的实时推理循环逐帧提取关键点攒够seq_len帧后让模型预测然后在画面上叠加类别文字和置信度。这个脚本本身不大但有几个参数值得留意直接影响到体感。cap cv2.VideoCapture(0) buffer deque(maxlenseq_len) while True: ret, frame cap.read() keypoints extract_pose(frame) if keypoints is not None: buffer.append(keypoints) if len(buffer) seq_len: input_seq np.expand_dims(list(buffer), axis0) pred model.predict(input_seq, verbose0)[0] label_id np.argmax(pred) confidence pred[label_id] cv2.putText(frame, f{labels[label_id]} {confidence:.2f}, ...)逻辑说明buffer用deque(maxlenseq_len)滑动窗口保证输入始终是最新的 30 帧关键点。np.expand_dims把(30, 99)的序列扩成(1, 30, 99)因为模型训练时输入带 batch 维。verbose0关掉 predict 打屏否则实时推理时终端会被刷爆。参数说明置信度低于某个阈值时建议显示“unknown”避免误判。我做的时候阈值设为 0.6低于这个值不显示动作名。这里最大的坑是摄像头采集的帧率和手机视频的帧率不一样采集训练数据时用的 30fps摄像头推理时如果也是 30fps 就没问题但如果你训练数据来自 60fps 视频实际推理会感觉灵敏度不对这是时间步对齐的问题后面还会细说。4. 动作识别避坑手册我从翻车现场整理的五条血泪经验4.1 训练时 loss 为 NaN精度直接崩掉现象训练到第几十个 epoch 时 loss 变成nan准确率瞬间掉到接近 0之后再也恢复不过来。原因最常见的是学习率太大或者数据里面有 NaN 值。MediaPipe 在某些极端角度下会检测不到关键点返回的坐标是空值直接塞进 LSTM 训练就爆了。学习率用默认的 adam 0.001 一般没事但如果你手动加到了 0.01很容易跑飞。解决在dataset_builder.py里加上一步清洗把包含 NaN 的帧直接置零并用np.nan_to_num兜底。学习率改成 0.0005 再试一次。我验证过90% 的情况是数据里的脏值导致不是网络结构问题。4.2 模型精度 99%但摄像头实测一塌糊涂现象训练集准确率接近 100%验证集也有 95% 以上一上摄像头就乱跳动作识别完全对不上。原因典型的过拟合加重度视角依赖。训练数据如果是同一个人同一个背景录的模型学到的是背景纹理和人的体型而不是动作模式。我曾经在宿舍固定机位录的数据换到实验室摄像头下直接废掉。解决数据采集时至少换 3 个背景、2 个不同身高的人每类动作录 80 个样本以上。如果条件有限就用数据增强对视频帧做水平翻转、亮度扰动、缩放扰动。注意翻转之后关键点坐标也要相应做映射不然 label 和坐标对不上。4.3 序列长度不一致导致 build 数据集时报错现象dataset_builder.py跑到一半提示ValueError: setting an array element with a sequence。原因每个视频样本的帧数不一样最后拼出来的 npy 数组每个元素形状不一致。numpy 不允许在一个数组里塞不同长度的序列直接抛异常。解决在提取骨骼点时统一截断或填充到seq_len。我一般写一个pad_or_truncate函数超过 30 帧就取前 30 帧不足 30 帧就在末尾补零帧。补零帧的关键点全是 0LSTM 会理解成“关键点丢失”影响可接受。4.4 OOM 错误训练到中途内存爆炸现象model.fit跑了一会儿提示ResourceExhaustedError: OOMGPU 显存或系统内存占满。原因输入序列全部 load 进内存了加上model.predict的中间变量堆积。如果视频数量多、每段 30 帧、每帧 99 维数据量本身不算大但如果你的seq_len改成 60 或者把关键点扩展到 132 维内存用量会翻番。解决用tf.data.Dataset.from_tensor_slices构建输入管道配合.batch(16).prefetch(1)让数据边读边训练而不是一次性导入。另一个思路是使用model.fit(..., use_multiprocessingTrue)但如果是 Windows 系统多进程反而容易卡死建议直接调低batch_size到 8。4.5 模型保存后加载预测结果全错现象训练好之后model.save(action.h5)重新加载后预测准确率大幅下降甚至输出固定类别。原因大概率是你加载模型时自定义层或预处理函数没同步。这个工程的模型没有自定义层所以最常见的原因是 predict 时输入数组的维度顺序不对或者使用了model.predict(x)而x缺少 batch 维。我在加载后总会加一句model.summary()确认输入形状。另一个隐蔽坑是类别顺序在保存后没保存下次加载时不知道label_id0代表哪个动作预测结果和显示标签对不上。解决把action_labels.txt和模型放同一个目录并在推理脚本启动时读进来不要硬编码在代码里。5. 最后一步画出混淆矩阵验证模型短板再决定要不要换 Transformer模型跑通之后很多人就以为完工了。我自己的习惯是还会做一个“混淆矩阵 逐类 F1”的验证这是答辩时最好用的素材也是判断模型能不能上线的最低标准。先把train_lstm.py里保存模型的回调改一下让它同时保存验证集上的预测结果然后用 matplotlib 画出混淆矩阵的热力图。你会发现哪些动作是孪生动作——比如“蹲下”和“弯腰”在关键点序列上高度相似混淆矩阵里那个方块变量非常显眼这种动作就要考虑换输入特征或者加大数据量。再进一步如果 LSTM 已经在验证集上逼近 95% 但再往上很难可以考虑把 LSTM 换成 Transformer 编码器。我不建议直接推翻 LSTM而是做一个小的消融对比。以action.npz为输入把模型最后一层换成MultiHeadAttention加GlobalAveragePooling1D训练同样的 epoch看 F1 是否有提升。实际操作里序列长度只有 30 左右时Transformer 的收益有限因为 LSTM 足够建模这么短的时序了。如果你有 60 帧以上的长序列Transformer 的positional encoding会更占优势。我当时用 30 帧做了一个对比LSTM 的 F1 是 0.91Transformer 是 0.90没差别果断留用 LSTM。真要说有没有什么技巧让动作识别准确率再上一个台阶我会建议做一个“预测结果的时序平滑滤波”。LSTM 在逐帧滑动窗口上预测时偶尔会有一两帧误判在视频上表现成闪烁。我用一个简单多数投票维护最近 5 帧的预测类别取出现最多的那个作为最终输出。这个改动几乎零成本但能把肉眼可见的抖动消掉大半。从那以后我每次跑完实时推理都会强制走一遍这个平滑过滤再去评估准确率。虽然看着土但效果非常真实。希望这段记录能帮你在复现这个压缩包时少走几条弯路。本文还有配套的精品资源点击获取
返回列表