SinclairSchneider commited on
Commit
09f6e2a
·
verified ·
1 Parent(s): f5a38e0

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +70 -7
README.md CHANGED
@@ -40,6 +40,13 @@ tensor-parallel 4, which is exactly why 4× 48 GB Ada cards are such an
40
  attractive target — and exactly why it is painful that the default serving
41
  stacks refuse to run there.
42
 
 
 
 
 
 
 
 
43
  ## Measured performance
44
 
45
  4× RTX 6000 Ada (48 GB, PCIe-only, TP=4), `fp8_ds_mla` KV cache,
@@ -53,6 +60,12 @@ stacks refuse to run there.
53
  The BF16 MTP head drafts nearly perfectly on this checkpoint; a ~1.5–1.65×
54
  speedup from a single speculative token is about as good as MTP-k=1 gets.
55
 
 
 
 
 
 
 
56
  ## Why Ada needs special handling
57
 
58
  The stock DeepSeek-V4 serving paths gate on newer architectures at three
@@ -96,8 +109,11 @@ Everything below is automated by
96
  (forcing the FlashInfer backend crashes on an SWA-cache shape mismatch),
97
  `--kv-cache-dtype fp8_ds_mla --block-size 256`, and the `deepseek_v4`
98
  tokenizer / reasoning-parser / tool-call-parser modes.
99
- - **MTP**: `--speculative-config '{"method":"mtp","num_speculative_tokens":1}'
100
- --max-num-batched-tokens 2048`.
 
 
 
101
 
102
  ## The one required source patch (MTP only)
103
 
@@ -119,11 +135,54 @@ a single tiny layer, so the unfused fallback costs nothing measurable. The
119
  patcher is idempotent, backs up the original, and refuses to apply against
120
  any file that doesn't match the `dev145` layout.
121
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  ## Quickstart
123
 
124
  ```bash
125
  # 1. Build the environment (venv, pinned wheels, patch, verification,
126
- # generated serve.sh / canary.sh / systemd unit):
127
  ./setup_deepseek_v4_sm89.sh ~/deepseek-v4-serve SinclairSchneider/DeepSeek-V4-Flash-W4A16-FP8-MTP-Ada
128
  # (the original repo id works identically:
129
  # ./setup_deepseek_v4_sm89.sh ~/deepseek-v4-serve canada-quant/DeepSeek-V4-Flash-W4A16-FP8-MTP)
@@ -138,10 +197,14 @@ any file that doesn't match the `dev145` layout.
138
  ~/deepseek-v4-serve/canary.sh
139
  ```
140
 
141
- Expect ~80 s of weight loading plus ~5 s for the MTP drafter, brief Triton
142
- JIT compiles during warmup and the first requests, then steady-state
143
- throughput. For unattended operation, the setup script also generates a
144
- systemd unit (see [`deepseek-v4-flash.service`](./deepseek-v4-flash.service)).
 
 
 
 
145
 
146
  ## Gotchas the scripts already handle
147
 
 
40
  attractive target — and exactly why it is painful that the default serving
41
  stacks refuse to run there.
42
 
43
+ > **262k is the checkpoint's context ceiling, not the recommended serving
44
+ > length on 48 GB Ada.** After weights + activations + CUDA-graph pools, only
45
+ > ~1 GiB/GPU is left for KV cache, so a full 262k context fits only at high
46
+ > `--gpu-memory-utilization` and leaves almost no headroom. For concurrent or
47
+ > agentic workloads the generated defaults cap `--max-model-len` lower (98304)
48
+ > to keep KV *and* JIT headroom — see [Serving on 48 GB Ada](#serving-on-48-gb-ada-memory-concurrency-and-context) below.
49
+
50
  ## Measured performance
51
 
52
  4× RTX 6000 Ada (48 GB, PCIe-only, TP=4), `fp8_ds_mla` KV cache,
 
60
  The BF16 MTP head drafts nearly perfectly on this checkpoint; a ~1.5–1.65×
61
  speedup from a single speculative token is about as good as MTP-k=1 gets.
62
 
63
+ These figures are **single-stream throughput at the maximum-context operating
64
+ point** (262k, high utilization, `--max-num-batched-tokens 2048`). That is the
65
+ right point to *quote* peak tok/s, but not the right point to *run* a
66
+ concurrent or agentic workload on 48 GB cards — see the next section for why,
67
+ and for the defaults the setup script actually generates.
68
+
69
  ## Why Ada needs special handling
70
 
71
  The stock DeepSeek-V4 serving paths gate on newer architectures at three
 
109
  (forcing the FlashInfer backend crashes on an SWA-cache shape mismatch),
110
  `--kv-cache-dtype fp8_ds_mla --block-size 256`, and the `deepseek_v4`
111
  tokenizer / reasoning-parser / tool-call-parser modes.
112
+ - **MTP**: `--speculative-config '{"method":"mtp","num_speculative_tokens":1}'`.
113
+ `--max-num-batched-tokens` is `2048` at the peak-throughput point above; the
114
+ generated `serve.sh` raises it to `4096` for the agentic-serving defaults
115
+ (which enables chunked prefill — see the memory section, as its buffers come
116
+ out of the KV pool).
117
 
118
  ## The one required source patch (MTP only)
119
 
 
135
  patcher is idempotent, backs up the original, and refuses to apply against
136
  any file that doesn't match the `dev145` layout.
137
 
138
+ ## Serving on 48 GB Ada: memory, concurrency, and context
139
+
140
+ On these cards **KV cache is the thin slice** — weights, activations, and
141
+ CUDA-graph pools consume almost the whole 48 GB, leaving on the order of
142
+ ~1 GiB/GPU for KV. Two failure modes sit on opposite sides of a narrow tuning
143
+ window, and the generated defaults are the corner that clears both:
144
+
145
+ - **JIT-OOM (too little headroom).** The Triton sparse-MLA path compiles a
146
+ kernel specialization *per prompt shape*, lazily, and loading each freshly
147
+ compiled cubin (`cuModuleLoadData`) needs driver-level free VRAM *outside*
148
+ the torch pool. At high utilization a never-before-seen prompt shape
149
+ arriving mid-run can find no room to load its kernel and crash a worker
150
+ (observed in `_tf32_hc_prenorm_gemm`), taking the server down. Two things
151
+ defuse this: the generated `warmup.sh` compiles the shape space at startup
152
+ while memory is free, and the systemd unit uses `Restart=always` (a JIT-OOM
153
+ can exit *cleanly* from systemd's view, so `on-failure` is not enough).
154
+ - **KV-fit refusal (too little KV).** vLLM refuses to boot if a single full
155
+ `--max-model-len` sequence won't fit the KV pool. At the headroom-safe
156
+ utilizations below, full 262k does **not** fit; `--max-model-len 98304` does,
157
+ with room for the KV a long agentic trajectory actually uses.
158
+
159
+ **Concurrency: use `--max-num-seqs 1` for agentic workloads.** With several
160
+ 30–100k-token trajectories in flight, they cannot co-reside in the KV pool, so
161
+ vLLM preempts and *re-prefills* evicted sequences from scratch — prefix-cache
162
+ hit rate collapses below 40%, generation throughput drops to single digits
163
+ while prefill spikes, and wall-clock blows up roughly 10×. A single resident
164
+ stream (prefix hit ~85–91%) decoding continuously is dramatically faster in
165
+ practice. One stream that never evicts beats four that thrash.
166
+
167
+ **Utilization.** `0.97` maximizes the KV pool and works for a *watched* run
168
+ backed by warmup + auto-restart, but leaves only ~0.5–0.8 GiB/GPU free under a
169
+ long trajectory. For **unattended or shared** operation prefer
170
+ `--gpu-memory-utilization 0.95`: it restores ~2.4 GiB of headroom at identical
171
+ seq=1 throughput. The setup script exposes both as parameters; pick per how
172
+ closely you'll be watching.
173
+
174
+ **Smaller Ada cards (RTX 4090, 24 GB).** This recipe is validated on 4× 48 GB
175
+ (RTX 6000 Ada). A 159 GB checkpoint under TP=4 needs ~38 GiB/GPU for weights
176
+ alone, so it does **not** fit four 24 GB 4090s — you would need more cards
177
+ (e.g. TP=8) and an even tighter KV budget, and none of the memory figures here
178
+ transfer directly. The `rtx-4090` tag reflects the SM89 architecture the stack
179
+ targets, not a claim that this checkpoint fits on 4090-class VRAM.
180
+
181
  ## Quickstart
182
 
183
  ```bash
184
  # 1. Build the environment (venv, pinned wheels, patch, verification,
185
+ # generated serve.sh / warmup.sh / canary.sh / systemd unit):
186
  ./setup_deepseek_v4_sm89.sh ~/deepseek-v4-serve SinclairSchneider/DeepSeek-V4-Flash-W4A16-FP8-MTP-Ada
187
  # (the original repo id works identically:
188
  # ./setup_deepseek_v4_sm89.sh ~/deepseek-v4-serve canada-quant/DeepSeek-V4-Flash-W4A16-FP8-MTP)
 
197
  ~/deepseek-v4-serve/canary.sh
198
  ```
199
 
200
+ Expect ~80 s of weight loading plus ~5 s for the MTP drafter, then a Triton
201
+ shape-warmup pass (`warmup.sh`, also generated) that compiles the kernel
202
+ specializations up front, then steady-state throughput. For unattended
203
+ operation the setup script generates a systemd unit
204
+ (see [`deepseek-v4-flash.service`](./deepseek-v4-flash.service)) that runs the
205
+ warmup automatically after every start (`ExecStartPost`) and uses
206
+ `Restart=always` so a mid-run kernel-load OOM self-heals rather than leaving a
207
+ dead port.
208
 
209
  ## Gotchas the scripts already handle
210