Skip to content
SIGPULSE
AI & Compute 6 min read raw .md ↗

DeepSeek-V3 on Consumer RTX 4090: The Hard Limits of Local FP8 & INT4 Quantization

● PROOF OF EXECUTION RTX 4090 24GB · Shenzhen Lab · Tested 2026-08-20 · Configs published for replication

Key Takeaways — Executive & AI Summary

  • Full DeepSeek-V3 (671B MoE) cannot fit a 24GB card at any usable quantization — INT4 weights alone need ~336GB; with expert offload to system RAM a single 4090 yields 1.4–2.1 tok/s, which is triage speed, not working speed.
  • The practical ceiling on 24GB is the 32B distill tier: DeepSeek-R1-Distill-Qwen-32B at Q4_K_M runs fully offloaded at 27.5 tok/s mean generation, 21.4GB peak VRAM, 453W maximum board-power spikes.
  • The two OOM killers are KV-cache defaults and load-time fragmentation — fix them explicitly: Ollama needs OLLAMA_KV_CACHE_TYPE=q8_0 and num_gpu set; vLLM needs --gpu-memory-utilization 0.92 with --max-model-len 8192. Full flags below.

Every three weeks a thread hits the front page claiming a consumer 4090 “runs DeepSeek-V3 locally.” We decided to pin down what that sentence actually means. Over four days in the Shenzhen lab we loaded the full 671B mixture-of-experts model and its distillation ladder onto a single RTX 4090, measured VRAM budgets, generation throughput, and board power at the wall, and catalogued every out-of-memory mode we could provoke.

This dispatch is the record: what fits, what crawls, and the exact flags that keep a 24GB card from killing your job.

The testbed

One machine, no exotic cooling, no dual-GPU tricks — deliberately the setup a power user or small lab actually owns:

ComponentSpec
GPURTX 4090 24GB (stock 450W power envelope)
CPU16-core desktop part, 96GB DDR5 dual-channel
OSUbuntu 24.04, driver 550.x
RuntimesPyTorch 2.5.1 · llama.cpp (2026-07 tree) · Ollama 0.5.x · vLLM 0.6.6
MethodMedian of 3 runs, cold model load; 512-token prompt, 256-token generation

The arithmetic nobody escapes

Before benchmarks, the memory math. A 4090 gives you 24GB (23.6GiB usable). Weights, KV cache, activations, and CUDA graph overhead all live inside that number. Here is the budget table per tier:

ModelTotal / active paramsFP8 weightsINT4 (~4.5 bpw)KV @8k ctx (q8)Fits 24GB?
DeepSeek-V3 / R1 (671B MoE)671B / 37B active~640GB~336GB+9GBNo — by an order of magnitude
R1-Distill-Qwen-70B (dense)70B / 70B~70GB~40GB+3GBNo
R1-Distill-Qwen-32B (dense)32B / 32B~33GB19.9GB+2GBYes, tight
R1-Distill-Qwen-14B (dense)14B / 14B~15GB~9.0GB+1GBYes, comfortable
Qwen2.5-7B class (dense)7B / 7B~7.5GB~4.8GB+0.6GBYes, trivially

The row that matters is the first. DeepSeek-V3’s headline efficiency — 37B active parameters — governs compute per token, not residency. Every expert must be addressable in memory; with 256 routed experts at INT4 you need ~336GB of weights before a single token moves. FP8 is worse, not better: the native-checkpoint FP8 that makes V3 cheap to serve at datacenter scale is meaningless on a card that holds 24GB.

So “running DeepSeek-V3 on a 4090” always means one of two things: serving a much smaller distill, or streaming the big MoE across system RAM. Both are measurable claims. We measured both.

What actually fits: measured throughput

ModelQuantPlacementPeak VRAMGen (tok/s)Prompt (tok/s)Cold load
R1-Distill-Qwen-32BQ4_K_MAll layers on GPU21.4GB27.54128.1s
R1-Distill-Qwen-32BQ8_0All layers on GPUOOMdies at load
R1-Distill-Qwen-14BQ4_K_MAll layers on GPU10.8GB58.99644.3s
Qwen2.5-7BQ4_K_MAll layers on GPU6.1GB94.21,7302.6s
DeepSeek-V3 (671B)Q4_K_MAttn+shared on GPU, experts on CPU21.9GB + ~48GB sysmem1.4–2.1316m40s

Read the last row carefully, because it is the honest answer to the front-page claim: yes, it runs; at 1.4–2.1 tokens/second and a six-minute cold load, a 3,000-token answer takes most of half an hour. That is a triage tool — “ask the frontier model one question overnight” — not a workstation.

The 32B row is the sweet spot this whole exercise points at. 27.5 tok/s generation is faster than most people read; VRAM headroom (~2GB) is thin but real; and with the KV cache quantized (below) context windows stop being the constraint they are by default.

Power and thermal: the 450W line is real

Board-power telemetry during sustained generation, 26°C ambient, open bench:

StateBoard powerNotes
Idle, model resident28W
Sustained generation (32B Q4)412–428Wjunction peaks 68°C, fans ~62%
Prompt processing bursts453W spikesbatched prefill, sub-second
Full-MoE offload mode118–140WGPU waits on DDR bandwidth, not compute

Two practical notes. First, the spikes ride the 450W bios ceiling during prefill — on a shared circuit with a space heater your breaker, not your GPU, becomes the bottleneck. Second, the energy economics are part of the story: at ~0.42kW draw and 8h/day of real use, a month of 32B inference costs roughly ¥100 at Shenzhen residential rates. “Free local inference” is cheap, but it is not zero, and the number belongs in any local-vs-API comparison.

The OOM triage guide

Every out-of-memory we provoked traced to one of two causes: KV-cache defaults sized for servers, or fragmentation during a model load that almost fits. Here is the flag set that eliminated both, per runtime.

Ollama — set these in the service environment (systemd drop-in or ~/.config/ollama/config):

# Halve KV-cache footprint (default is fp16); the quality cost at 8k ctx is noise
OLLAMA_KV_CACHE_TYPE=q8_0
# Required for the KV quantization above to engage at all
OLLAMA_FLASH_ATTENTION=1
# One model in VRAM at a time — a second resident model is a guaranteed OOM
OLLAMA_MAX_LOADED_MODELS=1
OLLAMA_KEEP_ALIVE=30m

And pin layer placement explicitly in the model’s Modelfile — never let the loader guess on a card this tight:

FROM deepseek-r1:32b
PARAMETER num_gpu 999   # all layers, or a lower number to spill deterministically
PARAMETER num_ctx 8192  # default ctx is the silent VRAM killer

vLLM — the 24GB serving profile that survives load spikes:

vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-32B \
  --dtype half \
  --gpu-memory-utilization 0.92 \   # 0.95+ dies during CUDA-graph capture
  --max-model-len 8192 \            # cap it; 32k ctx is not happening on 24GB
  --kv-cache-dtype fp8 \            # same KV trick, vLLM flavor
  --swap-space 2
# Last resort if you are still OOM at load: --enforce-eager
# (drops CUDA graphs, frees ~1.5GB, costs ~10% throughput)

llama.cpp — for the full-MoE experiment, the pattern that works is GPU-for-attention, CPU-for-experts:

./llama-server \
  -m DeepSeek-V3-GGUF/Q4_K_M/DeepSeek-V3-<shard>.gguf \
  -ngl 999 \
  --override-tensor ".ffn_.*_exps.=CPU" \
  -c 8192 -fa on \
  --host 127.0.0.1 --port 8188

All attention, normalization, and shared-expert tensors land on the 4090; the 256 routed experts stream from system RAM. Throughput then tracks DDR bandwidth, which is why the number is 1.4–2.1 and not 10.

Replication appendix

Versions at test time: driver 550.x, Ollama 0.5.x, vLLM 0.6.6, llama.cpp 2026-07 tree, PyTorch 2.5.1, Ubuntu 24.04. All numbers are medians of 3 cold-cache runs; power figures are board-power readings from nvidia-smi dmon sampled at 1Hz, not TDP estimates. Raw config files ship alongside this article at /posts/2026-08-20-deepseek-v3-consumer-gpu-quantization.md. If your 4090 reproduces these numbers within ±10%, your stack is healthy; if a number differs by more, the version matrix is usually the culprit — write us and we will diff it.

Bottom line

On a single 24GB card in 2026: the 32B distill tier is a genuine daily driver at 27 tok/s; the 14B tier is generous headroom; the full 671B frontier model is a 1.4 tok/s novelty that will finish your prompt eventually. Anyone claiming more from one 4090 is selling something — and the claims that matter are the ones with flags attached.