feat(kimi-k3): Kimi K3 support: MXFP4 to BF16 conversion and inference graph - #58
feat(kimi-k3): Kimi K3 support: MXFP4 to BF16 conversion and inference graph#58worthant wants to merge 148 commits into
Conversation
* metal: fuse snake activation (mul, sin, sqr, mul, add) Mirror the CUDA, Vulkan and CPU snake fusion: same matcher on the naive 5-op chain, same F32 contract on a and inv_b, same F32/F16/BF16 kernel with F32 compute. Follows the Metal backend idioms: bf16 instantiation gated behind GGML_METAL_HAS_BF16 and concurrency ranges checked on the remaining chain nodes before encoding, as done by the bin fusion. Covered by the existing backend-agnostic SNAKE_FUSE tests. * metal: absorb snake fusion into ggml_metal_op_bin Extract the matcher to ggml_metal_op_can_fuse_snake, mirroring the Vulkan naming, and dispatch the fused path from ggml_metal_op_bin. The encode loop switch is back to a single call per case. Address review from ggerganov * metal: fix indentation in ggml_metal_op_can_fuse_snake
* ci : add HF_TOKEN to self-hosted workflows Pass the HF_TOKEN_CI repo secret as HF_TOKEN env var in the self-hosted build and server workflows. Fix the stale build.yml path reference. Assisted-by: pi:llama.cpp/Qwen3.6-27B * cont : add comment --------- Co-authored-by: ggerganov <ggerganov@users.noreply.github.com>
…l-org#25678) * cuda : relax tensor contiguity requirements for quantized concat * tests : add test cases for non-contiguous quantized concat * ggml : relax contiguity requirements for quantized concat --------- Co-authored-by: Stanisław Szymczyk <sszymczy@gmail.com>
…25637) In MODEL mode, modelPropsCache is never populated: fetchModelProps call sites are gated on router-only state (isRouterMode checks, routerModels always empty), so supportsThinking always reads an empty chat template once a model is auto-selected. Read serverStore.props.chat_template directly in non-router mode, since the global /props already describes the single loaded model.
…-org#25705) read_file with append_loc emits "{n}\u2192 {line}". The space after the arrow is meant as a separator, but it is indistinguishable from real indentation. Models strip "{n}\u2192" yet keep the space, so the old_text passed to edit_file carries a phantom leading space and never matches (normalize_for_fuzzy_match trims trailing whitespace only, never leading). Drop the separator space so the arrow abuts content: stripping "{n}\u2192" now yields the exact line with its real indentation preserved, and the failure mode cannot occur by construction. Update the description example to match the new format.
* Fix crash with draft-simple * Fix tests for spec decoding
) * opencl: route `sub_group_shuffle_xor` to qcom ext when KHR ext is unavailable KHR `sub_group_shuffle_xor` is not defined by compiler when `cl_qcom_subgroup_shuffle` is present, causing certain FA kernels fail to build. Define the KHR shuffle_xor using the qcom extension. * opencl: skip FA kernels with mixed and quant types for A7x to avoid compiler crash
match cli and completion, which don't enforce it
…kernel + wmma kernel) (ggml-org#25545) * cuda : CUDA GGML_OP_LIGHTNING_INDEXER implementation (generic vector kernel + wmma kernel) * chore : remove indentation of #pragma unroll * cuda : remove unnecessary kernel template declarations * cuda : add WARPS_PER_BLOCK and K_VECS_PER_BLOCK template parameters in lightning indexer kernels to avoid duplication of constants. * cuda : relax MMA architecture requirements to Turing in lightning indexer implementation * chore : renamed variables * chore : rename ggml_cuda_op_lightning_indexer() to ggml_cuda_lightning_indexer() * chore : TODO for AMD rocWMMA * chore : whitespace formatting * chore : another variable rename to fix problems caused by shadowing * chore : yet another rename, this time uppercased all constants * cuda : added alignment checks for Q and K tensors in lightning indexer implementation --------- Co-authored-by: Stanisław Szymczyk <sszymczy@gmail.com>
* feat: Add shimmer text animation for processing state indicators * feat: Redesign CollapsibleContentBlock component with improved UX * feat: Add conditional setting display support with dependsOn field * feat: Add showAgenticTurnStats setting for per-turn statistics * feat: Update ChatMessageAgenticContent with improved UI and new features * feat: Enhance file read tool UI/UX * feat: Refine styling of collapsible content and code preview blocks * feat: add terminal variant to CollapsibleContentBlock * feat: add built-in tools UI registry * feat: extract ChatMessageReasoningBlock and ChatMessageToolCallBlock * refactor: simplify ChatMessageAgenticContent to use extracted blocks * fix: correct markdown content block margin spacing * fix: reorganize SettingsChatFields layout and reset button positioning * fix: use direct map access in agentic store session methods * refactor: remove reasoning preview/throttle system from CollapsibleContentBlock * feat: add auto-scroll to reasoning block and remove showThoughtInProgress * feat: add ChatMessageToolCallDateTime component and support for new tool types * feat: improve auto-scroll reliability in reasoning block with RAF coalescing and MutationObserver * feat: show MCP server favicon for tools without a built-in icon * feat: add search-results parsing utilities and tests * feat: add ChatMessageToolCallSearchResults component * feat: integrate search results rendering into ChatMessageAgenticContent * feat: display tool call input alongside output in ChatMessageToolCallBlock * style: use muted foreground color in reasoning block content * chore: Format * feat: Refine reasoning block layout and make pending thoughts display configurable * feat: Stream tool call code blocks with auto-scroll and handle partial JSON * feat: add streaming permission gate infrastructure * feat: wire permission gate into the agentic loop * fix: bail out on abort and skip already-approved tool calls * fix: clear partial tool calls on abort and savePartialResponse * test: cover partial tool call cleanup end-to-end * refactor: Remove streaming permission gate logic * fix: Correct autoscroll and streaming gates for tool calls and reasoning blocks * refactor: Chat Message Assistant componentization * fix: Show health metadata for disabled MCP servers and promote connections on enable * fix: Inherit global enabled state for missing MCP per-chat overrides * refactor: Cleanup * refactor: Split ChatMessageToolCallBlock into dedicated components * feat: Add live streaming and auto-scroll for tool execution output * feat: Add line numbers and change markers to file edit diffs * chore: Formatting * feat: Add type definitions and utilities for recommended MCP servers * feat: Add recommended MCP servers configuration and storage key * feat: Add McpServerCardCompact component for recommended servers * feat: Add recommended servers section to Add New Server dialog * feat: Update McpServerForm to support authorization requirements * feat: Add select-none classes for text selection prevention * feat: Add recommended MCP server icon assets * refactor: Store dismissed MCP recommendations as a boolean flag * feat: Render tool results as JSON or Markdown based on detected content type * feat: UI improvement * feat: Render search block early and update heading to show execution state * fix: Prevent non-web-search tools from triggering the search UI block * refactor: Cleanup * refactor: Extract hardcoded icon size classes into shared constants * refactor: Extract hardcoded tool result separator into a shared constant * refactor: Tool Calls UI/logic * refactor: Cleanup * refactor: Cleanup * refactor: Cleanup
* opencl: exclude Adreno A7x from using Adreno MoE kernels Some compilers for A7x devices miscompile the repack kernels, corrupting the weights and causing MoE models to generate garbage output * opencl: exclude A6x and unknown Adreno from MoE weights repack
…ues for Adreno 850 GPU (ggml-org#25745) * opencl: workaround for A850 compiler compat * opencl: fix DX compiler version parsing and cleanup --------- Co-authored-by: Li He <lih@qti.qualcomm.com>
Assisted-by: pi:llama.cpp/Qwen3.6-27B
* CUDA: dedup MoE gate/up activation quantization (fp4) For MoE gate/up projections the src1 activation is broadcast across the routed experts (ne11 == 1), so ids_src1 maps every one of a token's n_expert_used slots to the same physical row. The MMQ path therefore re-quantized each token's activation n_expert_used times. For fp4 (NVFP4/MXFP4) src0, quantize each unique token row once instead of once per expert. For NVFP4 a single quantize+scatter kernel (quantize_scatter_mmq_nvfp4) quantizes each token once and writes the resulting block_fp4_mmq straight to all n_expert_used slots, using an inverse token->compact-row map (build_tok2c). MXFP4, and GGML_CUDA_MOE_QUANT_GATHER=1, use a two-kernel variant: quantize unique rows then gather into the expert-sorted layout (gather_mmq_fp4_blocks). Both are bit-identical to the previous gather-then-quantize path (identical source data, deterministic per-block quantization), verified by test-backend-ops MUL_MAT_ID (type_a=nvfp4, broadcast b=1; 790/790 for the default, gather, and per-expert paths) and by coherent end-to-end generation. Set GGML_CUDA_NO_MOE_QUANT_DEDUP=1 to force the original per-expert path. Same-binary A/B on RTX 5090 (sm_120), Qwen3.6-35B-A3B-NVFP4 prefill @8192 (nsys, graphs-off; the unchanged mul_mat_q GEMM confirms stable clocks): activation-quant GPU-busy drops 61% (78.2 -> 30.4 ms) with the fused quantize+scatter, vs 33% (78.2 -> 52.8 ms) for the two-kernel gather. The fused path avoids materializing and re-reading the 8x compact buffer, writing the expert copies directly from registers. * CUDA: bounds-check token ids in build_tok2c_kernel Guard against malformed ids_src1: skip out-of-range token ids (t < 0 or t >= n_tokens) and drop entries beyond n_expert_used per token instead of writing past the token's tok2c region. No behavior change for valid MoE routing data; test-backend-ops MUL_MAT_ID 790/790. * Refactor the code based on review comments - Removed previously added kernels that were not necessary anymore\ - Added an inverse mapping from (token, slot) to compact row. Each token is quantized once and scattered to its compact rows. * Adding q8_1 support for dedup and addressing review comments * Add pragma unrolls * Remove redundant cudaMemsetAsync call * Removing follow up redundancies --------- Co-authored-by: praneshgo <227579474+praneshgo@users.noreply.github.com>
PR ggml-org#16308 set info.devices[id].integrated = false unconditionally for all CUDA/HIP devices as a workaround for corrupted output on Jetson Orin (ggml-org#15034). On HIP/ROCm the device's real hipDeviceProp_t.integrated flag is needed: with the cached field forced to false, supports_buft() refuses CUDA host buffers on AMD APU/UMA parts, while get_type() already reads prop.integrated (ggml-org#23007) — an inconsistency that breaks integrated-GPU host-buffer use on ROCm. Guard the workaround so it only applies to non-HIP (CUDA) builds and restore prop.integrated for HIP, keeping the Jetson workaround intact for CUDA. Fixes ggml-org#23977 Signed-off-by: liminfei-amd <91481003+liminfei-amd@users.noreply.github.com>
Otherwise this gives lots of unnecessary warnings: W srv operator(): (CORS) skip non-localhost origin:
* support cuda virtual devices * disable NCCL path when virtual devices are used * label virtual devices in description; add GPUx2 server CI jobs * code refactor
…l-org#25733) * spec: fix dflash target tokenizer mismatch during conversion * fix ci ty check
…e graph New arch kimi-k3 (KimiK3ForConditionalGeneration, text_config kimi_linear): - compressed-tensors mxfp4-pack-quantized dequant (E2M1 nibbles low=even, E8M0 uint8 scale, group 32), verified against real Kimi-K3 shard tensors - KDA safe gate: g = lower_bound * sigmoid(exp(A_log) * (f_b(f_a(x)) + dt_bias)), full-rank output gate g_proj, A_log sliced to [:n_head] at conversion - gated MLA (NoPE): attn * sigmoid(g_proj(x)) before o_proj, q_lora_rank 1536 - Stable LatentMoE: router on full hidden, experts in 3584 latent space, RMSNorm after the weighted expert sum, then up-projection - AttnRes: residual-stream snapshot bank every attn_res_block_size layers, softmax mixtures before attention, before FFN and at model output - SiTU-GLU activation (LLM_FFN_SITU): beta*tanh(g/beta)*sigmoid(g) * lbeta*tanh(up/lbeta) Tested on a synthetic mini K3: convert -> BF16 GGUF -> Q8_0 -> generation.
8863f03 to
b2f13d7
Compare
|
Numerical parity verified against the Moonshot reference implementation (CPU, unmodified modeling_kimi_linear.py running on top of a fake fla package backed by flash-linear-attention's own naive_recurrent_kda torch reference). Setup: synthetic mini K3 (4 layers: 3 KDA + 1 gated MLA, dense layer 0, 2 MoE layers with 8 MXFP4 experts, AttnRes block size 2, real kimi tiktoken vocab), prompt of 7 tokens, logits compared at every position over the full 163840 vocab.
Diff magnitude is bf16 weight rounding noise (llama.cpp: bf16 weights + f32 activations; reference: f32 upcast of the same bf16 weights). Greedy continuation, 12 steps: llama.cpp used the cached path (KDA recurrent state + conv state + MLA absorption KV cache), reference ran cache-free full recompute. Token sequences are identical: This covers all four K3 deltas numerically: SiTU-GLU, AttnRes mixtures, LatentMoE (router on full hidden, latent norm after weighted sum), KDA safe gate with full-rank output gate, and the gated NoPE MLA. |
New kimik3 projector type, its graph builder and the mmproj converter. Also adds an optional clip.%s.attention.head_dim so build_vit stops deriving d_head from n_embd, which is wrong whenever a tower's qkv width differs from n_embd.
Graph node budget, LLM_TYPE for the 93-layer config, four hparams promoted to required, and an E8M0 NaN check during the MXFP4 repack. Details in the PR description.
Mirrors upstream PR 26185 commit cf11c4c. Without this the real checkpoint fails the n_expert assert at load; the synthetic test model (8 experts) never hit it.
99e21f3 to
4dfedb0
Compare
…_MAP The vision converter class lives in kimivl.py but the mmproj module map had no K3 entry, so --mmproj failed with 'not supported'. The vision-tower commit added the class without wiring the lazy module map.
The patchmergerv2 post-norm tensor had no entry in tensor_mapping so the mmproj conversion aborted. The text converter inherited kimi-linear's tokenizer-eos override (163585 [EOS], document terminator) while K3's chat turn terminator is 163586 <|end_of_msg|>; chat generation never stopped at turn end. Existing GGUFs can be patched in place with gguf_set_metadata.py.
K3's assistant output is an XTML-ish tagged format built by the template's
open_tag/close_tag macros. Two properties break generic parsing:
1. The generation prompt ends with open_tag('think'), so the completion
starts inside the think section with no opening marker in the output
(thinking_forced_open).
2. Only <|open|>/<|close|>/<|sep|>/<|end_of_msg|> are special tokens; tag
names ("think", "response", "message") are ordinary text tokens.
Adds common_chat_params_init_kimi_k3 (PEG_NATIVE) with detection on the
marker trio, reasoning extraction, response unwrapping, and tool-call
parsing of the tools/call/argument tag structure with argument types
taken from the tool schema. Includes the K3 chat template fixture and 9
test-chat cases derived from real generations of the full 2.8T model.
Verified end-to-end against Kimi-K3-Q2_K (GrEarl/Kimi-K3-GGUF) on 8x B200:
content, reasoning_content, streaming deltas, and tool_calls all correct;
finish_reason stop/tool_calls as appropriate.
Per-role message-start markers for token-level span splitting. User and assistant messages carry only the role attribute, so their full opener (through <|sep|>) is used; system and tool messages continue with more attributes (type=/tool=/index=), so those delimiters stop after the role's closing quote. Verified against the K3 tiktoken vocabulary that the closing quote is always a standalone token across all attribute variants, so the token-level prefix match stays exact.
…n.head_dim The mmproj converter writes the per-head dim because MoonViT-V2's qkv width (1536) is not derivable from the embedding length (1024); the writer method and KV constant were missing.
…s none Moonshot's tokenizer_config.json has no chat_template (K3 is API-first), so converted GGUFs were template-less and chat tools refused to start. Embed models/templates/Kimi-K3.jinja at conversion unless the checkpoint provides its own.
--chat-template already accepts MTMD; the file variant did not, which is inconvenient for models whose template only exists as a jinja file.
Active parameters per token: 69 KDA layers x 443.6M + 24 MLA x 232.2M + 92 MoE layers x 718.4M (16 of 896 experts, 2 shared, latent projections, router) + dense layer 0 FFN + lm_head = ~104B, matching Moonshot's published figure. The A50B label came in with the vision commits and understated it by half.
What this is
Support for Kimi K3 (moonshotai/Kimi-K3, 2.8T MoE, MXFP4 QAT) in llama.cpp: checkpoint conversion to BF16 GGUF plus a full inference graph for imatrix and quantization.
Note: this branch is cut from upstream ggml-org/llama.cpp master (0e4a036), which is about 136 commits ahead of our master, so the PR diff includes upstream commits. Merge by rebasing our master or cherry-pick the single feature commit.
Parts
Python (conversion):
C++ (graph):
Verified
References
Next