Happy · 2020年11月16日

720p实时视频插帧 | 旷视科技&北大提出RIFE

首发:AIWalker

图像/视频超分领域近期并无突破性的方法出现,故近期计划将图像/视频超分相关方法进行一次综述性汇总。计划从不同点出发对图像/视频超分进行一次“反思”之旅。本文是该旅程的第一站:图像降质过程
标题&作者团队

Paper: https://arxiv.org/abs/2011.06294
Code: https://github.com/hzwer/RIFE

该文是旷视科技&北大提出的一种实频插帧方案,相比已有基于光流的方案,该文所提方法具有好的性能与推理速度,针对720p视频可以实时进行2x插帧。值得各位同学了解一下。

Abstract

该文提出一种实时中间流估计(Intermediate Flow Estimation)算法RIFE用于视频插帧。现有视频插帧大多先估计双向光流,然后采用线性组合方式近似中间流,然而这种处理方式会在运动边界区域产生伪影问题。
作者设计一种中间流估计模型IFNet采用“Coarse-to-Fine”的方式直接预测中间流信息;然后按照所估计的中间流将输入图像进行仿射变换,最后采用另一个融合网络重建最终的结果。基于作者所提出的“leakage distillation”,RIFE可以通过端到端的方式进行训练并取得优异性能。
作者在几个公开数据集上进行了验证,所提RIFE具有更快的推理速度,同时取得了SOTA指标,见下图。

image.png

该文的主要贡献包含以下几点:

  • 提出了一种新颖而有效的IFNet直接估计中间流信息并用于视频插帧,同时IFNet可以从头开始训练,并可以通过连续两帧输入估计中间帧的光流信息。
  • 提出了一种有效的中间流的监督方案,可以取得更稳定的收敛与性能提升;
  • RIFE是首个基于光流的实时视频插帧方案,它能够以30fps对720p视频进行插帧。

Method

image.png

RIFE
上图给出了该文所提出的RIFE框架流程,它包含IFNet、Backward Warp以及Fusion Process三个模块,其中IFNet与Fusion部分是该文的核心创新点所在,所以在接下来的内容中我们将主要围绕这两个点进行介绍。
我们先简单介绍一下RIFE的大脉络。给定连续两帧RGB图像,视频插帧的目标是合成中间帧。首先IFNet直接对输入帧估计中间流信息,然后采用线性运动假设估计:
需要注意到:这就是IFNet的光流估计与双向光流估计的差异所在。IFNet只需进行一次光流估计,而双向光流估计则需要进行两次估计。在完成光流估计后,接下来就需要将连续两帧向中间帧进行warp变换,为消除变换帧的伪影问题,作者将输入帧、光流、变换帧同时送入到到FusionNet中进行重建。
从前面流程图可以看到:RIFE有两个关键单元号IFNet和FusionNet。IFNet用于估计中间流信息;FusionNet用于中间帧重建。

IFNet

image.png
image-20201114181757695

上图给出了IFNet的网络结构示意图,它的作用是根据两帧连续输入预测中间流。为更好处理大运动,IFNet采用了“Coarse-to-Fine”方式逐渐提升分辨率,也就是先在低分辨率上计算“粗糙”的光流,然后在高分辨率上计算“精细”光流。这也是目前光流估计中常用的一种处理方式。IFNet的这种光流估计方式可以描述如下:
其中表示当前中间流的估计,表示输入帧的仿射结果,表示第i个IFBlock。IFNet包含3个IFBlock,每个IFBlock具有一个分辨率参数,以及上采样操作、6个ResBlock以及一个上采样模块。可以参考上图以及下面的code进行理解(注:ResBlock中包含SE模块,同时可以看到下面的code和上面的示意图存在细微的差别:上采样部分)。

# Note: 这里仅列出了核心code  
class IFBlock(nn.Module):  
    def __init__(self, in_planes, scale=1, c=64):  
        super(IFBlock, self).__init__()  
        self.scale = scale  
        self.conv0 = conv(in_planes, c, 3, 2, 1)  
        self.res0 = ResBlock(c, c)  
        self.res1 = ResBlock(c, c)  
        self.res2 = ResBlock(c, c)  
        self.res3 = ResBlock(c, c)  
        self.res4 = ResBlock(c, c)  
        self.res5 = ResBlock(c, c)  
        self.conv1 = nn.Conv2d(c, 8, 3, 1, 1)  
        self.up = nn.PixelShuffle(2) 

为更好说明IFNet的优势,看一下下图咯。这里对比了IFNet与LiteFlowNet的视觉效果对比,可以看到IFNet的光流更为清晰、锐利;同时线性组合后光流存在更少的重叠和模糊现象。
image.png
image-20201114210101193

另外一点需要注意的是:IFNet仅需要进行一次光流估计。这也就导致了RIFE中的光流部分的推理耗时更快,对比见下表。可以看到:IFNet比其他视频插帧中的光流估计模块的速度快6-30倍。

image.png

image-20201114210351833

FusionNet

在得到了后,我们就可以通过Backward Warp得到粗糙重建结果。为降低仿射结果的伪影问题,作者提出了如下的调整与融合方式:
其中,M表示soft fusion map,表示重建残差。
类似SuperSlomo,DAIN等视频插帧方案,这里的FusionNet包含一个上下文特征提取模块和融合模块(UNet结构),注:上下文特征提取模块和融合模块的编码部分具有相似的结构,即包含4个stride=2的ResBlock;融合模块的解码模块包含4个反卷积进行特征分辨率上采样。最后,作者对融合结果通过sigmoid进行范围约束。大家可参考下面的核心code进行理解,ContextNet部分用于提取多尺度特征,FusionNet则是在ContextNet的基础上进行最终结果的重建。

# Note:ResBlock中的stride默认为2  
class ContextNet(nn.Module):  
    def __init__(self):  
        super(ContextNet, self).__init__()  
        self.conv1 = ResBlock(3, c)  
        self.conv2 = ResBlock(c, 2*c)  
        self.conv3 = ResBlock(2*c, 4*c)  
        self.conv4 = ResBlock(4*c, 8*c)  
......  
  
class FusionNet(nn.Module):  
    def __init__(self):  
        super(FusionNet, self).__init__()  
        self.down0 = ResBlock(8, 2*c)  
        self.down1 = ResBlock(4*c, 4*c)  
        self.down2 = ResBlock(8*c, 8*c)  
        self.down3 = ResBlock(16*c, 16*c)  
        self.up0 = deconv(32*c, 8*c)  
        self.up1 = deconv(16*c, 4*c)  
        self.up2 = deconv(8*c, 2*c)  
        self.up3 = deconv(4*c, c)  
        self.conv = nn.Conv2d(c, 4, 3, 1, 1)  
       def forward(self, img0, img1, flow, c0, c1, flow_gt):  
        warped_img0 = warp(img0, flow)  
        warped_img1 = warp(img1, -flow)  
        if flow_gt == None:  
            warped_img0_gt, warped_img1_gt = None, None  
        else:  
            warped_img0_gt = warp(img0, flow_gt[:, :2])  
            warped_img1_gt = warp(img1, flow_gt[:, 2:4])  
        s0 = self.down0(torch.cat((warped_img0, warped_img1, flow), 1))  
        s1 = self.down1(torch.cat((s0, c0[0], c1[0]), 1))  
        s2 = self.down2(torch.cat((s1, c0[1], c1[1]), 1))  
        s3 = self.down3(torch.cat((s2, c0[2], c1[2]), 1))  
        x = self.up0(torch.cat((s3, c0[3], c1[3]), 1))  
        x = self.up1(torch.cat((x, s2), 1))  
        x = self.up2(torch.cat((x, s1), 1))  
        x = self.up3(torch.cat((x, s0), 1))  
        x = self.conv(x)  
        return x, warped_img0, warped_img1, warped_img0_gt, warped_img1_gt  

Leakage Distillation

前面也提到了IFNet直接预测中间流信息,但是直接进行预测的难度是比较大的,因为这个信息是无法获取的且缺乏合理的监督信息。
为解决上述问题,在训练阶段,作者为IFNet添加了一个leakage distillation损失。此时需要一个预训练的光流模型提供额外的中间流信息,此时该损失定义如下:
除了上面提到的外,损失函数海报常规的重建损失(重建损失一般可选等)与Census Loss。

Experiments

训练数据:Vimeo90K;测试数据:UCF101,Middlebury等。FlyingChairs数据集上预训练的LiteFlowNet,优化器为AdamW,batch=64,初始学习率,con形式衰减。
直接上最终结果咯,见下图。可以看到RIFE取得了更好的SOTA指标,同时具有更快的推理速度。

image.png

image-20201114213214667

image.png

image-20201114213324074

更多消融实验分析建议查看原文,这里略过。前面已经对该文的核心进行了比较硬核介绍,对此感兴趣的可以去看一下原文或者留言与笔者一起讨论。

推荐阅读

本文章著作权归作者所有,任何形式的转载都请注明出处。更多动态滤波,图像质量,超分辨相关请关注我的专栏深度学习从入门到精通
推荐阅读
关注数
6194
内容数
191
夯实深度学习知识基础, 涵盖动态滤波,超分辨,轻量级框架等
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息