IA on-prem 8 min de lecture

Gemma-4 v23 sur le DGX Spark

Nouveaux runs vLLM v0.23.0 pour Gemma-4 sur DGX Spark : BF16, NVFP4 et MTP comparés sur decode, TTFT, tails et limites pratiques pour agents locaux.

Écrit par Django de Vreng

NVFP4 reste le choix pratique par défaut pour Gemma-4 sur le DGX Spark, mais MTP devient la position intermédiaire intéressante. Dans les nouveaux runs vLLM v0.23.0, NVFP4 reste devant en chat et en multi-turn, tandis que MTP dépasse nettement le run BF16 sans passer au re-quant NVIDIA.

J’ai relancé la même famille Gemma-4-26B-A4B sur le DGX Spark, cette fois avec vllm/vllm-openai:v0.23.0-aarch64-cu129-ubuntu2404. Les données brutes sont dans le repo de benchmark au commit 605faab6a599. L’Arena a maintenant trois nouvelles entrées : BF16 v23, MTP v23 et NVFP4 v23.

Le précédent article Gemma parlait surtout du prix du contexte en BF16. Ce run répond à une autre question : qu’est-ce qui change quand la même machine, la même famille de modèles et les mêmes workloads tournent sur vLLM v0.23.0, avec trois profils de serving côte à côte ?

Le setup resté identique

Les trois runs utilisent la même machine et la même forme de benchmark :

ComposantValeur
HardwareDGX Spark NVIDIA GB10, 128 GB unified memory
vLLM imagevllm/vllm-openai:v0.23.0-aarch64-cu129-ubuntu2404
KV-cachefp8
Prefix cachingdésactivé
Max model length131072
Benchmark commit605faab6a599

Les trois profils :

ProfilModèleServed nameGenerated
BF16 v23google/gemma-4-26B-A4B-itgemma-4-26b-a4b2026-06-22T23:16:36+02:00
MTP v23google/gemma-4-26B-A4B-itgemma-4-26b-a4b-mtp2026-06-23T03:29:52+02:00
NVFP4 v23nvidia/Gemma-4-26B-A4B-NVFP4gemma-4-26b-a4b-nvfp42026-06-23T01:35:33+02:00

MTP utilise donc le même chemin de modèle Google que BF16, mais servi avec le profil MTP. NVFP4 utilise le re-quant NVIDIA. Cette distinction compte, sinon tu compares discrètement deux choses à la fois : le comportement de l’engine et l’artefact modèle.

Chat : NVFP4 devant, MTP rattrape BF16

La première comparaison utile est le Run C : 1024 prompttokens, 1024 outputtokens, dix requêtes concurrentes. C’est une forme de chat propre : pas trivialement courte, mais pas non plus un monstre de contexte.

ProfilTTFT c10Decode/user c10Decode total c10
BF16 v231342.98 ± 449.90 ms11.47 ± 0.45 tok/s90.83 ± 7.87 tok/s
MTP v231400.13 ± 142.07 ms17.79 ± 1.55 tok/s138.97 ± 6.68 tok/s
NVFP4 v231138.26 ± 385.15 ms21.59 ± 0.98 tok/s151.22 ± 15.96 tok/s

C’est le coeur du résultat. MTP donne environ 55 pourcent de decode par utilisateur en plus que BF16 sur ce run chat. NVFP4 reste au-dessus, mais l’écart entre MTP et NVFP4 est beaucoup plus petit que l’écart entre BF16 et MTP.

La latence jusqu’au premier token reste dans le même ordre de grandeur. NVFP4 est le plus rapide ici, MTP n’est pas plus rapide que BF16 en TTFT. Cela colle au pattern : ces profils changent surtout le débit de decode. Le prefill reste du travail.

Le multi-turn est l’endroit où NVFP4 s’ouvre vraiment

Le Run E est pour moi le test closed-loop le plus proche de la production : cinq tours par conversation, dix conversations en parallèle, 2048 tokens de départ et 512 outputtokens par tour.

ProfilTTFT c10Decode/user c10Decode total c10
BF16 v232154.60 ± 858.63 ms10.69 ± 0.25 tok/s98.35 ± 3.95 tok/s
MTP v232368.00 ± 789.47 ms16.57 ± 1.32 tok/s143.47 ± 4.67 tok/s
NVFP4 v231966.10 ± 735.30 ms20.01 ± 0.80 tok/s182.90 ± 6.67 tok/s

C’est là que NVFP4 devient vraiment naturel. 182.90 tok/s au total pour dix conversations multi-turn sur un Spark, ce n’est pas un chiffre de démo, c’est un profil d’inference locale utilisable.

MTP reste utile. Pas comme gagnant, mais comme réponse à : et si je veux garder l’artefact Google BF16 tout en obtenant plus de decode ? Dans ce cas, 16.57 tok/s par utilisateur change beaucoup par rapport à 10.69.

Output long : plus de tokens, pas automatiquement plus de douleur

Pour les agents et la génération de code, le Run G compte : 256 prompttokens, 4096 outputtokens, dix requêtes concurrentes. Cette forme indique si les longues générations font s’écrouler la machine.

ProfilTTFT c10Decode/user c10Decode total c10
BF16 v23490.95 ± 4.88 ms12.47 ± 0.94 tok/s87.16 ± 3.88 tok/s
MTP v23564.16 ± 14.86 ms17.67 ± 1.92 tok/s127.52 ± 9.05 tok/s
NVFP4 v23368.83 ± 54.97 ms23.69 ± 1.65 tok/s120.96 ± 50.17 tok/s

Note la forme un peu étrange : NVFP4 a le meilleur decode par utilisateur, mais le decode total a beaucoup plus de variance. MTP est plus bas par utilisateur, mais plus stable dans ce run précis. Je ne regarderais donc pas seulement la barre la plus haute. Pour des agents, tu veux aussi de la prévisibilité, surtout si plusieurs runs continuent de streamer longtemps.

25k de contexte reste le mur

Quantization et MTP ne changent pas le fait qu’un grand contexte est surtout du prefill. À 25k prompttokens et c10, cela donne ceci :

ProfilTTFT c10Decode/user c10Decode total c10
BF16 v2339281.43 ± 20075.74 ms5.28 ± 2.13 tok/s28.49 ± 0.62 tok/s
MTP v2345640.37 ± 23247.85 ms6.05 ± 3.24 tok/s27.62 ± 0.27 tok/s
NVFP4 v2338575.15 ± 19624.30 ms7.40 ± 4.24 tok/s33.54 ± 0.03 tok/s

Ce n’est plus du chat. Avec dix prompts concurrents de 25k, tu attends en moyenne entre 39 et 46 secondes avant le premier token. NVFP4 aide encore un peu le decode, mais l’utilisateur ressent surtout une fenêtre vide avant que le stream démarre.

C’est la même leçon que dans le précédent article de benchmark Gemma-4, maintenant avec vLLM v0.23.0 en plus : le contexte n’est pas un champ d’entrée gratuit. Si tu fais porter 25k tokens à un agent local, tu le paies en TTFT.

Open-loop : la forme bureau reste utilisable

Les tests open-loop comptent plus pour le ressenti que les tableaux closed-loop. Ils envoient les requêtes selon un pattern d’arrivée au lieu de tout lancer en même temps.

H : baseline bureau

200 prompts random, request rate 0.3, burstiness 0.7.

ProfilOKOutput tok/sP95 TTFTP95 TPOT
BF16 v23200/200129.922835.43 ms197.57 ms
MTP v23200/200132.353394.53 ms178.77 ms
NVFP4 v23200/200139.052393.78 ms77.98 ms

NVFP4 est nettement plus agréable ici. Pas grâce à un output throughput beaucoup plus élevé, car 139.05 contre 129.92 tok/s n’est pas une révolution. La différence est dans le TPOT : 77.98 ms p95 contre 197.57 ms pour BF16. Le stream paraît beaucoup plus rapide dès qu’il commence.

I : replay ShareGPT

250 vraies conversations, même request rate.

ProfilOKOutput tok/sP95 TTFTP95 TPOT
BF16 v23250/25060.93456.10 ms115.31 ms
MTP v23250/25061.47576.82 ms77.32 ms
NVFP4 v23250/25061.99225.09 ms45.30 ms

C’est le meilleur proxy pour le chat normal. Des conversations courtes et réelles. NVFP4 donne un p95 TTFT de 225.09 ms et un p95 TPOT de 45.30 ms. En local, cela ne ressemble pas à un compromis.

J : pic du lundi matin

300 prompts random, target 1.5 rps, max concurrency 25.

ProfilOKOutput tok/sP95 TTFTP95 TPOT
BF16 v23300/300132.043006.73 ms199.23 ms
MTP v23300/300172.323870.47 ms235.91 ms
NVFP4 v23300/300218.902390.17 ms124.58 ms

Sous surcharge, NVFP4 reste aussi le plus utilisable. Toutes les requêtes réussissent, mais la queue décide qui ressent la douleur. BF16 et MTP donnent ici des tails moins agréables. MTP a plus d’output throughput que BF16, mais un p95 TTFT et un p95 TPOT plus mauvais. C’est exactement pourquoi je veux voir des percentiles, pas seulement des tokens par seconde.

Ce que je mets dans l’Arena

J’ai ajouté trois nouvelles entrées Arena au lieu d’écraser les anciennes entrées Gemma-4. Les anciens runs v0.20.1 restent utiles comme points de comparaison historiques. Ces nouvelles entrées sont explicitement v23 :

Le classement court pour mon propre usage :

  1. NVFP4 v23 pour le chat local, les agents et la charge bureau.
  2. MTP v23 si tu veux garder l’artefact modèle Google, mais que le decode BF16 est trop lent.
  3. BF16 v23 comme ligne de contrôle et pour les comparaisons où la précision compte plus que la vitesse de serving.

Pour 25k de contexte, aucun des trois ne règle le vrai problème. Là, il faut travailler sur le budget de prompt, le retrieval, la compaction de mémoire et l’architecture d’agent. Pas espérer qu’un profil de serving fasse disparaître l’attente.

Esc