基于pytorchVideo的行人实时动作识别实战:SlowFast模型集成与优化

发布时间:2026/9/7 2:58:11
基于pytorchVideo的行人实时动作识别实战:SlowFast模型集成与优化 简介面向视频理解与深度学习开发者这份资源围绕行人实时动作识别完整整合PyTorchVideo视频处理、YOLOv5行人检测、SlowFast动作特征提取及DeepSort多目标跟踪链路可直接用于智能监控、行人安全预警等真实场景的算法验证与二次开发。压缩包共47个文件以22个Python脚本为核心辅以模型权重.pt/.t7、标签配置.txt/.pbtxt/.yaml、示例视频与演示动图整体约184MB目录按yolo_slowfast.py、slowfast_detection.py、deep_sort等模块划分便于对照源码理解识别流程。已有407人学习浏览适合具备一定深度学习基础、希望快速搭建视频动作识别系统的研究者和工程师。通过自带权重与示例数据可省去繁琐的环境配置直观看到YOLOv5框选行人、SlowFast判断动作、DeepSort保持轨迹的完整效果还可在现有代码上替换数据集或调参是一份理论结合实战的优质参考资料。 做行人实时动作识别这个方向折腾了将近两个月从最开始只会在单张图片上做目标检测到最终把基于pytorchVideo的动作识别模型真正跑进实时视频流里中间踩了不少坑也积累了一些能直接用的经验。这个项目用到的核心工具是Facebook开源的pytorchVideo库它把SlowFast、I3D、X3D这些主流视频理解模型都封装好了配合预训练权重不需要从零去复现论文里的网络结构。如果你正打算做人体连续动作的识别或者想把动作识别从离线视频分析推进到在线实时场景这篇文章应该能帮你少走弯路。我会把整体设计思路、环境搭建、核心代码实现、以及我在真机调试时遇到的问题和解决方案都整理出来。1. 项目整体设计与思路拆解1.1 为什么选pytorchVideo而不是其他框架动手之前我对比过几个主流方案。OpenMMLab系的mmaction2功能很全文档也丰富但依赖链比较长装上之后光版本对齐就要折腾一阵。还有一个选择是直接用SlowFast的官方源码但那个仓库更像论文附带的实验代码要拿来接自己的业务逻辑需要改的地方不少。pytorchVideo恰好站在中间位置它是PyTorch生态内的官方视频理解库API设计风格和torchvision高度一致开箱即用而且背后的维护团队就是SlowFast、X3D这些经典模型的作者代码质量和论文复现度都有保障。另一个让我倾向pytorchVideo的点是它的torch.hub集成。加载一个训练好的动作识别模型只需要一行torch.hub.load模型结构和权重都在官方仓库里管理不用自己去翻下载链接、写加载逻辑。对于要快速验证方案的人来说这个便利性非常关键。而且它对视频解码、采样、数据增强这些标准化操作都做了统一封装我们可以把精力放在业务逻辑和性能优化上而不是跟底层视频处理的细节死磕。1.2 实时动作识别的核心难点动作是一个时间概念刚开始做这个项目时我犯过一个典型的认知错误以为动作识别就是把一张行人图片丢进分类网络输出一个动作标签。实际上动作天然带有时间维度——“举手”是一个动作“跑步”是一个动作但它们在单帧图像里只是一组静态姿势甚至两帧图片长得差不多、动作含义却完全不同。比如“起跳”和“落地”在单帧里都可能是屈膝的姿态只有看连续几帧的运动趋势才能区分开。所以pytorchVideo里的模型几乎都是3D卷积网络或者带时序建模能力的结构。以我用的SlowFast为例它把输入的视频片段拆成两条通路慢路径用低帧率提取空间语义信息快路径用高帧率捕捉运动变化最后再把两条通路的特征融合。这种设计本质上就是在回答“这个人在这段时间里做了什么动作”而不是“这张图里的人在摆什么姿势”。理解了这个区别我们在设计数据流的时候就会主动考虑短时窗口的帧缓冲也就是所谓的“clip”视频片段概念而不是简单地把每一帧独立送进模型。1.3 整体技术架构与处理流程确定了技术选型之后我把整个系统设计成两条串联的处理链路中间用消息队列解耦。链路的前半段是行人检测摄像头采集到的每一帧先经过一个轻量级检测器把画面里的行人用边界框标出来。后半段是动作识别对每个行人框维护一个固定长度的帧缓冲队列攒够一个clip后交给SlowFast模型推理输出动作类别和置信度。用检测识别两级串联而不是把整个画面直接丢给动作识别模型原因有两个。第一是计算量直接对整帧做3D卷积背景区域会白白占用大量算力先检测出区域再只对行人区域做识别计算成本大幅下降。第二是语义清晰度裁剪出来的行人区域去掉了背景干扰模型能更专注于人的姿态和运动识别准确率明显更高。这个思路在实际工程里被广泛采用也是目前行人动作识别的主流做法。整体流程可以看作一条流水线视频解码 → 目标检测 → 区域裁剪 → 序列缓冲 → 动作分类 → 结果平滑。2. 环境准备与依赖安装2.1 基础环境与版本对齐先把环境说明白因为pytorchVideo对PyTorch版本有要求不然后续会踩不少坑。我用的组合是Python 3.9、PyTorch 1.13.1、CUDA 11.7pytorchVideo推荐的版本区间是PyTorch 1.8以上但实测下来1.13最稳。如果你用的是PyTorch 2.x也可以但要注意torchvision和torchaudio的版本需要跟torch匹配否则导入pytorchVideo时可能会报符号找不到之类的错误。conda create -n action_recognition python3.9 conda activate action_recognition pip install torch1.13.1 torchvision0.14.1 torchaudio0.13.1 --extra-index-url https://download.pytorch.org/whl/cu117 pip install pytorchvideo pip install opencv-python # 视频解码用 pip install ultralytics # 行人检测用YOLOv8这里有一个细节值得注意pytorchVideo在底层依赖PyAV来做视频解码但如果你通过pip install pytorchvideo安装PyAV不一定会被自动装好。我第一次运行时就碰到了ModuleNotFoundError: No module named av所以建议单独确认一下pip install av2.2 用官方示例验证安装是否成功环境装好之后不要急着跑自己的代码先用pytorchVideo官方hub提供的预训练模型跑一次推理确认整条链路是通的。我建议用官方文档里的这个简单示例做验证import torch from pytorchvideo.data.encoded_video import EncodedVideo from pytorchvideo.transforms import ( ApplyTransformToKey, ShortSideScale, UniformTemporalSubsample ) from torchvision.transforms import Compose, Lambda, Normalize # 加载预训练模型这里用SlowFast的R50版本 model torch.hub.load(facebookresearch/pytorchvideo, slowfast_r50, pretrainedTrue) model.eval()如果模型能正常加载说明torch系列库和pytorchVideo之间的兼容性没问题。接着准备一个短视频文件按照Kinetics-400的预处理标准走一遍均匀抽帧、缩放短边到256、中心裁剪成256x256、做均值和标准差归一化。这里需要提醒的是Kinetics数据集用的均值标准差是[0.45, 0.45, 0.45]和[0.225, 0.225, 0.225]不是ImageNet那组很多人忽略这一点导致识别效果奇差。正确写法是mean [0.45, 0.45, 0.45] std [0.225, 0.225, 0.225] transform Compose([ ApplyTransformToKey( keyvideo, transformCompose([ UniformTemporalSubsample(32), # SlowFast慢路径抽32帧 ShortSideScale(256), Normalize(mean, std) ]) ) ])2.3 预训练权重与自定义数据集的准备思路官方hub加载的权重是在Kinetics-400上预训练的能识别400类动作比如跑步、跳舞、握手、鼓掌这些常见类别。但实际项目场景往往不是这400类比如你可能只关心“跌倒检测”或者“打架检测”这时有两个做法。第一个做法是直接利用Kinetics里的类别做映射比如“跌倒”在Kinetics里有falling这个类别这在小规模demo里够用但准确率和泛化性都比较有限。第二个做法是比较推荐的——在自己业务数据上做微调。具体操作是加载slowfast_r50的预训练权重把最后的全连接层改成自己的类别数然后在标注好的自采数据上训练。自采数据不需要太多但要注意每个动作至少要有几百段视频片段每段时长保持在2到5秒并且尽量覆盖不同拍摄角度、不同人的体型和穿着。我有一版模型就是只用了大约2000段自采视频微调的效果比直接套Kinetics权重好很多。3. 核心实现细节与实时管道搭建3.1 行人检测模块从YOLO到候选框处理实时检测这块我选的是YOLOv5s准确率和速度比较平衡。如果你的算力比较紧张可以换成YOLOv5n或者YOLOv8n检测速度能到毫秒级但对小目标的召回率会有所下降。核心代码很简单import torch detector torch.hub.load(ultralytics/yolov5, yolov5s, pretrainedTrue) detector.conf 0.5 detector.classes [0] # 只保留person类别 def detect_persons(frame): results detector(frame) boxes results.xyxy[0].cpu().numpy() persons [box for box in boxes if box[5] 0] # class_id 0是person return persons实际操作中有几个细节会影响后续识别效果检测框的抖动问题最让人头疼。因为每一帧独立做检测人稍微动一下或者遮挡变化检测框就会轻微抖动但动作识别模型对这些边界变化非常敏感框的抖动会折算成额外的“运动噪声”。为了解决这个问题我会对检测框做一次轻量级的平滑比如用简单的指数移动平均EMAsmoothed_box alpha * current_box (1 - alpha) * previous_smoothed_boxalpha设成0.4左右能明显减少抖动也不会让框显得太迟钝。但有一个前提——不同的人需要分别维护自己的平滑状态所以需要给每个行人分配一个跟踪ID。最简单的做法是用检测框的IoU关联前后帧的目标如果检测框与上一帧某个ID的IoU大于0.3就认为是同一个人。3.2 动作识别模型加载SlowFast的参数与预处理动作识别模型的加载和预处理是整个项目里最核心的部分。pytorchVideo对SlowFast的封装已经很完善我直接使用官方hub的接口model torch.hub.load(facebookresearch/pytorchvideo, slowfast_r50, pretrainedTrue) model model.eval()这里要重点解释SlowFast的一个特性它的输入不是单纯的图像张量而是一个包含两条通路的列表[slow_pathway, fast_pathway]。慢路径从原始clip中均匀抽取32帧快路径则按更高的帧率抽取数量是慢路径的alpha倍SlowFast里的alpha默认是8也就是说如果慢路径是32帧快路径是256帧。为了构造这两个通路pytorchVideo提供了SlowFastPathway相关的transforms但我在实际项目中偷了个懒直接用官方封装好的MultiCrop和pack_pathway_output这个函数会从输入clip中自动生成两条通路的张量。在慢路径和快路径之外还有一个参数需要注意就是clip的长度。前面我们提到动作识别需要看连续多帧但多少帧合适Kinetics预训练模型默认是32帧的clip大约对应2到3秒的视频片段。如果clip太短模型无法捕捉完整的动作周期如果太长一方面算力消耗大另一方面动作的起止阶段会引入噪音。我试过16帧、32帧、64帧三组32帧是准确率和速度的最佳平衡点。实时管道里我会用30FPS的帧率维持一个约1秒的环形缓冲区每秒做一次推理。3.3 实时视频流处理环形缓冲区与跳帧策略实时视频流的处理跟离线推断有本质区别。离线视频可以一次性读入所有帧但摄像头是源源不断产生新帧的我们需要设计一个既能保证实时性、又不会丢关键信息的缓冲机制。我最后采用的是“环形缓冲区跳帧推理”的组合。每一帧检测出行人后把裁剪好的行人区域缩放到模型需要的尺寸例如256x256放入该行人ID对应的事件的环形缓冲区。缓冲区容量固定为32帧新帧挤进来时最旧的一帧被覆盖。这样当缓冲区满后每一次读取缓冲区内容拿到的其实就是最近1秒的动作片段。但这里有个问题如果每一帧都做一次动作识别计算量会是检测模块的几十倍对GPU压力非常大。所以我会设置一个跳帧参数inference_interval比如每隔4帧才跑一次动作识别大约7到8FPS的推理频率中间跳过的帧只更新缓冲区不做推理。测试下来这种策略在保持识别准确率的前提下把GPU占用率降到了原来的四分之一左右。frame_idx 0 buffer RingBuffer(capacity32) while cap.isOpened(): ret, frame cap.read() if not ret: break if frame_idx % 2 0: # 每两帧做一次检测减少CPU压力 persons detect_persons(frame) for person in persons: pid track_id(person) buffer[pid].push(crop_person(frame, person)) if frame_idx % inference_interval 0 and buffer[pid].is_full(): clip buffer[pid].get() action infer_action(clip) draw_overlay(frame, person, action) frame_idx 13.4 推理加速与性能压测FP16与TensorRT实时系统的性能压测是绕不开的一关。我最初在单张RTX 3060上跑全套流程检测加识别一起算只能到8到10FPS离“实时”差距不小。后来做了三个优化把FPS拉到了接近20。第一是启用FP16半精度推理。PyTorch的autocast机制用起来很简单只需在推理代码外包裹一层上下文管理器with torch.no_grad(), torch.cuda.amp.autocast(): preds model(clip)FP16带来的加速在Ampere架构的显卡上非常明显SlowFast的推理时间直接从约60毫秒降到约35毫秒。注意如果模型里有一些自定义算子不支持FP16可能会报类型错误但官方hub里的R50模型没有这个问题。第二是减少重复张量拷贝。我之前写代码时图省事每次都把裁剪后的行人区域先存成numpy再转成tensor这个转换过程在每帧每个行人上都要执行累计开销很大。后来改成直接用torchvision.transforms.functional.crop在tensor上操作省掉中间的数据搬运。第三是TensorRT加速方案本身很有效但集成工作量稍大。我的做法是先把SlowFast导出为ONNX再用TensorRT自带工具转成engine文件。这些工程化细节比较多这里不展开如果你暂时不需要极致性能FP16已经能覆盖大多数场景。压测数据我整理在表里优化阶段检测耗时识别耗时整体FPS纯PyTorch FP328ms62ms9FP16半精度8ms35ms16FP16跳帧48ms35ms19TensorRT跳帧46ms22ms244. 常见问题与排查技巧实录4.1 典型报错与解决方案实操过程中肯定会遇到各种报错我把项目里遇到的高频问题整理成一个速查表方便你对号入座。问题现象可能原因解决方案ModuleNotFoundError: No module named avPyAV未安装pip install av模型加载时报torch.hub找不到权重网络问题或hub缓存损坏清空~/.cache/torch/hub后重试输入clip维度报错slow/fast通路shape不匹配用pack_pathway_output统一封装识别结果乱跳、类别不稳定检测框抖动或clip帧序错乱加入检测框EMA平滑检查缓冲区的帧顺序GPU显存不足clip太长或batch太大缩短clip到16帧启用FP16CPU占用率异常高视频解码默认用CPU用PyAV解码并尝试硬解最坑的一次是模型加载完成后推理结果总是混乱的最后发现是因为我在UniformTemporalSubsample之前先做了ShortSideScale导致抽帧的索引对应的空间尺度全乱了。pytorchVideo的预处理顺序是有讲究的先抽帧再缩放是官方推荐做法改回来就好了。4.2 识别结果抖动与误检的优化心得识别结果抖动这个问题的根因往往不在模型而在输入。我前面提过检测框的EMA平滑但这只是第一层。第二层是要对模型的输出类别做时间域的平滑常见方案是幂等投票或者指数滑动平均。我最后采用的是“窗口投票”维护最近10次推理结果取出现频率最高的类别作为最终输出如果最高频率低于60%就输出“未知”。这个小改动把识别稳定性提升了一个档次误检率降低了大约一半。另外对于人体连续动作的识别我建议在业务层面再设计一层状态转移逻辑。比如“跌倒”这个动作模型输出的可能是“跌倒”和“躺下”两种类别交替出现但如果我们加入上一帧的状态——只有从“站立”或者“行走”转入“跌倒”才触发告警就不会因为某帧误读成“躺下”而频繁误报。这种基于业务语义的规则过滤往往是量产系统和demo之间的分水岭。4.3 实时延迟超标时的排查路线如果你的摄像头画面端到端延迟很大从动作发生到界面显示结果超过2秒先不要急着怀疑模型推理慢按照这条路线排查先看采集端是否有丢帧再看缓冲队列大小是否设置得过大然后是检测模块是否因为单线程处理导致帧积压接着检查动作识别推理频率是否过高最后才是GPU性能瓶颈。我在初期遇到过一个问题缓冲队列满后才开始推理导致画面延迟接近3秒后来改成“缓冲区满后取最旧的32帧”而不是“等待最新帧填满”延迟立刻降下来了。说到底实时动作识别系统是一个典型的“延迟-准确率”权衡问题每一毫秒的延迟都可能是从某个缓冲策略里省出来的。不要指望一个调整就能同时在两个指标上都最优想清楚你的场景更在乎哪个维度。做实时动作识别越到后面越会明白模型本身只是整个系统的一小部分。pytorchVideo把视频理解模型的门槛降了下来真正拉开差距的是数据质量、前后处理逻辑和工程优化。我个人最深的体会是先花时间把数据采集和标注做好把检测与识别的边界理顺再考虑是不是要上TensorRT否则模型再强也扛不住数据乱。最后再分享一个实用的小技巧调试阶段一定要在界面上把当前clip的关键帧、检测框和模型类别置信度一起可视化出来亲眼看到模型为什么误判往往比闷头调参效率高得多。这个经验值得每个做动作识别的人反复体会。本文还有配套的精品资源点击获取