Repository navigation
core: read ModelOpt NVFP4 checkpoints as stored - #758
Conversation
|
Overlap note: #730 adds the same NVFP4 values in |
1799f0a to
221841b
Compare
|
@jschmied, agreed. #758's #757 also adds to |
221841b to
1799f0a
Compare
…n block The GLM-5.3-Flash CUDA port reads nvidia/GLM-5.3-Flash-NVFP4 as stored. admit() checks config.json's quantization_config (top level, else text_config's) for quant_method modelopt, quant_algo NVFP4 and 4-bit float weights in groups of 16, and refuses anything else with a reason the caller logs (the Why of nemotron/config.zig), so a test reads the reason instead of failing on an error log. MIXED_PRECISION is refused for now. Which linears are NVFP4 is left to the tensors, not to the block's ignore list: the pinned revision 423acf37 stores the MTP layer's experts in BF16 without listing layer 45 there (da920bb0 added it). The fixture is that revision's config.json.
nvfp4.zig is the format the GLM-5.3-Flash CUDA port's W4A16 linears read: e2m1 codes two to a byte (input 2j in byte j's low nibble) [n, k/2], an e4m3 scale per 16 inputs [n, k/16], and weight_scale_2 as an fp32 scalar that multiplies. dims() checks the four tensors fit together; Linear.read() maps them from a Checkpoint and marks input_scale as used, since the W4A4 math's static input scale is not read by W4A16 but a leftover tensor would refuse the checkpoint; row() gives a row as e2m1 x e4m3 x global in f32, the reference the GPU kernels will be compared with. stored() says a module is NVFP4 by its weight_scale tensor. The e2m1 and e4m3 values come from core.quant's nvfp4 and fp8 (ashhart#730), as f32. The fixture is the whole header of nvidia/GLM-5.3-Flash-NVFP4 (147,661 names, dtypes and shapes, gzip'd): every NVFP4 linear reads, 42 MoE layers x 288 experts x 3 plus the three dense MLP layers' 3, all under .mlp., and the MTP layer's experts stay BF16.
1799f0a to
b3886b1
Compare
|
@jschmied, as planned: rebased onto 1.0.9, and with #730 in, |
…rence, not an f32 row of its own
|
Pushed |
|
Thank you, @Bizuayeu. Admitting NVIDIA's ModelOpt NVFP4 checkpoints from config.json's quantization block, and letting the tensors say which linears are NVFP4, is the right call for a revision whose MTP layer is BF16 without being listed. Pinning the whole header as a fixture makes the reader easy to trust. Both commits ship in TensorFold 1.0.12 under your name ( All five of your tests pass on macOS and on a GB10 under Linux. We decoded GLM-5.3-Flash on CUDA (#804) is the first caller. Posted by Ash's AI Assistant Synthena |
The contributor's two commits landed above with the same code; this keeps the PR's head in the history with no change to the tree.
…and ashhart#757 onto the candidate
…date The contributor's five GLM commits landed above, with our fixes after them; the head's first seven commits are the same changes as ashhart#757, ashhart#758, ashhart#766, ashhart#762, ashhart#764 and ashhart#763, which the candidate already has from their own heads. This keeps the PR's head in the history with no change to the tree.
…th core/quant's reference
What this changes
Three commits for NVIDIA's ModelOpt NVFP4 checkpoints, the format nvidia/GLM-5.3-Flash-NVFP4 ships in:
modelopt.admit()checksconfig.json'squantization_config(top level, elsetext_config's) forquant_methodmodelopt,quant_algoNVFP4 and 4-bit float weights in groups of 16, and refuses anything else byname. Which linears are NVFP4 is left to the tensors, not the block's ignore list: the pinned revision stores the
MTP layer's experts in BF16 without listing them there.
nvfp4.zigreads a linear as stored: e2m1 codes two to a byte[n, k/2], an e4m3 scale per 16 inputs[n, k/16], andweight_scale_2as an fp32 scalar.dims()checks the tensors fit together,Linear.read()mapsthem and marks
input_scaleused (W4A16 doesn't read it, and a leftover tensor would refuse the checkpoint).Its test decodes the linear it read with
core.quant's fp64reference(core/quant: FP8 and NVFP4 values and float64 references in one place #730); the third commit drops the f32row()the first version had, so the file adds no e2m1 or e4m3 decoding of its own.The fixtures are that revision's
config.jsonand the checkpoint's whole header (names, dtypes and shapes, gzip'd,425 KB): every NVFP4 linear reads, and the MTP layer stays BF16.
Receipt
c36b536d) plus this change; one GB10 (DGX Spark, sm_121, CUDA 13.3).zig build test: 470 passed, 5 skipped, 0 failed; the five new tests (admit, refusals by name, dims, a linearagainst
core.quant's reference, every linear of the checkpoint's header) need this change.zig build test-cuda-host: 434 passed, 0 failed.zig fmt --check: clean.lean_check: 538, as main.fd2b0c00), from an empty cache:zig fmt --checkclean,zig build testandzig build test-cuda-host0 failed,lean_check534.Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo.