Skip to content

fix: keep MiniMax-H3 VAE weights resident across temporal chunks - #2103

Merged
leejet merged 1 commit into
leejet:masterfrom
losewayy:h3-vae-runner-lifetime
Oct 6, 2026
Merged

leejet merged 1 commit into
leejet:masterfrom
losewayy:h3-vae-runner-lifetime

Conversation

@losewayy

@losewayy losewayy commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Each temporal chunk of the MiniMax-H3 video VAE decode (and encode) goes through VAE::decode/VAE::encode, whose trailing runner_end() evicts the weights from the compute backend (~4.6GB for the decoder). With 7 temporal chunks per decode this re-stages the full weights 7 times, and under auto-fit on a VRAM-constrained GPU the params land on the disk tier, so every chunk re-reads the safetensors (~3s each, ~20s wasted per video).

Keep the runner alive across the temporal chunk loop and end it once when the loop finishes. VAE::decode/VAE::encode gain a non-virtual overload taking an auto_end flag (mirroring compute()'s auto_runner_end); the virtual signatures are unchanged, so every existing override keeps working.

MiniMax-H3 is the only affected model: it is the only VAE runner that drives VAE::decode/VAE::encode inside a temporal chunk loop (Wan/LTX do temporal tiling inside _compute within a single runner lifetime).

Tested

  • sd-cli -M vid_gen, MiniMax-H3 (Q4_K DiT + Q2_K_M Qwen3-VL + fp16 video VAE), 864x480, 124 frames, 8 steps, seed 12345, auto-fit defaults, CUDA 13 / Windows / RTX 5070 Ti Laptop (12 GB)
  • decode_first_stage: 53.4s -> 34.3s (-36%); generate_video: 299.7s -> 281.7s; decoded output is bit-identical to unpatched (per-frame pixel diff 0.0)
  • Builds clean on master with the recorded ggml

The encode path shares the same defect and is fixed the same way; it cannot be exercised end-to-end on a 12 GB card because the H3 encoder workspace demand (~9.8GB per chunk) exceeds the device budget — the same failure occurs on unpatched stock, so this is not a regression.

Each temporal chunk of the MiniMax-H3 video VAE decode and encode went through VAE::decode/VAE::encode, whose trailing runner_end() evicts the ~5GB weights from the compute backend, so the next chunk re-staged them (under auto-fit even re-reading the safetensors from disk).

Keep the runner alive across the temporal chunk loop and end it once when the loop finishes. VAE::decode/VAE::encode gain a non-virtual overload with an auto_end flag; the virtual signatures are unchanged so existing overrides are unaffected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants