π£ DeepSeek-V4-Flash-0731 (284B MoE) on 2Γ 24 GB β CPU expert offload, and why we are publishing no TPS numbers #909
Replies: 9 comments 9 replies
|
I think publishing a range of T/s is still helpful; if folks are way off noting that someone else has better numbers might make them see what else they can tweak (like RAM speed in BIOS). & if the T/s is too slow, some folks won't bother with it, like me with 1 RTX3090. |
|
I do not understand how you get requirements of 150+GB SDRAM for the full weight model: Full size model runs fine with 128GB CPU + 48GB GPU here. I have AMD Ryzen 7900X3D with 4x32GB DDR5 SDRAM, (G.SKILL DDR-6600 downsped to 3600mhz due to 4-sticks) Approx 30k tokens into a run I am seeing Experimental boosting of SDRAM up to 4400mt/s gets me to: I'm still not understanding the layer loading you do, and why on earth you put the download logic into your run-script. Is there a simple command to try that does NOT download anything?? |
|
Good news: After more DRAM tuning (around 4400mt/s with tighter timings) I get: At beginning Later in gen, depending on what's being done Invocation is naive llama-cli with -fit on as above. Will run report.sh once i've studied it. |
|
A first 4-card Q8 baseline for the configuration you said nobody had booted yet. This is not yet a recommended production recipe; we are still iterating on placement, batching, and speculative decoding. Rig
This used plain llama.cpp with CPU expert offload, not the ConfigurationClub report resultOne canonical
The completed run measured approximately:
The failed stress check was then run separately with The stress script should make this timeout configurable, matching the existing - --max-time 600
+ --max-time "${STRESS_REASONING_TIMEOUT_S:-600}"The important practical finding so far is that This is an exploratory baseline only. We are now using short iteration tests before running another long report, and will publish a final usable configuration after placement and speculative-decoding tests converge. |
|
First canonical numbers for both shipped dual slugs β from the reference rig, at last. These were owed since the slugs shipped: both went out Rig: 2ΓRTX 3090 (24 GB, PCIe-only), EPYC 7543 guest (32 cores), 8-channel DDR4-3200, 196 GB RAM. Stock
|
| metric | result |
|---|---|
| decode, narrative | 17.1 t/s (draft acceptance ~0.33) |
| decode, code | 26.9 t/s (acceptance ~0.70) |
| TTFT (short prompt) | 169 ms |
| prefill @10k / @90k | 369 / 287 t/s (CV β€0.6% across boots) |
| VRAM | 23.3 + 22.8 GiB, no swap |
greedy protocol (temp 0, /completion) |
35.2 t/s β different protocol, never compare to the sampled rows |
llamacpp/deepseek-flash-dual-iq2 β reach tier (~86 GB host RAM gate)
Same protocol, same host:
| metric | result |
|---|---|
| decode, narrative / code | 15.4 / 24.3 t/s (acceptance mean 0.46) |
| TTFT | ~165 ms |
| prefill @10k / @90k | 436 / 311 t/s |
| greedy protocol | 32.2 t/s |
What the pairing tells you
- Q8 is both the quality AND the decode-speed tier here (~10% faster than IQ2): the drafter accepts far fewer tokens against 2.6-bit experts, and that costs more than the smaller expert reads save. IQ2's case is the RAM gate (86 vs 146 GB) and prefill (+18% @10k β less weight volume over PCIe).
- Decode is strongly content-dependent through the drafter (17 narrative vs 27 code on the same boot) β when comparing rigs in this thread, compare like prompts.
- One honest asterisk: in 2 of 3 Q8 boots, a host-side contention mode we're still chasing halved sustained code decode for a few consecutive runs (narrative, greedy, and prefill never affected; acceptance normal; zero guest-visible cause). Numbers above are from clean boots; the anomaly is documented in the repo and under investigation.
Both slugs stay π£ Incubating until the quality 8-pack lands β that's next. BENCHMARKS.md rows 2β3 carry the full detail as of today's commit.
@mgabor3141 β your 4-channel Triad (51.4β52.0) is within noise of what this rig measured in its own 4-channel era, so your no-drafter Q8 numbers and these drafter-attached ones now bracket the DSpark contribution on near-identical host bandwidth. That's a comparison nobody planned and it's the most useful accident in this thread.
|
What this tells me is i want noonghunna's 8-channel DDR4-3200 :D That's nominal 200GB/s RAM vs my tweaked 58GB/s. So my experts are sitting on memory 28% as fast as the 8CH DDR4. At my safe (no speculative) decode of 8.8 vs 27 t/s that's close to linearly scaling with memory speed. However if i go with buun-llama-cpp I'm pulling 12.5 t/s until a few k context, then it crashes. So I'm hoping to get that running someday. Will share more then. Delete this if it's a waste of space. Thanks and cheers. |
DeepSeek V4-Flash on dual RTX 3090s β a tuning campaign with real numbersSharing our experience tuning DeepSeek V4-Flash (the 284B MoE, Q8-class) on a Hardware and baselineWhere we started: ~7.2 answer-tokens/s in real use. Where we ended: 16.93 TPS median (code workload) after tuning, and a clear Engine and model
What we swept and what we found1. Speculative depth: 2 is the sweet spot
Depth 5 had the highest MoE cache hit rate but the lowest throughput β 2. Code vs narrative: acceptance is the differentiator
Code is 15% faster despite a slightly lower cache hit rate. The drafter 3. CPU threads: the club default is safe but not optimal
The real knee is 15β16 threads. Thread 15 beats the 4. Batch/ubatch 2048 vs 4096: a prompt-heavy profile, not a universal win
4096 is a legitimate prompt-heavy profile: big uncached prompts, short The honest caveats
What we'd tell others
The fork itself is solid β Club's MoE cache integration matched the exact NOTE: Written with Deepseek Flash v4 :P |
|
I should also note that I just bought a WRX80 Threadripper Pro 3975WX system and will be attempting the same experiment with higher memory bandwidth to see how much the needle moves. |
Uh oh!
There was an error while loading. Please reload this page.
We just shipped
llamacpp/deepseek-flash-dual-q8andllamacpp/deepseek-flash-dual-iq2β a 284B MoE running on two 24 GB cards, by keeping 137 GiB of routed experts in host RAM and pinning a few expert bundles back onto the GPUs.It's DeepSeek-V4-Flash-0731, GGUF quants and the DSpark drafter by @unsloth. Stock upstream
llama.cppβ zero patches. All credit for the model goes to DeepSeek; unsloth made the quants and the drafter, and the DSpark runtime is ggml-org#25784.A third slug,
llamacpp/deepseek-flash-multi4-q8, ships for 4-card rigs β authored but never booted by us, because we have two cards.π£ Why this is Incubating, and why there are no TPS numbers
We are deliberately publishing no performance or quality figures. Not modesty β we don't think ours would predict yours.
Everything else in the catalog is GPU-resident, so the GPU is the variable and our numbers travel reasonably well. These slugs are not GPU-bound. Under expert offload the GPU sits idle most of the time β we measured SM at ~12.8% β waiting on ~40 sequential GPUβCPU handoffs per token. What you get is set by:
-t 48burned 94% CPU to deliver 31% of peak. More threads made it worse.So a decode number from our rig would be close to meaningless on yours, and publishing one invites exactly the wrong comparison. We'd rather ship the config, tell you honestly what we don't know, and collect real numbers from real rigs.
Also genuinely untested: quality. No 8-pack has been run on either tier β and IQ2_XXS carries ~2.6-bit experts, where it matters most.
deepseek-flash-dual-q8deepseek-flash-dual-iq2This is not a recommendation β below it the box thrashes or OOMs. Preflight refuses to launch and tells you the number. The IQ2 tier exists precisely so the model fits a smaller box.
Why this model
Two tiers, and they are different capability profiles, not a speed/quality slider:
Three levers compose: CPU expert offload + partial residency (bundles pinned back onto the GPUs, sized automatically from your detected free VRAM) + the DSpark drafter.
Ships at 200K context, not 262K. At 262K it boots, reports healthy, answers a trivial prompt β and then dies on the first real prefill with a CUDA OOM. Which is its own lesson: on this class of config, a clean boot and a passing smoke test are both insufficient.
How the offload actually works
Worth spelling out, because there are two very different ways to run a model that doesn't fit, and they behave nothing alike.
The common approach is layer-granular β
-ngl Nputs N whole layers on the GPU and leaves the rest entirely on the CPU. Simple, and the engine can size it for you. But "the rest" includes those layers' attention, which is the latency-critical part.These slugs are expert-granular instead:
On this model the routed experts are 137 GiB β about 91% of the file β against a 11.7 GiB dense stack. So offloading experts alone moves nearly all the weight off the GPU while keeping all 43 layers of attention resident and fast. Layer-granular offload would banish attention for roughly half the model to get the same VRAM saving.
Then residency puts some experts back. Whatever VRAM is left after the dense stack, KV, compute buffers and the drafter gets filled with whole expert bundles, pinned to specific cards:
Two details that matter if you hand-edit this:
-otis first-match-wins. The device rules must come before the=CPUcatch-all. Reverse them and every expert silently lands on CPU β no error, no warning, just a config that quietly isn't what it claims.You don't tune any of this. The launcher reads free VRAM per device and emits the rules, so a 24 GB card and a 32 GB card each get what they can hold β and a rig with more cards gets more experts resident, which also means less host RAM needed, since every pinned layer is a layer not in CPU memory.
Why this makes your numbers differ from ours
The trade is that a token's expert weights now stream from host RAM, and the GPU waits for them: ~40 sequential GPUβCPU handoffs per token, with the GPU at ~12.8% SM utilisation (versus ~43% when fully resident). The card is idle, not busy.
Which is the whole reason we're not publishing throughput: the bottleneck has moved off the GPU and onto your memory subsystem and core count.
Getting it
It defaults to IQ2 deliberately β it's the tier most rigs can actually run, and guessing wrong costs you a 151 GB download. Either way
setup.shalso fetches the DSpark drafter, which is not optional: both slugs pass-mdand won't boot without it (the main GGUF carries no embedded prediction head, so DSpark is the only speculative path).Engine floor:
server-cuda-b10236or newer. DSpark landed in ggml-org#25784 and is absent from earlier pins β the flag simply isn't understood. The catalog pin already satisfies this.Run it
Command line β
π£ incubatingmeans non-functional-by-default, so--forceis required:Expect 8β10 minutes to load (
--no-mmap, and it's 151 GB). Served model name:deepseek-v4-flash.In the c3 cockpit β they show in the Catalog tab with a π£ glyph, no toggle needed, and the catalog now carries a host RAM column plus
offload = n-cpu-moeandspec = DSpark, so you can see the gate before you commit to a download (his for deprecated / hardware-incompatible slugs, which these are not). Select one and launch withfβ force, because incubating is non-functional by default.You don't need to size residency yourself: the launcher reads free VRAM per device and injects the expert-bundle placement, so a 24 GB card and a 32 GB card each get what they can hold.
Run the evals β this is the ask
Two non-overlapping passes. Operational health:
bash scripts/report.sh --full # verify + stress + soak + bench + agenticBehavioural quality β the 8-pack, both reasoning modes:
pip install git+https://github.com/noonghunna/benchlocal-cli.git git clone https://github.com/noonghunna/benchlocal-cli && bash benchlocal-cli/tools/build-sandboxes.sh bash scripts/quality-test.sh --full --no-thinking bash scripts/quality-test.sh --full --enable-thinkingmax_tokensandcontentcomes back empty while the reasoning trace eats the budget β it looks like a failure and isn't. Give it room.If a long generation times out on the operational leg, raise
VERIFY_LONG_TIMEOUTβ the default is sized for GPU-resident models and these run far slower.What'd help
Your numbers, with your RAM configuration attached β channels populated, speed, core count, and the
-tyou used. That last part matters more than usual: we expect the thread knee to move with core count, and one rig can't map that curve.Specifically useful:
multi4-q8. Nobody has run it. Residency should be much better with four cards, and host RAM should fall as card count rises β every layer pinned to a GPU is a layer not in host RAM. Untested.Credits
All reactions