AI视频行为识别之SlowFast测试实践

安防智能行为识别

暴力伤医、校园霸凌、天灾人祸等事件频频发生,安防成为国家和人民重视的问题。利用目标检测、骨骼关键点检测、人体姿态估计、视频行为监控识别等行为识别技术,可以精准定位行人并测定数量,识别打斗、闯入、倒地、攀登、离开岗位、聚众、可疑停留等多个危险/不安全行为。

定义及理解

https://zhuanlan.zhihu.com/p/103566134行为识别分类及含义

行为识别Action Recognition是指对视频中人的行为动作进行识别,即读懂视频。根据要处理的动作类别和真正要处理的任务不同,在各种情况下所说的行为识别的任务略有差异,首先对两组概念进行对比和区分:
1.Hand gesture, Action, Activity
Hand gesture:集中于处理视频片段中单人的手势
Action:短时间的行为动作,场景往往是短视频片段的单人行为,比如Throw,catch,clap等
Activity:持续时间较长的行为,场景往往是较长视频中的单人或多人行为,例如Reading a book,making a phone call, eating, talking to each other, hugging,palying basketball等
这里提一句,Action和Activity的主要区别在于Action是指动作,Activity是指行为,可以认为Action的粒度更细,而Activity的粒度更粗,也可以说Action是Activity的子集。但其实在实际的算法中,有时候也没必要将二者完全区分开。
2.Classification,Detection
Classification:给定预先裁剪好的视频片段,预测其所属的行为类别
Detection:视频是未经过裁剪的,需要先进行人的检测where和行为定位(分析行为的始末时间)when,再进行行为的分类what。
我们这里所涉及到的行为识别Action Recignition可能是Hand gesture/Action/Activity和Classification/Detection任意组合情况,不做太绝对的区分。但是通常所说的行为识别更偏向于对时域预先分割好的序列进行行为动作的分类,即 Trimmed Video Action Classification。

开源数据集

开源数据集参考
按照数据集是否包含深度信息,可以将行为识别数据集分为RGB和RGBD两类,我们这里只讨论RGB数据集:
UCF-101
HMDB-51
Kinetics-700、Kinetics-600、Kinetics-400
AVA数据集

算法模型

基于深度学习的方法

视频行为分析深度学习算法分类及发展
按照是否先检测人体关键点(骨骼关键点),基于深度学习的方法可以简单地划分为“skeleton-based”和“video-based”两类。

(1)skeleton-based的代表性算法包含ST-NBNN,Deformable Pose Traversal Convolution,以及最近比较火热的图卷积方法(例如ST-GCN)。

video-based方法包含几种主流的方法:
(2)TwoStream
TwoStream将动作识别中的特征提取分为两个分支,一个是RGB分支提取空间特征,另一个是光流分支提取时间上的光流特征,最后结合两种特征进行动作识别,代表性方法如TwoStreamCNN及其扩展,TSN,TRN等。
(3)C3D
3D convolution 直接将2D卷积扩展到3D(添加了时间维度),直接提取包含时间和空间两方面的特征,这一类也是目前做的比较多的topic。代表方法如开山之作C3D及其之后的扩展P3D,R(2+1)D,ECO等,最近FAIR提出了SlowFast算法,CVPR2019上也有相关的论文(比如MARS) 。
(4)LSTM
这种方法通常使用CNN提取空间特征,使用RNN(如LSTM)提取时序特征,进行行为识别。代表方法如CVPR2015的LRCN,但我暂时没有找到特别有代表性的新论文。

对通用行为识别的算法进行了简单的分类和举例,每个类别仍有大量算法未罗列。总的来说多个分支都有最新研究出现,但是相对的基于骨架的图卷积方法和基于视频的3D conv方法更多一些。本次重点学习和实践基于3D conv的方法。

C-3D开源项目实战

1.视频分析模型(行为识别):C3D

https://blog.csdn.net/hehuaiyuyu/article/details/107052789
github:原代码:https://github.com/facebook/C3D
TensorFlow:https://github.com/hx173149/C3D-tensorflow

工作流程

数据集:Sports-1M
从每个训练视频中随机取出2秒长的5个片段,调整帧大小为128*171(大约为UCF-101一半分辨率)
随机裁剪成 16x112x112 的片段(shape:[ N, C, nframe, H, W ] -> [ N, 3, 16, 112, 112 ],16帧片段非重叠),形成抖动,以 50%的概率随机翻转
使用SGD优化器,batch size为30,初始学习率为0.003,每150K次迭代除以2,优化在1.9M迭代(约13epochs)停止

网络结构

在这里插入图片描述

基于不强的算力而设计的网络(C3D):8个卷积层、5个池化层、两个全连接层,以及一个softmax输出层
所有3D卷积核均为3×3×3(d x k x k ,d为时间深度),步长为1×1×1
为了在早期阶段保留更多的时间信息,设置pool1核大小为1×2×2、步长1×2×2(时间深度为1时,会单独在每帧上进行池化,大于1时,会在时间轴上,也就是多帧之间进行池化)
其余所有3D池化层均为2×2×2,步长为2×2×2
每个全连接层有4096个输出单元

3D卷积和池化

在这里插入图片描述

3D卷积和池化更适合学习时空特征,通过3D卷积和3D池化,可以对时间信息建模,而2D卷积只能在空间上学习特征。
2D卷积输入图像和视频时,输出的都是图像,而3D卷积输入视频后,输出的也是一个视频(3D特征图),保留了输入的时间信息。
C3D网络将完整的视频作为输入,不依赖于任何处理,可以轻松扩展到大数据集。

kernel 的时间深度

在这里插入图片描述

设计实验对比:
设置了4种固定尺寸的3D卷积核(左图),分别为1×3×3 、3×3×3、5x3x3、7x3x3,表明 3×3×3结果最优。
设置3种对比的网络结构,不同层的3D卷积核的时间深度分别为:
时间深度不变: 3−3−3−3−3
时间深度递增:3−3−5−5−7
时间深度递减:7−5−5−3−3
表明当卷积网络中所有的3D卷积核的时间深度一致,都为3×3×3时,效果最优。
综上:3x3x3 卷积核效果最优。

2.视频行为识别ActionRecognition:SlowFast

https://zhuanlan.zhihu.com/p/103577209
视频行为识别需要从视频中提取鲁邦的外观(空间语义)和运动特征来进行行为识别,所谓SlowFast是指采用Slow和Fast两种采样率的path(输入两个path的是视频采样后的帧)来并行处理视频,Slow path以较低的采样率来处理输入视频(2D卷积+3D卷积),提取随时间变化较慢的外观特征,为了提取鲁邦的外观特征,卷积核的空间通道数较大;Fast path以较高的采样率来处理输入视频(3D卷积),提取随时间变化较快的运动特征,为了降低该通道的复杂度,卷积核的空间通道数较小;然后通过横向连接对两个path的特征进行融合,进行行为识别。
作者文中提了一个“可能比较粗糙且为时尚早的类比”,在灵长类动物的视网膜神经细胞中,有80%的细胞以较低的速率工作,它们对视觉运动变化不敏感,但是可以提供良好的空间和颜色细节(这类比为Slow Path中的卷积核来提取外观特征,总参数量占两个通道总参数的80%左右);剩余20%的细胞以较高速率工作,能够敏感地捕捉运动变化(这类比为Fast Path的卷积核来提取运动特征,总参数占20%左右)。
在这里插入图片描述

SlowFast模型结构图如上图所示,其主要的工作流程大致如下所示:
step1:用快慢两种速率采样输入视频
step2:采样后的视频帧对应输入到Slow/Fast两个分路
step3:Slow分路使用ResNet 2D Conv + 3D Conv提取视频空间语义特征,size {T,S²,C}
step3:同时Fast分支使用ResNet 3D Conv提取视频时域运动特征,size{αT,S²,βC},其中α>1,β<1
step4:横向连接统一两个分路的特征
step5:Softmax进行分类
在这里插入图片描述

上图是一个SlowFast网络的实例。卷积核的尺寸记作{T×S², C} ,其中T、S和C分别表示时序temporal, 空间spatial和频道Channel的尺寸。跨度记作{temporal stride, spatial stride ^ 2}。速度比率(跳帧率) 为 α = 8 ,频道比率为1/β = 1/8。τ 设置为 16。绿色表示高一些的时序 分辨率,Fast通道中的橙色表示较少的频道。

与Two Stream、C3D的区别

(1)与Two Stream方法的区别
对行为识别有一定了解的小伙伴应该知道Two Stream方法采用RGB + Optical flow两个通路来分别提取视频的空间语义特征和运动特征进行行为识别,而本文的SlowFast也是两个通路提取两方面特征进行识别,二者的主要区别有如下几个部分:
a:SlowFast更强调两个分路不同的采样和处理速率,这也是SlowFast的核心思想
b:Two Stream两个分路的backbone是相同的,而SlowFast中的Fast分支更轻量级
c:双流是手工设计的特征,无法端到端学习,而SlowFast可以端到端学习两个分路的所有参数
(2)与C3D系列方法的区别
另一种广泛的行为识别方法是C3D及其改进,C3D采用3D卷积同时提取空域和时域特征,SlowFast中虽然也用到了3D卷积,但和C3D行为识别模型是有区别的:
a:C3D模型将2D卷积扩展到时空域,同时处理空域和时域的信息(默认时域和空域是平等的、对称的),而SlowFast采用和TwoStream类似的想法将空域和时域的处理拆分开,这更符合时域和空域特征的关系(二者不应该像一幅图的x,y那样对称处理)
b:SlowFast中用到了3D卷积,但又不太相同。Slow通路前几层使用2D卷积,后两层才用3D卷积(实验发现比全用3D卷积效果更好);Fast通路每一层都用的是3D卷积,但是各层维持时域维度大小不变,尽可能地保留时域信息(而C3D中是越深的层时域维度越小)。

测试使用的数据集

Kinetics-600 dataset介绍
https://github.com/facebookresearch/SlowFast/blob/master/slowfast/datasets/DATASET.md
https://blog.csdn.net/liuxiao214/article/details/80144375
activitynet比赛始于2016CVPR,是与ImageNet齐名的在视频理解方面最重要的比赛
在这个比赛下的Task A – Trimmed Action Recognition比赛是一个视频分类比赛,数据集就是kinetics-600数据集。数据集有Google的deepmind团队提供,2017年是第一届比赛,当时有400个类别,20多万数据,今年又对数据集进行了扩增,现在有600个类别,共50万左右的视频。
视频来源于YouTube,一共有600个类别,每个类别至少600个视频以上,每段视频持续10秒左右。类别主要分为三大类:人与物互动,比如演奏乐器;人人互动,比如握手、拥抱;运动等。即person、person-person、person-object。
每个视频大小70K300K不等平均150K来计算,50万左右大概就是70G

AVA数据集
https://blog.csdn.net/zchang81/article/details/78291527
https://zhuanlan.zhihu.com/p/157869607
教机器理解视频中的人类动作是计算机视觉领域中的一个基础研究问题,对个人视频搜索和发现、运动分析和手势交流等应用十分必要。尽管近几年图像分类和检索领域实现了很大突破,但是识别视频中的人类动作仍然是一个巨大挑战。原因在于动作本质上没有物体那么明确,这使得我们很难构建精确标注的动作视频数据集。尽管很多基准数据集,如 UCF101、ActivityNet 和 DeepMind Kinetics,采用了图像分类的标注机制,并为数据集中的每一个视频或视频片段分配一个标签,但是仍然不存在包含多人不同动作的复杂场景的数据集。
为了推进人类动作识别方面的研究,谷歌发布了新的数据集 AVA(atomic visual actions),提供扩展视频序列中每个人的多个动作标签。AVA 包括 YouTube 公开视频的 URL,使用包含 80 个原子动作(atomic action)集进行标注(如「走路」、「踢(某物)」、「握手」),所有动作都有时空定位,从而产生 57.6k 视频片段、96k 标注人类动作和 210k 动作标签。你可以点击 https://research.google.com/ava/ 查看 AVA 数据集并下载标注。论文地址:https://arxiv.org/abs/1705.08421。

测试及代码理解

https://github.com/facebookresearch/SlowFast
https://blog.csdn.net/j18423532754/article/details/108579716
https://blog.csdn.net/j18423532754/article/details/108704092

1、环境部署(打包成镜像后续可以使用)

使用pytorch镜像2011py3-nvidia
https://pytorch.org/get-started/locally/#windows-prerequisites

(pytorch_video) root@207ec743a7bb:/workspace# vim install.sh
#!/bin/bash
#conda create -n pytorch_video python=3.8
#conda activate pytorch_video

pip install torch==1.8.1+cu111 torchvision==0.9.1+cu111 torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html

pip install 'git+https://github.com/facebookresearch/fvcore'

pip install simplejson

conda install av -c conda-forge
#pip install av
#pip install iopath
conda install -c iopath iopath

pip install psutil

pip install opencv-python
apt update
apt-get -y install libsm-dev libxrender1  libxext6 build-essential libgl1-mesa-dev
pip install tensorboard
pip install pytorchvideo
pip install sklearn
pip install 'git+https://github.com/facebookresearch/fvcore.git'
pip install 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'
git clone https://github.com/facebookresearch/detectron2 detectron2_repo
pip install -e detectron2_repo
2、运行

启动容器
docker run -it --gpus all --shm-size=1g --ulimit memlock=-1 --ulimit stack=67108864 -v /mnt:/mnt slowfast/c3d:V3 /bin/bash
数据准备:
在/workspace/dataset文件夹下面,完成数据的制作。测试完成后可以使用csv_creat.py中的rm_data函数进行删除。

设置运行
conda activate pytorch_video
cd /work/space/SlowFast
export PYTHONPATH=./slowfast:$PYTHONPATH

python tools/run_net.py --cfg configs/Kinetics/C2D_8x8_R50.yaml DATA.PATH_TO_DATA_DIR /workspace/dataset/Kinetics_600_data/ NUM_GPUS 1

python tools/run_net.py --cfg configs/Kinetics/SLOWFAST_8x8_R50.yaml DATA.PATH_TO_DATA_DIR /workspace/dataset/ NUM_GPUS 1 TRAIN.BATCH_SIZE 16 MODEL.NUM_CLASSES 600

构建CSV文件,csv文件的分隔符与_C.DATA.PATH_LABEL_SEPARATOR = ","要一致。
csv文件的标签是整数,真正训练时需要有一个词典对应起来。
安装pyav时需要使用conda安装,否则在解析视频文件时会报错

计算速度v100
[06/17 10:18:25][INFO] train_net.py: 478: Epoch 0 takes 4428.52s. Epochs from 0 to 0 take 4428.52s in average and 4428.52s in median.
[06/17 10:18:25][INFO] train_net.py: 484: For epoch 0, each iteraction takes 1.22s in average. From epoch 0 to 0, each iteraction takes 1.22s in average.

[06/17 23:40:19][INFO] train_net.py: 478: Epoch 10 takes 4406.75s. Epochs from 0 to 10 take 4425.27s in average and 4424.49s in median.
[06/17 23:40:19][INFO] train_net.py: 484: For epoch 10, each iteraction takes 1.21s in average. From epoch 0 to 10, each iteraction takes 1.22s in average.
[06/17 23:40:19][INFO] precise_bn.py: 126: Computing precise BN statistics for 110 BN layers …

基于骨骼关键点的图卷积开源项目

下次再参考学习整理


前置任务:人体姿态估计

背景及定义
https://zhuanlan.zhihu.com/p/102457223

人体关键点检测(Human Keypoints Detection)又称为人体姿态估计,是计算机视觉中一个相对基础的任务,是人体动作识别、行为分析、人机交互等的前置任务。一般情况下可以将人体关键点检测细分为单人/多人关键点检测、2D/3D关键点检测,同时有算法在完成关键点检测之后还会进行关键点的跟踪,也被称为人体姿态跟踪。

目前COCO keypoint track是人体关键点检测的权威公开比赛之一,COCO数据集中把人体关键点表示为17个关节,分别是鼻子,左右眼,左右耳,左右肩,左右肘,左右腕,左右臀,左右膝,左右脚踝。而人体关键点检测的任务就是从输入的图片中检测到人体及对应的关键点位置。

算法及场景方法分类
目前的人体关键点检测算法按照是否包含3维深度信息可以分为2D关键点检测和3D关键点检测,2D关键点检测开始地更早,研究地也更成熟,但近年来3D关键点的检测开始受到大家的广泛关注(一方面是2D的研究达到一定程度,另一方面是3D更酷炫、用途也更广泛)。
不区分2D、3D的情况下,人体关键点检测可以分为单人关键点检测和多人关键点检测两类,其中多人关键点检测的研究更广泛(但不代表单人关键点检测就不好,只是任务不同罢了,且很多多人关键点检测算法中会用到单人的关键点检测算法),本文也默认讨论的是多人关键点检测。

在2D多人关键点检测(多人姿态估计)中,top-down方法先进行目标检测(人),再对每个检测到的人进行单人的关键点检测(单人姿态估计);bottm-up方法先检测所有人的关键点,然后再对关键点进行分组关联。一般来说,top-down方法精度更高,而bottom-up方法速度更快。

在3D关键点检测(3D姿态估计)中,我举出了两个示例算法,其中VideoPose3D利用视频的时序信息,离线地进行3D关键点检测(更准);而Towards 3D Human Pose Estimation in the Wild只使用单帧信息,在线地进行3D关键点检测(更快)。

  • 1
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SlowFast架构是一种在视频行为识别中广泛使用的架构,它结合了慢速和快速两种不同的卷积神经网络。以下是SlowFast架构的核心代码: ```python import torch import torch.nn as nn import torch.nn.functional as F class Bottleneck(nn.Module): def __init__(self, in_planes, planes, stride=1): super(Bottleneck, self).__init__() self.conv1 = nn.Conv3d(in_planes, planes, kernel_size=1, bias=False) self.bn1 = nn.BatchNorm3d(planes) self.conv2 = nn.Conv3d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) self.bn2 = nn.BatchNorm3d(planes) self.conv3 = nn.Conv3d(planes, planes*4, kernel_size=1, bias=False) self.bn3 = nn.BatchNorm3d(planes*4) self.shortcut = nn.Sequential() if stride != 1 or in_planes != planes*4: self.shortcut = nn.Sequential( nn.Conv3d(in_planes, planes*4, kernel_size=1, stride=stride, bias=False), nn.BatchNorm3d(planes*4) ) def forward(self, x): out = F.relu(self.bn1(self.conv1(x))) out = F.relu(self.bn2(self.conv2(out))) out = self.bn3(self.conv3(out)) out += self.shortcut(x) out = F.relu(out) return out class SlowFast(nn.Module): def __init__(self, block, num_blocks, num_classes=10): super(SlowFast, self).__init__() self.in_planes = 64 self.fast = nn.Sequential( nn.Conv3d(3, 8, kernel_size=(1, 5, 5), stride=(1, 2, 2), padding=(0, 2, 2), bias=False), nn.BatchNorm3d(8), nn.ReLU(inplace=True), nn.Conv3d(8, 16, kernel_size=(1, 3, 3), stride=(1, 2, 2), padding=(0, 1, 1), bias=False), nn.BatchNorm3d(16), nn.ReLU(inplace=True), nn.Conv3d(16, 32, kernel_size=(1, 3, 3), stride=(1, 2, 2), padding=(0, 1, 1), bias=False), nn.BatchNorm3d(32), nn.ReLU(inplace=True), nn.Conv3d(32, 64, kernel_size=(1, 3, 3), stride=(1, 2, 2), padding=(0, 1, 1), bias=False), nn.BatchNorm3d(64), nn.ReLU(inplace=True) ) self.slow = nn.Sequential( nn.Conv3d(3, 64, kernel_size=(1, 1, 1), stride=(1, 1, 1), padding=(0, 0, 0), bias=False), nn.BatchNorm3d(64), nn.ReLU(inplace=True), nn.Conv3d(64, 64, kernel_size=(1, 3, 3), stride=(1, 2, 2), padding=(0, 1, 1), bias=False), nn.BatchNorm3d(64), nn.ReLU(inplace=True), nn.Conv3d(64, 64, kernel_size=(1, 3, 3), stride=(1, 2, 2), padding=(0, 1, 1), bias=False), nn.BatchNorm3d(64), nn.ReLU(inplace=True), nn.Conv3d(64, 128, kernel_size=(1, 3, 3), stride=(1, 2, 2), padding=(0, 1, 1), bias=False), nn.BatchNorm3d(128), nn.ReLU(inplace=True) ) self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) self.avgpool = nn.AdaptiveAvgPool3d((1, 1, 1)) self.fc = nn.Linear(512 * block.expansion, num_classes) def _make_layer(self, block, planes, num_blocks, stride): strides = [stride] + [1]*(num_blocks-1) layers = [] for stride in strides: layers.append(block(self.in_planes, planes, stride)) self.in_planes = planes * block.expansion return nn.Sequential(*layers) def forward(self, x): fast = self.fast(x[:, :, ::2]) slow = self.slow(x[:, :, ::16]) x = torch.cat([slow, fast], dim=2) x = self.layer1(x) x = self.layer2(x) x = self.layer3(x) x = self.layer4(x) x = self.avgpool(x) x = x.view(x.size(0), -1) x = self.fc(x) return x ``` 该代码定义了SlowFast架构中的Bottleneck块和SlowFast类,用于构建整个网络。其中,Bottleneck块是SlowFast中的基本块,用于构建各个层;SlowFast类则是整个网络的主体部分,定义了各个层的结构和前向传播的过程。在构建网络时,可以根据需要调整Bottleneck块和SlowFast类的超参数,以满足不同的视频行为识别任务需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值