Comfyui-MMH3-UltimateUpscale README

The project's README from github.com/bbaudio-2025/Comfyui-MMH3-UltimateUpscale. As one markdown file: README.md.

Comfyui-MMH3-UltimateUpscale

Upscale long, high-resolution MiniMax H3 video on a VRAM-limited GPU — in a single node.

This node re-samples (enhances / upscales) an already-denoised MiniMax H3 AV latent through the full auto pipeline under tight VRAM constraints: it processes the clip with temporal chunking (so arbitrarily long videos fit in memory) + spatial tiling (so arbitrarily high resolutions fit in memory), keeping peak VRAM bounded to a single tile, while preserving the audio track intact.

MiniMax H3 generates video as a nested latent that bundles 24-channel video and 32-channel audio in one tensor. Standard ComfyUI upscale nodes do not understand this structure. MMH3 Ultimate Upscale wraps the entire temporal split -> latent upscale -> spatial split -> per-tile sampling -> spatial stitch -> temporal stitch loop into one node, so you can upscale a finished H3 clip the same way you would upscale a normal latent — without breaking audio and without running out of VRAM even on small cards.


Changelog


Features


Advantages

Temporal consistency & smooth time transitions

Pixel-space consistency & smooth spatial transitions

Other


Why chunked re-sampling beats dynamic VRAM offloading

Modern PyTorch/CUDA can shuffle weights between RAM and VRAM on demand, so in principle you can generate without tiling even when the working set exceeds VRAM. In practice this is dramatically slower, and the reason is a bandwidth gap of one to two orders of magnitude:

Path Typical bandwidth
GPU VRAM (GDDR/HBM) ~1000 GB/s
PCIe 4.0 x16 (RAM ↔ GPU) ~32 GB/s
PCIe 5.0 x16 ~64 GB/s

Diffusion sampling runs tens of sequential denoising steps, and a transformer revisits its blocks in the same cyclic order every step — the worst case for any residency cache. If the weights do not fit, nearly all non-resident bytes are re-moved over PCIe on every step:

T(offload) ≈ steps × non-resident bytes / PCIe_bandwidth      ← bandwidth-bound
T(chunked) ≈ pieces × FLOPs_piece / GPU_FLOPS                 ← compute-bound

Unified-memory page faults additionally serialize the CUDA stream, so GPU utilization collapses to single digits. Chunked re-sampling instead bounds the peak working set to all weights + one piece's activations, keeping every forward pass compute-bound. The price is only a small, predictable redundancy:

A constant factor of ~1.2–1.8× always beats a 15–60× per-byte penalty. Host↔VRAM offloading only pays when the excess is small and every moved byte gets high reuse; large-DiT multi-step denoising satisfies neither.


Tuning chunk & tile sizes for your VRAM

Per-piece sampling VRAM ≈ model weights + activations, where the activation part scales roughly with chunk_length × tile_width × tile_height:

Aim for the largest pieces that keep peak VRAM just under capacity (watch ComfyUI's VRAM meter during the first tile), keeping total redundancy within roughly ×1.3–1.8. Starting points for H3:

GPU VRAM tile_width × tile_height chunk_length (multiple of 17 px frames)
8 GB 320–384 34–68
12 GB 384–512 51–102
16 GB 512–576 102–153
24 GB 576–768 136–170

Notes:


Nodes

Node Role
MMH3 Ultimate Upscale Main node. Runs the whole loop. Inputs: latent, conditioning, model, noise, sampler, sigmas, optional negative + cfg, and the three optional param inputs.
MMH3 Temporal Split Params chunk_length (px frames, multiple of 17), temporal_overlap (multiple of 17), anchor_strength.
MMH3 Spatial Split Params tile_width / tile_height (px, multiple of 32), spatial_w_overlap / spatial_h_overlap (px, multiple of 32), fade_width / fade_height (seam mask fade), min_tile_size, overlap_mode, overlap_blend.
MMH3 Latent Upscale with Model Params H3 3D model upscaler: model_name, width, height (snapped to a multiple of 32), device, precision.
MMH3 Latent Upscale Params Model-free interpolation: method, width, height (snapped to a multiple of 32).

Typical workflow

  1. Generate an H3 AV latent with MiniMax H3 (video + audio in one latent).
  2. (Optional) MMH3 Temporal Split Params → connect to temporal_split_param.
  3. (Optional) MMH3 Latent Upscale with Model Params or MMH3 Latent Upscale Params → connect to latent_upscale_param.
  4. (Optional) MMH3 Spatial Split Params → connect to spatial_split_param.
  5. Feed latent, conditioning, model, noise, sampler, sigmas into MMH3 Ultimate Upscale.
  6. Decode the output latent with the H3 VAE.

The width/height you set for upscaling must match the conditioning's generation size (the size the video was conditioned at, after upscale).

Upscale model format: .safetensors only

MMH3 Latent Upscale with Model Params only lists and loads .safetensors checkpoints (.sft is accepted as well, matching ComfyUI core). Pickle formats (.pth / .pt / .ckpt) are skipped while scanning and are rejected before the file is opened.

Why: torch.load() on a pickle checkpoint can execute arbitrary code the moment the model is selected. weights_only=True reduces the risk but is not a reliable mitigation on torch < 2.6 (pickle-time bypass, CVE-2025-32434). Refusing pickle entirely removes that surface.

If you have a .pth checkpoint you trust (for example minimax_h3_latent_upscaler_3d_fp32.pth), convert it once:

import torch, safetensors.torch
sd = torch.load('model.pth', map_location='cpu', weights_only=True)
sd = sd['model'] if isinstance(sd, dict) and 'model' in sd else sd
safetensors.torch.save_file(sd, 'model.safetensors')

If weights_only=True fails, the file is not a plain state dict and should not be trusted — don't work around it by switching back to weights_only=False. Checkpoints left in the folder are reported as ignored in the console at startup.


Reference Projects

This node is built on top of following existing community projects:

The H3 3D upscaler network code and normalization statistics are adapted from the second project; the temporal/spatial split, anchor and append logic follow the first.


Extra

This project was vibe-coded by AI, If you run into any problems, it's best to search with AI.😂

Comfyui-MMH3-UltimateUpscale (bbaudio-2025/Comfyui-MMH3-UltimateUpscale)

Searching Database…

这是什么?一个 ComfyUI 自定义节点,在显存有限的 GPU 上放大长时间、高分辨率的 MiniMax H3 AV 视频潜表示,在单个节点内使用时间分块和空间平铺,同时保持音轨完好。
它是独立应用,还是 ComfyUI 自定义节点?它是一个 ComfyUI 自定义节点包(Python),接入现有的 ComfyUI 安装,添加诸如“MMH3 Ultimate Upscale”之类的节点,而不是独立运行。
在 ComfyUI 工作流里怎么用它?把它作为 ComfyUI 自定义节点安装,用 MiniMax H3 生成 H3 AV 潜表示,然后把它连接到 MMH3 Ultimate Upscale,并按需连接 Temporal Split、Spatial Split 和 Latent Upscale 参数节点,最后用 H3 VAE 解码输出的潜表示。
我需要 MiniMax H3 模型和特定的 checkpoint 文件吗?需要——它作用于 MiniMax H3 AV 潜表示;基于模型的放大模式会从 latentupscalemodels 文件夹加载 minimaxh3latentupscaler3d.safetensors checkpoint;无模型插值模式则不需要额外 checkpoint。
依赖它之前有什么要注意的坑?只会加载 .safetensors/.sft 格式的放大 checkpoint——出于与 CVE-2025-32434 相关的安全原因,pickle 格式(.pth/.pt/.ckpt)会被拒绝。实验性的 LTX2.5 支持也被标记为音频部分有 bug,明确还不可靠。
许可证或 checkpoint 处理上有什么特别之处吗?项目采用 MIT 许可证,并刻意拒绝 pickle checkpoint 格式(.pth/.pt/.ckpt),因为对它们使用 torch.load() 可能执行任意代码,而 weightsonly=True 并不能完全消除这一风险。
我实际需要多少显存?README 给出了调参表:从 8GB 配 320-384px 平铺和 34-68 帧分块,到 24GB 配 576-768px 平铺;无论视频多长,显存峰值始终被限制在大约一个平铺的激活量。
为什么不直接依赖 PyTorch 的自动 CPU/GPU 卸载,而要平铺?PCIe 带宽(32-64 GB/s)比显存慢 15-60 倍,多步扩散采样时按需流式加载模型权重会让 GPU 利用率崩掉;分块重采样只付出约 1.2-1.8 倍的少量冗余。
放大后音轨还能保留吗?能。嵌套 AV 潜表示中的音频通道在每次分块和拼接时都原样传递,从不被重新采样,因此放大不会产生任何音频伪影。
实验性的 LTX2.5 节点是什么?LTX25 Ultimate Upscale 把同样的分块/平铺管线扩展到 LTX2.5 的嵌套视频+音频潜表示,采用固定的 2 倍模型放大,但它被标注为高度实验性,音频输出被注明有 bug。
Size
0.2 MB
Stars
238
Updated
CommitOct 07
Age
1mo
Commits · 90 Days