Skip to content

feat(minimax-h3): the ORIGINAL bf16 DiT release is indexable — 13 shards, 66.3 GB - #98

Merged
localai-bot merged 1 commit into
mainfrom
row/H3-BF16-SHARDED-DIT
Aug 7, 2026
Merged

feat(minimax-h3): the ORIGINAL bf16 DiT release is indexable — 13 shards, 66.3 GB#98
localai-bot merged 1 commit into
mainfrom
row/H3-BF16-SHARDED-DIT

Conversation

@localai-bot

Copy link
Copy Markdown
Collaborator

What this enables

The MiniMax-H3 bf16 release ships 13 safetensors shards totalling 66.3 GB, and every DiT loader in the tree took a single file. That is why every H3 render so far used a quantized DiT — and H3 is unusually quantization-sensitive (Q3_K_M → Q4_K_M alone turned a murky lattice-covered silhouette into a photoreal close-up; ComfyUI PR 15298 attributes it to the partial split-half RoPE producing channel-wise magnitude outliers that corrupt even INT8). "What does full precision look like?" was not an askable question.

After this PR the original release is indexable:

  • MiniMaxH3ShardedCheckpoint::Open(dir) (new minimax_h3_sharded.cpp) resolves tensors through the checkpoint's own model.safetensors.index.json weight map, never by scanning, with one index over every shard — the shape of the in-tree template LoadMiniMaxH3EncoderWeights(const std::vector<SafetensorsFile>&, ...). A tensor the index names but whose shard does not contain it throws by name; silently skipping it would read as zeros and render.
  • EnumerateMiniMaxH3ShardedTensors produces the same names+shapes manifest the GGUF and NVFP4 arms build, so ParseMiniMaxH3DitParamsFromGgufManifest derives the geometry from shapes alone here too.
  • LoadMiniMaxH3DitFromShards is the host-f32 reference loader (comparison baseline and CPU path for reduced checkpoints).
  • MiniMaxH3IsFp32IslandTensor single-sources the upstream fp32-island split the three existing streamers each hand-rolled. It is load-bearing, not a precision nicety: vt::MatmulBT rejects an (f32 activation, bf16 weight) pair.
  • examples/minimax_h3_gen accepts --dit <dir> everywhere it accepted a DiT file. Every existing --dit form is unchanged.

This is the checkpoint half. The device streamer the real 66.3 GB load needs is the stacked follow-up row/H3-BF16-SHARDED-STREAM, split out so each PR stays inside the 900-line review cap (this one is 775 non-exempt lines).

Gates I ran, post-rebase

Rebased onto f34e0d17 and re-gated after the rebase — these are the numbers observed here, not the pre-rebase report.

  • test_minimax_h3 72/72 cases, 54497 assertions, clean Release build of libvllm.a, test_minimax_h3, minimax-h3-gen.
  • Index + name mapping over a synthetic 4-shard set: every tensor resolves to the shard the index named and to the bytes written there; a tensor named in the index but missing from its shard throws with its name in the message; the derived geometry equals the single-file path field for field.
  • Real geometry without the weights: a 13-shard release whose headers declare the real 535 tensors at their real shapes with the payload as a sparse hole (66.3 GB declared, 144 KB on disk) parses to the shipped geometry 50 / 5376 / 56 / 128 / 14336 / 24 / 32 / 1x2x2 / 5120, and minimax-h3-gen --dit <dir> --dump-params prints all 20 fields on it.
  • Full scripts/agent-preflight.sh --staged: green.

Two pre-existing main breakages repaired

f34e0d17 (#95) left main red on two gates, which blocks any branch off it. Both are repaired here, in the same file/lane:

  • check-env-doc: VT_H3_ACT_DUMP and VT_H3_ACT_CALL shipped undocumented; docs/ENVIRONMENT.md now documents both.
  • check-agent-record: a §9 spec table ran straight into the next table with no separator (4 pipes where 3 were expected, 4 lines); it now has one.

Verified pre-existing by running both checkers on a pristine origin/main worktree first.

What is NOT claimed

  • No bf16 render exists. Nothing here produces a full-precision render, and no bf16-vs-quantized quality or speed comparison is made. The question is unblocked, not answered.
  • No device load of the real 66.3 GB release ships in this PR — the host-f32 reference loader would need ~132 GB and must not be used there. That is the stacked follow-up.
  • The real load's measured peak RSS is unmeasured. This row ran CPU-only: no GPU job, no download.

@localai-bot

Copy link
Copy Markdown
Collaborator Author

Force-pushed: added a real defect fix that this stack's ASan+UBSan lane exposed.

MiniMaxH3ReadSafetensorF32 read 16-bit payloads through reinterpret_cast<const uint16_t*>(tensor.data)[i]. safetensors puts the payload straight after a JSON header of arbitrary length, so a tensor's first byte is only 2-byte aligned if the writer happened to pad — the format does not require it. LoadMiniMaxH3DitFromShards is the first caller to hand that function an unpadded file, and UBSan caught it immediately:

minimax_h3_vae_loader.cpp:88:86: runtime error: load of misaligned address 0x… for type 'const uint16_t', which requires 2 byte alignment
    #0 vllm::MiniMaxH3ReadSafetensorF32(...)  minimax_h3_vae_loader.cpp:88
    #1 vllm::LoadMiniMaxH3DitFromShards(...)  minimax_h3_sharded.cpp:215

Now a byte-wise memcpy load, which has no alignment precondition.

RED-first proven locally, on the same -fsanitize=address,undefined build: reverting only this fix reproduces CI's message at the same line and exits 1; with it, test_minimax_h3 is 73/73 / 55203 assertions under ASan+UBSan with zero findings (and 72/72 / 54497 on this PR's own slice). The synthetic shard writer is deliberately left unpadded so the case stays covered.

Note the finding surfaced on #99 (whose test reaches the reference loader), not here — but the fix belongs in this PR, because this is the PR that introduces the shipped caller (--dit <dir> --device cpu).

…rds, 66.3 GB

Branch: row/H3-BF16-SHARDED-DIT (helper; CPU-only, no GPU job, no download).
Written 2026-08-06 off 075b9f2, REBASED onto f34e0d1 and re-gated before
landing; every number below is the POST-REBASE re-run, not the earlier report.

Every H3 render so far used a QUANTIZED DiT, and H3 is unusually
quantization-sensitive: Q3_K_M -> Q4_K_M alone turned a murky lattice-covered
silhouette into a photoreal close-up (ComfyUI PR 15298 attributes it to the
partial split-half RoPE producing channel-wise magnitude outliers that corrupt
even INT8). "What does FULL PRECISION look like?" could not be asked, because
every DiT loader took a SINGLE file while the bf16 release ships 13 safetensors
shards totalling 66.3 GB.

This is the CHECKPOINT half. The device streamer the real 66.3 GB load needs is
the stacked follow-up row/H3-BF16-SHARDED-STREAM, split out so each PR stays
inside the 900-line review cap.

- MiniMaxH3ShardedCheckpoint::Open(dir) (new minimax_h3_sharded.cpp) resolves
  tensors through the checkpoint's own model.safetensors.index.json weight map,
  never by scanning, with one index over every shard — the shape of the in-tree
  template LoadMiniMaxH3EncoderWeights(const std::vector<SafetensorsFile>&, ...).
  A tensor the index NAMES but whose shard does not contain it throws BY NAME;
  skipping it would read as zeros and render.
- EnumerateMiniMaxH3ShardedTensors builds the same names+shapes manifest the
  GGUF and NVFP4 arms build, so ParseMiniMaxH3DitParamsFromGgufManifest derives
  the geometry from SHAPES ALONE on a sharded checkpoint too.
- LoadMiniMaxH3DitFromShards is the host-f32 REFERENCE loader (comparison
  baseline and the CPU path for reduced checkpoints; ~132 GB on the real
  release, so not for real runs), and MiniMaxH3IsFp32IslandTensor single-sources
  the upstream fp32-ISLAND split the three existing streamers each hand-rolled.
- examples/minimax_h3_gen accepts --dit <dir> everywhere it accepted a DiT file,
  for both --dump-params and the run path; every existing --dit form unchanged.

Gates (CPU, re-run post-rebase: test_minimax_h3 72/72 cases / 54497 assertions;
clean Release build of libvllm.a, test_minimax_h3 and minimax-h3-gen):
(1) index + name mapping over a synthetic 4-shard set — every tensor resolves to
the shard the index named AND to the bytes written there, a missing-from-shard
tensor throws WITH ITS NAME, and the geometry equals the single-file path field
for field; (2) real geometry without the weights — a 13-shard release declaring
the REAL 535 tensors at REAL shapes with a SPARSE payload (66.3 GB declared,
144 KB on disk) derives the SHIPPED geometry
(50 / 5376 / 56 / 128 / 14336 / 24 / 32 / 1x2x2 / 5120), and
`minimax-h3-gen --dit <dir> --dump-params` prints all 20 fields on it.

Also repairs two gates that f34e0d1 (#95) left RED on main and that block any
PR branched from it: docs/ENVIRONMENT.md now documents VT_H3_ACT_DUMP and
VT_H3_ACT_CALL (check-env-doc), and the §9 spec table that ran into the next
table without a separator now has one (check-agent-record).

Also fixes a real latent defect this row's ASan+UBSan lane exposed:
MiniMaxH3ReadSafetensorF32 read 16-bit payloads through
reinterpret_cast<const uint16_t*>, which is UB on a safetensors file whose JSON
header leaves the payload odd-aligned — the format does not require padding, and
LoadMiniMaxH3DitFromShards is the first caller to hand it such a file. Now a
byte-wise memcpy load. RED-first proven locally on the same sanitizer build:
reverting it reproduces CI's `load of misaligned address ... requires 2 byte
alignment` at the same line and exits 1; with it, test_minimax_h3 is 73/73 /
55203 under -fsanitize=address,undefined with ZERO findings. The synthetic shard
writer stays deliberately UNPADDED so the case remains covered.

Honest residuals: NO device load of the real 66.3 GB release ships here, no
measured peak RSS, and no bf16-vs-quantized render or speed number. The
bf16-vs-quant quality question is UNBLOCKED, not answered.

FOLLOWING_AGENTS_PROTOCOL
Assisted-by: Claude Opus 5 (1M context)
@mudler
mudler force-pushed the row/H3-BF16-SHARDED-DIT branch from 098ef36 to 016a07d Compare August 7, 2026 08:45
@localai-bot
localai-bot merged commit 6492b91 into main Aug 7, 2026
13 checks passed
@localai-bot
localai-bot deleted the row/H3-BF16-SHARDED-DIT branch August 7, 2026 09:20
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