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