论文阅读 | Video Super-Resolution Transformer

2023-05-16

引言:2021年用Transformer实现视频超分VSR的文章,改进了SA并在FFN中加入了光流引导
论文:【here】
代码:【here】

Video Super-Resolution Transformer

引言

视频超分中有一组待超分的图片,因此视频超分也经常被看做是一个序列问题。这种序列问题的解决方法通常有RNN,SLTM,和transformer。由于transformer并不需要递归也更适合,并备受关注

注意力机制

目前用transformer处理图片的思路是全连接注意力机制,the fully connected self-attention(FCSA)
(这里的这个FCSA的概念是作者提出来的,作者举例VIT和PIT都是FCSA,因此我把它当做对整个图像的分成的块做自注意力)
然而,作者认为这样的FCSA的机制并不能很好的提取空间局部信息,但是局部信息对于VSR来说又是很关键的。
此外,除了空间局部信息,时域信息也是很重要的,视频中的图片中的信息可以通过相邻的图片进行补充。现在,该如何用transformer来处理时域信息也是没有被探索过的(这个领域还没有人做)

前馈网络
现有的前馈网络token-wise feed-forward layer不能实现图像之间的对齐,这里强调token,即是指全连接都是在每一个token中实现的,token和token之间没有关联。token 之间的特征关联在FCSA模块中实现的,但是在FFN中没有特征传播。因此,在这个模块中,作者实现了以像元为单位(而不是token),实现了特征传播和特征对齐

问题定义

第一个定义是映射函数的loss
在这里插入图片描述
第二个定义是神经元组成/参数传播的定义,同时这个连接了不同神经元的映射与真实映射之间的loss应该小于一个epsilon
在这里插入图片描述
第三个定义为视频超分的定义和目标
在这里插入图片描述
第四个定义为transformer的架构
在这里插入图片描述
(这一块有点枯燥,主要是作者的第二个定义,神经元的参数传播为后面的公式推导奠定基础)

视频超分 Transformer

作者介绍了这样一个公式,来证明FCSA不太适合视频超分tranformer(公式没有看懂,我这里就跳过了)
在这里插入图片描述
总之,作者通过这个公式论证了全连接注意力机制FCSA会导致梯度消失的问题

When q is not sufficiently large, the fully connected attention layer may result in the gradient vanishing issue. It implies that the gradient descent will be “stuck” upon the initialization, and thus will fail to learn the k-pattern function. Therefore, the fully connected self-attention layer cannot use the spatial information of each frame since the local information is not encoded in the embeddings of all tokens. Moreover, this issue may become more serious when directly using such layers in video super-resolution.

而如果用作者提出的,则时空卷积自注意力机制STCSA很好的解决了这个问题
在这里插入图片描述

STCSA的实现
即将图片划成8 * 8 * 5的小块(这里的5是指连续的图片数),在8 * 8 * 5的3D块中实现块中的像元单位的特征自注意力
在这里插入图片描述
同时,作者还加入了一个3D位置编码信息,编码规则如下
在这里插入图片描述

代码(作者非常贴心的加上了尺寸的注释)

class globalAttention(nn.Module):
    def __init__(self, num_feat=64, patch_size=8, heads=1):
        super(globalAttention, self).__init__()
        self.heads = heads
        self.dim = patch_size ** 2 * num_feat
        self.hidden_dim = self.dim // heads
        self.num_patch = (64 // patch_size) ** 2
        
        self.to_q = nn.Conv2d(in_channels=num_feat, out_channels=num_feat, kernel_size=3, padding=1, groups=num_feat) 
        self.to_k = nn.Conv2d(in_channels=num_feat, out_channels=num_feat, kernel_size=3, padding=1, groups=num_feat)
        self.to_v = nn.Conv2d(in_channels=num_feat, out_channels=num_feat, kernel_size=3, padding=1)

        self.conv = nn.Conv2d(in_channels=num_feat, out_channels=num_feat, kernel_size=3, padding=1)

        self.feat2patch = torch.nn.Unfold(kernel_size=patch_size, padding=0, stride=patch_size)
        self.patch2feat = torch.nn.Fold(output_size=(64, 64), kernel_size=patch_size, padding=0, stride=patch_size)

    def forward(self, x):
        b, t, c, h, w = x.shape                                # B, 5, 64, 64, 64
        H, D = self.heads, self.dim
        n, d = self.num_patch, self.hidden_dim

        q = self.to_q(x.view(-1, c, h, w))                     # [B*5, 64, 64, 64]    
        k = self.to_k(x.view(-1, c, h, w))                     # [B*5, 64, 64, 64]   
        v = self.to_v(x.view(-1, c, h, w))                     # [B*5, 64, 64, 64]

        unfold_q = self.feat2patch(q)                          # [B*5, 8*8*64, 8*8]
        unfold_k = self.feat2patch(k)                          # [B*5, 8*8*64, 8*8]  
        unfold_v = self.feat2patch(v)                          # [B*5, 8*8*64, 8*8] 

        unfold_q = unfold_q.view(b, t, H, d, n)                # [B, 5, H, 8*8*64/H, 8*8]
        unfold_k = unfold_k.view(b, t, H, d, n)                # [B, 5, H, 8*8*64/H, 8*8]
        unfold_v = unfold_v.view(b, t, H, d, n)                # [B, 5, H, 8*8*64/H, 8*8]

        unfold_q = unfold_q.permute(0,2,3,1,4).contiguous()    # [B, H, 8*8*64/H, 5, 8*8]
        unfold_k = unfold_k.permute(0,2,3,1,4).contiguous()    # [B, H, 8*8*64/H, 5, 8*8]
        unfold_v = unfold_v.permute(0,2,3,1,4).contiguous()    # [B, H, 8*8*64/H, 5, 8*8]

        unfold_q = unfold_q.view(b, H, d, t*n)                 # [B, H, 8*8*64/H, 5*8*8]
        unfold_k = unfold_k.view(b, H, d, t*n)                 # [B, H, 8*8*64/H, 5*8*8]
        unfold_v = unfold_v.view(b, H, d, t*n)                 # [B, H, 8*8*64/H, 5*8*8]

        attn = torch.matmul(unfold_q.transpose(2,3), unfold_k) # [B, H, 5*8*8, 5*8*8]
        attn = attn * (d ** (-0.5))                            # [B, H, 5*8*8, 5*8*8]
        attn = F.softmax(attn, dim=-1)                         # [B, H, 5*8*8, 5*8*8]

        attn_x = torch.matmul(attn, unfold_v.transpose(2,3))   # [B, H, 5*8*8, 8*8*64/H]
        attn_x = attn_x.view(b, H, t, n, d)                    # [B, H, 5, 8*8, 8*8*64/H]
        attn_x = attn_x.permute(0, 2, 1, 4, 3).contiguous()    # [B, 5, H, 8*8*64/H, 8*8]
        attn_x = attn_x.view(b*t, D, n)                        # [B*5, 8*8*64, 8*8]
        feat = self.patch2feat(attn_x)                         # [B*5, 64, 64, 64]
        
        out = self.conv(feat).view(x.shape)                    # [B, 5, 64, 64, 64]
        out += x                                               # [B, 5, 64, 64, 64]

        return out

这样就完全考虑8 * 8感受野内的局部特征了,但是块与块之间的边缘只能朝一个方向进行特征传播
于是作者提出了一种新型的FFN

feed-forward Network实现
作者首先将5张图片中的相邻光流求出来,如果边缘图像的另一边没有图了,则跟自己作光流
在这里插入图片描述
这样可以得到5 * 2张光流图(这里的5指视频图片数),每张图片都有它的前向流图和后向流图,然后前向warp和后向warp后,原有的每张图的时间位置上都可以多加两张图,分别来自前一时刻图片前向warp得到,和后一时刻的图片后向warp得到
在这里插入图片描述
然后通过两组图片的融合,即生成了最终结果
在这里插入图片描述
值得一提的是,这里的FFN和传统FFN不同,由于前面的SA部分保留的图片的原有尺寸,这里的FFN直接用3*3卷积实现

class FeedForward(nn.Module):
    def __init__(self, num_feat):
        super().__init__()
        
        self.backward_resblocks = ResidualBlocksWithInputConv(num_feat+3, num_feat, num_blocks=30)
        self.forward_resblocks = ResidualBlocksWithInputConv(num_feat+3, num_feat, num_blocks=30)
        self.fusion = nn.Conv2d(num_feat*2, num_feat, 1, 1, 0, bias=True)
        self.lrelu = nn.LeakyReLU(negative_slope=0.1, inplace=True)
        
    def forward(self, x, lrs=None, flows=None):
        b, t, c, h, w = x.shape
        x1 = torch.cat([x[:, 1:, :, :, :], x[:, -1, :, :, :].unsqueeze(1)], dim=1)  # [B, 5, 64, 64, 64]
        flow1 = flows[1].contiguous().view(-1, 2, h, w).permute(0, 2, 3, 1)         # [B*5, 64, 64, 2]
        x1 = flow_warp(x1.view(-1, c, h, w), flow1)                                 # [B*5, 64, 64, 64]
        x1 = torch.cat([lrs.view(b*t, -1, h, w), x1], dim=1)                        # [B*5, 67, 64, 64]
        x1 = self.backward_resblocks(x1)                                            # [B*5, 64, 64, 64]

        x2 = torch.cat([x[:, 0, :, :, :].unsqueeze(1), x[:, :-1, :, :, :]], dim=1)  # [B, 5, 64, 64, 64]
        flow2 = flows[0].contiguous().view(-1, 2, h, w).permute(0, 2, 3, 1)         # [B*5, 64, 64, 2]
        x2 = flow_warp(x2.view(-1, c, h, w), flow2)                                 # [B*5, 64, 64, 64]
        x2 = torch.cat([lrs.view(b*t, -1, h, w), x2], dim=1)                        # [B*5, 67, 64, 64]
        x2 = self.forward_resblocks(x2)                                             # [B*5, 64, 64, 64]

        # fusion the backward and forward features
        out = torch.cat([x1, x2], dim=1)      # [B*5, 128, 64, 64]
        out = self.lrelu(self.fusion(out))    # [B*5, 64, 64, 64]
        out = out.view(x.shape)               # [B, 5, 64, 64, 64] 

        return out

实验

在这里插入图片描述
在这里插入图片描述
在别的文章里有看到块与块之间会出现伪影,然而文章的结果挺完美的

总结

用transformer解决VSR的问题,虽然在空间小范围内进行attention是可行的,也不会造成太大的计算量,但是总觉得对于transformer的优势没有发挥出来,大的感受野和全局信息的利用才是transformer的优势所在

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

论文阅读 | Video Super-Resolution Transformer 的相关文章

  • Android:如何获取设备的真实屏幕尺寸?

    我尝试了不同的方法来获取设备的屏幕尺寸 但它总是返回错误的尺寸 791x480代替854x480 可能是导航栏的原因 我的设备当前运行的是 JellyBean 4 1 1 I tried Display display getWindowM
  • 将 CIFilter 与 AVFoundation 结合使用 (iOS)

    我正在尝试将滤镜应用于在 iOS 上使用 AVFoundation 创建的视频合成 滤镜可以是模糊 像素化 棕褐色等 我需要实时应用效果并能够将复合视频渲染到磁盘 但我很高兴从其中之一开始 不幸的是 我似乎无法弄清楚这一点 这是我能做的 我
  • Android 中如何获取帧

    实际上 我需要从视频中获取所有帧 但在使用 Mediametadataretriever 缩略图 时间戳获取帧时 我经常重复获取第一帧 然后获取特定时间帧 我通过更改所有 GetFrameAtTime options 尝试了很多修复 但仍然
  • 如何使用 ffmpeg 提取时间精确的视频片段?

    这并不是一个特别新的问题领域 但我已经尝试过那里建议的内容 但运气不佳 那么 我的故事 我有一大段 15 秒的直接来自camera mov 视频 我想从中提取特定的块 我可以通过开始时间和停止时间 以秒为单位 来识别该块 我首先尝试执行我称
  • 使用 ffmpeg 提取帧的最快方法?

    您好 我需要使用 ffmpeg 从视频中提取帧 有没有比这更快的方法 ffmpeg i file mpg r 1 1 filename 03d jpg 如果 JPEG 编码步骤对性能要求太高 您可以始终将未压缩的帧存储为 BMP 图像 ff
  • 揭秘Python中的super?

    我试图了解 super 在 python 中的工作原理 并尝试了以下示例 class A object def init self print in A s init class B object def init self print i
  • Javascript - 对父母调用 super 父母?

    我在 Odoo 中定义了当前自定义 javascript 视图的扩展 openerp account move journal test function instance var t instance web t lt instance
  • Android - 如何合并两个视频

    基本上 我正在寻找一种将两个 mp4 视频文件 在 SD 卡上 组合在一起的方法 更像是在第一个视频的末尾附加第二个视频 我进行了很多搜索 但找不到合适的解决方案 好吧 我根本找不到任何解决方案 所以我的问题是 是否有一个库可以组合 并可能
  • BATCH - 从 Windows 命令行获取显示分辨率并设置变量

    echo off set h wmic desktopmonitor get screenheight set w wmic desktopmonitor get screenwidth echo h echo w pause 而不是得到
  • 如何在 Jekyll 博客中包含视频标签/mp4 视频

    I am not寻找一种方法链接到 YouTube https stackoverflow com questions 10529859 how to include video in jekyll markdown blog 122738
  • java设置图像的分辨率和打印尺寸

    我编写了一个程序 生成一个 BufferedImage 以显示在屏幕上 然后打印 图像的一部分包括 1 像素宽的网格线 即 一行为1个像素 行与行之间大约有10个像素 由于屏幕分辨率的原因 图像显示得比这大得多 每行有几个像素 我想将其绘制
  • 我如何对 youtube 嵌入播放器进行编程,使其在点击时取消静音

    如何设置 YouTube 嵌入式播放器在单击时取消静音 你可以看到我提到的嵌入式播放器http www harvestarmy org http www harvestarmy org主页 右边的那个写着 来自 YouTube 的最新视频
  • 在 Chrome 中为

    我已经看到这个问题多次出现 但没有任何明确的解决方案 我正在加载一个简单的视频
  • HTML5 视频:使用 Blob URL 流式传输视频

    我有一个 Blob 数组 实际上是二进制数据 我可以表达它 但是效率最高 我现在正在使用 Blob 但也许Uint8Array或者有什么会更好 每个 Blob 包含 1 秒的音频 视频数据 每秒都会生成一个新的 Blob 并将其附加到我的数
  • 使用 Vlc DotNet 库显示视频

    我在 Visual Studio 2012 中制作了一个 C Windows 窗体应用程序 并从该网页添加了 dll http vlcdotnet codeplex com http vlcdotnet codeplex com 我已经获得
  • 如何在 cv2.VideoWriter 中使用 FPS 参数?

    好的 所以我正在制作视频 我想确切地知道如何使用 FPS 参数 它是一个浮点数 所以我假设这是我想要的每帧之间的间隔 你能给个例子吗 我只想知道视频会如何随着 FPS 参数值的变化而变化 因为我制作的视频现在太快了 谢谢 确实只是这样 fr
  • 如何在控制台中播放和暂停 Youtube 视频?

    转到一个 url 例如 https www youtube com embed zvCBSSwgtg4 https www youtube com embed zvCBSSwgtg4 并打开 chrome 控制台 我想知道什么 javasc
  • 某些网站如何在 iOS Safari 中内嵌播放视频?

    非常令人难以置信 因为我认为所有视频都可以在常规野生动物园中扩展为全屏播放 例如检查一下 https entertainment theonion com the onion reviews rogue one 1819596116 htt
  • 在 HTML5 中设置视频高度

    也许这是一个简单的问题 但它真的让我发疯 我只想设置 HTML5 视频的高度和宽度 我正在使用这段代码
  • FFmpeg av_read_frame 无法正确读取帧?

    好吧 我已经下载了一些 yuv 格式的原始 UHD 序列 并在 mp4 容器中使用 ffmpeg 对其进行编码 h264 4 4 4 100 质量 25fps 当我使用 ffprobe 找出编码了多少帧时 我得到 600 所以这是 24 秒

随机推荐

  • go中使用sqlite

    1 安装mingw64 1 1 下载mingw sqlite作为一个快速开发的数据库 xff0c 理应被go支持 xff0c 但是要在go里面使用sqlite xff0c 实际上是要下载sqlite的源代码编译的 xff0c 当然 xff0
  • map 详解(C++)

    现实中的数据很多是关联的 xff0c 例如书本名称和价格 xff0c 每条数据都含有两部分 xff1a 信息学竞赛一本通 xff1a 80 高等数学 xff1a 27 5 生物信息分析 xff1a 35 5 我们可以使用map存储这类一对一
  • 详解Ubuntu文件的结构

    首先我们知道 xff0c linux系统文件结构和windows系统文件结构不同之处在于 xff0c linux系统文件统一挂载在根目录下的 xff0c 而windows系统的文件是分磁盘挂载的 windows下通常分C盘D盘E盘等 xff
  • Go 语言 exec 实时获取外部命令的执行输出

    Go 语言 exec 实时获取外部命令的执行输出 在 Go 语言中调用外部 Linux 命令可以通过标准的 os exec 包实现 xff0c 我们一般的使用方式如下 xff1a span class token keyword packa
  • ubuntu 18.04 arm64版 安装docker 踩坑

    一 安装ubuntu 18 04系统 可以参考该系列其他文章 二 安装docker 1 先卸载可能存在的旧版本 apt remove docker docker span class token operator span engine d
  • Linux网络中的桥 (Bridge)

    桥简介 桥 xff0c 从字面来讲就是在一条河流上面建造一条路 xff0c 对 xff0c 就是这样 xff0c 甭管是多大多长跨江还是跨海 xff0c 它都是起到连接两岸的作用 在计算机的网络世界中也存在这种连接的两个网络的设备 xff0
  • MySQL8.0 开启远程连接

    一 MySQL 开启远程连接需要先在服务器上登录到 MySQL mysql u root p 1 然后 Enter password 二 修改 root 账户的 Host 1 打开 mysql 数据库 use mysql 1 2 查看 us
  • 实时天气API

    restful接口查询天气 实时天气 API 和风天气开发平台 实时天气 全国4000 个市县区和海外15万个城市实时天气数据 包括实时温度 体感温度 风力风向 相对湿度 大气压强 降水量 能见度 露点温度 云量等数据 请求URL nbsp
  • C程序的内存结构

    以类Unix环境下的程序运行为例 xff0c 说明C程序的运行过程和内存分配 xff0c windows环境下原理一致 xff0c 但实现细节会有区别 xff0c 所以首先我们要明白 xff1a 程序的内存布局 Program Memory
  • AD采用多层原理图和ROOM方式高效率绘制重复性功能电路板图

    我们在使用altium designer绘制原理图和PCB时 xff0c 往往会遇到多路重复性的电路 xff0c 其功能和走线完全一致 xff0c 在条件允许的情况下我们可以采用多层原理图和ROOM方法避免重复性劳动 本文以两路RS485电
  • Ubuntu网络频繁掉线解决方案

    转自 xff1a http www cnblogs com ljxxz p 5089863 html 年底了 xff0c 实验室终于给配了个电脑 xff08 Ubuntu系统 xff09 xff0c 博主欣喜若狂啊 xff0c 然而装好后发
  • 部分Windows 10企业版用户无法使用微软Edge浏览器

    图片来自 xff1a neowin 很多关于Windows 10的问题悬而未决 xff0c 在微软正式推出Windows 10之前还有一个多月的时间 xff0c 很多事情都会发生改变 就在本周 xff0c 来自Gartner Inc的分析师
  • 无法远程连接如何排错

    无法远程连接如何排错 去北京天安门广场 连接服务器 服务器位置 10 0 0 200 1 连接不上服务器 测试我和天安门广场之间的道路是否通畅 百度地图 连接不上10 0 0 200 测试和200通信是否正常 ping 10 0 0 200
  • 51单片机实时时钟显示

    51单片机 43 DS1302 43 DS18B20 43 LCD12864 用的IIC通信 xff0c 写的一个ds3231时钟模块的程序 xff0c 可更改时间 xff0c 下面是 h文件里面的部分代码 ifndef ds3231 h
  • RouterOS(ROS)软路由阿里云动态域名解析Aliyun DDNS

    本文讲解ROS借助阿里云的 DNS API 来实现域名与动态 IP 的绑定 xff0c 用来达到外网访问内网设备的需求 一 给域名添加A记录解析 1 点击登录阿里云域名控制台 2 给域名添加一个A记录解析 xff0c 记录值可以随意填写 x
  • <X>远程登录服务

    文章目录 一 ssh1 ssh服务的用途2 基本用法3 ssh 服务的 key 认证 二 文件传输1 实验环境2 scp 命令3 rsync命令 三 文件的归档与压缩1 文件归档2 文件的压缩3 tar 43 压缩 四 日志1 journa
  • springboot项目正常启动后却无法访问

    报错内容 xff1a Resolved org springframework http converter HttpMessageNotReadableException Required request body is missing
  • 如何解决远程桌面登录后闪退

    在cmd中输入这个命令 xff0c 可以防止登录远程桌面后闪退 mstsc admin
  • ubuntu22.0.4 kolla多节点搭建openstack ,skyline

    kolla部署openstack 基础 更新软件包索引 span class token function sudo span span class token function apt span update 2 安装 Python 构建
  • 论文阅读 | Video Super-Resolution Transformer

    引言 xff1a 2021年用Transformer实现视频超分VSR的文章 xff0c 改进了SA并在FFN中加入了光流引导 论文 xff1a here 代码 xff1a here Video Super Resolution Trans