Nodes/Model Utility Toolkit/MiniMax H3 Unfold AdaLN
ComfyUI Node

MiniMax H3 Unfold AdaLN

Undoing ComfyUI's compressed H3 weights (you need two models)

By silveroxides·Created 2 years ago·Updated 3 days ago· 17
MiniMax H3 Unfold AdaLN
    • output_path
    • report
    ◄model_a▾►
    ◄model_b▾►
    ◄output_filenameminimax_h3_unfolded►
    ◄discard_patterns►
    ◄glob_patternsfalse►
    ◄curve_rank8►
    ◄curve_grid1025►
    ◄process_devicecuda►
    ◄exclude_patterns►
    ◄include_modefalse►

    MiniMax H3 - the 33B omni-modal video model that dropped in August 2026 with native stereo audio - is a big file, reported around 42.5GB at full precision. So the H3 checkpoints you download for ComfyUI are mathematically squeezed: the AdaLN conditioning linears, which turn the timestep embedding into per-block modulation, ship in a compressed "folded" form. For generation you'd never know.

    You find out when you try to do surgery on the weights. Train on it, merge it, extract a LoRA from a diff, hand it to a tool that expects the original H3 architecture, and you hit tensors that don't look like what the model card describes. MiniMax H3 Unfold AdaLN rebuilds the full-width AdaLN weights from a folded model, using a second, non-folded H3 as the reference that supplies the time embedder and the dimensions the squeeze threw away.

    Why it takes two models

    The fold samples silu(time_embedder(t)) across 1025 timesteps, stacks the samples into a [grid, 2688] matrix, and takes an SVD. That curve is low-rank - the top 8 directions capture it to within a reconstruction error the pack quotes as under 1e-4 - so the fold stores those 8 directions as a small lookup table, pre-projects every AdaLN weight to 8 columns, and drops the time embedder entirely.

    Reversing it isn't free. Projecting a [*, 2688] matrix down to [*, 8] discards whatever lives outside that 8-dimensional subspace, permanently - so the node needs a witness, Model B, the original unfolded base, to put back what it can't recover. With the basis V (shape [2688, 8]) recomputed from Model B's time_embedder.proj_in / proj_out weights:

    1. Project Model B's full-width AdaLN weight onto the basis: B_w @ V.
    2. Take the difference in folded space: D = A_w − (B_w @ V), where A_w is Model A's folded rank-8 weight.
    3. Lift that difference back to full width: output = B_w + D @ Vᵀ.

    Then it copies Model B's four time_embedder tensors in under Model A's key prefix, drops adaln_t_table, and rewrites the config metadata - time_embed_dim back to 2688, adaln_curve_grid removed - so loaders build the unfolded architecture.

    Read that formula and the limitation falls out: you get Model B's weights plus an in-subspace correction, so anything a merge or finetune changed outside the rank-8 curve basis is gone. If Model A is just Model B run through the fold, D is ~0 and you get B back essentially intact.

    The inputs you actually touch

    • model_a - the folded H3 to unfold, from your diffusion_models folder.
    • model_b - the reference unfolded base, and the one that matters. It must be the same lineage Model A was folded from; point it at an unrelated H3 finetune and you get that finetune's weights plus a correction - a blend, not a reconstruction.
    • output_filename - no extension needed; .safetensors is appended and the file lands in models/diffusion_models.
    • curve_rank / curve_grid - must match how Model A was folded. 8 and 1025 match the standard ComfyUI H3 checkpoints, hence the defaults.
    • process_device - cuda for the SVD and matmuls, cpu when VRAM is tight.

    The filter trio (discard_patterns, exclude_patterns, include_mode) is the pack-wide layer-filters feature: whitespace-separated patterns, matched as regex substrings by default, or as *wildcards* with glob_patterns on. discard_patterns deletes layers from the output entirely.

    Outputs: output_path - the category-relative filename you feed back into a load-diffusion-model node - and report, a text summary of layers unfolded, time-embedder tensors restored and output size. The report's "basis reconstruction error" line describes Model B's curve fit, not your output file's error.

    Installing it

    ComfyUI Manager, search Model Utility Toolkit (the registry display name) or ComfyUI-ModelUtils. Manually:

    cd ComfyUI/custom_nodes
    git clone https://github.com/silveroxides/ComfyUI-ModelUtils
    pip install -r ComfyUI-ModelUtils/requirements.txt
    # requests, Pillow, mutagen, av, unifiedefficientloader>=0.5.2
    

    Restart ComfyUI afterwards. The node is written against comfy_api.latest, so it wants a reasonably current build - on an older one the pack won't register. The heavy dependency is unifiedefficientloader, the streaming safetensors reader that keeps RAM flat while walking a 40GB file one tensor at a time. The pack is silveroxides' model-surgery toolbox - the same author behind the Chroma GGUF quants half the Chroma workflow posts link to - sitting beside his fold, merge, rename-keys and LoRA-extraction nodes.

    Where people get burned

    Quantized models are rejected outright. Both slots run a low-bit guard that raises on ComfyUI quantization metadata, legacy scaled_fp8 sidecars, or more than two isolated low-bit tensors - full-precision fp16/bf16 safetensors only. GGUF is out by construction.

    Wrong curve_rank/curve_grid fails silently. No error, just reconstruction against the wrong basis and a model that generates subtly wrong video. If you didn't fold it yourself, leave them at 8 and 1025.

    Shape mismatches error loudly. Model A's AdaLN weights must be [*, 8] and Model B's [*, 2688], or you get a ValueError naming the key; no time_embedder.proj_in/proj_out in Model B and you get a KeyError.

    It's one long write. Expect a big pause and a lot of disk; tensors stream one at a time so VRAM stays modest. It's an output node too, so queueing runs it with nothing wired up. And include_mode on an unfold leaves some layers full-width and some still rank-8 - an expert knob, not a first experiment.

    CategoryModelUtils/DiffusionModels

    Inputs (10)

    NameTypeDefaultDescription
    model_aCOMBOSelect the folded MiniMax H3 model (Model A) to unfold.
    model_bCOMBOSelect the reference original/unfolded MiniMax H3 base model (Model B) to supply the time embedder and missing dimensions.
    output_filenameSTRINGminimax_h3_unfoldedName for the reconstructed unfolded model file, saved in your diffusion_models folder.
    discard_patternsSTRINGLayers to completely remove from the final file (one name or pattern per line). Useful to strip parts you do not need.
    glob_patternsBOOLEANfalseEnable simple wildcard matching (* to match anything). If unchecked, uses regular expressions.
    curve_rankINT81–64Basis rank used when the model was folded (default 8, matching standard ComfyUI H3 checkpoints).
    curve_gridINT102565–4097Sampling resolution used when the model was folded (default 1025, matching standard ComfyUI H3 checkpoints).
    process_deviceCOMBOcudaHardware device used to perform the math. Use cuda (GPU) for speed, or cpu if you run low on VRAM.
    exclude_patternsSTRINGSpecific layers to skip unfolding, keeping them at their folded size (one name or pattern per line).
    include_modeBOOLEANfalseInvert the exclude filter: only unfold layers matching the pattern, and keep everything else untouched.

    Outputs (2)

    NameTypeDescription
    output_path*—
    reportSTRING—