SwiftVR 5B 生成式 CDA-VSR 3.11M 判别式 各含官方配置 + 自研优化 20 条标准片源 × 4 组 = 80 次运行 RTX 5090 32G ↓ PyIQA 客观评测 ↓ ×2 GT Benchmark
统一任务:输入 768p,输出 2× 放大。20 条片源覆盖 5 种宽高比、每个比例 4 个不同的人、73–362 帧不等。 全部 80 次运行零失败。四组产出同一目标分辨率,可直接并排对比。
| 配置 | 20 条总耗时 | 自身优化幅度 | 显存峰值上限 | 显存中位 | 相对最快 |
|---|---|---|---|---|---|
| SwiftVR 官方 | 877.1 s | 基线 | 29.68 GiB | 29.00 | 2.88× 慢 |
| SwiftVR 优化 | 304.5 s | 2.88× | 22.11 GiB | 19.72 | 最快 |
| CDA-VSR 官方 | 881.6 s | 基线 | 5.16 GiB | 3.94 | 2.90× 慢 |
| CDA-VSR 优化 | 347.8 s | 2.53× | 4.85 GiB | 3.70 | 1.14× 慢 |
横轴按帧数排序。片子越长四条线越收敛 —— 两边的固定 warmup 开销都被摊薄了。
五条片源,每条给出输入(bicubic 2× 放到同一画布,仅作参照)和四组输出。四组产出分辨率完全相同。 网页版统一截取前 5 秒并重新编码,细节有损失;判画质请用机器上的原始输出。
2× 任务没有 ground truth,所以算不了 PSNR/SSIM。下面两个是代理量, 只能横向比同一条片子的不同配置,不能当作画质分数 —— 锐度既会因真实细节上升、也会因振铃和过锐上升;闪烁里混着真实运动。
上面那两个代理量(锐度 / 闪烁)只是自己写的启发式。这一节换成成熟实现的标准指标(PyIQA), 在同一批 20 条真实 MiniMax 产出上跑。没有 2K ground truth,所以做的是无参考画质加一项源一致性。 参评的六个方法里有两个是不花 GPU 的放大参照系,用来给「模型到底赚了多少」定一个地板。
绿色 = 该指标下四个模型之间的最优。灰色两行是参照系,不参与「最优」的评选 —— 它们在 Downsample LPIPS 上必然接近 0(把原片放大再原样缩回去本来就等于原片),列出来是当刻度尺用的。
六个方法跑的是同一批 20 条片源,所以正确的比法是逐条相减再平均,而不是比两个独立均值 —— 后者会被片子之间的巨大方差淹没,而那部分方差在配对时会抵消。 CI 为 2000 次 bootstrap 重采样的 95% 区间(种子固定,可复现)。
W / T / L = A 在 20 条里赢 / 平 / 输的条数(按该指标自己的方向)。 粗体行表示 95% CI 不跨 0,即差异在这 20 条上稳定成立。
manifest.json,由完整性检查一次性冻结。
每个指标共 20 × 24 × 6 = 2880 次评测。2× 输出 → torch F.interpolate(mode="area") 缩回源分辨率 → 与 MiniMax 原片做 LPIPS(AlexNet)。
两路视频锁步解码,任何一路读短立即报错中止,绝不允许因帧数不齐而静默错位。manifest.json。issues.csv 里。issues.csv,没有静默忽略。上面那一节测的是「在真实 MiniMax 分布上,输出好不好看 / 改了多少」。这一节测的是另一回事: 有 ground truth 时,还原得准不准。两者结论并不一致,这正是必须两个都跑的原因。
我们的生产任务是 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 ────────────────┘
bench_manifest.json 里)。
LQ 必须是压缩视频,因为 CDA-VSR 是压缩域模型、要从码流里取运动矢量;
它的 deLR/mvs/residual 全部解自这一个文件。
顺带修掉了 MiniMax 那轮的一个不对等:那次 SwiftVR 读的是原始 mp4、CDA-VSR 读的是重编码版本。libx264 -crf 0 yuv420p 编码后再评,
色度下采样对六者完全一致。)native_size / crop_yx。max|diff| 必须为 0,否则该条直接判失败。restore_video 和
单线程驱动都一样。MiniMax 那 20 条的输出边长全是 32 的倍数(1536/2688/1344/2048…),
所以从没触发过;YouHQ40 的 1080 一上来就撞上了。本页 benchmark 把 GT 对齐到 32 来绕开它,
但生产上只要输出高度不是 32 的倍数(1080p 首当其冲),就会中招。
4k+1,
所以 32 帧的 UDM10 片子只输出 29 帧(10/10 全中),YouHQ40 的 33 帧刚好整除、只有那条 31 帧的中招。
评分一律只取公共前缀,差额记进 bench_issues.csv —— 没有补帧,没有静默对齐。
Heuristic ranking — not a calibrated quality score。restore_video 的四线程流水线,改单线程顺序驱动(官方 Space 的
app.py 用的就是后者)。又快又省 3–4 GiB,还绕开了下面那个死锁 bug。ModulatedDeformConv2d 换成 torchvision 原生 deform_conv2d。
最关键的一步:mmcv 是 C 扩展,dynamo 无法追踪、必然 graph break;换成原生算子后 torch.compile
才能吃下整图。该替换经过逐位等价验证(整网 max|diff| = 0.000e+00),不是「能跑就行」。两个模型产出同一目标分辨率,但内部走的路完全不同。SwiftVR 先把输入双线性放大到目标分辨率、 再做 encode→DiT→decode;CDA-VSR 的重建头只有 ×4,必须先算到 4 倍边长再降回来。
| 宽高比 | 片数 | 输入 768p | 目标输出 2× | 输出 Mpx | CDA-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 权重常驻。
这两个模型的瓶颈完全不在同一侧,直接决定了「加一张卡」还是「加 CPU/换 IO」才有用。
| 机器 / 片源 | 输出 | 总耗时 | GPU 计算 | 视频解码 | 编码写出 | GPU 占比 |
|---|
解码几乎免费(0.2–0.7 秒,占比 1–2%),编码占 8–12%。加 CPU 对 SwiftVR 没意义 —— 换更快的卡才有效。
| 配置 | 机器 | 总耗时 | GPU 净算 | GPU 占比 | 其余(IO + 编解码) |
|---|---|---|---|---|---|
| CDA-VSR 官方 | 5090 | 881.6 s | 333.3 s | 37.8% | 548.3 s |
| CDA-VSR 官方 | 4090 | 1096.9 s | 418.9 s | 38.2% | 678.1 s |
| CDA-VSR 优化 | 5090 | 347.8 s | 199.6 s | 57.4% | 148.2 s |
| CDA-VSR 优化 | 4090 | 489.2 s | 284.9 s | 58.2% | 204.2 s |
cv2.imread + np.load,再在 5376×3072 上做 CPU 端 resize,
所以近 2/3 的时间不在 GPU 上。我的优化把预取搬到后台线程、把降采样搬到 GPU,
GPU 占比从 38% 提到 58% —— 但它依然是这条链路上最该继续优化的地方,而不是模型本身。
同一套代码、同一份权重、同样的 20 条片源,两台机器采用完全相同的执行协议: 单配置顺序执行、4 分片跑在 GPU 0–3、全程无其他负载。
| 配置 | 5090 (32G) | 4090 (24G) | 4090 慢 | 5090 峰值 | 4090 峰值 |
|---|---|---|---|---|---|
| SwiftVR 优化 | 304.50 s | 443.36 s | 1.46× | 22.11 GiB | 22.11 GiB |
| CDA-VSR 官方 | 881.57 s | 1096.94 s | 1.24× | 5.16 GiB | 4.92 GiB |
| CDA-VSR 优化 | 347.83 s | 489.17 s | 1.41× | 4.85 GiB | 4.85 GiB |
| CDA-VSR 官方 · 仅 GPU 净算 | 333.28 s | 418.85 s | 1.26× | — | — |
| CDA-VSR 优化 · 仅 GPU 净算 | 199.63 s | 284.94 s | 1.43× | — | — |
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 的数字全部重测过。最初那版把 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 s | 877.12 s | −1.8% |
| SwiftVR 优化 | 306.46 s | 304.50 s | −0.6% |
| CDA-VSR 官方 | 1015.73 s | 881.57 s | −13.2% |
| CDA-VSR 优化 | 443.27 s | 347.83 s | −21.5% |
Conv2d(num_feat,48)+PixelShuffle(4),
发布的权重按 ×4 训练。要原生 ×2 得改重建头并重训或微调 —— 不在本次范围内。
所以它走「真实 768p → 原生 ×4 → 3072p → 降到 1536p」,额外算力如实计入。basicsr/models/video_recurrent_model.py:310 的 t = 100 是写死的字面量,
在 REDS4 上看不出来(每 clip 正好 100 帧)。我们的片子是 73–362 帧:73 帧的会 IndexError,
241/362 帧的会静默只算前 100 帧。改成 t = len(frames),其余一字未动。
注意这是发布脚本的问题,不是模型的限制 —— 模型是在线递归的,可处理任意长度流。runner.py 的
record_error() 用阻塞式 q.put() 往 maxsize=3 的有界队列发停止信号,
OOM 时队列必满 → put 永不返回 → 主线程卡死在 join()。表现是 GPU 0% 占着显存挂住,
而不是崩溃退出。已打补丁;改用单线程驱动可整个绕开。fi % 25 == 0 判 I 帧。所以 LR 必须重编码成 GOP=25、I 帧落在 25 的倍数上、且无 B 帧
(-bf 0 -refs 1 -sc_threshold 0)。这一步的重编码是第二代压缩,计入了 CDA-VSR 的输入质量。
测试机 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