Salut les amis !
Il y a une semaine, j’aurais juré que c’était impossible.
C’était même le titre de mon post : Why DFlash on Qwen3.6-27B doesn’t fit on a 24GB single GPU. Le 28 avril, j’avais sorti la calculette VRAM, additionné le target (17 Go), le drafter (6 Go), les buffers (3 Go), le KV cache (2 Go). Total 28 Go. J’avais 24. Conclusion sèche : “impossible avec les paths publics actuels (Q1 2026)”. J’avais même listé les conditions pour qu’un jour ça change.
Spoiler : ces conditions sont toutes tombées en quatre jours. Aujourd’hui mon Olares One sort 80 t/s en moyenne sur Qwen3.6-27B avec DFlash actif. Voilà comment.
Petit rappel pour ceux qui débarquent
DFlash, c’est une technique de speculative decoding : un petit modèle “drafter” propose des tokens à l’avance, le gros modèle valide en parallèle, on multiplie la vitesse par 2-3 quand l’acceptance est bonne. La technique a été publiée par z-lab à ICLR 2026, et elle est notoirement performante — Lucebox tape 134 t/s sur RTX 3090 avec.
Sauf que pour la faire tourner, il faut un drafter en VRAM en plus du target. Et c’est là que mes 24 Go se cassent les dents : le drafter z-lab pèse 6 Go en BF16, c’est trop. Conclusion du post du 28 avril : il faudrait soit un drafter quantizé (personne ne l’avait fait), soit un fork llama.cpp avec support DFlash (existait mais pas testé sur Blackwell consumer mobile).
J’avais terminé mon post par “si quelqu’un sort un drafter quant, faites-moi signe.”
Le 28 avril, dans la soirée
Pas de commentaire, pas de tweet. Mais en fouillant HuggingFace dans la soirée, je tombe sur un repo récent : spiritbuun/Qwen3.6-27B-DFlash-GGUF. Date de publication : ce matin même. Deux fichiers :
dflash-draft-3.6-q8_0.gguf— 1,75 Godflash-draft-3.6-q4_k_m.gguf— 1,03 Go
Le drafter en Q8_0 fait trois fois moins que le BF16 z-lab. Je refais la math VRAM dans un coin de page :
| Composant | Taille |
|---|---|
| Target Qwen3.6-27B Q4_K_M | 16,8 Go |
| Drafter Q8_0 | 1,75 Go |
| KV cache @ 32K | ~2 Go |
| Buffers + cudagraph | ~1,7 Go |
| Total | ~22,3 Go → tient sur 24 |
Premier ingrédient tombé. Reste à trouver un moteur d’inférence qui sait faire DFlash.
Le même spiritbuun maintient un fork llama.cpp (buun-llama-cpp) qui ajoute exactement ça : --spec-type dflash avec le drafter Q8_0 GGUF. Deuxième ingrédient. Si je build leur fork pour mon hardware (Blackwell consumer mobile, sm_120 — totalement non testé par eux), j’ai potentiellement les deux moitiés du puzzle.
Je clone, j’écris un Dockerfile, je lance buildx en émulation amd64 sur Mac. Et je vais me coucher.
Le 29 avril, 2h30 de compile plus tard
Image aamsellem/buun-llama-cpp-dflash:0.1.0. 2,4 Go. Push Docker Hub. Deploy sur Olares.
Le pod boot. Le target charge. Le drafter charge. llama-server annonce qu’il est prêt sur le port 8000. Pas de crash CUDA, pas de mismatch d’arch. Sur le papier, tout va bien.
Je lance mon bench standard : trois prompts Space Invaders en HTML, max_tokens=800.
Run 1: 800 tok in 235s = 3,40 t/s
Run 2: 800 tok in 525s = 1,52 t/s
Run 3: 800 tok in 824s = 0,97 t/s
Aïe. 3,4 qui dégrade à 0,97. C’est vingt-cinq fois plus lent que mon vLLM Turbo (88 t/s) sur exactement le même hardware. Le drafter est censé accélérer, là il étrangle. Et la dégradation à chaque run sent le memory leak ou le cache qui se corrompt progressivement.
Je regarde les logs détaillés. Le cycle DFlash met 1860 ms par batch, dont 1521 ms de phase verify. Sur Lucebox la même opération prend 15-25 ms. Trois ordres de grandeur d’écart. Les kernels CUDA custom de DFlash sont visiblement écrits pour Ampere et Ada Lovelace, pas pour les SM Blackwell consumer.
Ok. Pas de fix côté config. C’est un bug runtime. Je file une issue propre sur le repo de spiritbuun : issue #35, avec les trois runs, les logs détaillés, la commande exacte, le hardware. Et je pose la patate.
Le 1er mai, fin d’après-midi
Notification GitHub. Spiritbuun répond :
“I think this may be fixed now - can you repull and give it another try?”
Entre temps, 8 commits sur master. Je lis les messages :
cab1fb597:dflash: add p_min confidence threshold + adaptive draft length905483277:--no-fused-gdnflag pour debug115995e41: disable fused GDN kernels on non-CUDA backends-
- un merge de 325 commits depuis llama.cpp upstream
Le premier commit attire l’œil : “p_min confidence threshold + adaptive draft length”. Sur Blackwell consumer, le drafter doit probablement maintenir un seuil de confiance minimum avant d’émettre, sinon les kernels custom rentrent dans des chemins de calcul exotiques qui se dégradent. Hypothèse plausible.
Je relance buildx pour rebuild. Encore deux heures de compile sur OrbStack. Tag : aamsellem/buun-llama-cpp-dflash:0.2.0. Push, redeploy. Pod ready. Je relance les trois runs Space Invaders.
Run 1: 800 tok in 10,82s = 73,94 t/s
Run 2: 800 tok in 9,96s = 80,31 t/s
Run 3: 800 tok in 9,41s = 85,06 t/s
Moyenne 80 t/s. Pas de dégradation entre les runs, plutôt l’inverse — ça monte légèrement parce que le KV cache se met en place.
+2300 % par rapport à v0.1.0. Quatre-vingts fois plus rapide en quatre jours. Le passage de 0,97 à 85 t/s tient en un seul commit upstream (le p_min confidence threshold). C’est ça l’écosystème open source en 2026 — ça bouge à la semaine.
Comparaison sur Olares One
Pour situer où ce 80 t/s tombe :
| Stack | Modèle | t/s avg |
|---|---|---|
| llama.cpp standard | UD-Q4_K_XL, pas de spec decoding | 33-36 |
| buun-llama-cpp DFlash | Q8_0 GGUF drafter | 80 |
| vLLM Turbo (Genesis) | Qwen3.6-27B int4 + MTP n=3 | 88 |
| Lucebox DFlash v1.4.4 | Qwen3.6-27B Q4_K_M | 88,5 |
DFlash arrive dans la cour des champions. Pas premier en absolu — vLLM Turbo et Lucebox restent légèrement devant. Mais c’est la première démonstration publique sur Blackwell consumer mobile (sm_120 RTX 5090M), et c’est avec un drafter quantizé qui rentre en VRAM — exactement le problème que je décrivais comme insoluble il y a quatre jours.
À ma connaissance, PR #86 de Lucebox annonce 218 t/s sur RTX 5090 desktop 32 Go via leur path custom, mais leur HTTP server n’est pas encore en place et leur engine ne charge pas le drafter GGUF spiritbuun. Les deux paths vivent en parallèle pour l’instant.
La config qui marche
Image : aamsellem/buun-llama-cpp-dflash:0.2.0 (CUDA 13.1, sm_120 native, NO_VMM, libcuda stub link).
Args llama-server :
--model Qwen3.6-27B-Q4_K_M.gguf
--model-draft dflash-draft-3.6-q8_0.gguf
--spec-type dflash
--n-gpu-layers 99
--n-gpu-layers-draft 99
--ctx-size 32000
--ctx-size-draft 256
--batch-size 256 --ubatch-size 64
--parallel 1 --flash-attn on --jinja
--chat-template-kwargs '{"enable_thinking": false}'
Détail important : désactivez le thinking. Le drafter spiritbuun n’a pas été entraîné sur la distribution avec balises <think>, donc l’acceptance s’effondre quand le modèle les émet. Selon spiritbuun ça vaut ~1,8× supplémentaire.
La vraie leçon
Il y a quatre jours j’avais titré “impossible”. J’avais raison à l’instant T : sur les paths publics du 28 avril, ça ne tenait pas. Mais l’écosystème open source en 2026 a une demi-vie de 72 heures sur les “impossibles”. Quelqu’un quelque part a la bande passante pour publier un drafter quantizé en une nuit, fixer un bug de kernel sur un hardware qu’il n’a même pas, mettre les commits sur master sans même l’annoncer.
La leçon que je veux retenir, et que j’aurais dû appliquer plus tôt : avant d’écrire “impossible”, attendre une semaine. Pas par lâcheté éditoriale — au contraire, mes négatifs honnêtes restent utiles pour cartographier l’état du moment. Mais en marquer la durée d’expiration explicitement. “Impossible avec les paths publics du 28 avril”. Pas “impossible”. Tout court.
Mon post du 28 avril, mis à jour ce soir, pointe maintenant vers celui-ci. Le négatif et le positif vivent ensemble dans l’archive. C’est plus honnête que de réécrire l’histoire.
Ce qu’on n’a pas encore testé
Quelques pistes ouvertes pour pousser au-delà de 80 :
- DDTree budget tuning — Lucebox sur RTX 5090 desktop tape 218 t/s avec budget=22. Le défaut sous-utilise.
--no-fused-gdnON vs OFF — les kernels GDN fusés peuvent encore avoir des soucis sur sm_120.- Context plus large — 32K conservatif. 80K devrait tenir.
Pour reproduire
spiritbuun/Qwen3.6-27B-DFlash-GGUFQ8_0 (1,75 Go)spiritbuun/buun-llama-cppHEAD compilé pour sm_120- Sur Olares One via ma market : app
dflashqwen36one(la market est ici si vous l’avez pas encore)
Crédits
- spiritbuun pour le fork llama.cpp + le drafter GGUF + le fix express après mon issue #35
- z-lab/dflash pour la méthode Block Diffusion drafter
- unsloth pour le Qwen3.6-27B Q4_K_M GGUF
- Lucebox pour le bench RTX 5090 desktop qui prouvait que sm_120 pouvait y arriver
Voilà ! Si vous tournez sur 5090M, 4080M, 3090 ou 4090 24 Go et que vous reproduisez ces 80 t/s — ou les battez avec un sweep DDTree — 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.