Skip to content

MiniMax H3 / FastH3 on Metal: any step count, with the schedule and AdaLN tables made natively - #959

Closed
drowzeys wants to merge 3 commits into
ashhart:mainfrom
drowzeys:upstream/h3-steps
Closed

drowzeys wants to merge 3 commits into
ashhart:mainfrom
drowzeys:upstream/h3-steps

Conversation

@drowzeys

Copy link
Copy Markdown
Contributor

Stacked on upstream/h3-firstframe, which is stacked on upstream/h3-metal (#949, #950). Review those first.

FastH3 now runs at any step count on TensorFold's Metal runtime, without a precomputed schedule. The native tool builds everything a run's step count decides:

  • the sigma schedule (the checkpoint's own rungs, or N spread from its first);
  • every row's timestep at every step;
  • the timestep embedding;
  • each of the 50 blocks' AdaLN modulation tables, plus the final layer's.

Before this, a case file fixed the step count and carried 155 MB of tables per run. Now one case runs at 4, 8 or 16 steps, the trade-off between speed and quality the distilled checkpoint was trained for. It is also the first piece of the exporter moved into Zig.

On the Mac Studio (M5 Ultra), FastH3 8-Step V2 at 864x480 with 124 frames:

  • Exact schedule. The Euler pairs, the sigma the model sees and the grid ratio, are bit-identical to the Python exporter's for every one of the 8 steps, video and audio. A host test checks them.
  • Parity at the engine's own noise floor, at 4, 8 and 16 steps. At a mid-schedule step the velocities match the MLX reference as closely as two runs of the engine match each other (table below).
  • Tables in 0.7–1.3 s for the whole run, 50 blocks (3.0 s once, with the weights not yet in the page cache): one GPU pass of the new h3_modulation kernel over the checkpoint's 26 GB of AdaLN weights, read in place.
  • Forward speed is unchanged: 8.85 s a step on the GPU.
  • One new kernel. h3_modulation passes gates 1–4 of the kernel contract with 0 limit problems. Lean check: 517, with 0 added.

Parity

Each reference case was written by the fork's exporter with --steps N --at K: the MLX reference takes steps 0..K-1 itself, then gives its velocity at step K. The native tool runs steps=N,from=K on it.

  • Self-noise is the same native binary with only the fp32 summation order of its 128-term tile scores reversed. FastH3's top-k routing makes that the floor for any two implementations.
  • Reference: the Python 0.6 H3 family in bf16 on MLX 0.32.3, with FastVideo's reference routing.
Schedule, step Video against the reference Audio against the reference Self-noise, video Self-noise, audio
4 steps (spread), step 3 cosine 0.99791, rel. error 0.065 cosine 0.99972, rel. error 0.024 cosine 0.99865, rel. error 0.052 cosine 0.99974, rel. error 0.023
8 steps (the checkpoint's), step 5 cosine 0.99839, rel. error 0.057 cosine 0.99987, rel. error 0.016 cosine 0.99866, rel. error 0.052 cosine 0.99992, rel. error 0.013
16 steps (spread), step 9 cosine 0.99850, rel. error 0.055 cosine 0.99987, rel. error 0.016 cosine 0.99888, rel. error 0.047 cosine 0.99994, rel. error 0.011
8 steps, step 5, with the case's own tables (#949's path) cosine 0.99838, rel. error 0.057 cosine 0.99980, rel. error 0.020

Tables against the reference's. 56,583,428 of 77,414,400 values (73.1%) are bit-identical at 8 steps, and 76.1% at 4 steps. The largest difference is 0.0625 at values up to 16.25, which is one bf16 step at that size.

  • The cause is upstream of the tables. The reference computes the timestep embedder with MLX's GPU float32 matmul, which on the M5 differs from MLX's own CPU result by up to 7.8×10⁻³ relative.
  • This change sums in float64 on the host and matches MLX's CPU result to 9.4×10⁻⁶.
  • The velocities above show the difference does not move the output past the noise floor: 8-step video cosine 0.99839 with these tables, against 0.99838 with the reference's.

What it adds

  • zig/src/families/h3/schedule.zig (host only):
    • the checkpoint contract, fastvideo_inference.json; a preview checkpoint's shifts come from its scheduler folders;
    • N rungs spread from the first;
    • the shifted schedule in float64, cast once as FastVideo does;
    • Euler pairs;
    • the per-row plan, with keyframe rows at 0.999 and held reference audio at 1.
    • Three host tests, in zig build test on every host.
  • zig/src/families/h3/modulation.zig:
    • the sinusoid and timestep embedder on the host;
    • each block's and the final layer's AdaLN on the GPU;
    • the plan written into the model's per-step lines.
  • h3_modulation in h3_rows.metal: Y = X Wᵀ + B with fp32 sums, bias added in fp32, rounded once to bf16, and written in the (part, line, channel) order the norms read. It is registered in the contract tests and in registry.zig.
  • zig/tests/h3_steps.zig and three new tool words:
    • tables: the case's schedule, made here;
    • steps=N;
    • from=K: the case holds step K's rows.
    • When the case has the same schedule, the tool compares its tables with the case's value for value.
  • A recipe section, and Checkpoint.floats for float32 or bf16 host reads.

Receipts

Commands, from the Mac Studio (M5 Ultra, macOS 27.0.1, Zig 0.17.0):

zig-out/bin/tf-h3-dit <FastH3>/transformer 14 s8-at4/case.safetensors out tables,from=4
zig-out/bin/tf-h3-dit <FastH3>/transformer 14 s4-at2/case.safetensors out steps=4,from=2
zig-out/bin/tf-h3-dit <FastH3>/transformer 14 s16-at8/case.safetensors out steps=16,from=8

Every run held the machine's shared GPU lock; no Ollama model was loaded except on the first case-tables run (an idle model, not ours).

  • Kernel contract and host suite: see the last pull request of this stack (upstream/h3-ref2va), where they ran on the tree that includes this one.
  • h3_modulation alone: PASS at gates 1–4 (worst 0.996 of the bound at gate 3; exact sums at k 2688, where fp16 would miss by 1952× and bf16 by 3840×), and its launch fits M1 to M5.

Next steps

  • Preview checkpoints. The contract already reads their shifts. Their weights come as a LoRA (FastH3 4-step Preview v1), and merging a LoRA in Zig is its own pull request, not done here.
  • Rotary tables and the tile map. Moving these into Zig as well would leave the exporter only the prompt's rows and the noise.

Licenses

The code is Apache-2.0. MiniMax H3 and FastH3 weights are under the MiniMax H3 Community License. No weights are included.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PfjmufXm4L7qsVNFyRw9ZK

@ashhart

ashhart commented Oct 17, 2026

Copy link
Copy Markdown
Owner

Thank you, @drowzeys, we will carry the H3 schedule and timestep work with your credit into the shared H3 schedule path; the landing order and remaining checks are in our reply on #961.

Posted by Ash's AI Assistant Synthena

@ashhart ashhart mentioned this pull request Oct 17, 2026
…de the engine

A video and audio model's denoising transformer on the M5 tensor units, in the checkpoint's precision: bf16
weights read in place, products on the prefill kernels' tfp::gemm_nax (MLX's GEMM, fp32 sums), FastH3's
tile-routed attention in bf16 with fp32 scores and an online softmax. zig build tf-h3-dit runs every denoising
forward for a case file. The lane core, the server and the other families are untouched.

Thirteen kernels are registered with the kernel contract and pass gates 1-4; their launches and the two GEMM
entry points are in registry.zig. The recipe holds the receipt.
A case exported with a first frame holds the keyframe's rows between the text and the audio. They enter like video
rows on every pass at the keyframe noise level and are never stepped. Text to video is bit-identical to before.
…aLN tables made here

The rungs, shifts and per-row timestep plan come from the checkpoint's contract (or N rungs spread from its first);
the timestep embedder runs on the host and each block's AdaLN projection on the GPU (h3_modulation, registered with
the kernel contract), so a case no longer fixes the step count.
ashhart added a commit that referenced this pull request Oct 18, 2026
… beneath it

The H3 and FastH3 transformer on Metal as a test tool beside the release's, clips that start from an image, any step
count with its schedule and AdaLN tables, the released MiniMax-H3 weights with re-voicing of a finished clip, and
Ref2VA's reference pictures, videos and audio. Against this branch: build.zig runs the H3 schedule's host tests
beside the XPU admission tests.
@ashhart

ashhart commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Thank you, @drowzeys, for H3/FastH3 on Metal. The selected work from #959 is included through #961 (013b75368) in 1.1.0, within one family and the bf16 tf-h3-dit test tool. Geometry/media checks and transactional schedule replacement accompany the integration. Full scope and numerical, resource and reference-media results are on #961: Apple M5 Ultra H3 kernels passed 15/15 with controls; full FastH3/H3 checkpoint/media-tool cells remain unrun.

Posted by Ash's AI Assistant Synthena

@ashhart

ashhart commented Oct 19, 2026

Copy link
Copy Markdown
Owner

The bf16 H3 Metal component shipped in 1.1.0 as 013b75368; thanks @drowzeys. We're closing it as landed.

Posted by Ash's AI Assistant Synthena

@ashhart ashhart closed this Oct 19, 2026
BlivionIaG pushed a commit to BlivionIaG/TensorFold that referenced this pull request Oct 20, 2026
…hart#950, ashhart#959 and ashhart#960 beneath it

The H3 and FastH3 transformer on Metal as a test tool beside the release's, clips that start from an image, any step
count with its schedule and AdaLN tables, the released MiniMax-H3 weights with re-voicing of a finished clip, and
Ref2VA's reference pictures, videos and audio. Against this branch: build.zig runs the H3 schedule's host tests
beside the XPU admission tests.
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