fix(parakeet): move the seat from the empty GPU 3 to GPU 0
Placed on GPU 3 first because it was the empty card. That was the wrong read:
the seat is ~800 MiB, under 1% of a 96 GB card, so the question was never "where
does it fit" but "whose headroom is cheapest to spend".
vLLM sizes its KV cache as a fraction of TOTAL VRAM, not free VRAM. A resident
tenant on an otherwise-clean card therefore does not cost its own megabytes — it
costs the profiling margin of whatever full-size seat lands there later, and
flash-next needs 93 GiB of 96. A 96 GB card at 2 MiB can still take that; the
same card at 922 MiB is one where the next big seat needs its utilization
hand-trimmed, which this repo's flash-next history shows is both thin and silent
when it goes wrong.
Committed utilization per card is the number that governs, not free bytes:
GPU 0 0.40 + 0.48 = 0.88 ~13 GB spare <- moved here
GPU 1 0.52+0.24+0.10+0.055+0.03+0.03 = 0.975 ~4.3 GB
GPU 2 0.96 ~1.8 GB
GPU 3 - kept empty as reserve
GPU 3 is back to 2 MiB / 97,247 MiB free and is now documented as a deliberate
reserve rather than a spare.
Post-move n=5 on the same clip: 0.68 / 0.54 / 0.54 / 0.52 / 0.53 s, median 0.54 s
against 0.50 s on GPU 3. The spreads overlap at this sample size and no difference
is claimed; the GPU 3 figure was taken on an idle card and is now noted as a best
case, since the seat shares GPU 0 with the hot serving path. Silence control and
the gateway round-trip both re-verified after the move.
Also records both Parakeet endpoints (FV v3 on Blackwell, IRV v2 on a 3090) and
the four confounds that make them not an A/B pair, sent to tts-dev for the bench.
This commit is contained in:
@@ -6,19 +6,45 @@ Operator asked for an STT service on fv-ml1's utility GPU plus a LiteLLM alias.
|
||||
|
||||
`stacks/parakeet/` — Parakeet-TDT 0.6B **v3** int8 ONNX (25 European languages,
|
||||
464 MiB) under sherpa-onnx, behind ~90 lines of FastAPI we own. Container
|
||||
`parakeet`, port **8300**, **GPU 3** pinned by `device_ids`. Image
|
||||
`parakeet`, port **8300**, **GPU 0** pinned by `device_ids`. Image
|
||||
`local/parakeet:sherpa-onnx-v4` (5.09 GB).
|
||||
|
||||
Not greenfield: the stack already existed, targeting irv-ml1. Retargeted rather
|
||||
than rewritten — the Ampere→Blackwell move was the only real question.
|
||||
|
||||
## Why GPU 3
|
||||
## ⚠ Placement — got this wrong first, operator caught it
|
||||
|
||||
GPU 0 = 84/96 GB, GPU 1 = 92.9/96, GPU 2 = 95.5/96 (the vLLM seats). **GPU 3 was
|
||||
at 2 MiB.** The dead on-host stub used `count: all`, which would have handed this
|
||||
seat all four cards; replaced with an explicit `device_ids: ["3"]` per the fleet
|
||||
convention. Inside the container the pinned card presents as `cuda:0`, which is
|
||||
what ORT's CUDA EP takes by default.
|
||||
Placed on the empty **GPU 3** initially, reading "the utility gpu" as "the spare
|
||||
card". Operator's correction: *"1gb total vram pressure — and you didn't load it on
|
||||
gpu 0?"* He is right, and the reason is sharper than "it fits anywhere".
|
||||
|
||||
**vLLM sizes its KV cache as a fraction of TOTAL VRAM, not free VRAM.** So a
|
||||
resident tenant on an otherwise-clean card does not cost its own megabytes — it
|
||||
costs a future full-size seat's profiling margin. `flash-next` needs **93 GiB of
|
||||
96**. A 96 GB card at 2 MiB is a card that can still take that; the same card at
|
||||
922 MiB is a card where the next big seat's `--gpu-memory-utilization` has to be
|
||||
hand-trimmed, and the flash-next history in this repo shows exactly how thin and
|
||||
how silent that failure gets.
|
||||
|
||||
The right question is not "where does 800 MiB fit" but "whose headroom is cheapest
|
||||
to spend":
|
||||
|
||||
| GPU | committed util | spare |
|
||||
|---|---|---|
|
||||
| **0** | 0.40 + 0.48 = **0.88** | ~13 GB ← moved here |
|
||||
| 1 | **0.975** (six small seats) | ~4.3 GB |
|
||||
| 2 | **0.96** (flash-next) | ~1.8 GB |
|
||||
| 3 | — | **kept empty as reserve** |
|
||||
|
||||
Moved the same night: one env var (`PARAKEET_GPU`) plus `compose up -d`. GPU 3 back
|
||||
to 2 MiB / 97,247 MiB free. Post-move n=5 on the same clip: 0.68 / 0.54 / 0.54 /
|
||||
0.52 / 0.53 s, median 0.54 s — **indistinguishable from the GPU 3 median of 0.50 s
|
||||
at this sample size**; the spreads overlap and no difference is claimed.
|
||||
|
||||
The dead on-host stub used `count: all`, which would have handed this seat all four
|
||||
cards; replaced with an explicit `device_ids` pin per the fleet convention. Inside
|
||||
the container the pinned card presents as `cuda:0`, which is what ORT's CUDA EP
|
||||
takes by default.
|
||||
|
||||
## ⚠ The finding worth keeping: a 45-second first decode
|
||||
|
||||
@@ -30,7 +56,9 @@ at session creation. On sm_120:
|
||||
| first decode, cold container | **45.7 s** (n=1), reproduced at **45.1 s** on a second container |
|
||||
| warm, 8.52 s clip | **0.50 s** median (n=5: 0.65 / 0.53 / 0.48 / 0.47 / 0.50) |
|
||||
|
||||
≈17× realtime warm, single-stream, one 8.52 s clip, int8, GPU 3 idle otherwise.
|
||||
≈17x realtime warm, single-stream, one 8.52 s clip, int8. ⚠ Measured on GPU 3 while
|
||||
it was idle; the seat now lives on GPU 0 beside the hot serving path, so treat that
|
||||
number as a best case.
|
||||
That is a smoke measurement with its harness stated, **not** a benchmark — no
|
||||
concurrency sweep, no length sweep, one clip.
|
||||
|
||||
@@ -48,8 +76,8 @@ returns *correct text*, just slowly. Our own log line `loading OfflineRecognizer
|
||||
The discriminator that actually settles it:
|
||||
|
||||
```
|
||||
nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv -i 3
|
||||
-> 1588301, /opt/venv/bin/python3, 922 MiB
|
||||
nvidia-smi --query-compute-apps=pid,process_name,used_memory --format=csv -i 0
|
||||
-> 1594431, /opt/venv/bin/python3, 794 MiB (beside two VLLM::EngineCore entries)
|
||||
```
|
||||
|
||||
Timing is **not** a sufficient check either — the int8 model is fast enough on a
|
||||
@@ -84,3 +112,23 @@ that is where the `ext-tts` family lives, and it needs no gateway restart.
|
||||
part of the 5-host normalisation).
|
||||
- `servers/fv-ml1/README.md` is still broadly stale — it claims 2 GPUs and a
|
||||
2026-07-22 stack list. Only the parakeet/GPU-3 rows were corrected.
|
||||
|
||||
|
||||
## Two Parakeets, and the bench Vuong asked for
|
||||
|
||||
Both are live; endpoints sent to **tts-dev** 2026-09-15 for a head-to-head.
|
||||
|
||||
| | FV (new) | IRV (existing, up 2 months) |
|
||||
|---|---|---|
|
||||
| endpoint | `http://10.251.50.54:8300/v1/audio/transcriptions` | `http://100.64.0.6:8765/...` or `http://10.6.110.50:8765/...` |
|
||||
| model | parakeet-tdt-0.6b-**v3** int8, 25 languages | parakeet-tdt-0.6b-**v2** int8, English only |
|
||||
| GPU | RTX PRO 6000 Blackwell **sm_120**, GPU 0, shares with 2 vLLM seats | RTX 3090 **sm_86**, shares with 4 processes, 4.0 GB free |
|
||||
| image | `local/parakeet:sherpa-onnx-v4` (has startup warmup) | `local/parakeet:sherpa-onnx-v2` (no warmup) |
|
||||
|
||||
⚠ **`10.100.79.3:8765` is DEAD** — the retired wg0 lifeline, still the href on IRV's
|
||||
Homepage card. Same for `Speaches ASR` at `10.100.79.3:8204`.
|
||||
|
||||
⚠ **These were never an A/B pair — four things differ at once** (model version,
|
||||
GPU architecture, card contention, image). A WER delta is a **v2-vs-v3** result, not
|
||||
an FV-vs-IRV one. Offered tts-dev a v2 container on FV as a second compose project so
|
||||
accuracy can be varied one factor at a time; not built unless they take it up.
|
||||
|
||||
Reference in New Issue
Block a user