
【斯坦福CS231n 学习笔记7】Video Understanding
学习了视频理解相关的内容,将计算机视觉从2D图片推广到了视频。
前面的内容都在处理静态图像上的识别、检测、分割等问题,而这里主要是将视觉从单张图片扩展到了视频。
视频可以被视为增加了一个时间维度的图像序列,输入数据通常表示为一个 4D 张量,维度为 (或者 ),其中 是通道数, 是时间(帧数), 和 是空间分辨率。实际在深度学习框架中还会多一个 batch 维度 ,因此训练时常见的输入形状会变为 ,有些数据管线也会使用 。
视频的数据量相较于静态图片来说巨大,一段标准的高清视频可能每分钟占用 1.5 GB 到 10 GB 空间,直接原始视频输入到 GPU 显存显然是不显示的,因此需要将视频进行降采样。
常见的方法有:
早期的方法采取将视频视作一系列独立的图像的方式,使用标准的 2D CNN(例如在 ImageNet 上预训练的模型)来独立处理每一帧,获得每一帧的分类预测,最后对所有帧的预测结果去平均作为视频的分类结果。
这虽然忽略了帧之间的时序关系,导致其对于需要依靠运动区分的动作类别识别上效果并不好,但在某些背景是静态、动作变化不剧烈的场景下,是一个很好的对照基线。
Late Fusion主要是使用同一个的 2D CNN 分别处理相隔一定时间间隔的若干帧,直到网络的末端(全连接层)前才将特征向量展平为一个超长向量,然后输入给一个 MLP,输出类别分数 。此处不再是平均概率,而是允许 MLP 在拼接后的向量上学习一些“跨帧组合规则”,有利于模型更好地学习帧与帧之间对于动作识别的关联。但是由于跨帧交互只发生在最后的 MLP 中,融合发生得较晚,网络深层的空间感受野已经很大,丢失了底层的精细运动信息,难以捕捉局部的动态。
并且由于输入到 MLP 的维度是 , 一旦变大,参数量与计算量会随之膨胀,因此难以保持模型的轻量,导致 MLP 变得非常重。
为了解决拼接+MLP 太重的问题,可以将时空维度先汇聚掉,得到一个固定维度的 clip 表征。首先通过逐帧 2D CNN 得到 ,而后同时对 做平均,得到 ,再接一个线性分类层输出类别分数:
这个方法没有额外的复杂度,输出维度固定为 ,不需要担心 变化带来的参数爆炸,但是由于把时间和空间都平均掉之后,得到的是一种全局统计,失去了对时序结构(先后顺序、持续时间、局部运动轨迹)以及空间对应关系的表达能力。
为了获得底层的运动信息,网络需要能够从一开始就能看到多帧,并且在最早的低层特征阶段去对比帧情况的变化。
原始的输入是 ,Early Fusion 的第一步是将其 reshape 成 ,即将 帧的 RGB 通道直接在通道维度堆叠起来,然后再做一次标准的 2D 卷积,这样第一层卷积的每个输出通道,都可以同时线性组合来自不同时间帧的局部 patch,具备了比较帧的能力,从而对运动边缘、局部位移产生响应。
但是代价就是第一层卷积就破坏了时间结构,第一层能够学到一些短时的差分/速度线索,但是更高层无法逐步扩大时间感受野,也无法形成从局部运动到更长动作结构层级表达。模型所做的事情更像是在将多帧当作一个更厚的图像输入,而不是建模时序。
3D CNN 通过使用 3D 版本的卷积核与池化,让信息在网络中逐层融合,而不是一开始就压缩或者最后才汇聚。在 3D CNN 中,卷积操作都被扩展到了时间维度。
Lecture 10 使用了一个表格来对 Early Fusion、Late Fusion 和 3D CNN 进行对比:
对于 Late Fusion:其感受野在时间维度上一直都是 1,即网络在特征提取阶段并没有将不同的帧混在一起,直到最后做全局平均池化或者输入到 FC Layer 时时间维才将 20 帧全部汇聚到一起,时间信息最后才融合,且是一次性融合。
对于 Early Fusion:在第一层将 帧当作 个通道输入 Conv2D,因此感受野一直为 20,时间维度不会以可持续且可扩展的方式被处理,在一层被压缩后,后面没有一个显式的 轴让网络逐层推理。时间信息一开始就被一次性混合掉了。
对于 3D CNN:可以看到在时间维度上的感受野会像空间感受野一样逐渐扩大,这种逐层扩大时间范围的形式,可以让网络首先学习局部短时的运动模式,再在更深层的将短时模式组合成长时动作结构,在动作识别上更加贴近任务需求。
对于 Early Fusion,输入可以看作一个 3D 网格,每个点有 维特征,权重的形状等价于
其只会在 上滑动,因此输出变成
时间维度直接消失了,假设有一个从蓝到橙的变化出现在 clip 的早段和晚段,Early Fusion 的第一层在权重中对应的是不同的时间通道位置,模型需要为同一种运动模式在不同时间段出现而学习不同的参数组合。
这样导致了模型不具备时间平移不变性,同一组动作模式的特征并不一样。
而 3D 卷积核的权重为:
其会在 三个维度一起运动,于是输出保持 3D 网格:
只要学习到一个检测某种短时变化的卷积核,就可以在 clip 的任何时间位置复用,具备时间平移不变性。
C3D 是一个 3D CNN,几乎全程使用 conv 和 pooling,就像是图像分类任务中的 VGG 一样,依靠重复堆叠笑的卷积核来构造深层网络。网络在最开始时不急着在时间上降采样,而是先保留较高的时间分辨率,让早期层可以更充分地捕捉短时运动模式,到后面层数更深、语义更强时,再逐步将时间维压缩以获取更加抽象的动作表达。
但是由于只是单纯堆叠卷积核,每一层都引入了额外的时间计算与中间激活存储,计算量会快速膨胀。
人类在很多情况下并不需要清晰的纹理和外观细节,仅靠形体如何移动就能够判断发生了什么动作。动作类别的区分往往更加依赖时间结构与相对运动模式,而不是单帧外观。因此如果只用 RGB 帧进行训练,理论上网络也能够从像素变化中自己学习运动,但是这会把学习难度堆得很高,并且需要大量数据与算力。因此一个新的思想就是先把运动以某种形式表示出来,再用这种表示进行训练。
Optical flow 是一个在图像平面上的二维位移场,对每个像素位置 ,光流给出一个向量:
表示在相邻两帧之间,这个像素对应的点在图像平面上大致移动了多少(水平位移 ,垂直位移 )。因此光流图本质上是一个形状为 的张量(2 个通道分别存储 和 方向的位移量)。
Optical flow 的经典约束是亮度一致性,同一个物体表面上的点在短时间内发生移动时,其在图像上的亮度不会突然变化太大,因此可以写成:
做一阶泰勒展开得到光流约束方程:
在局部线性近似下,空间梯度 , 与时间梯度 对 , 形成一个线性约束,通过这个约束,假设知道图像在某一点处变量或变暗的速度 ,以及该点周围的纹理变化情况 ,那么就可以推断出该点的运动情况,于是可以将运动检测转化为梯度计算。
光流的常见可视化方式主要有两种:
由于人类视觉系统对外观和运动的处理机制不同,既然空间和时间性质差异巨大,不如分开处理。
在 Two-Stream Networks 中,输入视频流被分成空间流与时间流。
3D CNN 的感受野在时间维度上是有限的,它很擅长捕捉 5 秒以内的局部运动模式,但是如果两个运动模式之间相隔较远,短 Clip 的方式就会天然看不到它们之间的因果或顺序关系。
既然本质上是一个序列问题,那就使用 RNN/LSTM 上本来就有的处理序列的成熟工具来解决,CNN 负责抽局部视觉特征,用 RNN 负责更长时间跨度上的信息汇聚与记忆。
可以使用一串重复的 CNN 模块表示一种非常常见的工程流水线,将长视频切分成若干时间片段,对每个片段使用 2D CNN 或 3D CNN 提取一个特征向量/特征表示,这样就将原始像素序列转换为了特征序列。接着将这些局部特征交给循环网络,在每个时间步读取一段局部视觉特征,然后将特征压缩到隐藏状态中,以覆盖更长的时间跨度。
但是这种方法在实际工程中会导致显存开销过大,常见的做法是先将 CNN 在大数据上预训练好,然后将其作为固定的特征提取器,将抽好的特征序列用于训练 LSTM,即分阶段训练策略,牺牲了一部分端到端的灵活性以换取可训练性与可扩展性。
在 CNN 内部,每个输出单元只依赖于一个固定大小的时间窗口,因此较为擅长学习局部时序结构,但是时间覆盖范围有限,而 RNN 每个隐藏状态向量在定义上都可以依赖之前所有时间步的输入,因此更像是在建模全局时序结构,往往丢失空间结构且训练与推理存在顺序依赖。于是出现了 Recurrent Convolutional Network 来解决这个问题。
Recurrent Convolutional Network 的核心设计是整个网络都在处理而为特征图 ,而不是将每一帧压成一个向量再用于训练 RNN,这样可以避免空间结构被压缩,使模型的动作线索更容易表达。
在某一层、某一时刻的特征,依赖于两个来源:
但是使用长时序建模的方案还是离不开 RNNs 的通病:无法并行训练,对于长序列来说过慢。
在这个方案中,输入视频 clip 先经过一个 3D CNN 得到中间特征:
选择对时空特征做 attention 而非对原始像素,这样能够使 token 的语义更强,噪声更少,也更加符合将注意力作为一个可插拔模块的工程定位。
而后进一步将 Q/K/V 具体化为三条 的卷积分支,因为 的每个位置本质上是一个 维向量,通过 卷积对每个位置做同一套线性投影,能够保持在时空网格上共享参数。
先将 从 展平为二维矩阵:
而后计算 和 的注意力权重:
任何一个时空位置 都会对所有其他 分配权重,以捕捉跨帧的长程依赖、跨空间的远距离关联,而不再局限于卷积核的局部邻域。
在此之后再使用注意力权重对 Value 做全局加权,得到输出:
再使用 的卷积映射回原通道数:
最后再使用残差连接,将 Non-local block 作为增强项叠加在原特征上:
这能够让网络在优化时更加稳定,如果全局注意力学习不到有用的信息,至少能够退化回原本的 3D CNN 表征,如果能够学得到有用信息,就在原特征上补充跨时空的长程依赖信息。
可以在 3D CNN 的若干个阶段之间插入多个 non-local blocks,使得 backbone 在局部卷积建模之外,还能够周期性地进行一次全局信息重分配。但是这又引入了一个新问题,应该如何搭建一个高效的3D CNN 架构。
图像领域已经积累了大量优秀架构,如果每次做视频相关的模型都从零设计 3D 网络,不仅成本高,而且很难利用图像侧的预训练与经验。I3D 的核心思想就是拿一个 2D CNN 作为模板,将里面的每一个 2D 的算子一致地替换为 3D 版本。
在原本的网络中会有很多以下算子:
I3D 将其系统替换为
并且让特征在网络中保持为 的时空张量,直到逐层下采样后再聚合。
Inflating 并不是单纯的形状替换,还包括一个非常关键的初始化技巧。假设在图像网络中有一个 2D 卷积核 ,将其膨胀成 3D 卷积核之后,希望得到 ,I3D 的初始化就是将 2D 的权重沿时间维复制 次,然后除以 ,即
如果输入视频在时间上是常量,那么 3D 卷积的输出应当退化为 2D 卷积的出书,而复制并且除以 保证了退化一致性,时间维的加和不会将响应幅度放大 倍,输出尺度与原 2D 卷积相匹配。
对于视频而言,视频的 token 数量太大,如果将视频按照 patch 切分为 token,那么 token 数量约为
标准的自注意力的复杂度为 ,只要时间帧数或者分辨率增加,计算与显存就会迅速不可承受。
这里给出了三种应对策略:
通过将网络当作可微分函数,用反向传播拿到对输入的梯度,然后直接在输入空间中做梯度上升,合成一段最能够让某个类别得高分的输入,就能够获得一个可视化的图。
以 Two-Stream 为例,对输入的的目标做前向传播,固定目标类别,前向算出该类别的分数 ,然后对输入求梯度 ,然后更新输入:
这里的 可以是 RGB 输入,也可以是堆叠的光流。
当在光流输入上做合成时,如果完全不加约束,优化会产生很多不自然、噪声状的高频流场,因此需要在目标函数中加入一个让光流在空间上更加平滑的正则项:
通过调节 的大小能够得到两种模型偏好的运动证据:
视频分类任务中默认的输入是已经裁剪好的 clip,里面大概率是某个动作的核心过程,模型只需要输出一个类别就可以完成任务,Temporal Localization 要做的是,输入一段很长的未裁剪视频 ,输出若干个动作片段集合
其中 与 是动作开始与结束时间, 是动作类别, 是置信度,即不紧要判断是否存在某个动作,还需要输出其在时间轴上的边界,这会带来新难点:一是边界本身很模糊;二是背景片段占比通常很高,这会让数据的分布更不均衡,误检更加常见。
从建模的角度看,Temporal Localization 通常需要先对视频做采样并提取一维时间序列特征,在时间维度上得到一个特征序列,然后使用 proposal(类似于 anchor/proposal)产生候选时间段,或者用更加直接的方式对每个时间步进行预测,再通过 NMS 或者其他后处理将重叠候选去除掉,并且输出最终段。
Spatio-Temporal Detection 是将输出再结构化一层,动作往往是由某个主体发起的,因此不仅仅要在时间轴上定位动作发生的片段,还要在空间上给出主体的位置。
这类任务的难点会比 temporal 更“复合”:因为现在同时要处理检测的难点(遮挡、小目标、多人、视角变化)和动作识别的难点(细粒度动作、交互、时序上下文),并且两者还强耦合——例如同一个动作标签(如 “talk to” 或 “listen”)往往需要依赖与他人关系的上下文,而这个上下文又可能在空间上并不落在主体框内部,因此只看 actor box 内的像素并不一定足够,因此很多方法会强调“把周围环境/其他人”作为上下文一起建模。
这部分主要是在说明 video understanding 部分较为前沿的相关研究内容。
视频本质是多模态的,音频信号往往包含视觉无法捕捉的关键信息。视觉信号擅长捕捉空间和物体,而音频信号擅长描述事件和动态,通过联合训练音频网络和视觉网络,能够显著提高分类准确率。
一个视频中有多种乐器同时演奏,音频是混合的,利用视觉信号作为条件,将混合音频分离出独立的音轨。网络学习通过建立“像素区域”与“特定频率波形”之间的关联,通过“看”不同的位置,网络可以“听”到不同的声音。一般而言,会通过从视频中定位/裁剪出每个发生源的视觉区域,提取与语音高度相关的时序视觉特征,然后将这些视觉特征作为条件,预测混合音频谱上的分离 mask,使用 mask 将混合谱拆分开并且重建波形,得到分离的音频。
Lecture 10 还提到了一些更为一般性的音频视觉融合工作:
主要可以抓住三个不同的层次:
对于长视频,如果对每一帧都跑重模型,成本会非常高,但是如果只随机抽取几帧,又很容易错过关键动作瞬间。因此需要在保证精度的前提下,要么使用更好的采样,要么使用更轻量的模型。
比较具有代表性的策略如上所示,大体可以分为以下三类:
在第一视角(egocentric)与多传感器场景里,视频理解的输出往往不再是单一动作标签,而是更结构化的关系预测,例如“谁在和谁对话/谁在听谁”,甚至输出随时间变化的交互图(conversational graph)。此时音频不仅提供语音内容,还可能提供空间线索(方向性、说话活动检测),而视觉提供主体位置、头部朝向、注视与手势等信息;模型需要把这些证据统一到一个时序图结构中,预测节点(人物)之间的边(交互关系)随时间的变化。
将视频理解接到 LLM 上,让模型能够做更开放式的描述、问答、推理与对话。
这类方法的几乎都是首先通过视频取样与压缩,将长视频通过抽帧、抽 clip 或通过视频编码器生成更少的 video tokens 来进一步压缩,而后经过视觉/视频编码器如 ViT/Video Transformer/3D backbone 等方式得到时空特征,经过对齐与投影,将视频特征映射到 LLM 的 embedding 特征空间,使其能够作为视觉语言 token 被语言模型所消费,也有的模型是需要先对齐再投影,本质上都是为了让多模态表征在进入 LLM 之前就更加语义化、更加一致,最后再通过指令微调与多任务,通过视频问答、描述、时序定位式问答等数据,让 LLM 学会在语言层面调用视频信息。
参考如下:
https://cs231n.stanford.edu/index.html