Quo Vadis, Action Recognition? A New Model and the Kinetics Dataset
https://space.bilibili.com/511378644
目录
3 看图过方法:LSTM、3D-convnet、two-stream、3D-Fused two-stream、two-stream 3D-convnet
第二步如何能更好地把这个 3D 网络训练起来——bootstrapping
代码理解把一个 2D 的预训练模型用来初始化一个 3D 模型
总结一下之前的这五种形式,以及他们训练和测试的时候,这个输入输出长什么样,模型具体有多大
大家好,今天我们就一起来读一下视频领域里另外一篇重要的论文,I3D。这篇论文其实有两个非常重要的贡献,可以直接从它的论文标题里看出来。一个就是他提出了一个新的模型,也就是他文章中说的一个 inflated 3D network I3D。 inflated 的意思就是扩大膨胀,也就是说我们如何能够把一个 2D 模型扩张到一个 3D 模型。这个方法的好处就是说,你不用再费尽心思地去设计一个专门的视频理解的网络了,你可以使用那些 2D 里已经设计好的网络,比如说 VGG、Resnet,那你直接把它扩张到 3D 就可以了。甚至你还可以用一些巧妙的方式把它预训练模型也利用起来,这样不仅设计上简单,而且还能省掉很多预训练的麻烦。那另外一个贡献就是说他提出了一个新的数据集,也就他这里说的 Kinetics 数据集。这个数据集刚开始提出的时候只有 400 类,所以叫 Kinetic 400,然后接着又推出了 connects 600, connects 700,也就分别对应的是 600 类和 700 类。视频的数量也从最开始的 30 万涨到了 50 多万,最后涨到了 60 多万。你乍一听觉得其实这个视频数量并不是很多,毕竟我们上次也讲过,在 14 年的时候就已经有 Sports one million 数据集了,是有 100 万个视频。然后在 2016 年的时候, Google 又推出了这个 YouTube eight million 数据集,就是有 800 万个视频。但是 YouTube eight million 实在是太大了,做数据集的人也知道别人都玩儿不动,所以他在举办比赛的时候都是直接给大家分享已经抽取好的这些特征,而不是告诉你怎么去下载原始视频,因为你即使下载下来了,你也玩儿不动。那 Sports one million 数据集因为全都是关于运动的这些类,这个应用场景有点儿局限,你如果只在运动视频上去做预训练,那按道理来说是很难拓展到其他领域里去的,而且 100 万个视频在当时来说也还是稍微有点大,所以说这篇文章的作者就利用了这个机会,提出了这个 kinative 数据集,它的类别比较均衡,难度也比较适中,而且 30 万个视频也不算特别大,很多人都可以玩得动。所以说一经提出就得到了广泛的使用,一直到现在,只要是做视频分类的,那基本一定要在这个数据集上去出一个结果的,你不出审稿人也会问你要,是逃不掉的。
标题
那论文的题目其实我们刚才已经大概说过了,这篇文章的主要卖点就是这个一个新的模型和这个 Connex 数据集,但是这个题目还是比较花哨的,这题目说 call Vattis action recognition,这个 call Vaddis 作者在图一里也有说,这个其实是一个 1951 年的一个电影,这个电影的名字直接翻译过来叫 where is this going,我看百度上有几个名字,一个就是直译过来的,就是你要去哪。另外一个就是说的这个电影本身讲的是什么?讲的是古罗马时代一个昏君的故事,但这里其实我一直不是很明白,作者为什么要用这个电影当作这篇论文的一个研究动机,或者为什么要用这么一个插图当作这个图一,可能这个电影真的很有名。那作者这里其实想说的意思是,如果你只通过一张图片来看的话,你是不能区分很多动作的,比如说你不知道这两个演员是不是要去亲对方了,还是说他们俩已经亲过了,然后更重要的一个问题是,不论是他亲过还是没亲过,那这个动作接下来该如何发展?这些问题我们通过单一的一张视频帧都是无法回答的,那只有通过看到了视频,只有理解了这个上下文的含义,你才能知道这些动作到底发生了没有,以及未来有可能会发生什么,
然后接下来作者就是说视频领域就缺少这么一个大的视频数据集,所以导致现在大家也不能很好的去研究这个视频理解的框架。所以本文中作者他们就证实了这个视频的模型最好还是要在视频上去预训练。具体来说就是本文又提出了一个又大又好的这个视频数据集,然后在这个视频数据集之上他们又训练了一个新的模型,叫 I3D 模型,然后这个模型在现有的这些视频数据集上都取得了巨大的这个效果提升。比如说在 Kinessay 数据集上预训练过之后,然后再在 UCF 101 这个数据集上去做一下微调,最后的结果直接就能刷到 98 了,直接就宣告了 UCF 101 数据集的终结,以及 Connexy 数据集的这个崛起。就从这篇论文之后,大家不仅刷不动 UCF 101 这个数据集了,而且即使你能刷得动,即使你还能获得一点点这种提升,审稿人也是不会放过你的,一定会问你为什么不跑 Kinesday 这个数据集。所以从这个角度上来说, I3D 这篇论文算是开启了一个新的时代。但其实比较讽刺也比较有意思的一个事实就是,大家现在发现 kinessay 这个数据集还是非常 special heavy,直白点儿说就是你从这个视频里选最中间那一帧,然后你对这一帧做一个图像动作分类,它的准确度就已经很高了,完全不需要太多的上下文信息,也完全不需要模型具备这种太强的时序建模能力,所以跟这篇论文想要达到的目标还是有一定距离的。但是这个任务真的是很难,因为直到现在大家都不能想到一个很好的方式去构建一个很好的视频数据集,从而能够让学到的模型真的能关注到这种时序上的信息,真的能去处理这种长时间的复杂的视频,而且真的能够拓展到生活中方方面面的领域里去,所以说视频理解研究的道路还非常漫长。
作者团队
那看完了这么华丽的标题,接下来我们看一下作者团队,一作。 Jura 来自于DeepMind,基本上是推动了 Kinesseed 这个数据集一系列的发展,他去年也有另外一篇比较有意思的工作叫做perceiver,我们之前也邀请他在我们 i c VR e 上组织的一个视频理解的 tutorial 里做了一个演讲,主要内容就是讲perceiver,感兴趣的同学可以去我之前 b 站的视频里找一下。那2作AZ 就是老熟人了,上次我们讲的双流网络也是来自于他们 VGG 组的工作。
整体梳理
那在我们开始精读论文之前,还是老规矩来把论文整体梳理一遍。
首先刚开始的这个摘要部分和这个引言部分,作者就是讲了一下,现在缺少这么一个大型的有用的视频数据集,从而很难训练一个有效的而且能够扩展的一个视频理解模型。所以本文中就提出了 Kinessay 这个数据集,而且提出了一个新的模型叫I3D。
然后论文接下来的几页,也就是第二章,主要就讲了一下他们这个方法部分。这篇论文的写作非常有意思,它没有这个 related work,也就是没有这个相关工作的部分,因为这些相关工作跟他们即将要说的内容非常的相关,读者必须对这些相关工作有一定的了解,才能欣赏到他们这篇论文的这个必要之处。所以作者就把之前的相关工作和他们自己的方法都融合到一个大的章节里了。作者上来就先讲了三种过去非常流行的这个视频理解的方法。第一种就是先有一个卷积神经网络,后面跟了一个LSTM,卷积神经网络用来抽特征,让 LSTM 用来处理时序信息。第二种方式就是直接训练一个 3D 网络。第三种方式也就是我们上次刚讲过的这个双流网络。在讲完之前的这三种方式之后,作者就提出了他们自己的方法,叫做 I3D 网络。
那在讲完了方法之后,自然就是展示一些结果,然后在最后一个章节就展示了一些模型。学到特征的这个可视化,文章整体上还是非常易读的,
摘要
接下来我们就一起来精读这篇论文。我选的是最新的 ARCHIVE 版本,是 2018 年 2 月份最后一次更新的,作者上来现在摘要里说,因为这个目前的数据集都太小了,比如说 UCF 101 和 H M D B 51,他们分别有 101 个类别和 51 个类别,而且他们的这个视频数量对于 UCF 来说的话是 13000 个视频, HMDB 是 7000 多个视频,所以说是相当少的。那在这么小的数据集上就往往很难去发挥深度学习的这个威力。所以说在 CVPR 161、 CCV 16 的时候,很多方法在这两个数据集上的表现都很相似了,比如说在 UCF 上,大家的这个结果都是 9394 的这个准确度。作者这里就想强调说,其实这些方法肯定是有强有弱的,但是因为你的这个数据集太小,所以说已经让他无法能够去识别这种好的视频网络架构了。所以说这篇文章就提出了一个新的数据集,叫做 Kinetics 数据集,然后他们也在这个数据集上重新把之前的这些最好的网络结构全都又试了一遍,看看到底谁强谁弱。那我们从这个写作的方式也明显可以看出来,其实这篇文章更主要的卖点是这个数据集,所以说他把数据集放到了摘要的第一段,模型放到了第二段。那具体来说,这个新提出的数据集kinetics,它有 400 类,也就是我们常说的 K400 数据集,每一类都有超过 400 个这个视频段落。这里的 CLIP 的意思其实就是说一小段视频,比如说 K400 这个数据集,它所有的视频都只有 10 秒这么长,都是把对应的这个人体的动作从视频里精准地抠出来了,所以说是一个标注得非常仔细,也标注得非常好的一个数据集。我们一般就把这种五六秒或者十几秒的一个视频段落,那就叫做一个 video clip。然后作者接下来说,因为有了这个新数据集之后,他们就在现有的方法上都去重新测试了一下他们的结果。而且最重要的也就是他们最想卖的一个点其实是迁移学习,意思就是说在这个大数据集上预训练过的模型,到底能够在小规模的那些数据集上能有多大的提升?
那接下来第二段作者就讲了一下他们的对模型的改进,那主要来说他们就提出了一个双流的 inflated 3D 网络,这个网络是来自于 2D 网络的这种inflation,也就这种扩张。那至于为什么叫扩张,其实作者这里的意思是说他把已经一个调好的网络,比如说 Resnet 直接拿过来,然后把里面所有的这种 3 * 3 的kernel,或者说 3 * 3 的这种 pooling 全都变成 3 * 3 * 3,然后一个针对视频理解的网络结构就生成了,这样一个好处,就是说你不用再费尽心思去设计一个专门针对视频理解的网络架构了。毕竟在 2017 年之前,大家已经做了很多这种模型上的改进。从 Alex net 一路到 VGG Inception net 到Resnet,已经得出了很多很有用的结论,比如说堆叠这种 3 * 3 的 kernel 就很好,比如说分类的,最后不需要用这种全链接层。还有就是一个网络该被分成几个阶段,每个阶段里又该包含有多少个 residual block 这些其实之前的论文在 2D 的这个网络上已经做过很多的消融实验了,那既然有这么多前任的工作,那最好的方式或者说最简单的方式自然就是说把这些网络能够直接用到视频里来,那毕竟视频也就是一帧一帧的,这个视频帧堆叠起来的,跟图片也没有太大的区别。如果你非要从头去设计这个视频网络的话,那所有之前的那些问题你都得考虑你到底选用什么样的 kernel size,你到底整个网络选取几个阶段,每个阶段要用多少个block,而且现在又多了一个时间的维度,那这个消融实验的量是非常巨大的。所以说如果能从一个 2D 的网络直接inflate,就是直接扩充成一个 3D 网络,是一个最简单最有效的方法,而且他们这里甚至后面通过一种叫 bootstrapping 的方法,能够把 2D 网络的这个预训练参数拿来做一个 3D 网络的初始化,就省得从头训练了。这个 inflation 的技巧一直到现在其实都有用,比如说Timesformer,也就是把 vision Transformer 给inflict。然后最后作者用这个实验数据说话,就是在我们这个大规模的 connect 数据集上预训练过之后,我们的这个双流 I3D 网络能在 HMDB 上达到 80 的这个效果, UCF 上达到 98 的这个效果。这样只看数字的话,可能读者还并不能理解这个效果有多么的惊人,但如果我们拿之前的这些数字来做对比的话,比如说 HMDB 51 之前最好的结果可能就在 70 左右,那 S3D 的话相当于是直接拔高了 10 个点,因为这个 HMDB 这个数据集也比较难,所以其实这种 80 的效果就已经很好了。一直到现在也没有太多的工作再去做这个数据集了,因为 80 就基本做到天花板了。同样的道理,在 UCF 101 这个数据集上,那 98 自然也是一个比较高的结果,再刷也无非就是刷到100%,其实已经没有意义了。所以说 I3D 这篇论文一出,其实就给 UCF 101 和 HMDB 51 这两个数据集判了死刑,基本接下来大家就只能用这两个数据集做一种辅助实验了,或者说把它当做一个迁移学习的标准,或者说最近自监督学习特征的一个衡量标准,而不能再单独的去作为一个有监督学习下的衡量标准,
引言
那接下来我们就一起来看一下引言部分,其实跟摘要讲得非常类似了,所以我们就快速过一下。作者上来先说 Imagenet 这个数据集所带来的好处,不光是说可以训练深度神经网络最主要的而且是一个最想不到的好处是说在这种大规模的数据集上进行预训练之后,我们可以直接从这个网络里抽特征。比如说之前常见的做法就是把 FC 6 或者 FC 7 就是倒数那两层的这个全连接特征抽出来,可以非常有效地迁移到其他任务上去。像之前这两篇论文里展示的一样,在 Pascal VOC 分类或者检测的任务上都能取得很好的效果,所以所有者这里写的就是说从 Imagenet 训练这种网络结构开始深度学习,慢慢地逐渐地就把别的这些任务也全都控制了,比如比如说分割深度估计、姿态估计和动作分类这些任务。然后作者接下来就说,但是在视频领域,其实这种先在大规模数据集上去做预训练,然后迁移到小数据集上,这种范式其实还没有被证实有效,因为视频领域还没有这么一个好用的或者说可用的大规模数据集,目前有的数据集其实就只有1万个视频左右,相对于其他任务或者说其他领域来说,这个数据量实在是太小了。所以说作者接下来自然而然的就提出了他们新的这个数据集,也就是 Kinetics 数据集,他说他们的数据集远比之前的这两个数据集要大多。比如说最开始第一版的这个 kennexy 数据集,也就是 K400 就有 400 个类别,然后每一个类别都有超过 400 个样本,而且每一个样本都是来自于一个独一无二的这个 YouTube 视频,所以说它的多样性是非常好的。而像之前的一些视频数据集,哪怕是 UCF 101,它里面有很多这种视频的小片段,也是从一个大视频里去截取出来的。
那构建一个新的数据集之后,自然而然第一步就是把之前最好用或者说最流行的方法都拿来 Benchmark 一下,这样一是可以看一下之前的那些方法有哪些优点,有哪些缺点,它们之间有哪些相似或者不同的特性,那第二点也是可以验证一下这个新数据集的有效性,因为有的时候这个新收集出来的数据集可能会有一些它自身自带的特性,或者我们说的这种 BIAS 导致它会过于简单或者说过于难。那这两种都是我们不愿意看到的现象,因为如果过于简单或者过于难的话,都会导致没有人真正地会去用这个数据集,那构建这个数据集的意义也就消失了。那好在这个 K400 数据集构建的还是不错的,所以说一直到今天大家还都在用,还都在它之上去做这种互相的比较。而在当时这篇论文里,作者主要就比较了三种之前比较流行的方式,一种就是卷积神经网络加LSTM,一种就是 3D 卷积神经网络,一种就是双流神经网络,其实也就代表了这种在视频领域,大家是如何通过不同的方式去使用这种视频里自带的这种时序信息的。因为视频跟图片相比,它就是多了一个这个时间的维度,所以说它主要的区别也就体现在你如何去利用好这个时序这样的信息。
所以说 LSTM 3D 神经网络,或者说双流使用光流是 3 种最常见的柳派,那作者这里就把它都拿来了测试了一下,然后发现这种先大规模的预训练,然后再在小数据集上做微调的时候,这几个网络的结果都表现得参差不齐,而且有的时候提升也不是很显著。这位作者取其精华弃其糟粕,最后就提出了他们的这个 toolstream I3D 网络 I 3D 本身就像我之前说的,就是把所有的那种 2D kernel 都变成了这种 3D 的kernel, 3 * 3 变成 3 * 3 * 3,包括这个pooling层也是从二维变成了三维,所以就非常直接地得到了一个非常深而且设计得应该不错的一个视频理解的网络。之所以他们还要用双流,是因为他们发现即使用了 3D 神经网络,这种对局部运动讯息的掌控神经网络学得还是不够好,加上双流之后还是能提高特别多的效果,才能得到我们之前在 UCF 101 上这种 98 的准确率。所以作者其实也就是把双流网络和 3D 神经网络给合到一起了。
然后作者最后说了一下,说在这篇文章里他们已经不去跟这种传统的方式去做比较了,比如说之前用得特别好的那种 back official words 的这种表示,在 1516 年的时候还是非常流行的,但是这篇文章就已经不去跟它比了。那作者也说因为 K400 这个数据集是公开的,所以说大家如果感兴趣,你们大家可以自己去试。
方法
那接下来我们一起来看这个主要的方法部分,一共有 5 节,前三节主要是回顾之前的方法,后面两节先是讲了一下他们提出的方法到底长什么样,以及他们具体的这个实践细节。
1 视频领域的网络有哪些选择
作者上来先说在这个 2D 的这个图像分类领域,其实已经有主导的这种神经网络结构了,之前可能是 VGG Inception,那现在是Resnet,大家都会去用,也没有什么意义,但是在视频领域到 2017 年的时候,大家还没有一个定论。但其实好笑的是,到现在为止,视频领域里也没有一个定论,到底用 2D3D 还是甚至去使用Transformer,也还没有一个固定的结论。然后当时来看就有几种选择,像刚才说过的,
- 1、要么就是一个纯 2D 的网络,后面再接上一些操作,比如说 LSTM 层,从而去做这种时间上的建模。
- 2、或者就是不论你用 2D 网络还是 3D 网络,我都给你配备上这个光流,那一旦有光流之后,你就有了这种时间上或者这种局部的运动信息的建模能力。
- 3、再或者那就是最简单最粗暴的方式,直接就上这个 3D 网络,直接学这种 special temporal 的时空特征,
那在作者这里就分别用 2. 12. 2 和 2. 3 这三个章节去描述了一下之前的这三种方式。
2 经过对比,I3D网络的提出是如何被提出的
最后再经过大量的对比,作者就提出了他们自己的这个 toolstream inflated 3D 网络,那这里有两个关键词,一个就是双流,另外一个就是这个inflated。那之所以为什么要用inflated,作者这里说因为之前的这种 3D 网络,因为它的参数量实在是过于巨大,但是你又没有这个合适的或者足够的这个视频数据去预训练它,最后就导致你的这个 3D 网络不能太深。那像 ICCV 15 的时候就有一个非常著名的工作叫C3D,它是比较浅的,只有八层,而且效果也比较一般,当时是没有超过双流网络的结果的,所以作者这里在使用了 inflated 这个操作之后,就可以直接启用这些特别深的最近特别好的网络。而且在使用了这些 2D 网络预训练的参数作为初始化之后, I3D 网络也不需要很多的视频数据去训练了,这就是使用 inflated 好处。
那至于为什么使用双流,那其实就是简单的 a 加 b 了,所以作者这里也不过多复述,就简单的直接说,我们发现这个双流的使用还是有效的,所以我们就用了。
具体来说,本文使用的网络结构是从 Inception v one 经过一些改造得来的,为什么使用 Inception 而不是使用Resnet,是因为当时在 16 年的时候也有很多论文做过这个消融实验,他们发现至少在当时的这个视频分类任务上, Inception 的结构比 Resnet 稍微好一点,所以说在这篇论文里,作者也就直接从 Inception 开始了。但是因为 Resnet 实在是太统治地位了,所以说在一年之后,在 non local 那篇论文里,作者就已经把 I3D 网络用 Resnet 进行实现了。然后自从那个时候开始,大家之后再说 I3D 其实很多时候也指的是 Resnet 基础的 I3D 网络,而不再是使用 Inception 的这个 I3D 网络。
3 看图过方法:LSTM、3D-convnet、two-stream、3D-Fused two-stream、two-stream 3D-convnet
那接下来我们就不看文字了,我们可以只看这个图2,就能快速地把之前的方法都过一遍,也能非常清楚地看到每个方法和每个方法之间的不同,以及本文中的这个 toolstream I3D 网络到底是如何从之前的方法上发展而来的?
图2a
那首先在二点儿一章节,作者就讲了这个卷积神经网络后面儿跟一个 LSTM 这种方式,其实还是把一个视频更多的看成了是一个图像分类的问题。因为从图片一,也就是从视频帧一开始一直往后走 23456 一直到k,对于这个视频来说,其实它是一张图片去过这个卷积神经网络的,也就是说整个这个抽特征的过程是完全分开的。然后一旦你抽完了所有的这个特征之后,你把这个特征全部扔给一个 LSTM 网络,因为 LSTM 是可以进行这种时序建模的,所以它就可以把每个时间戳上的这个特征糅合起来,看看到底整个视频在讲什么?然后经过一些计算,我们把最后一个时间戳上出来的那个结果后面加上一个全连接层,然后就去做这种分类任务了。那这种方式其实是一种非常合理的方式,大家之前也都是这么想的,就是图像每帧都分开做,然后用一个 LSTM 这种网络去模拟这个时序信息。但可惜这种方法在之前,至少这些数据集上它的表现并不是非常好。很快这种方式就被抛弃了,基本留下来的就是两个主流的框架,一个就是 2 里面讲的这个 3D 卷 d 神经网络,另外一个就是这种双流神经网,
图2b
那 3D 卷积神经网络其实非常的暴力了,那就是把这个视频 p 成一个一个的这个视频段,然后每一个视频段里有从 1 到 k 这么多个图片,然后他就把这么多个图片当成一个volume,整个就把这个视频扔给你这个网络了。那也就意味着你的这个网络能够进行时空学习。就是说你的卷积核必须是三维的了,你不光要处理这个二维上的这个图像,你还要处理额外的这个时间纬度,所以也就是我们说的这个 3 * 3 * 3,那这就会导致你的参数量变得很大,因为你相当于所有的这个参数层都多了一个维度,那之前在这个视频数据集少的情况下,它就不是很好训练,那效果也比较一般。但是在这篇论文里,作者说在我给你这么多数据之后,它的这个威力很有可能就显现出来了,而事实上也确实如此,他最后提出的这个 toolstream 的这个 I3D 网络其实就是一个 3D 的神经网络。但是在这个 图B 里就是说把这一个视频小段扔给一个 3D 神经网络,然后这 3D 神经网络就经过一些 3D com,然后 3D pulling,然后逐渐的做这些操作,然后最后也是返回给你一个特征,然后你在这个特征之上去做一个全连接层,最后做分类就可以。
图2c
然后第三种方案就是我们上回刚讲过的这个双流网络,双流网络的意思就是说如果你不想用 LCM 去做这种时序模拟,你也不想去训一个 3D 网络去做这种时空学习,那我们怎么能够去抓住这种时序信息呢?那一个非常简单的方式就是说我提前先帮你把光流抽取好。光流我们上次也讲过,是指光的流动,也就是指这个视频里每个物体的这个运动的轨迹,它自身就蕴含了非常准确而且非常强大的物体运动的信息在里面,所以它变相的相当于是一种视频里时序信息的一个特征表示。所以我现在只需要先从这个视频里头去抽取这个光流图,然后只需要学习一个映射,就是从这个光流到最后的这个动作之间的这个映射关系就可以了。而这个卷积神经网络本身其实并不需要知道这个运动是怎么发生的,也不需要去有这种时序模拟建模的能力,这些就全交给光流去做了,所以这个网络非常的简单,而且因为它对模型的要求也比较低,所以它也比较好训练,它的结果也非常的高。所以在 15 16 年的时候,这个双流网络是完全压着这个 3D 神经网络打的,基本上视频领域在 1516 年的时候, 90% 的工作都是基于双流网络。那具体点儿来说,这个双流神经网络就是有两个卷积神经网络,都是 2D 的,不是 3D 的。左边这个网络叫做空间流,它的输入是一帧或者多帧,这个视频帧它就主要负责学习这个场景信息,然后右边这一路叫做时间流,它的输入是光流图像,它主要就是为了学习这个物体的这个运动信息,然后这两个神经网络最后都会给一个特征,然后做一个分类的结果。然后当你有这个分类结果之后,你在这块做这个 late Fusion,最后就把这两个 Logis 加权平均一下就可以了。
其实到这儿也就是把之前最火热的三个方向,l,s,t,m,3,d、c、n、 n 和这个双流网络说完了。 LCM 基本是没什么后续工作,所以说主要就是 b 和c。
图2d = b+c
所以在 CVPR 2016 的时候,其实还有一篇论文就有机的把这个 b 和 c 结合到了一起,也就是作者这里说的这个 d 的结构 3D fused to stream 它是怎么做的?它就是说我刚开始是按双流网络的做法做,就是我这边的输入是图像一个2d cnn,然后我这块儿也是一个2d cnn,然后输入是光流,所以跟这个 c 有部分是完全一样的。但是有些研究者就觉得这个 c 里面的这个最后取了个加权平均实在是太简单了,很有可能不利于抓住这个视频里特别复杂的这种场景的变换。所以说 CVPR 16 的那篇文章就把这个最后的加权平均用一个比较小的 3D 卷积神经网络替代。那如果把之前的这种方式叫做 late Fusion 的话,也就是说在 Logic 层面去融合这个时间流和空间流的结果,那 d 这种方式就是叫 early Fusion,就是在还没出结果的时候,我就把你这个两个特征先融合在一起,然后用一个 3D 卷积神经网络去处理一下,然后最后直接得到一个分类结果。当然了,你这里这个 3 d c n 也是可以用 LSTM 替代的,对吧?但是因为效果不好,所以说大家接下来其实都是用这个 3 d c n 做的,后续还有一些工作顺着这个 d 又做了一些研究,就是到底应该刚开始用2D,后面用3D,还是刚开始用 3D 后面用 2D 呢?因为毕竟 2D 和 3D 的这个计算复杂度和训练难度都是不一样的,所以如何去找到这么一个好的折中的网络设计方案,其实也是很关键。那后续的结果一般证明就是这种前面用 2 d c n,后面用 3 d c n 的方式最好又好训练,而且结果也好。
图2e
那到这儿其实这个 ABCD 都是之前的方法,作者在他们自己的这个 case 把数据集上进行复现,得到结果,然后反复对比之后,作者也自己有一些心得,所以于是就提出了他们的这个第五种模型设计方案,也就是这篇文章提出的双流 I3D 网络。作者就觉得在只要有足够多的数据情况下,其实用这个 3 d c n 明显是要比 2 d c n 的效果是要好的。但是 3 d c n 也不是万能的,它还是有一些东西学不到,所以如果你用光流去帮助它一下,效果会更好。于是作者就也还是采取了双流的这种网络,但是每一个分支它都用的是 3D 卷积神经网络,那既然你每一支都已经是 3D 卷积神经网络了,你也就不存在什么 early Fusion 或者 late Fusion 了,所以说就没有必要再在后面再加一个 3 d c n n 去做这种Fusion,那于是他们就直接也是加权平均,最后出结果就可以了。
双流I3D网络的具体细节
那看完图2,其实大家已经从整体上对视频理解过去的一些网络结构有了解,而且也大概知道 to stream S3D 网络是怎么做的了。接下来就是一些具体的细节,作者这里分了四个部分,第一个部分就是讲如何去inflate,第二部分就是讲如何去 boot strap 这个模型的参数,第三部分就是如何去控制这个池化层,从而导致这个感受野是一个合适的范围。最后就是如何把一个 3D 网络变成一个双流的 3D 网络。
第一步就是如何做这个inflate
那首先我们来看第一步就是如何做这个inflate,那这一步肯定是很关键的,因为它这个模型的名称就是从这个来的,对吧? I3D inflated 3D 网络,那具体这是一个什么操作?其实就像我们刚才说的一样,它就是把一个 2D 网络很直接暴力的变成了一个 3D 网络。那举个例子的话,就拿 rise 50 来说, rise 50 它刚开始有一个 conv 层,然后接一个 Max pulling,然后后面有四个阶段,分别是 rise R345,然后每个阶段里分别有 346 三个 residual block。那怎么把这一个 2D rise 50 变成一个 3D rise 50,其实很简单,就是说整体的架构什么呢?都保持不变,就是你只要遇到一个 2D 的卷积kernel,你就把它变成一个 3D 的kernel。你只要遇到一个 2D 的 pulling 层,你就把它变成一个 3D 的 pulling 层就好了。一个 residual block 还是 conv bn Relu,然后还是那么多的 residual block,还是分了四个阶段,这些通通都不变,这个就叫inflate。那这个的好处我们也说了很多遍了,因为你就不用自己再去设计网络了,所有 2D 的那些设计好的网络你都可以直接用,那以后设计好的那些厉害的 2D 网络,你也可以用同样的方式直接拿到 3D 里来用。所以说像在之后的这个 non local network 里,作者也是用这种方式去把 RD 的网络 inflate 成 3D 网络的。然后在最新的 times former 里也是把 VIt 从 2D inflate 到 3D 了,一直到现在最新的这个 video swing Transformer CVPRR 刚接收的工作,它也是把一个 swing Transformer 从 2D 的 inflate 到 3D 了。
第二步如何能更好地把这个 3D 网络训练起来——bootstrapping
技术都是这么一个技术,那得到一个合理的做视频理解的网络结构,其实只是第一步,接下来更难的问题其实是如何能更好地把这个 3D 网络训练起来,这也就是作者接下来要讲的第二步,这个bootstrapping。 boot strapping 字面上的意思是引导,也就是说当你已经有一个什么东西之后,你在这个东西之上再去做一些改进,从而让这个东西变得更好。那在这里它的意思是说你如何能从一个 2D Imagenet 已经训练好的一个模型出发,用它去初始化一个 3D 模型,然后在这个初始化好的 3D 模型上继续去做训练,然后让它变得更好。那至于怎么做,其实还是比较有难度的,因为我们知道如果想用一个已经预训练好的参数拿过来做初始化,那最简单或者最好来说这两个网络应该是一模一样的。那这样呢?我们就可以直接把那个预训练好的参数搬过来就可以了。但是我现在预训练好的网络是一个 2D 的网络,但是我即将要训练,而且最后要用的网络是一个 3D 网络,虽然它的这个 Meta 结构,也就是说整体的这个架构是一样的,但是具体到每一步操作它都是不一样的。那到底该如何用一个 2D 预训练好的模型去初始化一个 3D 模型?作者这里就想了一个比较巧妙的方法,他的这个想法其实有可能也来自于平时的我们一个操作,那就是说平时我们在做这种用别的预训练模型去初始化我们自己的模型的时候,经常会做这么一个操作去验证我们初始化的对不对。那就是说给定同样的输入,我用这个输入在原来的那个模型上跑一遍,然后我们再在我们初始化后的这个模型上再跑一遍,那它俩得到的输出按道理来说应该是完全一样的,因为如果你的参数搬运的是正确的话,你这两个模型是完全对等的,那如果是同样的输入同样的模型,那你的输出就应该相等。那作者这里就受这个启发,所以就想出来了这么一个方式,他用同样一张图片,然后反复的这个复制粘贴,最后变成了一个视频,也就是说这个视频里全都是同样的视频帧,如果你去播放它,那其实是没有任何的变化的。这也就是为什么作者说它其实是一个 BORING video,就非常无聊的一个视频了。然后如果我以一种什么方式把这个 2D 已经训练好的网络参数用来初始化这个 3D 模型,最后我能让他俩的这个输出一致,那其实就能从侧面验证我这个 3D 模型是从这个 2D 模型初始化而来的,具体的做法就是作者把所有的这些 2D filter 全都在时间的这个维度上也复制粘贴了 n 次,就跟这个输入视频就对应起来了。也就是说原来你是一张图片对应一个 2D 神经网络,那假如说输入是x,这个网络是 w 的话,那你最后就得到了一个输出,这是 x 乘以w,那现在你的输入变成了一个视频,一个无聊的视频,也就是里面有 n 个x。然后你的参数这个 3D 神经网络也是一个 w 乘以n,那你最后就相当于得到了 n 份儿的这个 w 乘x,那如果你想让它俩的这个输出保持一致,那你就要做一些这个rescaling,也就是说在所有的这个 RD filter 上都除以这个n,那这样 n 倍的 w 乘 x 除以 n 之后,就又变成了 w 乘x,也就是说最后的这个输出上面图像的输出也是 w 乘x,下面的视频的输出还是 w 乘x。那这样就保证了,不论你现在是在网络的哪一层,不论你的输入是图片还是视频,你对应通过一个 2D 网络和 3D 网络之后得到的输出都是一样的,那这样再往后面的层传的时候,你后面的层也是能接得住这个输入的,因为它是完全一样的,所以你可以用预训练好的这个参数来进一步地做计算。
代码理解把一个 2D 的预训练模型用来初始化一个 3D 模型
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)
if self.pretrained_base and not self.pretrained:
//先去把 2D 网络的这个预训练参数下载下来,比如说要么是个 rise 50,要么是个 rise net 101
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))
weights2d = resnet2d.collect_params()
//通过这个 collect parameter 这个函数就可以得到所有这个 2D 网络的参数,就都存在 weights 2D 的这个变量里了
if self.nonlocal_cfg is None:
weights3d = self.collect_params()
//然后我们再把我们刚建立的这个 3D 网络也去 collect 一下parameters,就得到了这个 weights3D,那这个 3D 网络所有的模型参数就都存在这个 weights 3D 的变量里了
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)
weights3d = self.collect_params(init_patterns)
assert len(weights2d.keys()) == len(weights3d.keys()), 'Number of parameters should be same.'
//这里做了一个 assert 操作,因为 2D 网络和 3D 网络它的结构应该是一样的,也就是说它的层数应该是一样的,所以说这个 waits 2D 的长度和这个 waits 3D 的长度必须是一样的。
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 key2d, key3d in dict_transform.items():
//那接下来就非常直接了,就是做一个 for 循环,在这个 for 循环里,我们就一步一步把每一层的这个 2D 的参数就转移给这个 3D 参数
if 'conv' in key3d:
temporal_dim = weights3d[key3d].shape[2]
temporal_2d = nd.expand_dims(weights2d[key2d].data(), axis=2)
inflated_2d = nd.broadcast_to(temporal_2d, shape=[0, 0, temporal_dim, 0, 0]) / temporal_dim
//那至于哪一句话是在做这个 Boost drapping,其实就是这一行 585 行这个 inflate 2 d,也就是在你知道这个时间维度上的值。
//比如说论文里说的是 n 之后,我们先把 2D 的参数复制粘贴 n 次,然后再 rescale 一下,也就是除以n,这样 Boost drapping 这步操作就完成了。
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.'
那说了这么多,可能还是比较抽象,大家可能还是没太理解为什么可以这样,那就把一个 2D 的预训练模型用来初始化一个 3D 模型了。那往往当看文字看不懂的时候,我们就用代码来说话,在这里其实就一行代码就解决了这个事情。那这里就用我们 groundcivilly 的一个例子,就是 I3D Resnet 这个文件来看一下具体的这个inflate,还有 Boost draft 这个操作是怎么用代码实现的。那具体的实现就是这个 init with 这个函数,从这个 539 行开始。那最开始就是你先去把 2D 网络的这个预训练参数下载下来,比如说要么是个 rise 50,要么是个 rise net 101,然后你通过这个 collect parameter 这个函数就可以得到,所有这个 2D 网络的参数就都存在 with 2D 的这个变量里了。然后我们再把我们刚建立的这个 3D 网络也去 collect 一下parameters,就得到了这个 wait 3D,那这个 3D 网络所有的模型参数就都存在这个 weights 3D 的变量里了。这里做了一个 assert 操作,因为 2D 网络和 3D 网络它的结构应该是一样的,也就是说它的层数应该是一样的,所以说这个 waits 2D 的长度和这个 waits 3D 的长度必须是一样的。那接下来就非常直接了,就是做一个 for 循环,在这个 for 循环里,我们就一步一步把每一层的这个 2D 的参数就转移给这个 3D 参数,那至于哪一句话是在做这个 Boost drapping,其实就是这一行 585 行这个 inflate r d,也就是在你知道这个时间维度上的值。比如说论文里说的是 n 之后,我们先把 2D 的参数复制粘贴 n 次,然后再 rescale 一下,也就是除以n,这样 Boost drapping 这步操作就完成了。总之就这么一个 init with 的函数,但是属于一个非常用的技巧,所以说感兴趣的同学最好跑一下这个代码,就能对 Inflict 和 Boost Drapping 这两个操作有更深入的了解。
实验细节
那说完了 inflate 和 Boost drapping,其实这篇文章的精华就已经讲完了,因为毕竟名字就是I3D。接下来就是一些实验上的细节了,我们直接来看一下图 3 和下面的这个表一就可以了。那首先我们看这个图 3 的左边,它就是一个标准的 inception V1 的结构,只不过现在是被 inflate 过了。
那首先就是一个视频进来,经过一个 7 * 7 * 7 的conv,然后它的 stride 是2,那这个其实在 Inception V1 或者 Resnet 里,就是刚开始是一个 7 * 7 的conv,现在只不过是变成 3D 了。
然后接下来就会过一层这个 Max pulling,那在 Max Pulling 这儿作者是做了一些改动的,那按道理来说,原来的 Max Pulling 是 3 * 3,然后 stride 是 2 * 2,那如果就按文章中说的这种 inflate 方式来说,它应该变成 3 * 3 * 3,那这个 stride 也应该变成222,但事实上作者这里发现这个时间维度上最好不要做这种下采样,而事实上在最近几年的文章中,大家也都发现这个了,甚至从 slow fast 开始,基本大家在这个时间维度上是完全不做任何的下采样。比如说你输入是 64 帧,那你输出的时候还是 64 帧,因为本来 64 帧对应的时间维度就已经很短了,可能就只有 2 秒、 3 秒这么长,所以说对于描述一个动作来说,我们就不要再去做这种下采样。那 SND 的作者在当时其实也发现了这么一个现象,那所以说在刚开始的时候,它做了 1 * 3 * 3 的这种pooling,而且它的 stride 也是122
然后接下来又做了两次抗武
又做了一次铺令,然后在这个铺令里依旧是做的 1 * 3 * 3, stride 是122,就是在时间维度上还是没有做下采样,它只是在后面的几个阶段做了一些下采样。比如说这里这个 Max pool 是 3 * 3 * 3 的,而且 strike 的也都是2,这里也一样,最后这里也一样。
那至于中间的这些 inception MODULE,其实它就画在这个 TO 3 的右边了,那这个 inception MODULE 就跟之前的 inception MODULE 是完全一致的,只不过是把所有的 1 * 1 就变成 1 * 1 * 1,3 * 3 就变成 3 * 3 * 3 而已,别的都没有变化,所以说整体上来看,它的改动还是非常小的。
总结一下之前的这五种形式,以及他们训练和测试的时候,这个输入输出长什么样,模型具体有多大
那讲完了本文提出的I3D,在我们汇报实验结果之前,我们先大概总结一下之前的这五种形式,以及他们训练和测试的时候,这个输入输出长什么样,模型具体有多大,这样能对图 2 里的这五种模型结构有一个更清晰的了解。
那首先我们来看一下表一里这个模型的大小,我们一眼就可以看出来这个 3D 的这个卷积神经网络,它的这个模型参数是非常巨大,它有八十兆,比别的都大很多。那如果只是用一个 2D 的卷积神经网络,然后后面接一个这个LSTM,或者用双流网络这种形式的话,那其实网络大小就很小,就只有 9 兆和 12 兆这么大。所以这也就能解释之前在 1516 年的时候,大家为什么都去用这个双流网络,因为它不仅效果好,而且模型小,大家都玩得动。
然后我们来看一下本文提出的这个 toolstream I3D,它大概大小是 25 兆,也不算大,所以还是比较经济实惠,
那接下来我们就来看一下训练的时候这个输入长什么样。
1、那对于这个 Coonet 加上 LSTM 来说,它的输入是 25 帧的这个视频帧,那为什么它的时间跨度是 5 秒?因为这里所有的视频它的帧率都是每秒 25 帧。
2、然后对于 LSTM 这种方式来说,作者是每隔 5 帧去选一帧,那这样 1 秒就是 5 帧,那你选 25 帧的话就是 5 秒。
3、那对于 3D 卷积神经网络来说,因为它必须是要这种连续的帧输入,所以说它的输入如果是 16 帧的话,那其实就不到一秒钟,因为一秒是 25 帧,那它只有 16 帧,所以大概就是 0. 64 秒。
4、那对于双流网络来说,我们上次也讲过了,我们是先任选一帧,然后用接下来的这 10 帧去算一下这 10 个光流图,所以说它的时间跨度就 11 帧,那 11 帧其实是连半秒都不到的,只有 0. 4 秒。
5、对于这个 3D fuse 的工作来说,它是用了 5 个 RGB 帧,用了 50 个这个光流图像,所以它的跨度就比较长了,那一秒 25 帧的话, 50 个 flow 就相当于是你是 2 秒。
6、那最后对于他们提出的这个双流 I3D 模型来说,因为他们用的是 64 帧和 64 个光流图像,所以说它们是 2. 56 秒,那从这个意义上来说,它的这个输入最大,但同时它涉及的这个时间跨度也最长,对于视频理解来说算是一个好处。
那在测试的时候,其实这几种方式都差不多了,因为测试的时候为了尽量的公平去比较,所以说最好是把整个视频都囊括在内的,那对于 K400 数据集来说,每个视频都是 10 秒钟,所以说这里面它也都是 10 秒。至于为什么这个 3D 网络是 9. 6 秒,是因为它每次的输入都是 16 帧,那对于一个 250 帧的视频来说,它除不尽,所以最后它也就只能覆盖 240 个这个视频帧,所以就是 9. 6 秒。
实验结果
那讲完了方法部分,那最后我们就来一起看一下实验结果的话,作者就先在 UCF 101、 HMDB 51 和 k Nike 400 的数据集上分别去做了一下训练和测试,然后发现双流 S3D 网络是这五个结构中表现最好的。然后又用了一个表格去证明,如果我这个视频网络只用 K400 这个数据集去预训练,而不需要Imagenet,它的效果也是不错的。然后作者又在这个表格里去讲了一下,到底该怎么样在小数据集上去做微调,去做这种迁移学习,到底应不应该把这个骨干网络锁住,还是说整个网络一起来微调?最后作者就列了一个大表格,就把之前的方法全都列出来,然后最后证明双流 I3D 网络的效果最好,远远超过了之前最好方法的表现。我当时其实读到最后这个表格里的数字的时候也是惊呆了,瞬间觉得手头 UCF 101 和 HMDB 51 的实验都白做了。
那接下来我们就来看实验结果。首先我们看这个表 2 里就是对比一下这五个网络结构在这三个数据集上的效果到底如何?首先我们可以很直接的看出,因为黑体了,所以说这个双流 S3D 的网络在所有的这个设置下,它都能达到最好的效果。其次我们也发现就是 LSTM 和这个 3D 卷积神经网络,它的这个效果普遍都比较差,是完全没办法跟这个双流网络的结果去比的。
另外还有一个比较有意思的观察,就是不论你这个时间流比空间流的效果好还是坏,那最后你把这两只用 late Fusion 的方式结合起来以后,它的效果都能得到大幅提升,这就说明了光流始终对这个视频理解是有帮助的。这也就是为什么作者在这篇文章里,即使已经用了一个 3D 卷积神经网络,他还是想用光流,所以还是设计了一个双流I3D。
那因为提出 K400 这个数据集主要是用来做迁移学习的,所以说作者更关注这个就是迁移学习的效果,尤其是迁移到这个之前的 UCF 101 和 HMD 部 51 上的结果。在这个表 4 里,这个 original 这一栏其实就是说我在 UCF 101 上去训练,然后进行测试,完全不用K400,那大家可以看到这个结果还是普遍偏低的。然后后面两行这个 fixed 和 full fine TUNING 其实用了 K400 的,只不过这个 fix 是把骨干网络冻住了,然后 full fine TUNING 是整个 end to end 去训练的,整个网络的参数都可以改变,那我们可以看出来在这个 full fine tuning 的情况下的结果是最好的,这个倒也不奇怪,因为其实在之前双流网络就 2014 年的时候就已经证明这个整体微调的形式效果一般是会好一些的。
最后我们就来看一下这个跟其他最好的方法的一个比较,也是全文最重要的一个表格,读者买不买账,其实就看最后这个表格你的效果到底怎么样。那作者这里把整个表格分成了三部分,第一部分大概就是双流的一些形式,第二部分就是 3D 卷气神经网络,第三部分是他们自己提出的这个双流I3D。那我们可以看到在这个 3D 网络阶段,其实就 C3D 一个工作,还有之前的 deep video,而且 deep video 其实都不能算是一个纯 3D 的网络,也可以从侧面说明,在 S3D 这篇论文出来之前,其实 3D 神经网络是一点都不流行的,因为不好训练,而且效果我们也可以看到效果是非常的差。在别人的结果都是 80 多 90 多的情况下,竟然它是 60 多和80,那差的还是比较远。相比而言,双流的方法就好使得多,那双流网络之前的最好的方法也已经到 94 和 70 的这个水平了, 3D 差得也不是特别远。另外还有一个有意思的现象,就是之前在 1516 年的时候,大家有的时候还要跟传统的方法去比,或者把跟手工的特征进行结合,然后达到最好的效果。那像双流网络这边的方法,基本所有的论文都汇报了这个和 IDT 的特征结合的这个效果,而在 17 年之后,其实已经很少有人会这么做了,大家都是只跟深度学习的方法比,而且很少做这种和之前这种传统特征的融合了。那最后我们来看一下这个双流 I3D 的结果。作者先是单独展示了一下每一个分支的结果,如果只用视频帧的话有95,如果用光流的那一分支的话有 96. 7,那如果把它俩合在一起就有 98 h m d b 上就有80,效果是非常的好。然后为了验证作者之前在引言刚开始说的一个观点,就是说视频模型最好是在视频数据集上训练,而而且为了验证 K400 这个数据集足够大,可以足够用来做这个预训练,所以说作者这里只用 K400 去做这个预训练,而不用 image net 预训练的模型。那这里我们也可以看到,其实它对于这个效果跟上面这个差不多的 UCF 上稍微低了 0. 2 个点,但是 HMDB 又高了 0. 2 个点,所以基本是伯仲之间。那也就是自从有了 K400 这个数据集,这个 3D 网络的设计就有更大的设计空间了,因为意味着你可以从头开始训练,而不一定非要借助于一个 image net 预训练好的模型了。所以接下来像这种 RR 加 ED 网络, slow fast 模型, X3D 模型,它都是可以从头训练的,只不过训练的这个 epoch 会多一点,从 80 个或者 100 个 epoch 要增加到 200 个epoch,就是训练时间会长,但是你完全不需要一个 Imagenet 预训练模型。
结论
那最后我们来看一下这个文章的结论部分作者上来说,我们在引言的时候提出了一个问题,到底在视频领域这个迁移学习有没有用?那通过这篇文章一系列的实验,尤其是最后这张大表格,其实作者说实际上非常明显,这种在大规模的这个视频数据集上去做预训练完以后再去做迁移学习,这个得到的效果是非常好的。
但作者也比较谦虚,作者说这篇论文里我们只是探索了一下在 K400 上去做预训练,然后再在 UCF 101 和 HMDB 51 上去做了这种迁移学习,但这个只是视频分类,得到的结论也不一定准确。如果接下来能进一步验证,就是在 K400 上去做预训练,然后在其他视频任务上,比如说这种视频分割、视频物体检测,或者说光流计算上,在 K400 的预训练都能提供帮助的话,那这个数据集就太厉害了,而且这个影响力也会大不少。但作者这里说,因为时间和计算的关系,所以说这么多下游任务他就不一一去做了,最好是把这个数据集开放出来,大家可以一起来探索一下。
那除了做更多的这种下游任务之外,作者这里说他们在模型上的这个探索也没有做得非常的全面,比如说他们就没有考虑这种最近比较火热的这个 action tubes,或者这种 attention mechanism,那他没做也是好事儿,那这样别人就有更多的方向可以跟进了,所以其实紧接着很快在 CVPR 18 的时候, non local network 就出来了,其实就是在 I3D 的后面把 self attention 自注意力用了起来,而取得了更好的结果。所以说当你没有选定研究课题,或者说不知道接下来该做什么的时候,其实多看一下最近的一些论文,然后就看它的这个未来展望,或者它有什么东西没有做一般就可以了。因为这些方向或者这些课题一定是非常值得做的,所以说作者才会在最后的结论部分把它加进来,才会对它去进行这种展望。如果是不值一提的课题,作者根本就不会浪费空间在这写这个,当然有的时候这些课题可能也比较难,所以说作者没有精力,或者说也不知道该怎么做,所以把它写到了这个未来工作里。但是从研究方向上来说,往往写在结论里的这种未来工作都是非常好的研究方向。
总结
那最后又到了总结论文的时候了,像我们之前说的一样, I3D 这篇论文有两个贡献,一个是一个新的模型双流I3D,另外就是一个新的数据集 K400 数据集。之所以 SND 这篇论文这么的火,而且有这么多的人去跟进它,是因为它从两个方面上全面解决了这个训练的问题。
一方面就是说如果你没有数据,如果你想用这种 Imagenet 预训练好的模型参数,那好,你可以用我提出的这个 inflate 这个操作去把一个 2D 的网络变成 3D 的网络,这样你不仅不用设计 3D 网络,而且还可以直接用它预训练的模型参数去做这个初始化,最后微调的结果往往都会很好。所以我们之前也说在接下来的工作,比如说 P3D r 加 1D slow fast Timesformer, video swing Transformer,他们都有用到 inflate 和 Boost drapping,这个操作简单但是实用。
那另外一个方面就是说你不想用已有的这种 2D 框架,你想自己从头开始设计一个 3D 网络,你可以天马行空地去设计这个网络,那这个时候你就需要有一个大规模的视频数据集去预训练这个网络了。那这个时候 SMD 这篇论文也给了你这个选择,它提出的这个 K400 数据集就足够大,你可以在它上面重头训练一个网络,而不需要依赖于 Imagenet 预训练的参数。所以说接下来 slow fast, X3D 还有 MVIT 这些工作都是直接从头开始训练,只不过训练的这个 epoch 数多了一些,从 100 涨到 200 了。
所以说 S3D 这篇论文就从两个方面把所有的用户基本都考虑到了。那接下来如果你在做视频分类这个方向,不论你走哪条路,可能多多少少都要用到 k400这个数据集,或者多多少少都要用到 inflate 这个技巧。
那在我们下一期的这个视频串烧里面,我们也可以看到,自从有了 I3D 这篇论文,接下来对 3D 卷积神经网络的研究如雨后春笋一般全都冒了出来,双流网络瞬间就不香了。所以说从 17 年到 2020 年这三年, 3D 卷积神经网络基本霸占了整个视频理解领域,一直到 vision Transformer 的出现。而且也因为提出了 K400 这个数据集,所以说从 2017 年开始基本都会在 K400 这个数据集上去汇报,结果一直持续到今天。所以说 I3D 是视频分类领域里不可不读的一篇论文。