Repository navigation
馃毀 [WIP] MoE cache, CPU experts and GGUF support聽#671
Copy link
Copy link
Open
Labels
Description
Tracks the refactor of the MoE expert cache and the CPU expert path and GGUF support.
Where it stands
- The GPU slot cache splits into slot pools, one per layer or one per quant (feat(moe): split the offload expert cache into slot pools聽#689), and each MoE layer has its own expert method and bank set (feat(moe): serve experts of several formats through per-format slot pools聽#700).
- The engine takes each MoE layer's own quant method, and the CPU expert executor serves a weight format per layer (feat(moe): serve experts of several formats through per-format slot pools聽#700).
- Several decisions made before the model is built still read one model-wide
ModelConfig.expert_quant: whetherfusedis allowed,--moe-cpu-layers auto, the automatic offload / hybrid pick, and some family weight readers. - GGUF checkpoints load through the quant layer and run on vendored ggml-cuda kernels (feat(gguf): serve GGUF checkpoints on vendored ggml-cuda kernels聽#690): Gemma-4 26B-A4B and Qwen3.8-Flash-Next, text only, TP 1.
hybrid/cpuwork only for Q4_0 and BF16 experts; feat(cpu-moe): serve GGUF experts on the cpu and hybrid backends through ggml-cpu聽#704 (in review) runs every GGUF expert type on the CPU, quantized or float.
Work items
Cache
- Slot pools: one pool per layer or one per quant (quant tag and bank layout), sized equally or from an expert-use profile. feat(moe): split the offload expert cache into slot pools聽#689 @jason-fxz
- Bank sets that differ per layer: the banks are the union of the formats' roles, a layer without a role gets a zero-byte placeholder, and each format gets its own slot pool. feat(moe): serve experts of several formats through per-format slot pools聽#700 @andy-yang-1 @jason-fxz
Mixed quant per layer
- Engine, loaders and FTW checkpoints take each layer's own expert method; the CPU executor gets every layer's format as
(name, options)and treats all formats alike. feat(moe): serve experts of several formats through per-format slot pools聽#700 @andy-yang-1 @jason-fxz - Resident (
fused) experts of several formats. - Record each layer's expert quant in
ModelConfig(keepexpert_quantas the most common one for compatibility) and make the decisions taken before the model is built per layer:fusedeligibility,--moe-cpu-layers auto, the automatic offload / hybrid pick, and the family weight readers (qwen3_5_moereads stacked bf16 experts only whenexpert_quant == "none"). -
ft bench bw: record one entry per layer kind, keyed by(format, (H, I), options), e.g.("bf16", (H, I)),("nvfp4", (H, I)),("gguf", (H, I), Q4_0, Q6_K), and let the engine pick hybrid and the fetch fraction per layer. Today the profile is keyed by format only and the automatic fetch cap reads the most common format's entry for every layer. (feat(moe): bench hybrid fetch fractions per moe layer kind聽#734)
CPU expert executor
- Split the executor from the weight formats and the GPU handshake (refactor(cpu-moe): split the executor into weight formats and gpu sync backends聽#670). @jason-fxz
- Kernel IO for the handshake: a publish kernel writes a step's inputs into the pinned IO block and rings the doorbell, or skips a step without CPU routes; a combine kernel reads the CPU rows back. The coordinator skips tasks without routed experts (refactor(cpu-moe): split the executor into weight formats and gpu sync backends聽#670). @jason-fxz
- Hybrid decode: split the routes between GPU and CPU inside the hybrid ensure kernel instead of torch ops (perf(moe): split hybrid decode routes inside the ensure kernel聽#685). @jason-fxz
- Batch size > 1: split the work by expert, so an expert shared by several tokens is read once.
GGUF
Kernels and loading
- GPU: llama.cpp's ggml-cuda MMQ / MMVQ kernels for every GGUF type that has an MMQ kernel, prefill and decode (feat(gguf): serve GGUF checkpoints on vendored ggml-cuda kernels聽#690). @jason-fxz
- CPU: llama.cpp's ggml-cpu row kernels (quantized, and f32 / f16 / bf16), vendored unchanged and built for AVX2 as static libraries linked into
_cpu_moe; oneggufexecutor format per layer's (gate_up type, down type), and every type with a ggml-cpuvec_dotworks. Replaces theq4_0CPU format. feat(cpu-moe): serve GGUF experts on the cpu and hybrid backends through ggml-cpu聽#704 (on top of feat(moe): serve experts of several formats through per-format slot pools聽#700) @jason-fxz - Tokenizer: build GGUF tokenizers on transformers 5.18, which keeps USER_DEFINED and CONTROL tokens such as
<think>whole, with llama.cpp's stop tokens (build(deps): upgrade transformers to 5.18聽#698). @jason-fxz - Vision towers (
mmproj).
Model Support
Every model family FreeToken registers; the backticked name is the GGUF architecture llama.cpp's converter writes.
- Qwen3.8-Flash-Next (
qwen4exp) (feat(gguf): serve GGUF checkpoints on vendored ggml-cuda kernels聽#690). @jason-fxz - Qwen3.5 / Qwen3.6, also Qwen3.8-27B (
qwen35,qwen35moe). (feat(gguf): serve Qwen3.5 dense and MoE GGUF checkpoints聽#701) - Gemma-4 26B-A4B (
gemma4) (feat(gguf): serve GGUF checkpoints on vendored ggml-cuda kernels聽#690). @jason-fxz - Dense Gemma-4 (
gemma4). (feat(gguf): serve Gemma 4 dense GGUF checkpoints聽#706) - E-series Gemma-4 (
gemma4) - Llama (
llama). (feat(gguf): serve Llama and Mistral llama-arch GGUF checkpoints聽#722) - Qwen2 (
qwen2). (feat(gguf): serve Qwen2, Qwen3 and Qwen3 MoE GGUF checkpoints聽#707) - Qwen3 / Qwen3-MoE (
qwen3,qwen3moe). (feat(gguf): serve Qwen2, Qwen3 and Qwen3 MoE GGUF checkpoints聽#707) - Qwen3-VL / Qwen3-VL-MoE (
qwen3vl,qwen3vlmoe). - MiniMax-M2 (
minimax-m2). (feat(gguf): serve MiniMax-M2 and MiniMax-M3 GGUF checkpoints聽#725) - MiniMax-M3 (
minimax-m3). (feat(gguf): serve MiniMax-M2 and MiniMax-M3 GGUF checkpoints聽#725) - DeepSeek-V4 (
deepseek4). - DeepSeek-V4.1 (llama.cpp has no converter for it).
- Muse-Glimmer (
muse-glimmer). (feat(gguf): serve Muse-Glimmer GGUF checkpoints聽#724) - Mistral / Mistral 3 (
llama,mistral3). - gpt-oss (
gpt-oss). - GLM-4.5 / 4.7 (
glm4moe). (feat(gguf): serve GLM-4.5, GLM-4.6 and GLM-4.7 GGUF checkpoints聽#731) - GLM-5 / 5.1 / 5.2 (
glm-dsa). - GLM-5.3-Flash (
glm5-next).
Known issues
- MoE MMQ (the GPU path above 8 tokens) hits an illegal memory access when one token routes to the same expert slot more than once.
hybriddoes this on every step that has CPU routes: they are parked on slot 0 with weight 0 because the GGUF MoE kernel cannot skip inactive slots. Sohybridcrashes above 8 tokens per step for any quantized expert type; Q4_0 is the only one it runs today. - Qwen3.8-Flash-Next with
--ple-backend disk(wait-sync): the first CUDA graph replay of a batch size can hang, because the graph waits on a host flag that the engine sets only afterreplay()returns and the first replay also uploads the graph. Seen at 16 concurrent requests on the GGUF; not GGUF-specific. fix(engine): upload cuda graphs at capture so a stream wait cannot block the first launch聽#697 @jason-fxz - MMQ / MMVQ use 32-bit block offsets, so a weight view of more than 2^31 blocks is not supported, e.g. a Qwen3.8-Flash-Next offload pool of Q4_0 / Q8_0 experts above 20,971 slots. fix(gguf): reject ggml weights past the 32-bit block offsets of MMQ / MMVQ聽#699 makes it raise instead of faulting. @jason-fxz
- IQ1_M experts have no MMQ kernel, so MoE steps above 8 tokens fail.
- NVFP4 GGUF
.scale: llama.cpp's converter keeps each NVFP4 tensor'sweight_scale_2in a separate<name>.scaletensor. It is now applied on the GPU and CPU paths, and the gemma4, llama, qwen3, qwen3moe, qwen35 and qwen35moe loaders read it (feat(gguf): apply the weight scales of nvfp4 gguf tensors聽#732). - NVFP4 GGUF, still refused: an NVFP4
token_embd(the vendoredget_rowshas no NVFP4 case), and.scaleon glm4moe, qwen2, minimax-m2, minimax-m3, muse-glimmer and qwen4exp, which have no tested NVFP4 GGUF. llama.cpp's converter cannot produce a valid one for minimax-m2 and muse-glimmer.
Performance
do after basic GGUF CUDA/CPU kernel support.
- ggml CPU kernels for GGUF experts (measured on a Xeon 8480+, 12 threads): x86
quantize_row_q8_Kis scalar (about 5 us per row at K=2560); IQ types are compute-bound (30-40 GB/s per expert vs about 140 GB/s for Q4_K); with several tokens on the same experts, Q4_0 / Q4_K / Q8_0 run slower than on distinct experts (cause not investigated). - MoE MMQ: tune the tile width J of the flat grid; the automatic choice was up to 23% slower than the best J in a sweep.
- Native FP4 MMA (off unless
GGML_CUDA_FP4_MMA; needs an sm_120a / sm_120f build).
Reactions are currently unavailable
Activity
[-]MoE cache and CPU expert refactor[/-][+]馃毀 WIP: MoE cache and CPU expert refactor[/+][-]馃毀 WIP: MoE cache and CPU expert refactor[/-][+][WIP] MoE cache and CPU expert refactor[/+][-][WIP] MoE cache and CPU expert refactor[/-][+]馃毀 [WIP] MoE cache and CPU expert refactor[/+][-]馃毀 [WIP] MoE cache and CPU expert refactor[/-][+]馃毀 [WIP] MoE cache, CPU experts and GGUF support[/+]feat(gguf): serve GLM-5.3-Flash GGUF checkpoints on glm5-next