VGPNN 笔记(单视频多样化编辑,视频类比)
《Diverse Video Generation from a Single Video》
论文:https://arxiv.org/abs/2205.05725
《VGPNN: Diverse Generation from a Single Video Made Possible》
主页:https://nivha.github.io/vgpnn/
论文:https://arxiv.org/abs/2109.08591
项目:https://github.com/nivha/single_video_generation
两篇论文标题相似,原班人马,摘要也差不太多,好像是因为这篇论文 2022 才被 ECCV 接收,作者做了修正后重新上传。
旧版更全一些,新版删了很多东西,看旧版比较好。
然而我先看了新版,笔记前半段,到视频类比这一节(包括),都是根据新版写的,后面才发现旧版还有更多的内容,之后的都是根据旧版写的了。
左边第一行,把瀑布变成岩浆和肉;第二行,把岩浆变成瀑布和肉;第三行,把肉变成瀑布和岩浆。看起来效果都很好,视频里动起来的效果也很好。
右边,把人群摆出的数字,根据草图,变成另一个数字,效果看起来也很好。
可以实现 视频类比、草图变视频、改变空间关系、改变时间关系、可控 inpainting
方法其实和“图片类比”很像,都是基于高斯金字塔的 patch 匹配,可以看作是“视频类比”
与图片类比的区别有三点:
- 匹配时,变成了时空patch的匹配(废话hhh)
- 在部分用法中,匹配时还需要把光流也用来一起匹配
- 匹配时用了前一层的上采样作为QKV中的K来做匹配,而不是直接用当前层
- 引入了迭代优化过程,每一层都多匹配几遍
最近看了点别的,又做了些实验,在最后,缺陷那一节,加了一段处理 边缘抖动 和 果冻形变 的可能的方案,遇到类似问题别忘了回来看看
个人总结
用法一:给定一个视频,随机生成该视频的变体
给定两个视频,提取出时空金字塔(就是带时间维度的高斯金字塔),定义第 N N N 层是尺度最小的层(顶层),第 0 层是原视频
给定一个输入视频 x x x ,构建时空金字塔 { x 0 … , x N } \left\{x_{0} \ldots, x_{N}\right\} {x0…,xN} ,其中 x 0 = x x_{0}=x x0=x , x n = x n − 1 ↓ r x_{n}=x_{n-1} \downarrow _r xn=xn−1↓r , x n x_n xn 是对 x n − 1 x_{n-1} xn−1 的 bicubic 下采样,系数为 r r r (注意 r = ( r H , r W , r T ) r=(r_H,r_W,r_T) r=(rH,rW,rT) ,其中 r H = r W r_H=r_W rH=rW 是空间系数, r T r_T rT 是时间系数)
网络由很多 VPNN 层组成,每个 VPNN 处理时空金字塔的一层。
第 n n n 层 VPNN 输入 Q n , K n , V n Q_n,K_n,V_n Qn,Kn,Vn ,输出 视频 y n y_n yn
其中 Q n = y n + 1 ↑ r , K n = x n + 1 ↑ r , V n = x n Q_n=y_{n+1}\uparrow^r, \quad K_n=x_{n+1}\uparrow^r, \quad V_n=x_n Qn=yn+1↑r,Kn=xn+1↑r,Vn=xn 。
注意, Q N = x N + z N Q_N=x_N+z_N QN=xN+zN 。其中 z N z_N zN 为一个高斯噪声,在空间维度上随机,在时间维度上保持不变。
y n y_n yn 通过挑选 V n V_n Vn 中的 patch 替换掉 Q n Q_n Qn 中的 patch 得到,每次挑选哪个 patch 由 Q n Q_n Qn 和 K n K_n Kn 之间的最近邻投票的中位数决定。根据投票得到的对应关系,用 V n V_n Vn 来替换 Q n Q_n Qn ,如下图:
简单来说,
Q
n
Q_n
Qn 控制结构,
V
n
V_n
Vn 提供纹理,
K
n
K_n
Kn 控制如何用纹理填充结构(或者说控制纹理和结构的对应关系) 。一般的图片类比都是直接用
K
n
=
x
n
K_n=x_n
Kn=xn 查询,用
V
n
=
x
n
V_n=x_n
Vn=xn 填充,这里用
K
n
K_n
Kn 查询是因为
Q
n
=
y
n
+
1
↑
r
Q_n=y_{n+1}\uparrow^r
Qn=yn+1↑r 经过上采样,是模糊过的,与
K
n
=
x
n
K_n=x_n
Kn=xn 之间存在 mismatch,于是改用
K
n
=
x
n
+
1
↑
r
K_n=x_{n+1}\uparrow^r
Kn=xn+1↑r 。
迭代优化:为了提升生成结果的质量和锐度,我们会把 y n y_n yn 输入当前层的 VPNN 再跑一遍得到一个新的 y n y_n yn (很多基于 patch 的方法都用到了这种 类EM算法)(说是把输出输回去,但是这个有三个输入啊,输出又只有一个,到底是怎么输回去的?简单看了下代码,应该是用的 Q n = y n , K n = x n , V n = x n Q_n=y_n, K_n=x_n, V_n=x_n Qn=yn,Kn=xn,Vn=xn 来做的, Q n Q_n Qn 可以多次迭代更新)
用法二:视频类比
给定视频 S S S 和 C C C ,我们将 S S S 的纹理迁移到 C C C 的结构。
我们从 S , dyn ( C ) , dyn ( S ) S,\text{dyn}(C),\text{dyn}(S) S,dyn(C),dyn(S) 中分别提取时空金字塔。
其中 d y n ( ⋅ ) dyn(\cdot) dyn(⋅) 表示 提取光流,再用 k-means 量化。
我们按如下方式设置 QKV,以生成输出视频:
Level | Q | K | V |
---|---|---|---|
N (最coarse的层) | dyn ( C ) N \text{dyn}(C)_N dyn(C)N | dyn ( S ) N \text{dyn}(S)_N dyn(S)N | S N S_N SN |
n (其余层) | dyn ( C ) n ∣ ∣ Q n + 1 ↑ \operatorname{dyn}(C)_{n} || Q_{n+1} \uparrow dyn(C)n∣∣Qn+1↑ | dyn ( S ) n ∣ S n \operatorname{dyn}(S)_{n} | S_{n} dyn(S)n∣Sn | S n S_n Sn |
其中, ∥ \| ∥ 表示在 channel 维度上拼接。
该方案也可用于 草图到视频 的转换。
用法三:时空重定向
可以改变视频的长宽比(但是不使对象变形),改变视频时长(但是不改变运动速度)
空间重定向就是在初始猜测 Q N Q_N QN 上下功夫。把初始猜测 Q N Q_N QN 设定为 缩放后的视频 的 时空金字塔 的 最coarse层,剩下的步骤是和“用法一”的流程一样的,用 原视频 的 时空金字塔 继续做就行了。
时域重定向没讲。应该也是在初始猜测上下功夫吧。
用法四:可控视频 inpainting
需要 inpainting 的部分盖上有色的mask,用mask的颜色作为引导,如图
应该就是三个要点:
- 在需要 inpainting 的部分盖上有色 mask ,为后续合成提供线索。
- 控制金字塔的层数,使得最coarse层的单个 patch 正好能覆盖 mask,以此构造出初始猜测 Q N Q_N QN
- 重建时,在 V n V_n Vn 中排除被 mask 的部分
方法
为了同时捕获空间信息和时间信息,我们先用输入视频构建一个时空金字塔,然后 coarse-to-fine 地在多尺度上捕获内部数据。在每一个尺度,我们都引入 Video-Patch-Nearest-Neighbor 模块 (VPNN);VGPNN实际上就是就是一系列 VPNN 层。每一层的输入取决于应用,我们先专注于多样化视频生成的应用。
给定一个输入视频 x x x ,构建时空金字塔 { x 0 … , x N } \left\{x_{0} \ldots, x_{N}\right\} {x0…,xN} ,其中 x 0 = x x_{0}=x x0=x , x n = x n − 1 ↓ r x_{n}=x_{n-1} \downarrow _r xn=xn−1↓r , x n x_n xn 是对 x n − 1 x_{n-1} xn−1 的 bicubic 下采样,系数为 r r r (注意 r = ( r H , r W , r T ) r=(r_H,r_W,r_T) r=(rH,rW,rT) ,其中 r H = r W r_H=r_W rH=rW 是空间系数, r T r_T rT 是时间系数)
多尺度方法
在最 coarse 的层,对第一个 VPNN 层输入一个初始 coarse 猜测。初始 coarse 猜测是通过加一个随机高斯噪声 z N z_N zN 到 x N x_N xN 上构造的。噪声 z N z_N zN 促进从单个输入产生高度多样性的输出。 x N x_N xN 提示全局结构(比如头在身体上面)和全局动作(比如有一个人往前走),这些结构和动作会被 小型 时空patch 捕捉到。
初始 coarse 猜测 ( x N + z N ) (x_N+z_N) (xN+zN) 的 每个 时空patch 被替换为对应 x N x_N xN 中的 最近邻patch 。通过在 每个时空位置中 选择 相邻patch 的所有 建议 的 中位数(称为“投票”或“折叠”), 来生成 最 coarse 的输出 y N y_N yN 。
对后续层,每个 VPNN 层的输入,都是前一层输出的上采样 ( y n + 1 ↑ r ) (y_{n+1}\uparrow ^r) (yn+1↑r) 。每个 时空patch 都被替换为其对应输入 x n x_n xn 中的 最近邻patch (由于 patch size 保持不变,现在可以捕获更细节的信息了)。这样,每层的 y n y_n yn 在结构和动作上与 初始猜测相似,但是包含相应输入 x n x_n xn 的 相同的 时空patch 的统计数据。 y n y_n yn 是由中位数投票产生的。
为了进一步提升生成的金字塔中,每一层 y n y_n yn 的质量和锐度,我们在每层上多迭代几次,每次将当前层输出的 y n y_n yn 作为当前层的输入。(有点像 很多 patch-based 方法 [比如 8, 16, 36, 48] 里面引入的 类EM算法)
QKV体系
在一些情况下,我们必须在其他搜索空间中比较 patch ,而不是在输入的原RGB空间比较。于是我们采用 [16] 中使用的 QKV 体系。
例如,当我们比较 ( y n + 1 ↑ r ) (y_{n+1}\uparrow ^r) (yn+1↑r) 和 x n x_n xn 时,后者的 patch 比前者更锐化(也就是说有mismatch是吧)。我们设置 V = x n V=x_n V=xn 和 K = x n + 1 ↑ r K=x_{n+1}\uparrow^r K=xn+1↑r 来缓解这个问题,其模糊程度与 Q = y n + 1 ↑ r Q=y_{n+1}\uparrow^r Q=yn+1↑r 差不多。每个以 K j K_j Kj 为最近邻的 Q i Q_i Qi 都被替换为 V j V_j Vj (其中 i , j i,j i,j 表示时空位置)。
当我们做视频类比任务时,QKV体系尤其重要,它可以包含 Q Q Q 和 K K K 中更多的时域信息。
寻找对应
我们使用 PatchMatch 算法 [8] 来寻找 Q Q Q 和 K K K 的最近邻。
该算法在 GPU 上用 PyTorch 实现,时间复杂度为 O ( n × d ) O(n\times d) O(n×d) ,空间复杂度为 O ( n ) O(n) O(n) ,其中 n n n 表示视频尺寸(估计是 THW), d d d 表示 patch 尺寸。
这极大减少了运行时间和内存消耗,使生成高分辨率的视频成为可能。
整个 VPNN 如图3所示:
时域的多样性和一致性
为了增强时域多样性,我们设置 时域维度 比输入视频略小一点。输出视频中 不同空间位置的动作 可以从 输入视频中 不同时间位置 得到,提升总的时域多样性。
比如这张图:
注意,生成的两个舞者没有同步,这说明他们的动作来自于输入视频中不同的时域位置
注意到,两个芭蕾舞演员没有同步。
我们发现,当初始噪声 z N z_N zN 在空间中随机,但是在时域上保持一致的时候,能够最好的保留时域一致性。
应用
视频类比
一般的视频翻译要么需要在大数据集上训练,并且,要么受控于人类姿态或关键点检测 [例如 29,44, 45,46],要么受控于一个人体/动物模型 [例如 1,11,26,31,34,35,50] 。
当视频之间的动作和语义上下文都相似的时候,可以用我们的框架在视频之间迁移外观和动作。我们将其称为“视频类比”(受图片类比 [9,18,27] 启发)。更正式地说,我们生成新的视频,其时空布局来自于内容视频 C C C (应该是指结构),其总体外观和动态来自于风格视频 S S S (应该是指纹理)。
我们先提取两段视频中的“动态结构”,也就是光流(使用RAFT算法 [37] 提取),然后将其量化为几个档(用 k-means)。
我们从三个视频中提取三个时空金字塔:(i). 风格视频 S S S (ii). 内容视频的光流 dyn ( C ) \text{dyn}(C) dyn(C) (iii). 风格视频的光流 dyn ( S ) \text{dyn}(S) dyn(S)
我们按如下方式设置 QKV,以生成输出视频:
Level | Q | K | V |
---|---|---|---|
N (最coarse的层) | dyn ( C ) N \text{dyn}(C)_N dyn(C)N | dyn ( S ) N \text{dyn}(S)_N dyn(S)N | S N S_N SN |
n (其余层) | dyn ( C ) n ∣ ∣ Q n + 1 ↑ \operatorname{dyn}(C)_{n} || Q_{n+1} \uparrow dyn(C)n∣∣Qn+1↑ | dyn ( S ) n ∣ S n \operatorname{dyn}(S)_{n} | S_{n} dyn(S)n∣Sn | S n S_n Sn |
其中, ∥ \| ∥ 表示在 channel 维度上拼接。(woc这样Q和K不是会越来越大吗)
注意,在最coarse的层,两个视频只比较他们的光流。在更细化的层 C C C 的光流用于引导输出我们想要的时空布局。
左边展示了三个视频的互相转换
右边展示了草图到视频的转换,要做到这一点,光流由一个草图视频提供
空间重定向
给定一个目标形状,我们先将输入视频缩放 (bicubic) 到目标形状,然后对输入视频和缩放后的视频计算时空金字塔。
我们用 缩放后视频 最coarse的层 作为 初始猜测 Q N Q_N QN ,而且不加噪声。然后用“方法”这一节提到的流程正常算。注意到,在所有尺度上, V n V_n Vn 都保持不变,因此,在重建目标视频时,不会导致 patch 失真变形。
对于视频中的对象,保持了对象在输入视频中的原始尺寸和长宽比,对于整个视频,在长宽比发生很大变化的情况下,仍然保持了整体外观的一致性。视频中的动态和动作同样也保持住了。
举例来说
图中的气球没有被压扁,而是互相之间变得更紧凑了。而且气球的动作被保留下来了。
时域重定向
一种可能的用法是对输入视频生成一个更短的摘要视频。
大部分的深度视频摘要技术都是选择从视频中选择一些帧(见综述 [4] )。一些经典方法已经展示了用 合成新帧 的方法组成 摘要,其中原本是顺序执行的运动可以被并行化,反之亦然。
通过时域重定向,VGPNN 可以通过合成新帧来生成摘要。
见补充材料。(淦,又来?又不说是怎么做的,哇我心态崩了)
用同样的方法,我们也可以在时间上使视频变长,同时又保持原本视频中的运动速度。比如芭蕾舞演员的例子,整个舞蹈变长了,但是其中的每一小段舞蹈动作都与源视频一摸一样。
可控视频 inpainting
用带颜色的 mask 作为提示
我们设置金字塔的层数,使得最coarse层的单个 patch 正好能覆盖 mask。
我总结一下,应该就是三个要点:
- 在需要 inpainting 的部分盖上有色 mask ,为后续合成提供线索。
- 控制金字塔的层数,使得最coarse层的单个 patch 正好能覆盖 mask,以此构造出初始猜测 Q N Q_N QN
- 重建时,在 V n V_n Vn 中排除被 mask 的部分
缺陷
在VGPNN中(实际上是在所有单视频GAN中),生成的局部 patch 缺乏全局几何一致性。当相机有大幅运动,导致场景深度有明显变化时,这种问题会很明显。尽管每个帧看起来都不错,但是不同的 patch 并不能一起变形,这导致原本是刚体的物体会发生非刚体变形。
请看补充材料中的视频。https://nivha.github.io/vgpnn/supmat/index.html最下方
用第一个视频做随机生成。注意到山脉旋转时,上面的纹理出现了流动。
我认为这个现象是因为较细节的层的 patch 在匹配的时候过于注重纹理细节,而没有考虑到几何一致性。
也可能是因为纹理比较复杂,有点偏随机,导致光流没有找好。
不对,在随机生成任务里面应该就没用光流,那说不定配上一个好光流能解决这个问题。
等等,最近我注意到一些GAN也会有这个问题,做属性插值的时候边缘会抖动,我认为这两个问题之间可能存在共性。
那么,我认为这是由于上采样不够好导致的,应该是在上采样时没有足够好的平移一致性,也可能是由于上采样的倍数过大,导致很难做到足够好的平移一致性。也就是说,是低分辨率层的分辨率实在太低,而频率又比较高,亚像素不稳定,平移和上采样时容易受影响(换句话说就是,只能一格一格地平移,不能平滑地平移),所以无法产生稳定的结果,所以容易抖动。
按这个分析,在构造高斯金字塔的时候,减少每次下采样的倍率(不要一次降太多),提高下采样前的滤波强度,应该可以有效缓解这个问题。
还有一个方案,就是在训练时就做平移,让网络适应这一点,因为有可能是平移时插值得到的像素对后一层来说属于分布外的输入了。