Repository navigation
Conversation
|
Thanks, @ElderOrb. Serving ModelOpt NVFP4 and FP8 Qwen3.5 checkpoints on HIP through the BF16 rocBLAS path is in scope. A few things first:
We have no AMD GPU, so please post your own main-against-branch numbers, naming the gfx target, along with drafted replies equal to |
54ade02 to
5b32fc7
Compare
655c707 to
bba2f2b
Compare
|
@ElderOrb thanks, keeping the codes as stored is a much better design: the NVFP4 weights are now the checkpoint's, the E4M3 → BF16 table is exact, the NaN and zero-global refusals are in, and admission goes through
We have no AMD GPU, so please post main-against-branch numbers, naming the gfx target. |
dc497a5 to
62823de
Compare
|
Rebased and reworked since your note; the body above describes the current state. Summary of what changed:
Still open, and in the body: the |
|
Thanks @ElderOrb, this is a much better shape. The codes and E4M3 tables stay as stored, one product kernel serves On your FP8 question: the exact route, please. Widen the bare E4M3 values (exact in BF16), sum in f32, and apply the What's left, smallest first:
We have no AMD GPU, so your numbers are the receipt for this one. Main is closed for a release right now, but none of |
cb32ea6 to
6b1b659
Compare
…tower keeps rocBLAS
…ht, FP8 NaN codes, and the lean line
|
Thanks @ElderOrb. Here's what this head (
It looks like you're in the middle of getting the 27B to serve. Before the next push, here's what's left, blocking items first:
We have no AMD GPU, so your numbers are the receipt for this PR.
|
|
Thanks @ElderOrb. This head ( New on this head:
Still open from our 12 Nov note:
We have no AMD GPU, so your numbers are the receipt for this PR.
|
… the caller's error
…ct declines both formats
Serves NVIDIA's ModelOpt NVFP4 and FP8 checkpoints on the HIP engine without widening a weight.
What the checkpoint holds, and what the engine keeps
For a projection of N outputs from K inputs ModelOpt writes
weightU8 e2m1 codes [N, K/2] (input 2i in the low nibble),weight_scaleE4M3 [N, K/16] andweight_scale_2, one global scale. An FP8 layer writes E4M3 codes [N, K] and one f32 scale a projection.The host keeps exactly those tensors, and the device keeps that layout too - as
quant.mlxdoes - so an upload is a copy. The one transform is at read: an E4M3 group scale widens to BF16, exactly (three mantissa bits fit seven). An F32 block table is refused (ModelOpt writes E4M3, and the kernel reads a 16-bit table), and a stack of experts is refused because its experts carry a global scale each.The preflight counts what the device holds rather than the stored files:
table.deviceByteskeeps U8 and E4M3 code tensors as stored and counts only an E4M3 group table at two bytes a value.Kernels
quant/nvfp4_tiles.hppis one product kernel,tf_nvfp4_gemm: a thread an output element, a group's 16 inputs folded in f32 with the group's own E4M3 scale, the one global applied to the sum once, the nibble through an e2m1 bit table.quant/fp8_tiles.hppis its sibling for FP8,tf_fp8_gemm: each E4M3 code turns into the exact f32 it names, all of K sums in f32, and the projection's one scale multiplies the result once, as CUDA'sqmmf.cureduce does. That keeps those layers row-invariant and off rocBLAS.Both serve bf16 activations only, since the engine refuses an fp16 build for a ModelOpt checkpoint; one kernel serves a prompt's rows and a round's, so a row's bits never depend on its round.
Why dedicated kernels rather than the shared GEMM and stream tiles: both step along K in 32-code chunks (
kGemmK = 32,nch = a.k >> 5, a chunk's scale indexq >> gshift), and NVFP4's group is 16, so a chunk holds two scales:a.group / kGemmKis 0 and the shift would have to be negative.tiles/stream.hppandtiles/dot2_tiles.hipkeep only their MLX code.The engine
A ModelOpt checkpoint's own bf16 layers (an
lm_head, an unquantized linear, the MTP head) read as.denseon the row-invariant dense kernels rather than through rocBLAS, so rocBLAS is not opened at all. That route madeplain()false, which had gated a bf16 checkpoint's refusals, so a ModelOpt checkpoint now carries its own: an fp16 build and more than one rank are refused by name, and graphs stay off. A ModelOpt checkpoint with routed experts is refused by name too, before its shards are read.The format tag
core.quant.Formatno longer names NVFP4 or FP8: it andDecoderare the three formats both engines read. A projection still has to carry them, soquant.Projectiongains optionalnvfp4andfp8fields beside a nullablehandle, andformat()/decoder()return optionals. The family's host projection is its own union, withrows,bytes,read,halves,sliceRowsandsliceColsover it; its device projection is a union ofquant.Device,quant.nvfp4.Deviceand its FP8 tensors.Kernel contract
hip_records_nvfp4.zigholds both entry points' resources fromhip-kernel-contract-limits, in gfx1030, gfx1100, gfx1151, gfx1201 order:tf_nvfp4_gemm: 29 VGPRs / 49 SGPRs on gfx1030, gfx1100 and gfx1151, 31 / 48 on gfx1201.tf_fp8_gemm: 15 / 36 on the first three, 17 / 38 on gfx1201.No LDS either, bound 256, wave32. The same run compiles every group for the four chips, which is the gfx1100 and gfx1201 build.
tests/hip/contract_nvfp4.zigcarries a test type for both and the runner builds it; on gfx1151 (Radeon 8060S):The 174 limit problems are the repository's older records against this machine's hipcc (ROCm from the SDK, not the ROCm 10.1 the table was filled from); neither ModelOpt launch is among them.
Testing
zig build teston Windows: passes, 0 failures (7,900+ host tests).zig build hip-kernel-test -Dhip=true -Dhipcc=... -Dhip-arch=gfx1151: 20/20 steps, 165/171 tests (6 skipped). Both products are compared withquant.nvfp4.referenceandquant.fp8.e4m3in f64 against the bound each kernel's chain derives, and print the worst error (0.00-0.004 of it), and a row's bits alone equal that row in a round of four, bit for bit.unfit, the exact widen, halves and slices), the preflight count, the FP8 and F32 refusals, the ModelOpt MoE refusal, and that the same BF16 tensor reads.bf16on an unquantized checkpoint and.denseon a ModelOpt one.Not in this revision
Served numbers - decode and prompt tok/s, drafted against
"draft": false, concurrent against solo, resumed against fresh - are not here: this machine has no ModelOpt checkpoint to serve. The kernels' receipts above are the model-free ones; I will add the served numbers when a checkpoint is on it.