欢迎光临散文网 会员登陆 & 注册

I3D 论文精读【论文精读】

2022-04-03 12:30 作者:如果我是泡橘子  | 我要投稿

Que Vadis,Action Recognition?A New Model and the Kinetics Dataset


  • inflated:扩大、膨胀
  • Quo Vadis:1951 年的电影《where is this going?》,作者想要表达的意思是如果只通过一张图片来看的话,很难对动作进行区分,以及动作的后续发展(无法同过一张单一的视频帧进行判断,只有通过观看视频理解上下文含义才能得知


贡献


1、提出了 inflated 3D netword(I3D)模型,将一个 2D 模型扩张到一个 3D 模型,该方法的好处是不用再设计一个专门的视频理解网络,可以使用 2D 中已经设计好的网络(如 VGG、ResNet 等),将它们直接扩张到 3D 就可以了,甚至还可以用一些巧妙的方式将它们的预训练模型也利用起来,这样不仅涉及上比较简单,而且还能省掉很多预训练的麻烦

2、提出了 Kinetics 数据集,这个数据集刚开始提出的时候只有 400 类,所以叫做 Kinetics 400,紧接着又提出了具有 600 、700 类的 Kinetics 600、Kinetics 700,视频的数量也从最开始的 30 万涨到了 50 多万,最后涨到了 60 多万

  • 2014 年的 sport - 1 Million 数据集有一百万个视频,但是全部都是关于运动的类,应用场景比较局限(如果只在运动视频上做预训练,很难拓展到其他领域)
  • 2016 年 Google 推出了 youtube 8Million 数据集有 800 个视频,但是数据集实在太大,一般在比赛的时候都是直接分享已经抽取好的特征,而不是直接下载原始视频
  • Kinetics 数据集的类别比较均衡,难度适中,而且也不算特别大,因此使用门槛不高,一经提出就得到了广泛的使用(现在已经成为了衡量视频分类效果的必要的数据集)
  • 视频领域缺少一个大的数据集,导致不能很好地去研究视频理解的框架,本文中作者证实视频模型最好是在视频上进行预训练,因此本文提出了一个又大又好的视频数据集,在这个数据集之上训练了一个新的模型 -- I3D模型,它在现有的视频数据集上都取得了巨大的效果提升(比如在 Kinetics 数据集上预训练之后,再在 UCF-101 数据集上做微调,能够将最后的结果刷到 98,直接宣告了 UCF-101 数据集的终结以及 Kinetics 数据集的崛起,算是开启了一个新时代)
  • 现在大家发现 Kinetics 数据集还是非常大,如果从视频里选择最中间的那一帧,然后对这一帧做图像动作分类,它的准确度就已经很高了,完全不要太多的上下文信息,也完全不需要模型具备太强的时序建模能力,所以和这篇论文所想要达到的目标还是有一定的距离(但是想要做到这样确实比较困难,直到现在,也无法想到一个很好的方式去构建一个很好的视频数据集,从而能够让所学到的模型真的能够关注到时序上的信息,真的能够处理长时间的复杂的视频和拓展到生活中方方面面的领域里去,所以视频理解的道路还是非常漫长)





总览


  • 这篇论文没有相关工作(related work)这部分,因为这些工作与文中所要讲的内容非常相关,读者必须对这些相关工作有一定的了解才,能够欣赏到本文的必要之处,所以作者将之前的相关工作和自己的方法都融合到了一个大的章节中了
  • 视频中所选择的是最新的 Arxiv 版本( 2018 年 2 月份最后一次更新)



1、摘要


如今缺少一个大型的、有用的视频数据集,从而很难训练一个有效而且能够扩展的视频理解模型,所以本文中提出了 Kinetics 数据集,还提出了一个新的模型 I3D



2、方法


作者首先叙述了三种过去非常流行的视频理解方法

  • 第一种:卷积神经网络 + LSTM,卷积神经网络用来抽取特征,LSTM 用来抽取时序信息
  • 第二种:直接训练一个 3D 卷积神经网络
  • 第三种:双流网络

然后提出了自己的方法:I3D 网络



3、结果



4、模型学到的特征的一些可视化





摘要


因为目前的数据集都太小了,比如 UCF-101 (101 类,13000 个视频)和 HMDB-51 (51 类,7000 多个视频)

  • 在这么小的数据集上,往往很难发挥深度学习的作用,所以在 cvpr 16 、 eccv 16 的时候,很多方法在这两个数据集上的表现都很相似,作者认为这些方法其实都是有强弱之分的,但是因为数据集太小,所以无法识别视频网络架构的好坏了


所以本文提出了一个新的数据集-- Kinetics 数据集,同时作者重新把之前最好的网络结构在 Kinetics 数据集上测试了一遍现有的方法

  • 这篇文章最主要的买点是数据集,所以作者将数据集放到了摘要的第一段,模型放到了第二段
  • 新提出的 Kinetics 数据集有 400 类,也就是常说的 K400 数据集,每一类都有超过 400 个视频段落( video clip ,一小段视频,比如 K400 数据集所有的视频都只有 10 秒,都是将对应的人体动作精准地从视频中抠出来了,所以说是一个标注的非常仔细的好的数据集,一般将这种五六秒或者十几秒的视频段落叫做 video clip )
  • 另外一个作者最想要的非常重要的一个卖点是迁移学习,在这个大数据集上预训练过的模型到底能够在小规模的数据集上能够有多大的提升


作者在第二段讲述了对模型的改进,提出了一个 Two-Stream Inflated 3D 网络

  • 这个网络来自 2D 网络的扩张( inflation ) :这里的扩张指的是将一个已经调好的网络(比如说 ResNet )直接拿过来,然后将网络中所有的 3 * 3 的 kernel 或者 3 * 3 的 pooling 全部变成 3 * 3 * 3 ,这样就生成了一个针对视频理解的网络结构。
  • 这样做的好处是不用再费尽心思去设计一个专门的针对视频理解的网络架构了,在 2017 年之前大家已经做了很多这种模型上的改进:AlexNet -> VGG -> InceptionNet -> ResNet,并且已经得出了很多很有用的结论:堆叠的 3 * 3 的 Kernel 效果就很好;分类的最后不需要使用全连接层;一个网络应该被分成几个阶段,每个阶段中应该包含多少个 Residual block 等等,这些结论之前已经在 2D 的网络上做过很多的消融实验了,既然有这么多前人的工作,最好最简单的方式就是直接将这些网络用到视频理解中,毕竟视频也是由一帧一帧的视频帧堆叠起来的,跟图片的区别不是很大。如果说从头开始设计网络,之前所遇到的所有的问题都需要重新考虑:选用多大的 kernel size;整个网络选取几个阶段,每个阶段使用多少个 block 等等,而且视频又多了一个时间的维度,导致消融实验的量是非常巨大的,所以说如果能从一个 2D 的网络直接扩张成一个 3D 的网络是一个最简单有效的方法,而且本文中作者甚至通过一种叫做 bootstrapping 的方法将 2D 网路的预训练参数用来做 3D 网络的初始化,避免了从头开始训练(这种扩张的方法一直到现在都有用:TimeSformer 就是将 Vision Transformer 进行扩张)


最后作者讲述了实验数据,在本文所提出的大规模的 Kinetics 数据集上预训练过之后,本文所提出的 Two-Stream Inflated 3D 网络能够在 HMDB-51 上达到 80.9% 的效果(之前 HMDB-51 上最好的结果在 70% 左右,直接提高了 10 个点,因为 HMDB-51 数据集比较难,所以能够达到 80% 就已经很好了,一直到现在也没有太多的工作再做这个数据集了,80% 基本上已经是天花板级别了),在 UCF-101 上达到 98.0% 的效果(这也是一个很好的结果,再刷也无非就是刷到 100%)

  • 其实 I3D 论文一出,基本上 UCF-101 和 HMDB-51 这两个数据集之后也只能做一种辅助实验了,或者说将它们当作迁移学习或者自监督学习特征的衡量标准,而不能单独地作为有监督学习下的衡量标准





引言


ImageNet 数据集所带来的好处,不光是可以训练神经网络,最主要的、也是最意想不到的好处是在这种大规模的数据集上进行预训练之后,可以直接从网络中抽取特征(之前常见的做法是将 FC 6 或者 FC 7(就是倒数两层全连接层)的特征抽取出来),可以非常有效地迁移到其他任务(比如在 pascal voc 分类或者检测任务上,都能取得很好的效果)


所以从 ImageNet 训练网络结构开始,深度学习逐渐将其他的任务也全都控制了(比如分割、深度估计、姿态估计、动作分类等),但是在视频领域,先在大规模数据机上做预训练然后迁移到小数据集上的这种范式其实还没有被证实有效,因为视频领域中还没有一个好用的大规模数据集,目前有的数据集其实只有 1 万个视频左右,相对于其他任务或者其他领域来说,数据量太小了


所以本文提出了一个新的数据集 -- Kinetics 数据集,它远比之前的两个数据集要大得多

  • 第一版的 Kinetics 数据集,也就是 K400 数据集有 400 个类别,每个类别都有超过 400 个样本,而且每个样本都是来自于一个独一无二的 youtube 视频,因此多样性是比较好的(像之前的一些数据集,哪怕是 UCF-101 ,它里面有很多视频的小片段也是从一个大视频中截取出来的)
  • K400 数据集构建的还是不错的,直到今天大家都还在使用,并且在它上面做算法好坏的比较


在构建了一个新的数据集之后,作者将之前比较流行的而且好用的方法都拿来测试了一下

  • 不仅可以看一下之前的方法有哪些优缺点、相似性和不用的特性
  • 还可以验证一下新的数据集的有效性:有时新出来的数据集可能有一些自身自带的特性或者说 bias ,导致它会过于简单或者是过于困难(过于简单或者过于困难都会导致没有人真正的用这个数据集,也就没有构建这个数据集的意义了)


本文中比较了三种之前比较流行的方式,这三种方式也代表了在视频领域大家是如何通过不同的方式去使用视频里自带的时序信息的,因为视频跟图片相比就只是多了一个时间的维度,所以说主要的区别就是如何利用好持续的信息,所以这三种方式也是代表了三种常见的流派

  1. 卷积神经网络 + LSTM
  2. 3D 卷积神经网络
  3. 双流神经网络


通过测试作者发现,这种先大规模的预训练,然后再在小数据集上做微调的时候,这几个网络结构都表现的参差不齐,而且有的时候提升也不是很显著,所以作者就取其精华,去其糟粕,最后提出了一个 Two-Stream Inflated 3D 网络

  • Two-Stream Inflated 3D 网络本身就是将所有的 2D kernel 变成了 3D kernel,将 3 * 3 变成了 3 * 3 * 3,包括 pooling 层也是从二维变成了三维,所以最终得到了一个非常深而且设计的还不错的视频理解的网络
  • 之所以还是使用双流,是因为作者发现即使使用了 3D 神经网络,对局部信息的掌控神经网络学习的还是不够好,加上双流之后效果还是能够提高很多,才能得到在 UCF-101 上 98% 的准确率,所以作者也就是将双流网络和 3D 神经网络进行了结合


本文中,已经不再和传统的方式作比较了,比如 bag-of-visual-words 这种表示在 2015 、2016年的时候还是比较流行的,但是在本文中已经不去和它进行对比了。另外,因为 K400 这个数据集是公开的,所以作者也鼓励大家在这个数据集上进行尝试





方法


  • 前三节主要是回顾之前的方法,后面两节主要讲作者所提出的方法以及具体的实现细节


在 2D 图像分类领域其实已经有主导的神经网络结构了(之前是 VGG 、 Inception,现在是 ResNet),到现在为止视频领域中也没有一个定论:到底是用 2D 、 3D,还是使用 Transformer,在当时来看只有以下几种选择(作者在 2.1 、2.2 、2.3 这三个章节中分别描述了一下之前的这三种方式):

  • 要么就是一个纯 2D 的网络后面再接上一些操作(比如 LSTM 层),从而做时间上的建模
  • 或者不论是用 2D 网络还是 3D 网络,都配备上光流,一旦有了光流之后,就有了时间上或者局部的运动信息的建模能力
  • 或者直接用 3D 网络,直接学习 Special Temporal 的时空特征


最后经过大量的对比,作者提出了 Two-Stream Inflated 3D 网络

  • Two-stream:之所以使用双流就是简单的 a + b 了,因为作者发现双流的使用是有效的,所以作者就使用了双流
  • Inflated:之所以用 inflated 是因为之前的 3D 网络的参数量实在是过于巨大,但是又没有合适的或者足够的视频数据做预训练,最终就导致 3D 网络不能太深(ICCV 15 的时候就有一个非常著名的工作叫 C3D,只有八层,而且效果也比较一般,当时没有超过双流网络的结果,所以作者这里在使用了 inflated 这个操作之后就可以直接启用特别深的最近表现比较好的网络,而且在使用了这些 2D 网络预训练参数作为初始化之后,I3D 网络也不需要很多的视频数据做预训练了)


具体来说,本文所使用的网络结构是从 Inception V1 经过一些改造得来的

  • 为什么使用 Inception 而不是使用 ResNet ?因为当时在 16 年的时候有很多论文做过消融实验发现,至少在当时的视频分类任务上,Inception 的结构比 ResNet 稍微好一些,所以在这篇论文中,作者就直接从 Inception 开始了
  • 但是因为 ResNet 的统治地位,所以在一年之后的 non local 论文中,作者就已经把 I3D 网络用 ResNet 进行实现了,从那时起,每当大家再提起 I3D ,其实很多时候指的是 ResNet 基础的 I3D 网络



图2



1、卷积神经网络 + LSTM



这种方式其实还是把一个视频更多地看成了是一个图像分类的问题,因为从视频帧 1 开始一直到视频帧 k,对于视频来说是一张图片一张图片地通过卷积神经网络(整个特征抽取的过程是完全分开的),在抽取完特征之后,再将抽取的特征全部输入进 LSTM 网络(LSTM 网络可以进行时序建模,所以它可以将每个时间戳上的特征融合起来,从而去理解整个视频内容),经过一系列的计算之后,将最后一个时间戳上出来的结果后面加上一个全连接层,然后进行分类任务

  • 这种方式其实是一种非常合理的方式,图像每一帧分开做,然后用一个 LSTM 网络模拟时序信息
  • 但是这种方法至少在之前的数据集上表现并不是非常好,所以很快这种方式就被抛弃了,基本上留下来的就是两个比较主流的框架: 3D 卷积神经网络、双流神经网络



2、3D 卷积神经网络



这种方式就是将视频劈成一个一个的视频段,每个视频段中有从 1 到 k 张图片,然后将这些图片当成一个 volume ,这样就能将整个视频输入到网络中了

  • 同时也就意味着网络能够进行时空学习,也就是说卷积核必须是三维的,不光要处理二维上的图像,还需要处理时间维度,也就是 3 * 3 * 3,但是这样会导致参数量变得很大,相当于所有的参数层都多了一个维度
  • 在之前视频数据集比较少的情况下不是很好训练,效果也比较 一般,但是在这篇论文中,在给定数据集足够的情况下,该网络的威力就显现出来了
  • 事实上也确实如此,作者在最后提出的 Two-Stream I3D 网络其实也就是一个 3D 的神经网络,但是在图 2(b) 中就是将一个视频小段输入到一个 3D 神经网络中,在这个 3D 神经网络中经过一些 3D 卷积、3D 池化之后,最后返回一个特征,并在这个特征之上做全连接,最后做分类就可以了



3、双流网络


如果不想使用 LSTM 做时序的模拟,也不想训练一个 3D 网络去做时空学习,怎样能够抓住时序信息呢?一个非常简单的方式就是提前抽取好光流(这里的光流值的是光的流动,也就是视频中每个物体的运动轨迹),它自身蕴含了非常准确的而且非常强大的物体运动信息,所以它就是一种变相的视频中时序信息的特征表示。


所以只需要先从视频中抽取光流图,然后学习一个从光流到最后的动作之间的一个映射关系就可以了,而卷积神经网络本身并不需要知道运动是如何发生的,也不需要具有时序模拟建模的能力,这些只需要光流就足够了,所以这个网络非常的简单,而且因为它对模型的要求比较低,所以训练起来也比较容易,结果也非常好。


所以在 15 、16 年的时候,双流网络是远远优于 3D 神经网络的,这个阶段基本上 90% 的工作都是基于双流网络


具体来讲,双流网络就是有两个 2D 的卷积神经网络

  • 左边的网络叫做空间流,它的输入是一帧或者多帧的视频帧,主要负责学习场景信息
  • 右边的网络叫做时间流,它的输入是光流图像,主要负责学习物体的运动信息

这两个神经网络最后都会得到特征最后做分类,在得到这个分类结果之后,再进行 later fusion(指的是不同的特征使用不同的分类器,得到基于每个特征的分类结果,再对所有结果进行融合(可能是投票、加权平均等),这个融和发生在不同特征分类结果之间的融合),最后再将两个 logist 加权平均一下就可以了



4、3D-Fused Two-Stream


  • LSTM基本上是没有什么后续工作,主要是 3D 卷积神经网络和双流网络,所以在 CVPR 16 的时候有一篇论文有机地将 3D 卷积神经网络和双流网络结合到一起,也就是 3D-Fused Two-Stream



刚开始的时候是按照双流网络的做法,结构的前半段和双流网络相同

  • 左边是一个输入为图像的 2D 卷积神经网络
  • 右边是一个输入为光流的 2D 卷积神经网络


但是有研究者认为在双流网络中最后取了一个加权平均过于简单,很有可能不利于抓住视频中特别复杂的场景变换,所以 3D-Fused Two-Stream 这篇文章中就把最后的加权平均用一个比较小的 3D 卷积神经网络替代

  • 如果将双流网络中之前的方式叫做 later fusion:在 Logist 层面融合时间流和空间流的结果
  • 3D-Fused Two-Stream 中使用的方式叫做 early fusion:在还未出结果的情况下,就将这两个特征先融合在一起,然后用一个 3D 卷积神经网络进行处理,最后直接得到分类结果(这里的 3D 卷积神经网络也可以用 LSTM 代替,但是因为效果不好,所以基本上都是用的 3D 卷积神经网络)


后续还有一些工作顺着 3D-Fused Two-Stream 又做了一些研究:到底应该刚开始用 2D 后面用 3D,还是刚开始用 3D 后面用 2D?2D 和 3D 的计算复杂度和训练难度都是不一样的,所以如何去找到一个好的折中的网络设计方案十分关键。后续的结果证明:前面用 2D 卷积神经网络后面用 3D 卷积神经网络的方式最好,容易训练而且能够得到比较好的结果



5、双流 I3D 网络


  • 前面 4 种都是之前的方法,作者在自己提出的 K400 数据集上进行复现,得到结果之后然后进行反复对比,作者就提出了第五种模型设计方案


作者认为,只要在足够多的数据集的情况下,其实使用 3D 卷积神经网络明显是要比 2D 卷积神经网络的效果要好


但是 3D 卷积神经网络也不是万能的,还有一些东西学不到,所以使用光流进行辅助效果会更好,所以作者还是采取了双流网络,但是每一个分支都使用的是 3D 卷积神经网络

  • 因为每一个分支都是 3D 卷积神经网络,也就不存在 early fusion 或者 late fusion,所以就没有必要在后面再加一个 3D 卷积神经网络去做 fusion,于是直接进行加权平均,最后得出结果就可以了





具体细节


第一部分:Inflating 2D ConvNets into 3D


就是将一个 2D 卷积网络直接暴力地变成了 一个 3D 卷积网络


以 Res 50 为例,刚开始有一个卷积层,然后接一个最大池化层,后面有四个阶段:Res 2 3 4 5,每个阶段分别有 3、4、6、3个 Residual block,如何将一个 2D 的 Res 50 变成一个 3D 的 Res 50 ?

  • 整体的架构保持不变,只要遇到一个 2D 的卷积核,就将它变成一个 3D 的卷积核,只要遇到一个 2D 的池化层,就把它变成一个 3D 的池化层就可以了
  • Residual block 还是 Conv-BN-ReLU 的结构,并且数量不变
  • 还是分成了四个阶段


以上的这种转变方式就是 inflate ,这样做的好处是

  • 因为不用再重新设计网络,所有设计好的 2D 网络都可以直接拿来使用,以后如果有设计的更好的效果更好的 2D 网络也可以采用同样的方式转变成为 3D 网络


之后的 Non-Local Network 中,作者也是采用了这种方式将 2D 网络 inflate 成为 3D 网络的;在最新的 TimeSformer 中也是将 ViT 从 2D inflate 到 3D;现在最近的 Video Swin Transformer(CVPR 22)也是将 Swin Transformer 从 2D inflate 到 3D



第二部分:Bootstrapping 3D filters from 2D Filters


  • 得到一个合理的做视频理解的网络结构其实只是第一步,接下来更难的问题是如何能更好地将这个 3D 网络训练起来


bootstrapping 的字面意思是引导,也就是说当已经有一个东西之后,在此基础上再去做一些改进,从而让这个东西变得更好。这里的意思是说如何能从 2D 的在 ImageNet 上已经训练好的模型出发,去初始化 3D 模型,然后在这个初始化好的 3D 模型上继续进行训练使他变得更好

  • 具体实现上还是有难度的,因为如果想用一个已经预训练好的参数来做初始化,最简单或者说最好来说,这两个网络应该是一模一样的,这样就能够直接将预训练好的参数搬过来就可以了
  • 但是现在预训练好的网络是一个 2D 网络,而即将要训练并且最后要使用的网络是一个 3D 网络,虽然这两个网络整体的架构是一样的,但是具体到每一步操作都是不同的


如何用一个 2D 的预训练好的模型初始化一个 3D 的模型?

  • 平时在用别的预训练模型初始化自己的模型时,通常会进行以下操作来验证初始化是否正确:给定同样的输入,用这个输入在原来的模型上面跑一遍,然后再在初始化后的模型上跑一遍,两次所得到的输出按道理来讲应该是完全一样的(如果参数搬运是正常的话,这两个模型是完全对等的,如果是同样的输入、同样的模型,那么它们的输出就应该相等)
  • 作者受此启发,使用同样一张图片反复地进行复制粘贴最后变成了一个视频,也就是说这个视频中全是同样的视频帧,如果进行播放的话是没有任何的变化的,也就是作者所说的 boring video
  • 用什么方式能够将 2D 已经训练好的网络参数用来初始化 3D 模型(最后如果能够使得这两个模型的输出一致,就能从侧面验证这个 3D 模型是从 2D 模型初始化而来的)?具体的做法就是将所有的 2D Filter 全都在时间维度上复制粘贴 n 次,就和输入视频对应起来了
  • 原来是一张图片对应一个 2D 神经网络,假设入是 X ,网络是 W 的话,最后就会得到输出 X × W;现在输入变成了一个视频,视频里面有 n 个 X,3D 神经网络的参数也是 W × n,那么最后的结果就相当于得到了 n 份的 W × X
  • 如果想让 2D 神经网络和 3D 神经网络的输出保持一致,就需要做一些 rescaling (在所有的 2D Filter 上都除以 n),这样 n 倍的 W × X 除以 n 之后就又变成了 W × X,也就是说,最后输入为图像的 2D 神经网络的输出是 W × X ,输入为视频的 3D 神经网络的输出也是 W × X
  • 这样就保证了无论是在网络的哪一层,不论输入是图片还是视频,分别对应通过一个 2D 神经网络和一个 3D 神经网络之后,最后得到的输出都是一样的,这样再向后面的层进行传递的时候,后面的层也能接的住这个输入,因为它们是完全一样的,也就是说可以用预训练好的参数来做进一步的计算



使用 gluon-cv 中的 I3D 为例来解释具体的 inflate 和 bootstrap 是如何用代码实现的

  • 代码文件:https://github.com/dmlc/gluon-cv/blob/master/gluoncv/model_zoo/action_recognition/i3d_resnet.py
  • 具体的实现是文件中的 init_weights 函数(line 539)
 def init_weights(self, ctx):
   """Initial I3D network with its 2D pretrained weights."""

   self.first_stage.initialize(ctx=ctx)
   self.res_layers.initialize(ctx=ctx)
   self.head.initialize(ctx=ctx)

   """
   首先下载 2D 网络的预训练参数,Res 50 或者是 Res 101
   """
   if self.pretrained_base and not self.pretrained:
     if self.depth == 50:
       resnet2d = resnet50_v1b(pretrained=True)
     elif self.depth == 101:
       resnet2d = resnet101_v1b(pretrained=True)
     else:
       print('No such 2D pre-trained network of depth %d.' % (self.depth))

     """
     通过 collect_params 函数就能得到 2D 网络所有的参数,
     并将其存储在 weights2d 变量中
    """
     weights2d = resnet2d.collect_params()
     if self.nonlocal_cfg is None:
       weights3d = self.collect_params()
     else:
       train_params_list = []
       raw_params = self.collect_params()
       for raw_name in raw_params.keys():
         if 'nonlocal' in raw_name:
           continue
         train_params_list.append(raw_name)
       init_patterns = '|'.join(train_params_list)
       """
      通过 collect_params 函数得到新建立的 3D 网络所有的模型参数,
      并将其存储在 weights3d 变量中
     """
       weights3d = self.collect_params(init_patterns)
     """
     进行 assert 操作是因为 2D 网络和 3D 网络的结构(层数)应该是一样的,
     所以 weights2d 和 weights3d 的长度应该是一样的
    """
     assert len(weights2d.keys()) == len(weights3d.keys()), 'Number of parameters should be same.'

     dict2d = {}
     for key_id, key_name in enumerate(weights2d.keys()):
       dict2d[key_id] = key_name

     dict3d = {}
     for key_id, key_name in enumerate(weights3d.keys()):
       dict3d[key_id] = key_name

     dict_transform = {}
     for key_id, key_name in dict3d.items():
       dict_transform[dict2d[key_id]] = key_name

     cnt = 0
      """
     在 for 循环中一步一步地将 2D 网络中每一层的参数转移给 3D 网络
    """
     for key2d, key3d in dict_transform.items():
       if 'conv' in key3d:
         temporal_dim = weights3d[key3d].shape[2]
         temporal_2d = nd.expand_dims(weights2d[key2d].data(), axis=2)
         """
         inflate_2d 这一行其实就是在做 bootstrapping:
         在知道了时间维度上的值(temporal_2d)假设为 n ,
         先将 2D 网络的参数复制粘贴 n 次,
         然后再进行 rescale 操作(除以 n ),
         这样就完成了 bootstrapping 的操作
      """
         inflated_2d = nd.broadcast_to(temporal_2d, shape=[0, 0, temporal_dim, 0, 0]) / temporal_dim
         assert inflated_2d.shape == weights3d[key3d].shape, 'the shape of %s and %s does not match. ' % (key2d, key3d)
         weights3d[key3d].set_data(inflated_2d)
         cnt += 1
         print('%s is done with shape: ' % (key3d), weights3d[key3d].shape)
       if 'batchnorm' in key3d:
         assert weights2d[key2d].shape == weights3d[key3d].shape, 'the shape of %s and %s does not match. ' % (key2d, key3d)
         weights3d[key3d].set_data(weights2d[key2d].data())
         cnt += 1
         print('%s is done with shape: ' % (key3d), weights3d[key3d].shape)
       if 'dense' in key3d:
         cnt += 1
         print('%s is skipped with shape: ' % (key3d), weights3d[key3d].shape)

     assert cnt == len(weights2d.keys()), 'Not all parameters have been ported, check the initialization.'




第三部分:Pacing receptive field growth in space,time and network depth



第四部分:Two 3D Streams





实验细节


图3



左边是一个标准的 Inception-V1 的结构,只不过经过了 inflate 处理过了


当视频输入进来之后,首先经过一个 7×7×7 的卷积层(步幅为 2 ):在 Inception-V1 或者是 Resnet中,刚开始是经过一个 7×7 的卷积层,现在只不过是变成 3D 了


接下来经过一个最大池化层:这里的最大池化层作者进行了一些改动,原来的最大池化层是 3×3 (步幅为 2 ),如果按照文章中的 inflate 的处理方式的话,这里应该变成 3×3×3 (步幅为 2 2 2),但是作者发现时间维度上,最好不要进行这种下采样(事实上在最近几年的文章中,大家也都发现了这个问题,甚至从 SlowFast 开始,基本上在时间维度上是完全不做任何的下采样,比如输入是 64 帧,输出的时候还是 64 帧,因为 64 帧对应的时间本来就已经很短了,可能只有 2、3 秒钟,所以对于描述动作来讲,就不要再做下采样了),所以在刚开始的时候做了 1×3×3 的池化操作(步幅为 1 2 2)


然后又做了两次卷积和一次池化(这个池化操作依旧是 1×3×3 ,步幅为 1 2 2 ,在时间维度上依旧是没有做下采样)


在后面的几个阶段中做了几个下采样:





Inflated Inception-V1 中的 Inception model 如图右边所示,和之前的 Inception model 是完全一致的,只不过是将所有的 1×1 变成 1×1×1 了,3×3 变成了 3×3×3 ,其他的都没有变化,整体上改动还是非常小的



表1


表 1 中总结了之前所提到的五种形式,以及它们训练和测试的时候输入输出的大小、模型大小


模型大小

  • 3D 卷积神经网络的模型参数是非常巨大的,为 80 M ,远高于其它四种形式
  • 如果只是用 2D 的卷积神经网络 + LSTM 或者使用双流网络的这种形式的话,网络规模就会大大减小,大概只有 9 M 和 12 M(这也能够解释为什么在 15 、16 年的时候大家普遍使用双流网络,因为它不仅效果好,而且模型小,都能玩得动)
  • Two-Stream I3D 的模型大小大概是 25 M,也不算大,所以还算是比较经济实惠


训练的输入

  • 2D 的卷积神经网络 + LSTM 模型的输入是 25 帧的视频帧,时间跨度是 5 秒(为什么是 5 秒?因为这里所有视频的帧率都是每秒 25 帧,对于LSTM 这种方式来说,作者是每隔 5 帧选择一帧,这样的话一秒就是 5 帧,25 帧的话就是 5 秒)
  • 对于 3D 卷积神经网络来说,因为必须是要连续的帧输入,所以如果输入是 16 帧的话,其实就不到一秒钟(因为一秒是 25 帧,而这里只有 16 帧,所以大概是 0.64 秒)
  • 对于双流网络来说,是先任选一帧,然后用接下来的 10 帧计算出 10 个光流图,所以时间跨度就是 11 帧,11 帧其实是半秒都不到的,只有 0.4 秒
  • 对于 3D-Fused 模型来说,使用了 5 个 RGB 帧和 50 个光流图像,所以跨度比较长,一秒 25 帧的话,50 个光流图就相当于是 2 秒
  • 对于 Two-Stream I3D 模型来说,因为作者使用的是 64 帧和 64 个光流图像,所以是 2.56 秒,从这个意义上来讲,它的输入最大但同时设计的时间跨度也最长,这对于视频理解来讲算是一个好处


测试

  • 在测试的时候其实这几种方式都差不多,因为测试的时候为了尽量公平地去比较,所以最好是将整个视频都囊括在内的,对于 K400 数据集来说每个视频都是 10 秒钟,所以这里都是 10 秒
  • 至于为什么 3D 卷积网络是 9.6 秒,是因为它每次的输入都是 16 帧,对于一个 250 帧的视频来讲除不尽,所以最后只能覆盖 240 个视频帧,所以就是 9.6 秒





实验结果


表 2



  • 作者先在 UCF-101 、HMDB-51 和 Kinetics 400 数据集上分别进行了训练和测试,最后发现双流 I3D 网络是这五个结构中表现最好的


表 2 中对比了五个网络结构在上述三个数据集上的效果

  • 双流 I3D 网络在所有的设置下都能够达到最好的效果
  • LSTM 和 3D 卷积神经网络的效果普遍都比较差,和双流网络的结构是完全没法比的
  • 另外,不论时间流比空间流的效果好还是坏,最后将这两个分支用 later fusion 的方式结合起来以后,它的效果都能够得到大幅度的提升,这就说明了光流始终对视频理解是有帮助的,这也是为什么作者在这篇文章中即使已经用了一个 3D 卷积神经网络,但是想用光流,所以最后还是设计了一个双流 I3D 网络



表 3



  • 表 3 证明如果视频网络只用 K400 数据集做预训练而不需要 ImageNet ,最终的效果也是不错的



表4


  • 表 4 中说明了如何在小数据集上做微调(迁移学习):到底应不应该将骨干网络锁住,还是说整个网络一起进行微调
  • 因为提出 K400 数据集主要是用来做迁移学习的,所以作者更关注迁移学习的效果,尤其是迁移到之前的 UCF-101 和 HMDB-51 上的结果
  • 表 4 中的 Original 这一栏指的是在 UCF-101 或者 HMDB-51 上训练,然后进行测试,完全不用 K400 数据集,从表中可以发现这一栏还是普遍偏低的
  • 表 4 中的 Fixed 这一栏和 Full-FT 这一栏都用了 k400 数据集, Fixed 这一栏是将骨干网络冻住了; Full-FT 是整个 end-to-end 去训练,整个网络的参数都可以改变。通过表中的数据可以发现, Full-FT 的情况下的结果是最好的(这个结果其实并不奇怪,双流网络早在 2014 年的时候就已经证明整体微调的形式效果一般是会好一些的)



表 5


  • 表 5 是全文最重要的一个表格,它列出了之前的所有方法,最后证明双流 I3D 网络的效果最好,远远超过了之前最好方法的表现


作者将整个表格分成了三部分:

1、第一部分是双流网络

  • 相比而言,双流网络的方法更加好用,之前双流网络最好的方法已经能够达到 94 , 70 的水平了,和 I3D 差的也不是特别远
  • 之前在 15 、16 年的时候,大家有的时候还会去和传统的方法去比较,或者和手工的特征相结合达到最好的效果,双流网路有关的的论文基本上都汇报了和 IDT 的特征结合的效果,但是在 17 年之后其实已经很少有人会这么做了,都是只跟深度学习的方法进行比较,而且很少做和之前传统特征的融合了

2、第二部分是 3D 卷积神经网络

  • 这部分其实就 C3D 和 Deep Video
  • Deep Video 其实都不能算是一个纯 3D 的网络,也可以从侧面说明,在 I3D 这篇论文出来之前,其实 3D 神经网络是一点都不流行的,因为不好训练,而且效果非常的差,在其他形式的结果都是 80 , 90 左右的情况下, 3D 卷积神经网络只能达到 60 , 80 左右,差的还是比较远

3、第三部分是作者自己提出来的双流 I3D 网络

  • 作者先是单独展示了一下每一个分支的结果:如果只用视频帧的话能达到 95.6 ;如果用光流的分支的话能达到 96.7 ;如果将这两个结合到一起的话在 UCF-101 数据集上能达到 98 ,在HMDB-51 数据集上能达到 80.7 ,效果非常好
  • 为了验证作者之前在引言刚开始的时候所说的一个观点:视频模型最好是在视频数据集上训练,而且为了验证 K400 数据集足够大,达到足以用来做预训练,所以作者在第 4 、5 、 6 组实验只用了 K400 数据集做预训练,而不用 ImageNet 预训练的模型。最终得到的效果其实和前三组的效果差不多:在 UCF-101 数据集上稍微低了 0.2 个点,但是在 HMDB-51 数据集上又高了 0.2 个点,基本不分伯仲
  • 自从有了 K400 数据集, 3D 网络的设计就有了更大的设计空间,因为这意味着可以从头开始训练,而不一定非要借助于一个 ImageNet 预训练好的模型了。所以像接下来的 R(2+1)D 网络、SlowFast 模型、 I3D 模型都是可以从头开始训练的,只不过训练的 epoch 可能会多一点:从 80 或者 100 个 epoch 可能要增加到 200 个 epoch,训练时间会增加,但是完全不需要一个 ImageNet 预训练模型





结论


  • 作者在引言的时候提出了一个问题:迁移学习到底在视频领域有没有用?通过这篇论文中的一系列实验,尤其是表 5 可以发现,非常明显,其实这种在大规模的视频数据集上做预训练完之后得到的效果是非常好的
  • 作者谦虚地说,他只是探索了一下在 K400 上做预训练 ,然后再在 UCF-101 和 HMDB 51 上去做迁移学习,但是只是视频分类,得到的结论也不一定准确,如果接下来能够进一步验证在 K400 数据集上做预训练,然后在其他任务(比如说视频分割视频物体检测或者说光流计算)上在 K400 的预训练都能提供帮助的话,就能证明 K400 数据集确实很厉害,而且它的影响力也会大不少。但是作者因为时间和计算的关系,所以下游的任务就没有一一去做了,最好是将这个数据集开放出来,大家可以一起进行探索
  • 除了做更多的下游任务之外,作者在模型上的探索也没有做的非常全面,比如说没有考虑最近比较火热的 action tubes 或者 attention mechanism ,也为其他人提供了跟进的方向,所以在 CVPR 18 的时候 NonLocal Network 就出来了,其实就是在 I3D 的后面使用了自注意力(Self-Attetion)而取得了更好的效果(所以当没有选定研究课题或者不知道接下来该做什么的时候,其实可以多看一下最近的一些论文,重点关注一下这些论文的未来展望或者有什么东西是还没有完成的一般就可以了,因为这些方向或者说这些课题一定是非常值得做的,所以说作者才会在最后的结论部分将它加进来,才会对它进行展望,如果是不值得一提的课题,作者根本就不会浪费空间来写这些东西,这些课题可能也比较难,所以作者没有精力,或者说也不知道该怎么做,所以将它写到了未来工作中。但是从研究方向上来说,往往写在结论中的未来工作都是非常好的研究方向)





论文总结


I3D 这篇论文一共有两个贡献

1、新模型——双流 I3D

2、新数据集—— K400 数据集


之所以 I3D 这篇论文这么火,而且有这么多的人去跟进,是因为它从两个方面上全面解决了训练的问题

1、如果没有数据,如果又想用 ImageNet 上预训练好的模型参数,可以用论文中提出来的 Inflate 的操作将 2D 的网络变成 3D 的网络,这样不仅不用设计 3D 网络,而且还可以直接用预训练的模型参数进行初始化,最后微调的结果往往都会比较好

  • 接下来的工作(比如 P3D 、 R(2+1)D 、 SlowFast 、 TimeSformer 、 Video Transformer 等)都有用到 Inflate 和 Bootstrapping 这两个操作,简单但是实用

2、如果不想用已有的 2D 框架,而想要从头开始设计一个 3D 网络,可以天马行空地进行网络的设计,设计完网络之后,就需要一个大规模的视频数据集来进行网络的预训练,这篇论文所提出的 K400 数据集足够大,可以在这个数据集上从头训练一个网络,而不需要依赖于 IMageNet 预训练的参数

  • 所以说,接下来 SlowFast 、 X3D 、 MViT 这些工作都是直接从头开始训练,只不过训练的 epoch 数多了一些(从 100 涨到了 200)


所以说 I3D 这篇论文从两个方面将所有的用户基本上都考虑到了,接下来如果所研究的方向是视频分类,无论怎么做可能多多少少都要用到 K400 这个数据集或者是 Inflate 操作


自从有了 I3D 这篇论文,接下来对 3D 卷积神经网络的研究如雨后春笋一般全都冒出来了,双流网络瞬间就不香了。

  • 所以说从 2017 年到 2020 年的这三年,3D 卷积神经网络基本上霸占了整个视频理解领域一直到 Vision Transformer 的出现
  • 而且因为 K400 数据集的提出,所以从 2017 年开始,基本上都会在 K400 数据集上汇报结果,一直持续到今天


所以说,I3D 是视频分类领域不可不读的一篇论文





----end----

其它参考

1、《Quo Vadis, Action Recognition? A New Model and the Kinetics Dataset》,https://arxiv.org/abs/1705.07750

I3D 论文精读【论文精读】的评论 (共 条)

分享到微博请遵守国家法律