feat(minimax-h3): stream the ORIGINAL bf16 DiT to the device, one tensor at a time - #99
Closed
localai-bot wants to merge 1 commit into
Closed
feat(minimax-h3): stream the ORIGINAL bf16 DiT to the device, one tensor at a time#99localai-bot wants to merge 1 commit into
localai-bot wants to merge 1 commit into
Conversation
mudler
force-pushed
the
row/H3-BF16-SHARDED-STREAM
branch
from
August 7, 2026 08:03
7c800b1 to
ed8680c
Compare
mudler
force-pushed
the
row/H3-BF16-SHARDED-DIT
branch
from
August 7, 2026 08:03
9529ed0 to
098ef36
Compare
…sor at a time Branch: row/H3-BF16-SHARDED-STREAM (helper; CPU-only, no GPU job, no download), STACKED on row/H3-BF16-SHARDED-DIT. Split from that row so each PR stays inside the 900-line review cap; the seam is checkpoint-vs-device, not an arbitrary cut. row/H3-BF16-SHARDED-DIT made the 13-shard 66.3 GB release INDEXABLE, but its only loader was host-f32 — ~132 GB on the real release. The box has 122 GiB of UNIFIED memory (host and device draw on ONE pool), so "load to host, then stage" holds the model TWICE against that budget, and the non-streaming NVFP4 loader was already OOM-KILLED at anon-rss 125 GB on HALF this size. Without a streaming path the original release is not loadable at all. - StreamMiniMaxH3ShardedToDeviceBf16(queue, ckpt, out_params) in minimax_h3_device.cpp, beside its GGUF and NVFP4 twins so it reuses BindStreamedDitViews. Manifest first (names+shapes, no payload) so the geometry is known and a wrong name map is caught before a byte is allocated, then ONE tensor at a time. - Peak host memory, precisely: BF16-on-disk -> bf16 device slot (essentially the whole 66.3 GB) and F32 -> f32 island are both uploaded DIRECTLY out of the read-only mmap, with no host buffer at any point. Only a dtype MISMATCH costs one tensor's conversion buffer, freed before the next iteration. Each source range goes to MaybeReleaseSourcePages the moment its copy returns, so the page cache does not accumulate against the pool the weights live in. rope.inv_freq stays HOST-resident: BuildRopeCosSin runs before any kernel, so a device pointer there segfaults on the first forward. - MiniMaxH3ShardStreamStats (mirroring Nvfp4W4A16Stats) makes the path OBSERVABLE. This codebase has shipped a never-executing guarded kernel under a green suite before; counters are how that is prevented. - examples/minimax_h3_gen: --dit <dir> --device cuda streams and prints the stats line; --device cpu keeps the host reference loader. Gates (CPU, test_minimax_h3 73/73 cases / 55203 assertions; clean Release build of libvllm.a, test_minimax_h3 and minimax-h3-gen), over a 3-shard synthetic set whose dtypes exercise all four (on-disk x device) combinations: (1) streamed == non-streamed — all 46 weight views BIT-EXACT (memcmp == 0) vs StageMiniMaxH3DitWeights(kBF16), dtypes included (12 fp32 islands), and both device forwards return IDENTICAL logits (video and audio max|diff| both exactly 0.0); rope.inv_freq asserted HOST-resident. (2) the loader RAN — the counters are ASSERTED, not printed: observed shards=3 tensors=46 direct=37 converted=9 bytes=444504 host_peak=8192, so BOTH upload paths were taken, every bound view is owned by this loader's staging, and host_peak_bytes (one tensor's buffer) is under 1/4 of the bytes uploaded — the peak cannot scale with the model. Honest residuals: the real 66.3 GB load and its measured peak RSS are UNVERIFIED, as is CUDA memcpy straight from a file-backed mmap (valid pageable-source usage, every copy followed by a synchronize, but unexercised on device) — this row ran CPU-only. NO bf16-vs-quantized render or speed number is claimed. The quality A/B is now RUNNABLE; it has not been run. FOLLOWING_AGENTS_PROTOCOL Assisted-by: Claude Opus 5 (1M context)
mudler
force-pushed
the
row/H3-BF16-SHARDED-STREAM
branch
from
August 7, 2026 08:45
ed8680c to
2a448ab
Compare
mudler
force-pushed
the
row/H3-BF16-SHARDED-DIT
branch
from
August 7, 2026 08:45
098ef36 to
016a07d
Compare
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #98 (
row/H3-BF16-SHARDED-DIT). Base it onmainonly after #98 merges — the diff below is this row alone (437 non-exempt lines).What this enables
#98 made the 13-shard 66.3 GB bf16 release indexable, but its only loader was host-f32 — ~132 GB on the real release. This box has 122 GiB of unified memory: host and device draw on one pool, so "load to host, then stage" holds the model twice against that budget, and the non-streaming NVFP4 loader was already OOM-killed at anon-rss 125 GB on half this size. Without a streaming path the original release is not loadable at all.
StreamMiniMaxH3ShardedToDeviceBf16(queue, ckpt, out_params)lands inminimax_h3_device.cpp, beside its GGUF and NVFP4 twins so it reusesBindStreamedDitViews. Manifest first (names+shapes, no payload) so the geometry is known and a wrong name map is caught before a byte is allocated, then one tensor at a time.Peak host memory, precisely:
MaybeReleaseSourcePagesthe moment its copy returns, so the page cache does not accumulate against the same pool the weights live in.rope.inv_freqstays host-resident:BuildRopeCosSinruns before any kernel, so a device pointer there segfaults on the first forward.MiniMaxH3ShardStreamStats(mirroringNvfp4W4A16Stats) makes the path observable. This codebase has shipped a never-executing guarded kernel under a green suite before; counters are how that is prevented.examples/minimax_h3_gen --dit <dir> --device cudastreams and prints the stats line;--device cpukeeps #98's host reference loader.Gates I ran
test_minimax_h373/73 cases, 55203 assertions, clean Release build oflibvllm.a,test_minimax_h3,minimax-h3-gen.memcmp == 0) vsStageMiniMaxH3DitWeights(kBF16), dtypes included (12 fp32 islands), and both device forwards return identical logits (video and audiomax|diff|both exactly0.0).rope.inv_freqasserted host-resident.shards=3 tensors=46 direct=37 converted=9 bytes=444504 host_peak=8192. Both upload paths taken, every bound view owned by this loader's staging, andhost_peak_bytes(one tensor's buffer) under 1/4 of the bytes uploaded — the peak cannot scale with the model.scripts/agent-preflight.sh --staged: green.What is NOT claimed
cudaMemcpystraight from a file-backed mmap — valid pageable-source usage, every copy followed by a synchronize, but unexercised on device. This row ran CPU-only: no GPU job, no download.host_peak=8192is from a reduced synthetic checkpoint. It proves the bound is one tensor, not a number for the real release.