Skip to content
/ airelien.dev
Go back
Aurélien AMSELLEM

Gemma 4 E4B MTP sur RTX 5090M : 178 t/s, 24 h après le merge vLLM upstream

Le 6 mai à 14:39 UTC, lucianommartins merge la PR #41745 dans vLLM main : support natif des drafters Multi-Token Prediction de Gemma 4. Le 7 mai à 06:13 UTC, le nightly Docker est publié. À 06:35 UTC, mon Olares One sort 178,6 t/s avec 77,3 % d'acceptance — premier bench public Gemma 4 MTP sur Blackwell consumer mobile.

Salut les amis !

Le 5 mai 2026, Google publie les drafters Multi-Token Prediction officiels pour les quatre tailles de Gemma 4 (E2B, E4B, 26B-A4B, 31B). Petite explosion de hype sur r/LocalLLaMA — 891 upvotes en 12 h. Mais à l’époque, personne ne pouvait les utiliser : l’arch Gemma4AssistantForCausalLM avec ses centroid LM heads (top_k=32, num_centroids=2048) n’était reconnue ni par llama.cpp ni par vLLM.

Le 6 mai à 14:39 UTC, lucianommartins merge dans vLLM main la PR #41745 : “[Spec Decode] Add Gemma4 MTP speculative decoding support”. 9 fichiers, +1 121 / -72 lignes. Nouveau modèle Gemma4MTP, nouveau Gemma4Proposer, et — détail croustillant — la centroids masking optimization qui réduit le calcul du lm_head de 262 K à 4 K candidats via la sélection learned.

Le 7 mai à 06:13 UTC, le nightly Docker vllm/vllm-openai:nightly-1acd67a795ebccdf9b9db7697ae9082058301657 est publié sur Docker Hub.

À 06:35 UTC, soit ~22 min plus tard, j’envoie le premier prompt sur mon Olares One. 178,6 t/s en moyenne sur trois runs, 77,3 % d’acceptance rate. C’est le premier bench public Gemma 4 MTP sur du Blackwell consumer mobile (RTX 5090M sm_120, 24 GB GDDR7).

Voilà comment j’en suis arrivé là.

Le drafter, en 2 mots

Gemma 4 ships avec un petit modèle “assistant” entraîné jointement avec le target. Pendant l’inférence, il prédit plusieurs tokens en avant à partir du dernier hidden state du target ; le verifier accepte la séquence en parallèle si elle matche. Pour E2B/E4B il y a un détail élégant : un head à centroïdes qui réduit le softmax sur 262 144 tokens à un mask de 2 048 centroïdes — plus rapide ET (selon Google) sans perte de qualité.

Architecture du drafter Gemma4AssistantForCausalLM (lue dans config.json hier) :

- 4 hidden layers, hidden_size 256, intermediate_size 2048 (minuscule)
- 4 attention heads, 1 KV head (KV-shared sur 4 layers)
- centroid_intermediate_top_k=32, num_centroids=2048
- vocab_size 262144 (matche Gemma 4)
- 78 M params pour E2B-it-assistant (158 MB en safetensors)

C’est dédié MTP, pas un small Gemma 4 réutilisé. D’où la nécessité d’une PR upstream dédiée.

Pourquoi ça vient juste maintenant

Avant le 6 mai 14:39, l’arch gemma4_assistant était inconnue de vLLM — boot direct → NotImplementedError. La PR #41745 ajoute :

Côté config, ça se résume à :

--speculative-config '{"method":"mtp","model":"google/gemma-4-E4B-it-assistant","num_speculative_tokens":3}'

Le code détecte automatiquement model_type == "gemma4_assistant" et le convertit en gemma4_mtp au load.

La course aux nightlies

Bizarrerie de timing : le nightly standard vllm/vllm-openai:nightly du 6 mai à 06:08 UTC est antérieur au merge. Quand j’ai voulu tester en fin d’après-midi, j’ai d’abord essayé tokenspeed-preview-ubuntu2404 (pushé à 14:47 UTC, soit 8 minutes après le merge) — boot crash : NotImplementedError: Unsupported speculative method: 'mtp'. Le build cutoff devait être pré-merge.

Le 7 mai à 06:13 UTC, vLLM publie un nouveau nightly tagué nightly-1acd67a795ebccdf9b9db7697ae9082058301657 — commit 1acd67a du 2026-05-07 04:57 UTC (post-#41745 de plusieurs heures). Cette fois, ça boote.

Le manifeste Kubernetes

Sur Olares One le pod est super simple — pas de Genesis, pas de patches, pas de fork :

containers:
  - name: vllm-server
    image: docker.io/vllm/vllm-openai:nightly-1acd67a795ebccdf9b9db7697ae9082058301657
    command: ["sh", "-c"]
    args:
      - |
        exec vllm serve google/gemma-4-E4B-it \
          --served-model-name gemma-4-e4b-mtp \
          --host 0.0.0.0 --port 8000 \
          --max-model-len 32000 \
          --gpu-memory-utilization 0.85 \
          --max-num-seqs 1 --dtype auto \
          --trust-remote-code --download-dir /models \
          --enable-prefix-caching \
          --speculative-config '{"method":"mtp","model":"google/gemma-4-E4B-it-assistant","num_speculative_tokens":3}'
    env:
      - name: CUDA_DEVICE_MEMORY_LIMIT_0
        value: "24000m"   # workaround HAMi 0m parsing bug

Le seul truc spécifique Olares One c’est l’override CUDA_DEVICE_MEMORY_LIMIT_0=24000m — sans ça, HAMi parse “0m” comme 0 octet et toute alloc CUDA crashe à EagleProposer.__init__ → torch.zeros. Hors Olares, oubliez cette ligne.

Le bench

Trois prompts Space Invaders standards (HTML+CSS+JS, max_tokens=800, temp=0.6, top_p=0.95) :

Run 1 (cold start): 800 tok in  6,17 s = 129,73 t/s
Run 2:              800 tok in  4,17 s = 191,73 t/s
Run 3:              800 tok in  3,73 s = 214,38 t/s

AVG = 178,6 t/s, range 129-214.

Côté MTP metrics (extraites des logs vLLM) :

Mean acceptance length      : 3,32 (sur 3 draft tokens)
Per-position acceptance rate : 0,868 / 0,765 / 0,687
Avg Draft acceptance rate   : 77,3 %

77 % d’acceptance, c’est très haut. Pour comparaison, Qwen3.6 + MTP llama.cpp tourne autour de 64 % sur le même hardware. La différence vient probablement de l’optimisation centroids — le drafter E4B est petit ET entraîné spécifiquement pour matcher le target, donc le draft est plus précis qu’un drafter générique.

Comparaison sur Olares One (RTX 5090M 24 Go sm_120)

StackModèlet/sNotes
llama.cpp baselineQwen3.6-27B Q4_K_M33-37upstream pur
llama.cpp + MTP (PR #22673)Qwen3.6-27B-MTP-Q4_K_M @ 32K78,1recipe RDson
llama.cpp + MTP (PR #22673)froggeric MTP @ 128K65,1trade context for perf
vLLM no-Genesis + #39931 + --enforce-eagerQwen3.6-27B int4 AutoRound72,55workaround CG bug
vLLM Turbo (Genesis)Qwen3.6-27B int4 AutoRound88,028 patches
Lucebox DFlash v1.4.4Qwen3.6-27B Q4_K_M88,5engine custom
vLLM nightly + PR #41745Gemma 4 E4B + MTP178,6upstream pur, 1 PR

Note : Gemma 4 E4B est un modèle ~5 B effective, beaucoup plus petit que Qwen3.6-27B. La comparaison brute t/s n’est pas équitable. Mais pour les use cases agentic/voice à faible latence sur Gemma 4, on est sur du 178 t/s en stack 100 % upstream.

Update 8 mai : le pendant llama.cpp livre 206 t/s sur E2B et 140 t/s sur 26B-A4B

Côté llama.cpp, AtomicChat a aussi sorti son support Gemma 4 MTP (post r/LocalLLaMA à 200+ upvotes le 7 mai). Ils maintiennent un fork — AtomicBot-ai/atomic-llama-cpp-turboquant — qui ajoute l’arch gemma4_assistant, le --mtp-head runtime flag, et au passage TurboQuant KV cache (-ctk turbo3 -ctv turbo3) — bonus inattendu.

J’ai built leur fork pour sm_120 (image aamsellem/llamacpp-atomic-mtp:0.1.0, 2,72 Go) et bench les deux variantes target qu’on a sur HF :

Gemma 4 E2B + MTP (llama.cpp atomic)
  eval time = 4,84 ms per token = 206,56 t/s
  draft acceptance rate = 60,93 %
  3 198 tokens generated in 15,48 s
Gemma 4 26B-A4B + MTP (llama.cpp atomic)
  eval time = 7,14 ms per token = 140,03 t/s
  draft acceptance rate = 78,15 %
  3 238 tokens generated in 23,12 s

Le 26B-A4B fait 140 t/s avec 78 % acceptance — sur le premier run, hors warm-up. Ça dépasse le bench M5Max de référence d’AtomicChat (138 t/s). Et c’est un MoE 26B → la qualité d’un dense ~26 B avec la latence d’un dense ~6 B.

Donc côté Olares One on a maintenant deux paths Gemma 4 MTP validés :

PathModèlet/sStack
vLLM nightly + PR #41745Gemma 4 E4B178,6upstream pur, 1 PR mergée
llama.cpp + atomic-llama-cpp-turboquant forkGemma 4 E2B206,6fork tier-3 + 2 GGUF (target unsloth + drafter AtomicChat)
llama.cpp + atomic-llama-cpp-turboquant forkGemma 4 26B-A4B140,0fork tier-3 + 2 GGUF

Le pendant vLLM est plus propre côté maintenance (1 PR upstream qui va finir en stable), le pendant llama.cpp donne du t/s plus haut sur les petits modèles ET supporte le 26B-A4B MoE. Selon votre use case (latence vs qualité), vous prenez l’un ou l’autre.

Pourquoi ça change la donne

L’an dernier on aurait passé deux semaines à hacker un fork ou écrire des monkey-patches. Là, 24 heures après le merge upstream, le nightly Docker est dispo et le bench tourne. C’est le sens dans lequel l’écosystème va : les techniques qui passaient par des forks (DFlash via Lucebox, MTP via Genesis pour vLLM, MTP via am17an pour llama.cpp) finissent en mainline.

Pour Gemma 4 spécifiquement, l’équipe vLLM a fait du super taf — la PR ajoute une infrastructure qui sera réutilisable pour d’autres drafters arch dédiées (par exemple, un éventuel drafter dédié pour Mimo v2.5 ou les futurs Llama 4).

Pour reproduire

Ma reco si vous testez sur d’autres hardwares Blackwell consumer (5070, 5080, 5090 desktop) : envoyez vos chiffres dans les commentaires, on construit la base de comparaison.

Crédits

Voilà ! Si vous tournez Gemma 4 sur un Olares One et que vous reproduisez ces 178 t/s (ou les battez avec un sweep num_speculative_tokens), envoyez-moi vos chiffres. À très vite !


Disclosure — Tous les benchmarks de ce post tournent sur mon propre Olares One. Si le contenu vous a été utile et que vous envisagez d’en acheter un, commander via ce lien de parrainage vous donne 400 $ de réduction (3 599 $ au lieu de 3 999 $) et me rapporte 200 $. Je le mentionne par transparence — et oui, accessoirement, ça aide à faire vivre le blog (hébergement, domaine, et le temps que je passe à écrire ici). Lien valable jusqu’à fin juin 2026 environ.

Share this post on:

Commentaires