SeedVR2 3B 图片与短视频修复:原生 C++ / ncnn / Vulkan 移植 #6991
mingshi2333
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
SeedVR2 ncnn Vulkan 于 2026 年 9 月 6 日 开始开发,使用 C++20 和 ncnn 实现 SeedVR2 3B 的本地推理,支持 Vulkan 加速,可用于图片与短视频修复。提供独立 CLI、本地 Web 界面和可安装的 C++ SDK,输出 PNG、MP4 及 JSON 运行报告。模型准备完成后可离线使用,推理无需 Python。
移植包含官方权重转换、自定义算子、原生推理流水线和应用交付。当前验证配置为 3B、FP32-B、单步、CFG=1。
应用架构与技术栈
应用围绕三个需求组织:浏览器操作方便、命令行便于批量测试、其他 C++ 程序能够直接调用。三个入口共用原生 SDK,模型计算集中在同一套实现中。Web 的任务状态与模型执行分开,转换工具则在准备模型时单独运行。
flowchart TB Web["浏览器:React / TypeScript / Ant Design"] --> HTTP["Drogon:本地 HTTP API"] HTTP --> Jobs["任务队列与进程监督"] Jobs <--> DB[("SQLite:任务、事件、文件引用")] Jobs --> Worker["独立 C++ worker"] CLI["CLI11 命令行"] --> SDK["公共 SDK:seedvr2::restore"] External["其他 C++ 应用"] --> SDK Worker --> SDK SDK --> Pipeline["预检、模型校验、图片或短片编排"] Package[("模型包:manifest、图、常量")] --> Pipeline Pipeline --> Executor["逐图装载、执行与资源释放"] Executor --> Runtime["ncnn CPU / Vulkan + 自定义算子"]前端经 Vite 构建后内嵌到 C++ Web 程序中,安装后由同一个本地服务提供页面和 API,运行时不需要 Node。Python、PyTorch 和 pnnx 用于模型准备与参考验证,实际推理由 C++ SDK 执行。只需要 CLI 时可以关闭 Web 构建,不引入 Drogon 和前端构建步骤。
一次 Web 任务如何执行
用户导入文件后,服务保存媒体并分配 ID;提交参数时创建任务,SQLite 同时记录请求和状态。当前最多保留 8 个未完成任务,同时执行 1 个,控制多个大模型任务对显存和 RAM 的竞争。
任务服务为当前任务写入请求文件,启动独立 worker。worker 调用
seedvr2::restore,通过逐行 JSON 消息返回进度、结果或错误。服务校验消息并持久化事件,浏览器定期查询任务状态;刷新页面可以继续查看同一个任务。只有 worker 正常退出、报告包含完整阶段且输出文件身份核对成功,任务才标记为完成。取消由服务通知并监督 worker 退出。服务重启后,尚未完成的任务记为
INTERRUPTED,保留原因;用户重试时创建一次新的完整运行。这里恢复的是任务记录,没有从某个 DiT block 继续计算的断点恢复功能。进程监督实现和已验证的交付平台目前是 Linux。公共 SDK 与职责边界
公共入口定义在
include/seedvr2/pipeline.hpp:RestoreRequest描述输入、模型、输出目录、设备和内存策略,preflight做预检,restore执行图片或短片修复;verify_model和copy_model负责模型校验与离线复制。进度与取消使用回调,返回值包含输出文件、运行报告或明确错误。公共头文件使用标准 C++ 类型,不要求调用方引入 ncnn、CLI11 或 JSON 库。CLI 负责参数和终端输出,Web worker 负责进程消息,SDK 负责实际计算。外部工程通过
find_package(seedvr2 0.7 CONFIG REQUIRED)和seedvr2::sdk链接安装后的同一套库;测试程序也走这个入口。模型转换与原生推理
模型包按 VAE encoder → patch-in → 32 个 DiT block → patch-out → VAE decoder 拆成 36 个 ncnn 图。这样可以用官方中间输入单独重放一个组件,也可以随阶段装载和释放权重。C++ 流水线负责连接组件,并实现布局、后验采样、条件拼接和 Euler 更新。
flowchart TB Input["图片 / 短片 RGB"] --> Prepare["缩放、归一化;视频尾帧补齐"] Prepare --> Encoder["VAE encoder:像素到后验分布"] Encoder --> Posterior["后验采样与缩放:16 通道条件潜变量"] PosteriorNoise["原始后验噪声"] --> Posterior Posterior --> PatchIn["条件拼接 + patch-in:投影到 2560 维"] Noise["扩散噪声"] --> PatchIn PatchIn --> DiT["32 个 DiT block:更新视频与文本状态"] Text["固定正向文本与时间条件"] --> DiT DiT --> PatchOut["patch-out:还原速度预测"] PatchOut --> Euler["单步 Euler endpoint"] Noise --> Euler Euler --> Decoder["VAE decoder:潜变量到 RGB"] Decoder --> Output["裁回真实帧数;PNG / MP4 + run.json"]当前 3B 的关键关系如下,模型尺寸与调度均来自 SeedVR2 本身:
1×2×2patch58×2560正向文本条件,当前用户接口不接受自由文本提示图片使用单帧路径。视频在整个短片的潜变量上联合处理,保留时间轴上的 VAE 卷积和 3D attention。例如 8 帧先重复尾帧补到 9 帧,VAE 得到 3 个潜变量时间位置,解码后裁回 8 帧。当前跨片段 VAE cache 关闭,整段短片的输入、补齐和输出裁剪均写入报告。
AWA 如何导出和执行
AWA(adaptive window attention)的窗口随实际时间、空间网格变化。导出时通过 pnnx
moduleop保留模块边界,再检查属性、输入输出、归一化权重和 RoPE 频率,将节点映射为SeedVR2AWA。运行时根据实际形状生成窗口索引。每次 AWA 计算包含三步:
Vulkan 复用锁定 ncnn 的 SDPA QK/PV 着色器,配合项目的 FP32 softmax、gather/scatter 和文本归约。时序 VAE 的变换与卷积也由原生层处理。请求 Vulkan 时检查实际层支持和算术能力,不满足条件会返回错误。编解码、布局、噪声和 Euler 在主机执行,当前图间张量会下载后再上传到下一图。
转换路径为 官方实现与权重 → PyTorch / TorchScript → pnnx → 自定义层映射 →
.param/.bin与常量组成的模型包 → 原生 CPU/Vulkan。运行库固定为 ncnn3b7bdba7fc8aea8fd46779533eee027df77c639d,pnnx 导出单独固定为6a1bf000f363714839a36793addc8c879d3d899e;分配器适配与实际加载库的身份另记入报告。AWA 导出 / 真实 DiT block 导出。内存、模型包与资源生命周期
FP32 图文件包约 20 GB,执行器一次装载一个图:检查图结构、查询预算、选择权重放置、执行、取回必要输出,再销毁 Net 和分配器。相邻图复用必要的输出,本次运行共享着色器 pipeline cache。代价是逐图文件读取、装载和主机/GPU 传输。
auto / device / host控制 Vulkan 权重放置。自动模式在每次图装载前重新查询显存预算,按图文件大小估算权重准备空间并预留余量;预算不足或查询不可用时选择主机可见内存。host权重仍用于 Vulkan 计算,实际内存类型与驻留由驱动决定。报告保留请求的策略、选择原因和预算快照。这里的估算针对权重,尚未实现激活/工作区的自动卸载或 OOM 自动重试。默认缓冲读取权重,也可使用只读
mmap;映射保持到对应 Net 销毁之后。当前模型没有自回归 KV cache,也没有跨任务常驻的整包权重缓存。内存策略与测量。模型包独立于应用安装,manifest 记录图、常量、采样设置与来源。预检先检查参数、媒体几何、输出空间、设备和包身份,实际运行再校验全部权重哈希;离线复制校验两端,成功后再发布目标目录。每份
run.json绑定输入、模型 manifest、转换器、运行库,以及可执行文件和实际加载 SDK 的身份。相同输入数值验证还绑定两份原始噪声,任务画质另用目标和基线评估。代码组织
include/seedvr2/pipeline.hpp、examples/sdkapps/cli、apps/studio、apps/server、apps/workersrc/jobs/service.cpp、src/jobs/process.cpp、src/storage/workspace.cppsrc/engine/ncnn/pipeline.cpp、image.cpp、video.cppsrc/engine/ncnn/inference.hpp、graph.hpp、weight_io.hpp、memory.hpp,以及src/runtime/memory_policy.cppsrc/engine/ncnn/awa.cpp、video_layers.cpp、rms_norm.cpp、linear.cpp、softmax.cpp、shaderstools/export_*.py、tools/pipeline_contract.py、tools/pipeline_replay.pyCMakeLists.txt、cmake、.github/workflows/native.yml公共 API、任务服务、模型数学、图执行和包管理分别承担自己的职责。可以从 CLI 或外部 SDK 程序直接重现问题,再按组件定位;Web 层负责提交和展示结果。更细的调用边界见架构与源码导航。
DiT FP16 权重存储与模型下载
新增 32 个 DiT 块的 IEEE FP16 线性权重存储,ncnn 加载时展开到 FP32;激活与算术仍为 FP32,VAE、patch projection、bias 和自定义注意力属性保持原值。新模型包使用独立 profile 与 payload 哈希,CLI、Web worker 和 SDK 共用加载器。逐图内存预算按展开大小估算,避免把压缩文件大小当成运行时权重需求。
已公开 Hugging Face:DiT FP16 存储 和 Hugging Face:FP32-B。均为已转换的 ncnn 模型,包含图、权重、常量和 manifest,支持匿名下载;使用者可省去本机 PyTorch/pnnx 转换,原生程序仍从源码构建。
这项变化降低下载与磁盘占用,不等于 INT8、全 FP16 运算、显存减半或速度提升。分别安装图片与视频仍各自占用本机空间。
五条完整执行覆盖图片 CPU/Vulkan 及 9/8/17 帧 Vulkan 视频;每条记录全部 73 个模型边界及辅助张量,输出有限。相对原生 FP32,256×256 图片的 PSNR 约 40.03 dB、SSIM 0.99158;三个 128×80 视频的逐帧 PSNR 分别为 61.96–64.32 / 62.50–64.25 / 66.48–67.86 dB。旧 FP32 门槛保留为描述统计,不作为低精度接受条件。
保真度与修复质量分开:固定目标图片 PSNR 为 FP32 20.0184 / FP16 存储 20.0093 dB,三段视频的对应均值差小于 0.001 dB。样例仍是一张图片和来自同一来源的三个开发短片,不外推普遍画质。逐层误差、目标质量、时序残差和资源记录见 完整报告。
两个 HF 版本均完成固定 revision 的全量远端回读与图片/视频包原生校验;FP16 安装 SDK 完成隐藏源码、断网和 Unicode 路径下的真实图片执行,77 个诊断哈希与冻结 FP16 结果一致;下载模型的 39 项真实 Web 任务检查也已通过。公开后匿名访问范围单独记录。该实验使用同一台 Linux 主机系统库,不等于干净目标机或跨发行版验证。
对照结果
Linux x86_64,RTX 4060 Laptop 8 GiB,约 32 GiB RAM。对照使用锁定官方数学实现的 CPU FP32-B 参考,共享原始后验噪声和扩散噪声,逐元素检查全部 73 个张量边界。
本轮没有修改官方参考、权重、原始噪声或
atol=rtol=0.001的历史全链门槛。误差定位用相同输入的真实组件回放,修复了 VAE 分块卷积和 shortcut bias 顺序、归一化、注意力中的 FP32 舍入,以及 DiT 长点积的误差补偿。还抓到并修复了 CPU 留出视频的 72/73 回归。失败候选和诊断记录都保留在数值修复报告。下面四列依次为 bicubic → 原生 ncnn/Vulkan → 官方 FP32-B → 固定目标;来自实际输出,没有额外增强。
完整张量对照通过之后,画质仍需单独看。三段低分辨率开发视频的原生 PSNR 为 20.01 / 19.70 / 23.24 dB,bicubic 为 26.93 / 26.82 / 26.80 dB;SSIM 也较低,官方 FP32-B 在这些样例上有相同表现。这些素材来自同一来源和固定人工退化,不是代表性画质基准。全部图、视频与逐帧数据。
使用与当前边界
先安装教程中的系统开发依赖,从仓库根目录构建并直接下载运行:
python3 tools/build_native.py --cli-only --jobs 2 --prefix dist/tutorial python3 tools/download_models.py --precision dit-fp16 --kind image \ --output dist/tutorial/models/image --run input.png --result results/image # 视频包,最多 17 帧、输出长边 128 python3 tools/download_models.py --precision dit-fp16 --kind video \ --output dist/tutorial/models/video --run input.mp4 --result results/video --frames 17使用已有输入和新结果目录。去掉
--run/--result可仅安装;--plan查看字节数,--offline校验并复用本机模型。下载固定 revision,支持续传、逐文件 SHA-256 和原生校验;下载工具只需 Python 标准库,原生推理无需 Python。FP32-B 改用--precision fp32并指定另一模型目录。旧程序需从当前源码重新构建才能识别新的存储 profile。需要 Web 时构建去掉
--cli-only,准备 Node.js 24/npm,安装上述模型后运行dist/tutorial/bin/seedvr2-studio。自行转换可继续使用官方权重下载与本机转换入口;直接下载已转换模型不需要 PyTorch/pnnx 或uv。首次使用与离线搬移。普通 CI 检查构建、算子和应用接口,不下载大模型;完整官方权重转换、首次执行与隔离网络回放独立记录,不创建二进制 Release。原发布工作流因访问未公开模型返回 404,其构建已通过,但首次推理未执行;不把这次失败计作模型数值失败或完整交付通过。
应用已包含参数预检、Unicode 路径、进度与取消、模型身份/完整性校验、离线模型复制和安装 SDK。本机原生测试 36/36。Mesa 的小型测试为 10 项通过、12 项能力跳过:本机 llvmpipe 不保留这些补偿算子要求的 FMA 残差,程序会在模型加载前明确拒绝。能力探测和数值验收分开;大模型实机证据不由 CI 小型测试替代。
新增存储路径及 Web 标识修正提交
c9af01d的 Ubuntu GCC CLI、Clang CLI、GCC Web CI 均已通过;普通 CI 不包含完整 3B 模型实机执行。历史提交
7e56479的 Ubuntu GCC CLI、Clang CLI、GCC Web 远端 CI 全部通过:每项原生套件 24 项通过、12 项能力跳过,Web 另有 54/54 接口检查。下载归档的原始报告保留依赖日志、安装验证和跳过原因;远端 CI 没有运行完整 3B 权重。当前图片输出长边 ≤512;视频 ≤17 帧、长边 ≤128,输出无音轨 SDR MP4。官方 CUDA BF16/Apex/FlashAttention 默认路径、更高分辨率、长片、音轨、更多设备和代表性时序画质仍是后续工作。具体缺口与验收范围。
希望交流两个实现问题:如何在不同 Vulkan 驱动上可靠地保留补偿算法需要的 FMA 行为;以及在保留同输入数值证据的前提下,怎样减少这类逐图大模型执行的权重装载和图间传输成本。欢迎带设备、驱动、参数与
run.json的复现报告。All reactions