Repository navigation
feat(gguf): read NVFP4 token_embd rows in the vendored get_rows - #801
Conversation
Signed-off-by: iamanishx <manishbiswal754@gmail.com>
jason-fxz
left a comment
There was a problem hiding this comment.
Thanks, the kernel and the loader change look right. Checked on an RTX PRO 6000 (sm_120), torch 2.14.1+cu130, Triton 3.8.0:
dequantize_nvfp4matches ggml's own CPU and CUDA NVFP4 dequantization (nibbles at j / j+8,ue4m3_to_fp32already halved), andfreetoken.patchapplied to 8c2134a reproduces the vendored tree byte for byte.tests/kernels/test_ggml.py: 24 passed; with main'sgetrows.cu,dequantize.cuhandembedding/gguf.pyswapped back, the 5 new cases fail with the messages in the description.- Real checkpoints: there are public GGUFs of served architectures with an NVFP4
token_embd, so the last paragraph of the description can go. I ran three, one per layout:
| file | token_embd | output | FreeToken serves | NVFP4 table vs exact F16 table |
|---|---|---|---|---|
| FreedomAISVR/Qwen3.5-9B-NVFP4-GGUF | NVFP4 | Q6_K | yes | 6/6 prompts token-identical |
| jan1k/Qwen3.5-9B-Uncensored-Genesis-NVFP4-GGUF (244 scaled linears) | NVFP4 | NVFP4, no scale | yes | 6/6 token-identical |
| WhiskyAKM/Gemma-4-12B-it-qat-NVFP4-GGUF (fast) | NVFP4 | tied | yes | 6/6 token-identical |
The control is the same file with token_embd rewritten as F16 (every NVFP4 value is exact in f16; for the tied Gemma the original NVFP4 bytes are kept as output.weight, so the head runs the same kernel). Greedy, 200 tokens, thinking off, --cache-type naive.
One request, on the tests (rules in tests/README.md, "What earns a place here", merged after this branch's base): please keep only test_nvfp4_dequantize_and_rows with its _nvfp4_weights helper, and drop the other two tests along with the imports only they use. That test is the one that guards the new code: it checks against an independent reference, and a wrong nibble or scale index would otherwise go unnoticed. test_nvfp4_table_kernel_selection restates the two branches of unusable_reason. In test_nvfp4_table_embed_and_tied_logits, the embed half runs the same get_rows, and the logits half tests the NVFP4 GEMM from #732. Folding the kept test into test_q4_dequantize_and_rows as a second ggml type would also be fine.
Signed-off-by: iamanishx <manishbiswal754@gmail.com>
|
@jason-fxz i have updated the PR . Thanks for the review |
Upstream up to 507a8bf (FlashML-org#641, FlashML-org#811 cache flush, FlashML-org#801, FlashML-org#807, FlashML-org#804, FlashML-org#665, FlashML-org#803, FlashML-org#774). Conflicts resolved: - gguf/config.py: keep our rope --hf-overrides next to upstream's mmproj hf_fields - scheduler/cache.py: take upstream's _evict() helper, keep freeing the host bank slots - scheduler/scheduler.py: block/idle checks wait for both the kv ladder and a pending flush - glm_moe_dsa, minimax_m2 moe.py: keep our fp32-bias comments - api_server.py: import Query and Headers - tests/moe/test_fused_moe.py: keep our moe_align tests and upstream's sigmoid top-k test - tests/scheduler/test_cache_rebuild.py: the flush test's busy marker is a 1-token batch, next's overlap loop reads last_data[1] for the DFlash drain Assisted-by: Claude Opus 5.5
Part of #671 (the "NVFP4 GGUF, still refused" item, token_embd half).
An NVFP4 GGUF whose
token_embdis itself NVFP4 was refused: the GGUF embedding method looks rows up through the vendored ggmlget_rows, which has a dequant case for every ggml type except NVFP4, soGgmlEmbeddingKernel.unusable_reasonturned such tables away. Dense linears, experts and their.scalesidecars already work since #732; only the vocab table was missing.ggml-cuda/dequantize.cuh,ggml-cuda/getrows.cu: a pair-styledequantize_nvfp4fork_get_rowsand theGGML_TYPE_NVFP4dispatch. The 16-value sub-block is the kernel's block, so each byte's nibbles land at j and j+8 as NVFP4 packs them, and any row length that is a multiple of 64 works (the k-quant get_rows path needs a multiple of 256).freetoken.patch,VERSION: the hunks for both files, in the patch's file order. The patch applies cleanly to the upstream commit (8c2134a) and reproduces the vendored tree byte for byte.layers/quantization/embedding/gguf.py: NVFP4 tables load. A table with a.scaleis still refused: llama.cpp reads notok_embdscale and asserts that a tied NVFP4 output has no sidecar scales, so applying one would diverge from the reference. An untied NVFP4output.weightwith a scale goes through the linear path from feat(gguf): apply the weight scales of nvfp4 gguf tensors #732 as before.tests/kernels/test_ggml.py: NVFP4 dequantize and get_rows against gguf-py's CPU dequantization, exact in fp32 / bf16 / fp16 over every fp4 code and UE4M3 scale code; embed and tied-head logits throughGgmlEmbeddingKernel; kernel selection for scaled vs unscaled tables.Tested with:
RTX PRO 6000 Blackwell Server Edition (sm_120) and A10 (sm_86, software UE4M3 decode), driver 610.57.04, torch 2.14.1+cu130, Triton 3.8.0, nvcc 13.0, ggml JIT-built on each GPU:
24 passed on both. With main's
getrows.cu,dequantize.cuhandembedding/gguf.pyswapped back in,test_nvfp4_table_kernel_selectionfails with "NVFP4 GGUF tables are not supported" andtest_nvfp4_dequantize_and_rowswith "unsupported src0 type: nvfp4".