Repository navigation
feat(gguf): serve deepseek-v4.1 gguf checkpoints on deepseek_v41 - #890
Merged
Merged
Conversation
llama.cpp 10-25 added the deepseek41 layout. The reader takes the config from the file, undoes the converter (engram gate stored as the product, one per_layer_token_embd tensor, hash constants as KVs) and streams the Engram rows from the file as the HF path does.
37 of 46 tasks
Collaborator
|
Thanks for the PR. The reader matches llama.cpp's
Checked on an H100 (torch 2.14.1+cu130): |
Refuse an FTW of the GGUF before the writer creates the output dir and keep the side-file hook after the dense loop as on main. Check the Engram hash KVs and the table in parse_gguf_config, refuse a table with a .scale, and share the clamp and expert_count readers with the deepseek4 GGUF reader.
Contributor
Author
|
Thx, all four are in 86f716e. |
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.
Serves llama.cpp
deepseek41GGUFs on the family's own model classes, text only. Part of #671 (Model Support: DeepSeek-V4.1). llama.cpp has the converter since b11870 (ggml-org/llama.cpp#31086), so "llama.cpp has no converter for it" on that line is out of date.What it does
parse_gguf_configbuildsDeepseekV41Argsfrom the KVs and goes throughmodel_config_from_args, pulled out ofparse_config, so both flows build oneModelConfig. Some files leave outengram.vocab_sizeandengram.compressed_vocab_sizeand llama.cpp reads neither, so they come fromple.head_vocab_sizesand the token map.iter_gguf_weightsyields the names the HF loader yields. Dense tensors keep their ggml type and the routed experts load as GGUF banks. The converter stores the Engram gate as the productq_weight * k_weight, so it loads intoq_weightwithk_weightall ones.per_layer_token_embdtensor.gguf_engram_tablesslices it per layer andEngramDiskTablestreams the rows as on the HF path, then decodes them on the GPU withggml.dequantizeor a plain cast for BF16/F16/F32. The hash takes the file'sengram.token_map. Its offsets, primes and multipliers must match the KVs llama.cpp hashes with, and the table must be wide and long enough;parse_gguf_configchecks both, so a mismatched file is refused before any dense weight loads.embedtakes the quant config becausetoken_embdis packed, and the HF spec listsembedas unquantized so that path is unchanged._floatmoved fromdeepseek_v4/gguf.pytogguf/tensors.pyasdequantized_tensor, with the same body. The SwiGLU clamp andexpert_countreaders moved fromdeepseek_v4/gguf.pytogguf/config.py(uniform_swiglu_clamp,routed_expert_count) and both readers use them, so a scalar clamp or a per-layerexpert_countarray is handled the same way in both.expert_gating_funcother than sqrtsoftplus, hash-routed layers, rope scaling other than yarn, more than one latent KV head, non-uniform swiglu clamps, per-layer expert prunes, Engram tensors withoutple.layers, a missingper_layer_token_embd, and aper_layer_token_embd.scale(check_scaleslets an NVFP4 tensor's.scalethrough, and the table reader would not apply it).Verification
L40S 46 GB (sm_89), driver 610.57.04, torch 2.14.1+cu130, 16 vCPUs (ggml-cpu picks zen4), weights on a network volume. The
535f894row, the firstgguf_checktable and the first A10 test run are on535f894(main 0ad521d), before the review changes; those change where the checks run and the two helpers' place, not how weights are read. The other rows are from base 33cbb3c, before main took the llama.cpp pin (#873); the reader's weight path is unchanged since. 214 GiB RAM, 322 GiB for the two hybrid rows below. At 214 GiB the container hit its memory limit in the hybrid arm, and I haven't looked into why. Unit tests on A10 (sm_86).Each row: 4 prompts streamed at bs=1, 96 tokens each, then 16 arithmetic prompts together, then 48 staggered at concurrency 16.
--swa-decoder-replay exact535f894--moe-hybrid-max-fetch 0, exact replay, every route on the CPU--moe-cache-auto-ngl 999 --cpu-moe -t 16On
535f894GSM8K drops one. The lemon-tree (index 12) and vacuum (index 13) answers run out of their 384 tokens before the####line in all three runs, so they score on the last number written: on 12 this run stops on the 12-year break-even it was weighing, where the earlier run and llama-server stop on 13; on 13 all three stop in a check line after reaching 18.The config parsed from the UD-IQ1_M file matches
deepseek-ai/DeepSeek-V4.1-Flash-1017's config field by field, apart from the DSpark fields the file doesn't carry andengram_vocab_size(16000057 from the file against 16000000, which derive the same primes).Against llama-server on the same file:
tok_compare.pyagainst thedeepseek-ai/DeepSeek-V4.1-Flash-1017tokenizer: 0 differing texts (13 edge, 126,527 vocab, 20,000 combos).535f89430 are, and the other two are the cut-off 12 and 13 above.-ngl 999 --cpu-moe: FreeToken 0.56 nats, same top token on 22; llama-server with-ngl 00.36 nats, same top token on 21. At the prefix where the first prompt splits, the-ngl 0run picks the same token FreeToken does.scripts/gguf_checkover 9 repos, headers only (148 stubs, kernels probed on the A10). It checks config, a dry load and kernel coverage, not real weights:Tests on the A10,
535f894:tests/models tests/moe tests/kernels/test_ggml.py tests/server tests/checkpoint1365 passed, 250 skipped, 5 failed. main at 0ad521d on the same GPU: 1355 passed, 250 skipped, and the same 5 fail (qwen4_exp/test_qsa_backend.py::test_chunked_prefill_matches_one_shotx3,dflash/test_draft.py::test_block_forward_matches_referencefp32 x2). The new tests extend the existingdeepseek_v41files: a tiny checkpoint through the GGUF and HF readers gives equal prefill logits and decode logits within 2^-7 of the largest logit (the bf16 fused and ggml decode kernels round differently), the table slices decode to the source rows for BF16 and Q8_0, eager and from a captured graph, ids the file's token map merges hash to the same rows, and a wrong hash KV refuses.After the review changes, this head merged into main
66190a9, on the A10:tests/models tests/server tests/checkpoint1114 passed, 222 skipped, 5 failed; main66190a91101 passed, 222 skipped, the same 5 fail. The new tests (a scalar clamp parses and a per-layerexpert_countrefuses, a table with a.scalerefuses, a wrong hash KV refuses atparse_gguf_config,ft checkpointon a GGUF leaves no output directory) fail with535f894's sources and pass on this head.gguf_checkover 41 header stubs from unsloth/DeepSeek-V4-Flash-0731-GGUF, puwaer/DeepSeek-V4-Flash-0731-reap-150b-gguf, huihui-ai/Huihui-DeepSeek-V4-Flash-0731-abliterated-GGUF, unsloth/DeepSeek-V4.1-Flash-1017-GGUF and antirez/deepseek-v4.1-flash-gguf gives the same result per file on535f894and on this head: deepseek4 21/21, deepseek41 6/11 (the 5 under Not covered).Not covered
deepseek41vmmproj and the DSpark draft files are not read.43 is not a valid GGMLQuantizationType. Their MXFP8 tables use type 43 at 33 bytes per 32 values, which only unsloth's llama.cpp PR reads. Upstream 43 is one-byte F8_E4M3.--moe-strategy cpurefuses these mixed-type files, like other mixed-type GGUFs. A single-type file wasn't tested.ft checkpointrefuses these GGUFs before it creates the output directory (a newftw_check_sourcehook thatconvert_checkpointcalls beforeFTWWriter): serve the.gguf.