Run DeepSeek V4-Flash (a ~100 B-class sparse MoE, 256 experts, ~13 B active per token) on an Apple-Silicon Mac with 48 GB of unified memory — a model that normally "needs 128 GB+".
It works by keeping the model on SSD and streaming only the active experts for each token into a device-side LRU cache in unified memory. Dense/attention weights stay resident (8-bit); the 256 routed experts (mxfp4) live on disk and are pulled on demand. So RAM holds a working set, not the whole model.
Stock llama.cpp / mlx-lm can't even load this architecture yet (unknown model architecture: 'deepseek4'). This is a from-scratch MLX inference engine built specifically to run it on constrained RAM.
Performance: ~4.5–5 tok/s decode on a 48 GB M-series Mac. That's not fast in absolute terms — decode is fundamentally bottlenecked by SSD bandwidth (experts stream every token). The point is that a model this size runs coherently at all on a laptop that can't hold it.
- Apple Silicon Mac, 48 GB+ unified memory (developed on M5 Pro / 48 GB).
- ~155 GB free disk for the weights.
- Python 3.12,
pip install -r requirements.txt(MLX, gguf, torch, tokenizers, safetensors).
Two pieces, both derived from DeepSeek's MIT-licensed model:
-
Experts + tokenizer — the public MLX checkpoint:
hf download mlx-community/DeepSeek-V4-Flash-4bit --local-dir mlx-ckpt
(Experts are used as mxfp4 and streamed from here.)
-
8-bit dense companion — the dense/attention weights at higher precision than the uniform-4-bit checkpoint (this is what preserves quality). Get any DeepSeek V4-Flash GGUF that keeps dense at F16/Q8 — search HuggingFace for
DeepSeek-V4-Flash GGUF; the right files haveQ8Attn/F16HCin the name (the experts' quant doesn't matter, they're not used from the GGUF). Put the.ggufingguf/, write its filename intogguf/TARGET.txt, then build the ~15 GB companion once:python oracle/build_dense_companion.py # -> mlx-ckpt/dense_fp16.safetensorsAfter that the GGUF can be deleted — the engine reads dense from the companion (bit-identical). If the companion is absent it falls back to reading the GGUF directly.
Simpler but slightly lower quality: skip the companion and the engine will use the checkpoint's own 4-bit dense weights (perplexity ~+2%, no semantic errors in testing).
# stdin JSON REPL:
./scripts/serve.sh
{"prompt": "Write a Python function to reverse a linked list.", "max_tokens": 300}
{"cmd": "reset"}
# or an OpenAI-compatible HTTP server on :18091:
./scripts/serve-http.sh
curl localhost:18091/v1/chat/completions -d '{"model":"deepseek-v4-flash","stream":true,"messages":[{"role":"user","content":"hi"}]}'Knobs (env vars): CAP=1664 (expert-cache size), MAX_CTX=32768 (context window; rope tables allow
65536), PF_BATCH=1 (batched prompt digestion), TOPK=6 (routed experts — TOPK=5 is ~+10% for a mild
quality trade). DeepSeek V4-Flash is Chinese-trained; the daemon injects an "always respond in English"
system prompt by default.
The bottleneck here is how much of the model stays resident, so more unified memory translates fairly directly into speed:
- Raise the expert cache (
CAP). Every extra GB lets more of the 256 experts stay resident instead of streaming from SSD, so the cache-hit rate climbs and fewer bytes move per token. On 48 GB the default isCAP=1664(~31 GB active); with 64 GB you can push it well higher (tryCAP=2400+) before you approach swap. Tune against free RAM, not the macOS swap counter (it reads high spuriously). - Speculative decoding. The engine was built for a lossless draft/verify path (proven bit-exact in the research tree, not bundled here) that is memory-walled at 48 GB — verification needs the draft's and target's active experts resident at once. At ~64 GB that union fits, projecting ~6–7.5 tok/s.
- Expert offloading (
offload_cache_v4.py,pread_loader.py): a fixed-size device LRU over mxfp4 expert records, streamed via parallelpreadwith async load / compute overlap. Only the ~6 experts per token per layer that actually route are read. - Quantized dense (
v4_fast.py): attention/shared-expert/head weights quantized to 8-bit at load (quality-gated), kept resident.quantized_matmulon the decode path. - Batched prefill (
v4_prefill.py): the per-position expert gather is batched into one call — ~2× faster prompt digestion. - Serve layer (
v4_serve_fast.py,v4_http.py): chat-framed multi-turn with append-only KV reuse, turn-drop compaction, and EOS-stopping.
- ~5 tok/s, byte-bound. Decode speed is set by SSD expert streaming, not compute. It won't feel fast.
- Lossless speculative decoding is built (
v4_fast_spec.pyin the full project) and proven bit-exact, but the verify step's expert union doesn't fit alongside the model in 48 GB — it's a ~64 GB unlock. - Prefill/decode are the same ~200 ms/token because every prompt position also pays for its experts.
Engine code: MIT (this repo). The model is DeepSeek V4-Flash (© DeepSeek, MIT); expert checkpoint by
mlx-community. Built on MLX. This is research-grade software shared
as-is — expect rough edges.