[Help Wanted] MoE inference 13× slower than llama.cpp — expert weight scatter bottleneck on DeepSeek-V2-Lite #1
Unanswered
shifulegend
asked this question in
Q&A
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
🧭 Executive Summary
Project Zero is a from-scratch, dependency-free C inference engine for running large language models on commodity CPUs. We've achieved strong results on BitNet b1.58-2B-4T (beating bitnet.cpp by 1.8× on a Xeon), but have hit a fundamental bottleneck with Mixture-of-Experts (MoE) models — specifically DeepSeek-V2-Lite-Chat and OLMoE.
We are running at ~1 tok/s. llama.cpp runs the same model on the same hardware at 13.79 tok/s.
We're opening this discussion to get community input on the MoE weight scatter problem and any other ideas. All benchmark data, profiling results, and architecture documents are in the repo.
📊 Where We Stand
BitNet b1.58-2B-4T — ✅ Solved
Memory bandwidth is the bottleneck here, and we're at ~95% of the theoretical DRAM ceiling on the Xeon. This model is effectively solved.
DeepSeek-V2-Lite-Chat (MoE) — 🔴 13× Behind llama.cpp
Hardware profiling reveals the root cause:
IPC < 1.0 and 86% cache miss rate = we are severely memory-stalled. The CPU is spending most of its time waiting for RAM, not computing.
🔬 Root Cause Analysis
Problem 1 — F32 dequantization path (confirmed, partially fixed)
We currently dequantize all Q4_K weights to F32 at compute time, incurring 50× more memory bandwidth than llama.cpp's native Q4_K matmul kernels. For dense layers (BitNet), we've replaced this with custom AVX-512 ternary/VNNI kernels. For MoE expert layers, we're still on the F32 path.
Problem 2 — MoE expert weight scatter (primary bottleneck)
DeepSeek-V2-Lite has 64 experts per MoE layer (26 MoE layers total). Each token activates only 6 experts. The experts' weight tensors are stored sequentially in the 8.9 GB GGUF file — so the 6 active experts for a given token are scattered across the file's address space.
What this means in practice:
What llama.cpp does: At model load, it repacks expert weights into a layout where the weights for all experts in a layer are interleaved — so for any activated set of top-k experts, the relevant weights are contiguous. This trades a one-time load penalty for dramatically better cache/prefetch behavior during inference.
Problem 3 — MoE garbled output (fixed, awaiting validation)
Before P8, switching from incorrect dense-mode execution to correct sparse MoE revealed corrupted FP16 scale values in some Q2_K/IQ4_NL expert weight super-blocks. These NaN values cascaded through the residual stream → all logits became NaN → argmax always returned token 0 → endless
ãĢįãĢį...output.Fix applied (P8): NaN guards that zero out corrupt blocks instead of propagating NaN. Needs validation with DeepSeek-Q2_K model file.
🙋 What We're Looking For
1. Expert weight repacking strategy
How should we implement the interleaved expert weight layout at model load time for Q4_K_S GGUF files? Specifically:
ggml_tensorrepacking work for MoE? (Relevant source:llama.cpp/src/llama.cpp,ggml/src/ggml.c)madvise, huge pages) that could help before a full repack?2. Native Q4_K matmul kernel
We need an AVX-512 kernel that operates directly on Q4_K super-blocks (32-element blocks with 4-bit weights and FP16 scale + min). The goal is to replace the current dequant-to-F32 → F32 matmul pipeline.
3. NaN guard validation
If anyone has
DeepSeek-V2-Lite-Chat-Q2_K.ggufavailable, validation of P8 commitcc67445would be extremely helpful. Expected output: coherent text (notãĢįãĢį...) at ≥0.63 tok/s.4. General MoE inference optimization ideas
Any other strategies you've seen work for MoE inference on CPU — expert caching, speculative expert selection, weight format changes — welcome.
📁 Key Documents
All docs are in the repo and contain full data:
BENCHMARK_REPORT.mddocs/PERFORMANCE_CEILING_REPORT.mdMOE_RESEARCH_AND_FIX_PLAN.mdDEBUGGING_JOURNAL.md💻 Reproduce Locally
Requirements: GCC/Clang, pthreads, libm. No Python, no pip, no CUDA. Single binary.
🏷️ Labels suggested
performance,help wanted,moe,deepseek,gguf,avx512Beta Was this translation helpful? Give feedback.
All reactions