GB10 real-time serving: opt-in quantization + serve-path optimizations (2.2x: 101.7 -> 46.5 ms/frame) - #103
GB10 real-time serving: opt-in quantization + serve-path optimizations (2.2x: 101.7 -> 46.5 ms/frame)#103jethac wants to merge 11 commits into
Conversation
…ys in meta-device load The torch <2.5 pin blocks the CUDA 13.0 aarch64 wheels needed on sm_121 (reported in NVIDIA#3 by @acatovic; fix first shipped in the amarrmb fork, commit 94cbbbd). The loaders change zero-inits checkpoint-missing keys that survive meta-device load_state_dict as meta tensors (e.g. depformer_emb.7.weight with base-Moshi dep_q=8 checkpoints); no behavior change for personaplex checkpoints. See docs/pr-drafts/01-build-fixes.md. Co-authored-by: amarrmb <amar@devicenexus.ai> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Raw WAV voice prompts are float32 but Mimi encoder runs in FP16. Without this cast, encode_from_sphn() fails with RuntimeError: Input type (float) and bias type (c10::Half) should be the same. (cherry picked from commit add7726)
Performance optimizations for real-time inference: - --fp8 flag: FP8 dynamic quantization via torch._scaled_mm (1.4x speedup) - Skip other_mimi encode/decode (output always discarded, saves ~10ms) - Pinned CPU memory for DtoH audio transfer (saves ~2ms) - Mimi FP16 + torch.compile when --fp8 (saves ~3ms) - Frame profiling output every 50 frames - Relax torch version upper bound (2.9/2.10 work fine) Benchmarked on Jetson Thor (78ms total) and DGX Spark (74ms total). (cherry picked from commit 94cbbbd)
… opt-in flags Fixup for the previous (verbatim) cherry-pick so that stock invocation is byte-identical to upstream: other_mimi restored by default (new --skip-other-mimi flag), pinned DtoH opt-in via --pinned-io, fp16 mimi + torch.compile decoupled from --fp8 into --mimi-fp16, input/warmup dtypes follow the mimi parameter dtype, and --fp8 gains a startup capability check (CUDA, sm_89+). Verified: seeded no-flag offline run produces byte-identical WAV and token stream vs upstream/main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… in serve flow Skips depformer steps for codebooks whose sampled outputs are always overwritten by provided user-side tokens (see the invariance argument in docs/pr-drafts/02-depformer-early-exit.md). -10.3ms/frame at bf16, -7.5ms at w8a16 on GB10. Observation credit: NVIDIA#3 (@gplv2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit e563146)
Adapts the amarrmb fork server-path optimizations (commit 94cbbbd: skip discarded second mimi stream, fp16+compiled mimi) as opt-in offline.py flags with None-safe plumbing. Discarded-work citation and measurements in docs/pr-drafts/03-mimi-fast-path.md. Co-authored-by: amarrmb <amar@devicenexus.ai> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit d174f68)
Wires amarrmb's FP8 quantizer (previous commit) into offline.py as --fp8, and adds w8a16_quantize.py scaffolding: weight-only fp8-e4m3 storage with a naive dequantize-then-cuBLAS linear as a correctness baseline. The layer-selection and forward-patching machinery (module walk, min_features gate, depformer-self_attn skip, bare in_proj handling, class-level gating/attention patches) is derived from fp8_quantize.py, adapted to dispatch multiple schemes per instance. Co-authored-by: amarrmb <amar@devicenexus.ai> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ter GEMV + --w8a16/--fast presets Builds on the scaffolding from the previous commit; everything here is original to this series: a hand-written Triton GEMV that streams fp8 weights and dequantizes in registers (fp32 accumulate, bf16 activations untouched), per-output-channel scaling, GB10-tuned block configs, and the --w8a16 / --fast presets (--fast = --w8a16 --dep-q-exit 8 --skip-other-mimi --mimi-fp16). The kernel sustains 222-242 GB/s cold on sm_121 decode shapes vs 126-226 GB/s for torch._scaled_mm (sm89 path), which is why weight-only 8-bit beats full FP8 end-to-end on GB10 by ~16 ms/frame (step 67.2 -> 51.1 ms) while perturbing logits ~25-30% less. --fast: 101.7 -> 46.5 ms p50, p99.9 48.2 ms over a 30-min sustained run, zero 80 ms-budget misses. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n sm_121 Log-only capstone: at server/offline startup, if the CUDA device reports compute capability (12,1) (GB10 class) and none of the performance flags are set, emit a single logger.info pointing at the opt-in flags. No behavior or output change; never fires on other architectures or when any perf flag is active. Deliberately the LAST commit of the series so it can be dropped independently if maintainers prefer zero log additions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
These flags landed in offline.py but never reached server.py, so the live server could not actually use the fast path this PR exists to provide -- only the benchmark harness could. Adds the three arguments to the server, the same --fast preset guard used in offline.py (which refuses to run rather than silently degrade when CUDA or Triton is missing), the w8a16 quantization branch alongside the existing --fp8 one, and plumbs dep_q_exit through ServerState into LMGen.
|
Pushed two follow-ups that close gaps in this PR as originally filed:
Measured live on GB10 with One unrelated bug found while running this in anger is split out as #104 (a mid-stream client disconnect wedges the session lock permanently). It applies to |
Depends on #102 (GB10 installability fixes — this branch is based on it; GitHub shows those commits here until #102 merges).
Problem
PersonaPlex must produce one 80 ms audio frame every 80 ms. On NVIDIA
GB10 (DGX Spark / ThinkStation PGX / Jetson Thor class, sm_121, unified
LPDDR5X ~273 GB/s) stock bf16 measures ~101.7 ms/frame — real-time is
unreachable. Profiling (nsys, evidence links below) shows the LM step is
weight-streaming-bound: ~449 batch-1 GEMVs move ~13 GB of bf16 weights
per frame at only ~170-190 GB/s effective; dispatch overhead is <3 ms, so
the recoverable costs are weight bytes, redundant serve-path work, and
the depformer's unused half.
What this PR adds (ordered commit story)
preserved):
fp8_quantize.py(torch._scaled_mm dynamic FP8), plusserver-path optimizations (skip discarded second mimi stream, pinned
DtoH, fp16+compiled mimi, frame profiling).
--dep-q-exit 8): dep_q=16 runs 16sequential depth steps but the serve flow always provides the
user-side codebooks, so sampled outputs for codebooks 9..16 are
always overwritten before use — skipping them is output-invariant
(guards enforce the precondition). −10.3 ms (bf16) / −7.5 ms (w8a16).
--skip-other-mimi,--mimi-fp16):amarrmb's server-side ideas as opt-in offline.py flags with None-safe
plumbing (−5.4 ms and −1.9 ms).
--fp8wiring (derived work,Co-authored-by @amarrmb): offline-path wiring of their quantizer and
the shared layer-selection/patching scaffolding in w8a16_quantize.py
(module walk, min_features gate, depformer-self_attn skip, in_proj
handling, class-patch machinery), with a naive dequant baseline.
with per-output-channel scales, dequantized in-register by a
hand-written Triton GEMV; activations stay bf16. The GEMV
sustains 222-242 GB/s cold vs 126-226 for torch._scaled_mm on sm_121
(which lands on an sm89 path), so weight-only beats full FP8 by
~16 ms/frame while perturbing logits ~25-30% less.
--fast=--w8a16 --dep-q-exit 8 --skip-other-mimi --mimi-fp16.What is original here: the Triton dequant-in-register GEMV, the
per-channel w8a16 scheme built on it, the
--fastpreset, and thefinding that weight-only 8-bit outperforms full FP8 on sm_121 (a
kernel-dispatch effect, not a numerics one) — plus the depformer
invariance proof and all measurements/quality gates. The FP8 quantizer,
the serve-path optimizations, and the quantization scaffolding are
amarrmb's work, carried with commit-level attribution.
Ablation ladder (pre-registered protocol, 500 frames, real weights, GB10)
Sustained validation (30 min, dmon alongside)
38,453 warm frames: p50 46.65 / p99 47.75 / p99.9 48.20 / max 48.96 ms
— zero budget misses. GPU 51->66 C, SM clocks −1.8%, 33->37 W: no
thermal cliff; the headline holds warm.
Quality evidence (tolerance ladder)
scheme, 3 seeds x 1500 frames; harness self-test = exactly 0.0):
drift exponents ~0 for fp8 and w8a16 — flat, no error
accumulation; decisively sublinear = PASS.
spectral statistics inside the bf16 reference band; zero clicks >0.25
in ~30k decoded frames.
natural-female voice) in the fork's bench/results/20260724-audio-v2/.
fork's pgx-plan branch.
Reproduction / evidence links (fork, branch pgx-plan)
https://github.com/jethac/personaplex/tree/pgx-plan — bench/protocol.md
(pre-registered methodology), bench/bench.py + divergence.py (harness &
quality gates), bench/microbench/ (GEMV bandwidth lab + GB10 tuning
table), bench/results/ (per-frame CSVs, env blocks, ablations, soak,
audio). The harness + GB10 playbook are available as a follow-up PR on
request.
Zero-build install for GB10 users (no Rust, no source builds):
https://github.com/jethac/personaplex-gb10 — public repro repo with the
harness, pre-registered protocol, GB10 playbook, and prebuilt wheels
(release v0.1.0: this branch as a py3 wheel + an aarch64 cp312 sphn
wheel), installed by one script and verified end-to-end from the release
on a clean venv.
Pinned environment
Lenovo ThinkStation PGX — GB10 (sm_121, 48 SMs, 25 MB L2), aarch64,
128 GB unified LPDDR5X; Ubuntu 24.04, driver 595.71.05, CUDA 13.0;
python 3.12.3, torch 2.13.0+cu130, triton 3.7.1 with system ptxas
symlinked over the bundled ptxas-blackwell.
Behavioral guarantees
Zero change without flags. Every optimization is opt-in; each verbatim
contributor cherry-pick is immediately followed by a gating fixup commit so
that at the branch tip, stock invocation matches upstream. Evidence: a
seeded no-flag offline run (seed 42424, 30 s input, 375 frames, real
weights) on the branch tip vs upstream/main produced byte-identical
output WAV and byte-identical token stream (
cmpon both artifacts).The only remaining non-numeric deltas are (a) a per-50-frames timing log
line in the server loop (observability only; happy to gate or drop it on
request) and (b) one informational log line at startup on GB10-class
devices (sm_121) when no perf flag is active, pointing users at the
opt-in flags — added as the FINAL commit of the series so a maintainer
can drop it independently; it fires on no other arch and never when any
perf flag is set.
Per-flag prerequisites (checked at startup/model-build time with
actionable RuntimeErrors; no silent fallbacks — if a flag cannot meet its
performance contract, it errors rather than quietly degrading):
--fp8torch._scaled_mm--w8a16--mimi-fp16--dep-q-exit--skip-other-mimi--pinned-io--fastNo architecture-sniffing anywhere: capability checks only, no
sm_121conditionals; the Triton ptxas symlink workaround is documentation-only
(GB10 playbook), never code. The Triton GEMV is generic sm_80+.
Attribution
pr-build-fixes)@amarrmb: please flag any attribution adjustment you'd like — happy to
amend.
Gating notes
complete: a multi-seed listening matrix plus a 5-pair blind matched-pairs
A/B on mimi precision (0/5 discrimination; onset character tracks the
sampling seed, not precision) — full write-up in the fork's
bench/results/20260724-audio-v3/ and DIVERGENCE.md.
the fp8/server parts); task-level metrics (WER etc.) not measured.
Upstream overlap (pre-flight scan, 2026-07-24)
outright (~200 MB memory saving) — the same discarded-work observation
behind our --skip-other-mimi (credit to them for reaching it
independently). Difference: refactor: remove unused other_mimi MimiModel instance (~200MB memory savings) #72 changes default behavior by deleting
the second stream; ours keeps stock behavior byte-identical and makes
the skip opt-in per this PR's behavioral guarantees. If maintainers
prefer refactor: remove unused other_mimi MimiModel instance (~200MB memory savings) #72's hard removal, our flag reduces to a no-op and we would
rebase; if they prefer conservative defaults, refactor: remove unused other_mimi MimiModel instance (~200MB memory savings) #72's saving is
available here behind the flag.
(fix(server): prevent path traversal in voice_prompt query parameter #101 path-traversal fix, fix: disable compile fast path on H20 runtimes #84 H20 compile fast-path, Fix Issue #38: Multi-GPU support #79 multi-GPU,
Fix security issues found during code review #75/fix: use safe deserialization and tarfile extraction #70 security, fix: skip config.json download counter when HF_HUB_OFFLINE is set #62 HF_HUB_OFFLINE, Fix sphn API compatibility with Kyutai Labs implementation #44 sphn API, Refactor logging to follow Dependency Inversion Principle #20 logging
refactor, macOS/MPS series Add macOS Nix and MLX runtime support #100/fix: detect MPS automatically and document macOS setup #91/fix: enable MPS device support for macOS Apple Silicon #64/Fix performance issue & bug on mps (Apple Silicon) #25/Fix device placement when loading voice prompt embeddings #35). No semantic
conflicts with this series identified beyond refactor: remove unused other_mimi MimiModel instance (~200MB memory savings) #72; we will rebase at
filing time against whatever has merged.
🤖 Generated with Claude Code