目录
参考资料
论文:
Quo Vadis, Action Recognition? A New Model and the Kinetics Dataset
博客:
I3D(A New Model and the Kinetics Dataset)大体论文翻译及思考
第1章 引言
作者写这篇论文主要是因为以下两个问题:
(1)视频数据集的数量较少,无法有效评估模型性能:现有的视频数据集如 UCF-101
和 HMDB-51
的视频数量都比较少,很多模型因此都获得了比较接近的效果,没法有效的对模型性能进行评价(我们在mnist数据集上,可能自己随便搭个三五层网络,准确率可能都是0.99+,没有办法有效的评价不同模型的好坏)。
(2)经过 Imagenet
预训练的一些2D网络模型如何迁移到视频领域:Imagenet图像分类中出现了很多优秀的网络结构,并且这些模型和他们在Imagenet上的预训练权重能够很好的扩展应用到其他领域,如目标检测,分割等等。但是这些任务能够通过预训练+微调的方式获得一定的提升,是不是因为他们都是在Spatial领域呢?对于视频行为识别来说,多了一个Temporal领域,预训练模型能不能仍然work呢?
基于上面这两个问题,作者主要通过以下的方式解决:
(1)作者提出了一个新的大型视频行为识别数据集 Kinetics。这个数据集比UCF-101和HMDB-51大了两个数量级。包括400个人类动作的类别,每个类别都有超过400个clips。数据集是从Youtube中搜集的真实场景下的视频。
(2)作者提出了一种方法 Inflating
+Bootstrapping
,能够把2D卷积的权重,扩展到3D卷积上,就可以将那些在 ImageNet
上预训练好的2D模型直接迁移到3D的任务中。并基于此提出了一种Two-Stream Inflated 3D ConvNets (I3D) 模型。
(3)通过提出了视频领域的大型数据集 Kinetics,使得很多3D的模型可以现在这个大型数据集上进行预训练,并迁移到其他任务上进行微调,使得模型更容易训练了,并且性能更好。
第2章 相关的方法
2.1 ConvNet+LSTM
该方案主要考虑到 CNN
在图像分类领域的成功以及 LSTM
对于序列建模的能力,很自然提出将两者结合起来的方案。
CNN
需要对每一帧都提取特征,然后将视频的所有帧特征进行总汇,以此来表达对视频的表示,显然这样做忽略的时间结构特征。
LSTM
可以处理长时间依赖的问题,可以对视频从第一帧开始建模直到最后一帧,使用 CNN
网络对每帧提取特征,然后将特征送入LSTM来捕捉时间特征,最后一帧的输出用来对视频特征表示。
LSTM
往往依赖 CNN
的最后一层特征最为输入,因此不能够捕捉到low-level motion
的特征,而且对于遍历整个视频也很难去训练。
2.2 3D-ConvNets
3D ConvNets
是对视频建模最自然的方式,和标准CNN区别在于由2d conv
变为3d conv
,来捕捉spatio-temporal feature
。它的特点是直接把整个视频作为输入,进行端到端的学习。
但目前遇到一些问题:
(1)3D ConvNets
的3d conv
多了一个维度,参数量有较大增加,这将会很难去训练。
(2)没有利用那些 Imagenet
上成功的预训练模型来迁移学习,往往使用层数少的CNN在小数据集上从头训练。简要说就是要利用已有预训练模型,要减少参数或增大数据集。
2.3 Two-Stream Networks
该方案利用短的视频段来建模,用每个 clip
的预测分数平均的方式(其实C3D也是类似),但不同的是输入,包括一张RGB和10张optical flow
(其实是5张,x/y两个方向,运动特征)。
模型能使用two-branch
方式,利用预训练的imagenet模型,最后将预测结果平均下(最原始的,或者在最后softmax做融合),这样建模的模型比较好训练,同时也能获得更高的分数。
模型的两个输入流也可以在后面的 CNN
层来进行融合,这种方式叫做 Early Fusion
,同时可以end-to-end
训练。early fusion 和 later fusion的区别
第3章 I3D网络结构
该方案是论文提出的,出发点是要利用 Imagenet
的预训练模型,把 2D Conv
变成 3D Conv
,同时利用3D Conv
来提取RGB stream
的temporal feature
,最后再利用optical-flow stream
提升网络性能,也就大融合的方案(把有效的技巧都用上)。
3.1 Inflating(膨胀)
通过对预训练的2D conv
增加temporal维度,把
N
×
N
N×N
N×N 的filter变为
N
×
N
×
N
N×N×N
N×N×N 。简单的办法就是对
N
×
N
N×N
N×N 的filter重复复制
N
N
N 遍,并归一化,这样多的出发点是短期内时间不变性的假设,姑且把这当成3D filter
初始化的一种策略吧。
3.2 Bootstrapping(引导)
对于预训练权重,首先把2D卷积核在时间维度上复制 N N N 份,然后除以时间维度的维度 N N N ,这样做是为了扩展到3D卷积之后,每一层都仍然获取到类似大小的输出相应。如果不除以 N N N ,就会出现输出相应会增大 N N N 倍,改变了预训练时网络所学习到的数据分布。
从源码上分析可以看到如下操作:
from mxnet import nd
inflated_2d = nd.broadcast_to(temporal_2d, shape=[0, 0, temporal_dim, 0, 0]) / temporal_dim
nd
是mxnet
导入的一个类(from mxnet import nd),存储和变换数据的主要工具,跟Numpy的用法非常类似,里面的+,-,*,/,exp,sum,sqrt,dot等运算和np语法一样。
(1)nd.broadcast_to
就是对数组进行广播(复制)操作,用法参考:mxnet.ndarray.broadcast_to
>>> x = mx.nd.arange(0,3).reshape((1,3,1))
>>> x.asnumpy()
array([[[ 0.],
[ 1.],
[ 2.]]], dtype=float32)
>>> y = x.broadcast_to((2,3,3))
>>> y.asnumpy()
array([[[ 0., 0., 0.],
[ 1., 1., 1.],
[ 2., 2., 2.]],
[[ 0., 0., 0.],
[ 1., 1., 1.],
[ 2., 2., 2.]]], dtype=float32)
(2)调用numpy的ndarray数组进行 /
操作可以发现,对矩阵矩形运算会自带 广播机制
,也就是对矩阵中的每个元素进行相同的操作。
import numpy as np
a = np.array([1,2,3])/3
array([0.33333333, 0.66666667, 1. ])
上面过程可以理解为:
原来2D的网络输出的结果为 w × x w\times x w×x,现在复制了N份之后得到的3D网络,输出结果应该是 N × w × x N\times w\times x N×w×x ,你把这个输出传到下一层的时候就会出问题,和2D那边初始化好的参数对不上,2D那边每层都是 w × x w\times x w×x。
所以上面对2D卷积核的参数在时间维度上进行复制,然后用广播机制进行 /
,使得3D网络最后得到的输出和2D网络的输出一致,都是输出的
w
×
x
w\times x
w×x 。
3.3 Receptive Field(感受野)
我们已经把2D卷积核扩展成为了3D卷积核。但是2D池化窗口 k × k k×k k×k ,2D池化步长 s p × s p s_p×s_p sp×sp ,2D卷积核的步长 s c × s c s_c×s_c sc×sc 应该怎么扩展到3D?一个自然的想法是向卷积核一样,把2D k × k k×k k×k 的池化窗口直接变成 k × k × k k×k×k k×k×k ,同理步长也都直接对称的扩展。
但是考虑输入图像的高宽,以及时间维度的尺度差异,如果简单的在时间维度也使用相同的池化窗口,则会导致时间维度过快的变化,可能在浅层网络中把不同时间中的边缘特征进行过早的混合,影响空间特征的提取;
而如果时间维度的窗口或步长太小,则可能导致不能有效的提取空间动态信息。
根据当年大部分论文的操作,一开始不会对时间维度进行改变,在时间维度上不会过早进行下采样。
本文作者在 Inception-V1
中的设置为:
- 前两个池化窗口为 3 × 3 3×3 3×3 ,步长 2 × 2 2×2 2×2 的max pool扩展为池化窗口为 1 × 3 × 3 1×3×3 1×3×3 ,步长为 1 × 2 × 2 1×2×2 1×2×2 。即不过早的增大时间维度感受野,浅层网络中更加倾向于提取空间特征。
- 中间两个池化窗口为 3 × 3 3×3 3×3 ,步长 2 × 2 2×2 2×2 的max pool扩展为池化窗口为 3 × 3 × 3 3×3×3 3×3×3 ,步长为 2 × 2 × 2 2×2×2 2×2×2 。
- 最后一个avg pool的池化窗口扩展为 2 × 7 × 7 2×7×7 2×7×7 。
- Inception Module中的池化都扩展为和高、宽维度相同的窗口大小、步长。
第4章 训练和实验
4.1 训练细节
- 双流的两个分支在训练时分别训练,在测试时取平均。
- 对于所有的卷积层,都由一个BN和ReLU。
- SGD + momentum=0.9
- 把视频最短边resize到256,然后random crop 224×224 ,随机水平翻转。
- 如果视频较短,循环视频直到满足输入。
- 使用TV-L1算法计算光流。
4.2 实验结果
数据集不同,评测结果也不同。flow在UCF-101上效果比HMDB-51、kinetics上好(有更多camera运动的原因)。
在imagenet上训练后迁移到kinetics和直接在kinetics上的对比,迁移后的效果好,说明RGB流起的作用大。整体上I3D模型参数更少,更深,训练输入在时间和空间维度上都比C3D大。
第5章 Pytorch实现I3D
参考代码: