Hy3-295B (Hunyuan 3) NVFP4-W4A16 + MTP speculative on 2× DGX Spark (GB10) — 128K ctx, 21.8 tok/s single / 59.7 tok/s 6-way

Hy3 (Tencent Hunyuan 3, 295B MoE / 21B active) is up on 2× DGX Spark — sharing the full recipe as a starting point**

Got the final Hy3 release serving on two GB10 Sparks (TP=2 over the 200GbE RoCE fabric) with its native MTP speculative decoding live, and — after some fighting — the hy_v3 tool-call + reasoning parsers working too. Posting everything so others can skip the landmines.

**Setup**

- Weights: kodelow/Hy3-NVFP4-W4A16 (181GB, final-base, MTP layer preserved, MARLIN-only by design)

- vLLM 0.23.1, Ray 2-node TP=2, NCCL over ConnectX-7 (MTU 9000)

- ~90GB weights/node + FP8 KV → ~180K-token pool, 128K max ctx, 6 seqs

- GB10 flags per LibertAI’s verified bring-up: `–moe-backend marlin --enforce-eager` (FlashInfer’s native-FP4 path freezes GB10s)

**Benchmarks** (512-tok gen, temp 0.9/top_p 1.0):

- Single stream: **21.8 tok/s**

- 6-way concurrent: **59.7 tok/s aggregate** (~10/stream)

- MTP draft acceptance: pos-1 62–76%, pos-2 ~20%

**Two findings worth knowing before you tune:**

1. **Run `num_speculative_tokens: 1`, not 2.** Pos-2 MTP acceptance is only ~20% on GB10 — spec-2 is a net ~30% LOSS. (The official recipe’s “2” is tuned for H200/GB300.)

2. **`–enforce-eager` WINS.** Turning on CUDA graphs / inductor compile cost ~25% throughput with the marlin W4A16 decode path on sm121/vLLM 0.23. Counter-intuitive, measured multiple times.

**Gotchas that cost us hours (all fixed):**

- Multi-node needs explicit `–distributed-executor-backend ray`

- GMU must be **0.90** — a GB10 only exposes ~111.4GiB free of 121.69 at boot, 0.92 fails

- **Tool-call/reasoning parser crash:** this checkpoint’s special tokens carry a `:opensource` suffix (`think:opensource`, `<tool_call:opensource>`, etc. — chat template sets HYTK=‘:opensource’), but vLLM’s hy_v3 parsers hardcode the bare forms → startup crash with parsers on, fake plain-text tool calls with them off. Fix: sed the two parser files to the suffixed tokens. Structured `tool_calls` verified working after (finish_reason: tool_calls).

- TP=3 is impossible (8 KV heads don’t divide by 3) — it’s a 2-Spark or 4-Spark model.

**Full recipe, scripts, and all the bugs documented:**

Meant as a starting point — take it, tune it, PR it. Next thing we’re chasing is NVIDIA’s vLLM 26.06 container (NVFP4 paged-KV) for the KV headroom. Credit to kodelow (quant) and LibertAI (the GB10 flags). Happy to answer questions.

Just realized you beat me to it. I posted on another thread with similar results. I also observed second MTP broken somehow. Good tip on --enforce-eager that I did not try. Also nice tip for broken think chat template.

Thanks for publishing this Tony - really clean recipe and great MTP capability exploration!

I’ve linked it on the model card as the reference GB10 setup.

One thing to note - checkpoint currently ships with no KV calibration scales (it’s weight-only quant which I tested only with fp16 but), and current hypothesis for a language-drift issue with uncalibrated fp8 KV (details in nerhun’s thread).

Quantized KV is risky on this build until the calibrated revision lands, which is in progress.

Did the bench on my own quant with NVFP4-W4A16. Unfortunately, the tok/s speed is too slow for me. Wasted alot of time unsuccessfully on KVARN and NVFP4 KV , but for now, both of these are still show stopper. I wish they would release a 200B MoE with maybe 10B per layer. That would be ideal for a 2 Spark configuration.

Hopefully this would be useful to someone - Reasoning Low seems to be the ideal setting. I highly suspect that this model is benchtuned.

thats kind of why I fell back. If we could get the speeds up it would be a monster but its too slow for when deepseek is 60 tok/s

That’s my minimum expectation for single concurrency, or maybe at least 50 tok/s. I don’t have good experiences with DS3, so that’s been putting me off DS4. Will probably rest and try again.

Anyway, this is another interesting learning - also check this out (not implemented in vLL) and we probably don’t have enough ram - DFlare — AngelSlim