768p → 2× 超分方法对比

SwiftVR 5B 生成式 CDA-VSR 3.11M 判别式 各含官方配置 + 自研优化 20 条标准片源 × 4 组 = 80 次运行 RTX 5090 32G ↓ PyIQA 客观评测 ↓ ×2 GT Benchmark

统一任务:输入 768p,输出 2× 放大。20 条片源覆盖 5 种宽高比、每个比例 4 个不同的人、73–362 帧不等。 全部 80 次运行零失败。四组产出同一目标分辨率,可直接并排对比。

SwiftVR 优化版
304.5
20 条总耗时 · 最快
CDA-VSR 优化版
347.8
慢 1.14× · 但吃 ×4 劣势
显存差距
4.6×
22.11 vs 4.85 GiB 峰值
参数量差距
1600×
5B vs 3.11M
结论

两个模型没有一个「更好」,它们在做不同的事。CDA-VSR 还原,SwiftVR 重画。 在有真值的 benchmark 上,SwiftVR 的 PSNR-Y 比「什么都不做的 bicubic 放大」还低 6.8 dB; 而所有不看真值的观感指标,SwiftVR 全赢。这不是矛盾,这是判别式与生成式的本质分野。

要保真
CDA-VSR 优化
保真度 4/4 第一 · 4.85 GiB · 一卡可并行 6 路
要观感
SwiftVR 优化
观感 7/7 第一 · 22.11 GiB · 一卡只能单路
代价
−6.8 dB
SwiftVR 的 PSNR-Y 相对 bicubic
代价
+48%
SwiftVR 的 MUSIQ 相对 bicubic
如果你的场景是因为
画面必须忠于原始内容
证据类、人物身份、商品、字幕
CDA-VSR 优化 PSNR-Y / SSIM-Y / LPIPS / DISTS 四项保真度全部第一;SwiftVR 会改写它没把握的细节
只求好看,内容可以被润色
氛围镜头、背景、风格化素材
SwiftVR 优化 MUSIQ / CLIP-IQA / MANIQA / NIQE / DOVER 三项全部第一,且肉眼差距明显
要在一张卡上跑并发CDA-VSR 优化 4.85 GiB vs 22.11 GiB,差 4.6×;SwiftVR 在 32G 卡上只能单路常驻
输出高度不是 32 的倍数
1080p 首当其冲
不要用 SwiftVR 它会静默丢掉 8 行(详见 benchmark 一节),官方实现同样中招

① 一眼看懂:同一块画面,四种做法

下面每张图是同一帧的同一小块,放大 2 倍并排。裁哪一块不是我挑的 —— 程序扫描全帧,取「SwiftVR 偏离真值最多、而 CDA-VSR 偏离最少」的那块, 也就是两个模型对「这里到底是什么」分歧最大的地方。最右一格是真值

放大局部对比

两个方向的同一件事。

② 指标怎么读

本页一共 13 个指标,全部来自成熟实现(PyIQA 0.1.16 / DOVER 官方),没有自己重写的。 它们分三类,回答的问题完全不同,不能混着比

A. 无参考观感 —— 「好不好看」(不需要真值)

指标方向它在测什么分高说明不能告诉你
MUSIQ 多尺度 Transformer 打的「照片质量分」,在 KonIQ-10k 真人评分上训出来的 画面更接近人类觉得「清晰、干净」的照片 画面内容对不对。它没见过原图
CLIP-IQA 在 CLIP 语义空间里比较「a good photo」和「a bad photo」两个提示词的距离 语义上更像一张「好照片」 细节是真是假。语义像就行
MANIQA ViT 结构的无参考 IQA,同样 KonIQ-10k 权重,比 MUSIQ 更看重局部失真 局部伪影更少、纹理更「像真的」 纹理是不是原本就存在
NIQE 经典统计方法:与自然图像的统计分布差多远。不需要训练标签 (越低越好)统计特征越像真实自然照片 对生成的锐利纹理特别宽容,容易被「锐化」骗到
DOVER
overall / technical / aesthetic
视频质量模型,唯一一个看时间维度的。拆成两路:technical 看压缩/噪声/抖动等技术缺陷, aesthetic 看构图美感。overall 是官方的融合分,压到 0–1 整段视频观感更好,且时间上更稳定 同样看不到原始内容。技术分高≠还原准
这五个指标有一个共同盲点:它们都没见过原图。一个把模糊背景编成清晰树叶的模型, 在它们眼里就是「更清晰了」。所以只看这一组会得出「SwiftVR 完胜」——这正是本页要避免的误判。

B. 保真度 —— 「还原得准不准」(需要真值,只有 benchmark 有)

指标方向它在测什么分高说明不能告诉你
PSNR-Y 与真值的逐像素误差,取亮度通道,单位 dB。+3 dB ≈ 误差减半 像素层面更接近真值 好不好看。它对轻微整体偏移非常敏感,对「糊」比较宽容
SSIM-Y 结构相似度:比亮度、对比度、局部结构,0–1。比 PSNR 更贴近人眼 局部结构与真值一致 纹理细节的真实感
LPIPS 用 AlexNet 深层特征算距离 ——「人眼觉得像不像」,不是「像素差多少」 (越低越好)感知上更接近真值 它容许纹理有出入,只要「看起来是同一类东西」
DISTS 同时看结构和纹理统计,刻意对纹理的位移不敏感,专门用来评「重建出的纹理像不像」 (越低越好)纹理风格与真值一致 纹理是不是长在原来的位置上

RGB 版本的 PSNR/SSIM 也一并算了,放在 CSV 里 —— 文献惯例是 Y 通道,两种口径差值不小, 分开存是为了避免被混用。

C. 源一致性 —— 「改了多少」(无真值时的替代方案)

指标方向它在测什么分高说明不能告诉你
Downsample LPIPS
本项目自定义口径
把 2× 输出精确缩回原分辨率,再和 MiniMax 原片做 LPIPS。 逻辑:一个只做「放大」的模型,缩回去应该几乎等于原图 (越低越好)没怎么改动原内容 改得好不好。它只测「改了多少」,不测「改得对不对」
为什么需要它:MiniMax-20 是真实生产片源,没有真值,算不了 PSNR。 但「缩回去还等不等于原图」是一个不需要真值就能问的问题, 而它恰好抓住了无参考指标那个共同盲点。参照系摆在那里:把原图放大再缩回去, 这个数应该接近 0(实测 nearest 0.0045),模型偏离多少一目了然。

③ 为什么两套评测给出相反的结论

这是本页最重要的一节。同一批模型,两套评测排名几乎完全相反 —— 不是哪一套错了, 而是它们问的根本不是同一个问题。

每个指标内部把六个方法归一到 0–1(右 = 更好),所以不同量纲可以画在同一根轴上。 上半是保真度(有真值),下半是观感(无真值)。SwiftVR 的两条线分居两端。

拆开讲

  1. 无参考指标只能看输出本身。MUSIQ / CLIP-IQA / MANIQA / NIQE / DOVER 全部只吃一张(或一段) 画面,问「这像不像一张好照片」。一张清晰、锐利、纹理丰富的图就是高分 —— 不管这些纹理是不是原本就有。
  2. SwiftVR 是 5B 参数的生成式 DiT。它遇到信息不足的区域,会从训练分布里「补」一个合理的答案。 补出来的东西通常很好看,所以无参考指标一路走高。
  3. 但补出来的东西不等于真值。一有真值,这些「合理但不是原本那个」的细节就变成了纯误差: PSNR-Y 25.83 dB,比 bicubic 的 32.60 还低 6.8 dB —— 它比什么都不做还「错」得多。
  4. CDA-VSR 是 3.11M 参数的判别式模型。它只从压缩域先验和历史帧里恢复,不会凭空造。 所以保真度全面领先,观感全面落后。
  5. MiniMax-20 上没有真值,但 Downsample LPIPS 提前预言了这件事: SwiftVR 0.107 vs CDA-VSR 0.035,差 3.1 倍。后来的 GT benchmark 只是把这个结论钉死了。
该信哪个?取决于你的失败代价。
如果「画面里出现了原本不存在的东西」是不可接受的(人物身份、商品、文字、证据类内容), 信保真度那一组,选 CDA-VSR。
如果「不够好看」才是不可接受的,而内容被润色无所谓(氛围、背景、风格化素材), 信观感那一组,选 SwiftVR。
两组都不该被单独用来宣称「哪个模型更好」。

胜负矩阵

格子里是该指标下的名次(1 = 最好,共 6 个方法参与排名,含两个不花 GPU 的参照)。 颜色越绿越靠前,越红越靠后。左右两半几乎是彼此的镜像 —— 这就是上面那张图的表格版。

④ 真实 MiniMax 产出 · 无 GT 客观评测

上面那两个代理量(锐度 / 闪烁)只是自己写的启发式。这一节换成成熟实现的标准指标(PyIQA), 在同一批 20 条真实 MiniMax 产出上跑。没有 2K ground truth,所以做的是无参考画质加一项源一致性。 参评的六个方法里有两个是不花 GPU 的放大参照系,用来给「模型到底赚了多少」定一个地板。

绿色 = 该指标下四个模型之间的最优。灰色两行是参照系,不参与「最优」的评选 —— 它们在 Downsample LPIPS 上必然接近 0(把原片放大再原样缩回去本来就等于原片),列出来是当刻度尺用的。

共识排名

Heuristic ranking — not a calibrated quality score. 这只是各指标名次的算术平均。MUSIQ、CLIP-IQA、NIQE、Downsample LPIPS 量纲和含义都不同, 刻意没有把它们归一化成一个「综合 87.3 分」——那种分数看着好用,但没有任何校准依据。
配对逐条对比(paired per-video delta)逐条相减而非比均值,含 2000 次 bootstrap 的 95% CI

六个方法跑的是同一批 20 条片源,所以正确的比法是逐条相减再平均,而不是比两个独立均值 —— 后者会被片子之间的巨大方差淹没,而那部分方差在配对时会抵消。 CI 为 2000 次 bootstrap 重采样的 95% 区间(种子固定,可复现)。

W / T / L = A 在 20 条里赢 / 平 / 输的条数(按该指标自己的方向)。 粗体行表示 95% CI 不跨 0,即差异在这 20 条上稳定成立。

评测口径抽帧规则、Downsample LPIPS 的精确定义、参照系为什么也要编码、已知混淆项
  • 图像 IQA(MUSIQ / CLIP-IQA / MANIQA / NIQE):每条视频均匀抽样 24 帧所有方法用完全相同的帧号,帧号来自 manifest.json,由完整性检查一次性冻结。 每个指标共 20 × 24 × 6 = 2880 次评测
  • Downsample LPIPS:不抽样,逐帧全跑(每个方法 3724 帧)。协议是 2× 输出 → torch F.interpolate(mode="area") 缩回源分辨率 → 与 MiniMax 原片做 LPIPS(AlexNet)。 两路视频锁步解码,任何一路读短立即报错中止,绝不允许因帧数不齐而静默错位。
  • 这不是画质分。Downsample LPIPS 衡量的是「修复有没有改掉原内容」: 低 = 忠于原片,高 = 大量重写。它无法判断重写得好不好看。
  • 公共帧数取 min。SwiftVR 在 14 条片子上比原片少 1–3 帧(clip_len 分块的尾巴对不齐), 所以每条片子的评测长度取所有方法的最小值,逐条记录在 manifest.json
  • 两个参照系也编码成真实 mp4 再评(libx264 CRF 17)。如果按无损数组评, 它们会白拿一个所有已发布方法都没有的编码优势。
  • 已知混淆项:四个方法的交付编码设置并不一致(SwiftVR 用 imageio quality=85, CDA-VSR 用 CRF 17)。这是各自实际发布管线的属性,我们评的就是真实交付产物, 但它确实会影响无参考 IQA。20 条片子的码率分布都记在 issues.csv 里。
  • 完整性检查先于评测:逐条核对每个方法是否都有产出、分辨率是否严格等于源 ×2、 fps 是否一致、帧数是否一致、文件是否可解码。0 个 fatal,28 个 warn(全是上面那条帧数差), 全部落在 issues.csv,没有静默忽略。

⑤ ×2 Ground-Truth Benchmark

上面那一节测的是「在真实 MiniMax 分布上,输出好不好看 / 改了多少」。这一节测的是另一回事: 有 ground truth 时,还原得准不准。两者结论并不一致,这正是必须两个都跑的原因。

Full-reference(保真度,与 GT 比)

No-reference(观感,不看 GT)

配对逐条对比benchmark 上的逐条配对差与置信区间
×2 降质协议从 GT 自建 ×2 输入的完整流程、六方法共用同一 LQ、以及查出的两个 SwiftVR bug

我们的生产任务是 768p → 2×,不是论文里的 ×4,所以没有直接用数据集自带的 LQ (UDM10 自带的是 ×4 的 318×180,用它会答非所问)。统一从 GT 自己造 ×2 输入:

GT png  ──(居中裁到 32 的倍数)──▶  对齐后的 GT      ← 评分基准,无损 png
   │
   └──(bicubic 0.5×)──▶  LQ ──(libx264 crf23, GOP=25, 无 B 帧, refs=1)──▶  唯一共享的 LQ.mp4
                                                                              │
                    ┌─────────────────────────────┬───────────────────────────┤
                    ▼                             ▼                           ▼
              nearest/bicubic ×2            SwiftVR ×2              CDA-VSR 原生×4→area→×2
                    │                             │                           │
                    └──────────── 全部输出无损 png,分辨率 = GT ────────────────┘
  • 六个方法读的是同一个 LQ 文件(md5 记录在 bench_manifest.json 里)。 LQ 必须是压缩视频,因为 CDA-VSR 是压缩域模型、要从码流里取运动矢量; 它的 deLR/mvs/residual 全部解自这一个文件。 顺带修掉了 MiniMax 那轮的一个不对等:那次 SwiftVR 读的是原始 mp4、CDA-VSR 读的是重编码版本。
  • 评分两侧都是 PNG,量化指标从不经过有损容器。(DOVER 例外:它是视频模型, 必须给容器,所以六个方法统一用 libx264 -crf 0 yuv420p 编码后再评, 色度下采样对六者完全一致。)
  • GT 居中裁到 32 的倍数,理由见下面那条 SwiftVR 的 bug。YouHQ40 1080→1056、 UDM10 720→704 / 1272→1248,逐条记录在 manifest 的 native_size / crop_yx
  • GT 无损性是验证过的,不是假定的:GT png → 无损视频 → 解码回来逐像素比对, max|diff| 必须为 0,否则该条直接判失败。
顺带查出 SwiftVR 一个会静默丢行的 bug。它把 2× 目标高度上补到 32 的倍数再送进网络, 出来之后无条件裁掉补的那几行 —— 但那几行根本没出现在解码输出里, 于是 1080p 输出实际只有 1072 行,凭空少 8 行。官方 restore_video 和 单线程驱动都一样。MiniMax 那 20 条的输出边长全是 32 的倍数(1536/2688/1344/2048…), 所以从没触发过;YouHQ40 的 1080 一上来就撞上了。本页 benchmark 把 GT 对齐到 32 来绕开它, 但生产上只要输出高度不是 32 的倍数(1080p 首当其冲),就会中招。
另一处:SwiftVR 会吃掉片尾最多 3 帧。它把处理长度取整到 4k+1, 所以 32 帧的 UDM10 片子只输出 29 帧(10/10 全中),YouHQ40 的 33 帧刚好整除、只有那条 31 帧的中招。 评分一律只取公共前缀,差额记进 bench_issues.csv —— 没有补帧,没有静默对齐。

SPMCS 没有跑。原计划是「前两个数据集若分不开模型再上第三个」—— UDM10 与 YouHQ40 上 PSNR-Y 差 8 dB 以上、模型间每个配对的 95% CI 都不跨 0, 已经分得很开,再加一个数据集不会改变结论。两套评测的关系见 ③ 为什么两套评测给出相反的结论

⑥ 工程细节

以下全部默认收起。结论不依赖它们,但每一条都是这页数字站得住的原因。

速度、显存与逐条数据四组总览 · 逐条耗时 · 显存曲线 —— 20 条 × 4 组共 80 次运行的原始测量

四组总览

配置20 条总耗时自身优化幅度显存峰值上限显存中位相对最快
SwiftVR 官方877.1 s基线 29.68 GiB29.002.88× 慢
SwiftVR 优化304.5 s2.88× 22.11 GiB19.72最快
CDA-VSR 官方881.6 s基线 5.16 GiB3.942.90× 慢
CDA-VSR 优化347.8 s2.53× 4.85 GiB3.701.14× 慢
这不是同一量级的对比。SwiftVR 是 5B 参数的生成式一步 DiT,CDA-VSR 是 3.11M 参数的判别式在线 VSR, 小 1600 倍。而且 CDA-VSR 是在架构劣势下比的 —— 它发布的重建头只有 ×4,为了产出 2× 必须先算到 3072p(16:9 时 5376×3072,16.5 Mpx)再降采样,多出来的算力全部计入它的耗时。

逐条耗时

SwiftVR 官方 SwiftVR 优化 CDA-VSR 官方 CDA-VSR 优化

横轴按帧数排序。片子越长四条线越收敛 —— 两边的固定 warmup 开销都被摊薄了。

显存

SwiftVR 官方 SwiftVR 优化 CDA-VSR 官方 CDA-VSR 优化
显存是这次对比里差距最大的一项:SwiftVR 优化版仍需 22.11 GiB,CDA-VSR 只要 4.85 GiB。 SwiftVR 在 32G 卡上只能单路常驻;CDA-VSR 一张卡可以并行跑 6 路。
整帧视频对比5 条片源的完整画面并排播放(上面的放大局部更适合看差别)

视频对比

五条片源,每条给出输入(bicubic 2× 放到同一画布,仅作参照)和四组输出。四组产出分辨率完全相同。 网页版统一截取前 5 秒并重新编码,细节有损失;判画质请用机器上的原始输出。

我做了哪些优化SwiftVR 2.88× / CDA-VSR 2.53×,以及为什么 CDA-VSR 的瓶颈不在模型

我做了哪些优化

SwiftVR — 2.91×,显存 −7.6 GiB

  • clip_len 24 → 4。贡献最大的一步。官方 UI 写的是「Larger = more context」,实测反了: 小 chunk 更快、更省显存,闪烁更低、锐度更高。
  • 弃用官方 restore_video 的四线程流水线,改单线程顺序驱动(官方 Space 的 app.py 用的就是后者)。又快又省 3–4 GiB,还绕开了下面那个死锁 bug。
  • torch.compile,常驻只付一次编译代价。

CDA-VSR — 2.29×

  • 把 mmcv 的 ModulatedDeformConv2d 换成 torchvision 原生 deform_conv2d。 最关键的一步:mmcv 是 C 扩展,dynamo 无法追踪、必然 graph break;换成原生算子后 torch.compile 才能吃下整图。该替换经过逐位等价验证(整网 max|diff| = 0.000e+00),不是「能跑就行」。
  • bf16 autocast + channels_last + torch.compile
  • 后台预取线程 + pinned memory + 异步 H2D。压缩域先验每帧要读 2.4–4.1 MB 运动矢量,IO 很重。
  • ×4→2× 的降采样放到 GPU 上、在回传主机之前做。×4 输出是实际需要的 4 倍像素, 先降再传省掉 75% 的 D2H 和编码量。
优化后 CDA-VSR 只有 52% 的时间在 GPU 上(230.2s / 443.3s),其余是 IO 和编码 —— 它的瓶颈已经不在模型,而在压缩域先验的数据量(20 条片子的先验共 18 GB)。这是它的架构代价。

画幅:每个宽高比实际在算什么

两个模型产出同一目标分辨率,但内部走的路完全不同。SwiftVR 先把输入双线性放大到目标分辨率、 再做 encode→DiT→decode;CDA-VSR 的重建头只有 ×4,必须先算到 4 倍边长再降回来。

宽高比片数输入 768p目标输出 2× 输出 MpxCDA-VSR 内部 ×4 中间画幅SwiftVR 峰值CDA-VSR 峰值

16:9 与 9:16 那两档,CDA-VSR 内部要算到 5376×3072 = 16.5 Mpx,是最终所需 4.13 Mpx 的 4 倍。 这部分额外算力全部计入了它的耗时。SwiftVR 的显存峰值严格随输出像素线性增长 (12.03 + 2.44×Mpx,20 条实测最大残差 0.006 GiB),其中 12.03 GiB 是 bf16 权重常驻。

瓶颈在 GPU 还是 CPU

这两个模型的瓶颈完全不在同一侧,直接决定了「加一张卡」还是「加 CPU/换 IO」才有用。

SwiftVR:GPU 主导(73–80% 在 GPU 上)

机器 / 片源输出总耗时GPU 计算 视频解码编码写出GPU 占比

解码几乎免费(0.2–0.7 秒,占比 1–2%),编码占 8–12%。加 CPU 对 SwiftVR 没意义 —— 换更快的卡才有效。

CDA-VSR:CPU / IO 主导(官方配置只有 38% 在 GPU 上)

配置机器总耗时GPU 净算GPU 占比其余(IO + 编解码)
CDA-VSR 官方5090881.6 s333.3 s 37.8%548.3 s
CDA-VSR 官方40901096.9 s418.9 s 38.2%678.1 s
CDA-VSR 优化5090347.8 s199.6 s 57.4%148.2 s
CDA-VSR 优化4090489.2 s284.9 s 58.2%204.2 s
CDA-VSR 要读压缩域先验:每帧 2.4–4.1 MB 的运动矢量,20 条片子的先验共 18 GB。 官方配置是逐帧同步 cv2.imread + np.load,再在 5376×3072 上做 CPU 端 resize, 所以近 2/3 的时间不在 GPU 上。我的优化把预取搬到后台线程、把降采样搬到 GPU, GPU 占比从 38% 提到 58% —— 但它依然是这条链路上最该继续优化的地方,而不是模型本身
硬件对比:RTX 5090 vs RTX 4090同代码同权重同协议,4090 慢 1.4–1.46×,以及两处已知的口径瑕疵

硬件对比:RTX 5090 vs RTX 4090

同一套代码、同一份权重、同样的 20 条片源,两台机器采用完全相同的执行协议: 单配置顺序执行、4 分片跑在 GPU 0–3、全程无其他负载。

配置5090 (32G)4090 (24G)4090 慢 5090 峰值4090 峰值
SwiftVR 优化304.50 s443.36 s 1.46×22.11 GiB22.11 GiB
CDA-VSR 官方881.57 s1096.94 s 1.24×5.16 GiB4.92 GiB
CDA-VSR 优化347.83 s489.17 s 1.41×4.85 GiB4.85 GiB
CDA-VSR 官方 · 仅 GPU 净算333.28 s418.85 s 1.26×
CDA-VSR 优化 · 仅 GPU 净算199.63 s284.94 s 1.43×
结论:4090 比 5090 慢约 1.4–1.46×(同配置、同显存峰值)。 CDA-VSR 官方那行的 1.24× 偏低,是因为它近 2/3 时间耗在 CPU 上、摊薄了 GPU 差距 —— 只看 GPU 净算就回到 1.26×,优化配置则是 1.43×。
SwiftVR 官方配置在 4090 上不构成有效对比,已从上表移除。 20 条片子全部被迫降 clip_len(1:1 从 24→20,4:3/3:4 从 24→12,16:9/9:16 从 20→8), 因为 4090 的分配峰值最高只到 22.32 GiB,而 5090 用到 29.68 GiB。 两边跑的已经不是同一个配置,速度比值没有意义 —— 它的总耗时看起来是 884.45 vs 877.12 秒(1.01×,形同打平), 但那是小 chunk 换来的假象
4090 跑 SwiftVR 属于「刚好能跑」。优化配置峰值 22.11 GiB 顶着 23.65 GiB 可用, 只剩约 1.5 GiB 给 CUDA context —— 8 条 4.13 Mpx 的片子全过了但零余量, 画幅再大一点、或同卡再起一个进程就会翻车。CDA-VSR 峰值仅 4.85 GiB,一张 4090 可并行 4 路。

已知的两处硬件口径瑕疵

  • PyTorch 任何 wheel 都不含 sm_89 cubin。4090(sm_89)实际执行的是 sm_86 的 cubin, 靠 CUDA 大版本内二进制兼容;5090 执行的是原生 sm_120。 (CDA-VSR 优化版走 inductor/triton,那部分是为 sm_89 原生编译的。)
  • 5090 用 torch 2.10.0+cu130,4090 用 +cu128(驱动 535 限制)。torch 版本相同。

其余全部对齐并逐项核验:仓库 rev 相同、checkpoint 字节数相同、跑分脚本与打过补丁的 runner.py md5 一致、CDA-VSR 的 LR 重编码码流逐字节相同、 两边 DCN 后端一一对应(官方都用 mmcv、优化都用 tv shim,max|diff| = 0.000e+00)。

一次方法论更正最初那版 5090 数据是被并发污染的,重测后模型间结论改变了 —— 完整记录

一次方法论更正

本页 5090 的数字全部重测过。最初那版把 official(GPU 0–3)和 optimised(GPU 4–7) 同时启动了 8 个进程,而 official 是 CPU 重的配置,两者抢 CPU。 4090 那边只有 4 张卡可用、是顺序跑的,协议不一致。

线索是按输入像素归一化后的吞吐形状:4090 在五种分辨率上是平的(7.47–7.71), 5090 却浮动 1.85 倍、且在 768×768 那档绝对值反而低于 4090 —— 而 optimised 下 5090 每档都赢。 这不是硬件差异该有的形状。

配置(均为 5090)并发协议顺序协议差异
SwiftVR 官方892.85 s877.12 s−1.8%
SwiftVR 优化306.46 s304.50 s−0.6%
CDA-VSR 官方1015.73 s881.57 s−13.2%
CDA-VSR 优化443.27 s347.83 s−21.5%
这改变了模型之间的结论。按污染数据,SwiftVR 优化版比 CDA-VSR 优化版快 1.45×; 按干净数据只快 1.14×。原因正是上面那条 —— CDA-VSR 是 CPU 主导的,被并发惩罚得最重(−21.5%), 而 GPU 主导的 SwiftVR 几乎没受影响(−0.6%)。本页展示的是干净数据。
旧的自制代理指标锐度 / 闪烁两个启发式量,已被上面的标准指标取代,保留备查

客观代理指标

2× 任务没有 ground truth,所以算不了 PSNR/SSIM。下面两个是代理量, 只能横向比同一条片子的不同配置,不能当作画质分数 —— 锐度既会因真实细节上升、也会因振铃和过锐上升;闪烁里混着真实运动。

SwiftVR 优化 CDA-VSR 优化
锐度差距很大且系统性存在(20 条全部如此)。这符合两者的性质:SwiftVR 是生成式的,会「补」出 训练分布里的细节;CDA-VSR 是判别式的,只从压缩域先验和历史帧里「recover」,风格保守得多。 锐度高不等于更正确 —— 生成的细节可能并不存在于原始内容中。这一点必须靠人眼在上面的视频里判断。
口径与已知问题CDA-VSR 的 ×4 劣势、官方脚本的 t=100 bug、SwiftVR 的死锁 bug、残差近似等

口径与已知问题

  • CDA-VSR 在 ×4 劣势下参赛。它的重建头是 Conv2d(num_feat,48)+PixelShuffle(4), 发布的权重按 ×4 训练。要原生 ×2 得改重建头并重训或微调 —— 不在本次范围内。 所以它走「真实 768p → 原生 ×4 → 3072p → 降到 1536p」,额外算力如实计入。
  • CDA-VSR 官方脚本改了一行才能跑。 basicsr/models/video_recurrent_model.py:310t = 100 是写死的字面量, 在 REDS4 上看不出来(每 clip 正好 100 帧)。我们的片子是 73–362 帧:73 帧的会 IndexError, 241/362 帧的会静默只算前 100 帧。改成 t = len(frames),其余一字未动。 注意这是发布脚本的问题,不是模型的限制 —— 模型是在线递归的,可处理任意长度流。
  • SwiftVR 官方配置有 8 条在 clip_len=24 直接 OOM(4.13 Mpx 那两个比例), 自动回退到 20 才跑通。这是给官方配置放宽后的结果。
  • SwiftVR 上游有一个会静默挂死的 bug。runner.pyrecord_error() 用阻塞式 q.put() 往 maxsize=3 的有界队列发停止信号, OOM 时队列必满 → put 永不返回 → 主线程卡死在 join()。表现是 GPU 0% 占着显存挂住, 而不是崩溃退出。已打补丁;改用单线程驱动可整个绕开。
  • CDA-VSR 的残差是近似的。libavcodec 不暴露真实变换域残差,除非改 ffmpeg 解码器。 我们用运动补偿后的 Y 通道差值,与真实 warp 误差相关性 0.67–0.94。 运动矢量的符号约定经实证确认(用模型自己的 warp 函数:正号比反号的对齐 PSNR 高 4.4–10.4 dB)。
  • 帧类型不在磁盘上。README 说数据集含 frame-type 信息,实际代码是按位置硬编码 fi % 25 == 0 判 I 帧。所以 LR 必须重编码成 GOP=25、I 帧落在 25 的倍数上、且无 B 帧 (-bf 0 -refs 1 -sc_threshold 0)。这一步的重编码是第二代压缩,计入了 CDA-VSR 的输入质量。
  • 两边都用视频编码输出(CDA-VSR 官方脚本原本逐帧写 PNG,那样更慢)—— 这个选择对官方版有利。

测试机 viggle_new_5090(8×RTX 5090 32G,驱动 580.159.03)· SwiftVR:conda swiftvr, torch 2.10.0+cu130,官方 H-oliday/SwiftVR 权重 bf16 未量化 · CDA-VSR:conda cdavsr, torch 2.10.0+cu128,mmcv 2.2.0 源码编译(sm_120),官方 best.pth,权重 0 missing / 0 unexpected · 片源为 MiniMax-H3 历史输出,20 条覆盖 5 种宽高比 · 2026-08-21

评测部分(2026-08-21)· 指标实现 PyIQA 0.1.16(MUSIQ / CLIP-IQA / MANIQA / NIQE / LPIPS-Alex / DISTS / PSNR / SSIM),DOVER 官方实现 VQAssessment/DOVER + DOVER.pth v0.1.0, torch 2.10.0,8×RTX 5090 分片并行 · MiniMax-20:图像 IQA 每条 24 帧均匀抽样(全方法同帧号),Downsample LPIPS 逐帧全跑 3724 帧 · ×2 GT Benchmark:UDM10(10 条 / 32 帧 / GT 1248×704)+ YouHQ40(40 条 / 33 帧 / GT 1920×1056), GT → bicubic 0.5× → libx264 crf23 GOP25 无 B 帧 → 六方法共用同一 LQ,输出与评分全程 PNG · ↑ 越高越好,↓ 越低越好 · 完整口径见 evaluation/README.md