Accéder au contenu principal

Comment accélérer des LLM locaux avec le décodage spéculatif DFlash

Apprenez à accélérer l’inférence locale de Gemma 4 31B sur une seule RTX 4090 grâce au décodage spéculatif DFlash et à Flash Attention, comparés à une configuration de référence.
Actualisé 17 juin 2026

Ces dernières semaines, j’ai vu beaucoup d’engouement dans la communauté r/LocalLLaMA autour du décodage spéculatif, de DFlash, d’une meilleure gestion du cache KV et de builds optimisés de llama.cpp. Le plus intéressant, c’est que les utilisateurs obtiennent des accélérations majeures sans changer de matériel.

Dans ce guide, nous allons exécuter Gemma 4 31B IT en local sur une RTX 4090 24 GB avec BeeLlama.cpp, un fork de llama.cpp qui prend en charge le décodage spéculatif DFlash.

Nous allons tester le modèle de deux façons. D’abord sans DFlash pour établir une référence. Puis avec DFlash afin de comparer le gain de vitesse.

Obtenez une certification de haut niveau en matière d'IA

Démontrez que vous pouvez utiliser l'IA de manière efficace et responsable.
Obtenez une certification, faites-vous embaucher

Qu’est-ce que DFlash ?

En bref, DFlash s’appuie sur un modèle de brouillon qui prédit plusieurs tokens à l’avance, tandis que le modèle principal vérifie ces tokens au lieu de tout générer un par un. Lorsque beaucoup de tokens proposés sont acceptés, la génération s’accélère fortement tout en restant fidèle au comportement du modèle d’origine.

Dans mon essai, DFlash a apporté presque un gain de 3,7× sur certaines tâches, avec des sorties très proches de la référence. L’objectif de ce guide est de montrer la configuration, d’exécuter les deux versions et de comparer les résultats clairement.

Comment fonctionne DFlash

La génération standard des LLM est lente, car la plupart des modèles génèrent le texte token par token. Chaque token dépend du précédent, le modèle avance donc pas à pas dans la réponse.

DFlash accélére ce processuss en utilisant le décodage spéculatif.

Au lieu de demander au modèle principal de générer directement chaque token, DFlash emploie un modèle de brouillon séparé pour deviner d’abord plusieurs tokens à venir. Le modèle principal vérifie ensuite ces propositions en un plus grand pas. Si elles sont correctes, il les accepte ; sinon, il corrige et poursuit.

Pour le dire simplement :

  • Sans DFlash : le modèle principal écrit un token à la fois.
  • Avec DFlash : le modèle de brouillon propose un bloc de tokens, et le modèle principal vérifie rapidement ceux qu’il peut accepter.

Diagram of the DFlash speculative decoding workflow.

Schéma du flux de travail du décodage spéculatif DFlash.

C’est particulièrement utile pour des tâches structurées comme la programmation. Le code suit souvent des schémas prévisibles (imports, définitions de fonctions, indentation, boucles, syntaxe courante). Grâce à cela, le modèle de brouillon devine fréquemment les prochains tokens, ce qui permet au modèle principal d’en accepter davantage à chaque étape.

DFlash vs MTP : quelle différence ?

DFlash et Multi-Token Prediction (MTP) visent tous deux à résoudre le même problème : aider le modèle à générer plus d’un token par étape de décodage coûteuse.

La différence tient à la façon de créer les tokens de brouillon.

Méthode

Principe

Modèle supplémentaire ?

Atout principal

MTP

Utilise des têtes internes de prédiction multi-tokens pour prévoir les tokens futurs

Généralement pas de modèle de brouillon séparé

Configuration plus simple si le modèle prend déjà en charge MTP

DFlash

Utilise un modèle de brouillon DFlash séparé pour proposer de plus grands blocs de tokens

Oui

Peut apporter de forts gains sur des sorties structurées comme le code

En termes simples, MTP est généralement intégré au modèle lui‑même. Il prédit plusieurs tokens futurs via des têtes de prédiction internes, ce qui peut simplifier la configuration et être plus économe en mémoire lorsque c’est pris en charge.

DFlash, de son côté, utilise un modèle de brouillon séparé. La mise en place est un peu plus lourde, mais elle autorise un drafting plus agressif. C’est pourquoi DFlash peut offrir de gros gains sur des tâches structurées où les prochains tokens sont plus prévisibles.

1. Préparer l’environnement

Je vous recommande vivement d’exécuter cette configuration en local si vous avez un GPU RTX 3090 ou RTX 4090. Sinon, vous pouvez louer un GPU via RunPod, Vast.ai ou un autre fournisseur.

Pour ce guide, nous utiliserons un pod RunPod RTX 4090. Je suis parti du dernier template PyTorch de RunPod et j’ai fait quelques ajustements :

  • Ouverture du port 8910 pour le serveur llama.cpp
  • Stockage persistant augmenté à 100 GB
  • Ajout de mon jeton Hugging Face pour accélérer le téléchargement des modèles

Editing the latest Pytorch template in the Runpod

Avec cette configuration, le pod revient à environ 0,70 $ par heure, selon les tarifs et la disponibilité RunPod du moment.

Runpod Pytorch docker running on the RTC 4090 machine.

Une fois le pod déployé, ouvrez JupyterLab depuis le tableau de bord RunPod. Lancez ensuite un nouveau terminal et installez les dépendances de base :

apt update
apt install -y git cmake build-essential curl wget python3-pip

Installing Linux pages within the Jupyter Terminal.

2. Cloner BeeLlama.cpp

Ensuite, clonons BeeLlama.cpp, le fork de llama.cpp que nous allons utiliser.

BeeLlama.cpp est conçu pour une inférence locale GGUF plus rapide tout en conservant le flux de travail familier de llama.cpp. Vous gardez les mêmes outils, notamment llama-server, avec en plus des optimisations orientées performance comme le décodage spéculatif DFlash, le pilotage adaptatif du brouillon et la compression TurboQuant/TCQ du cache KV

Exécutez les commandes suivantes dans votre terminal JupyterLab :

git clone https://github.com/Anbeeld/beellama.cpp.git
cd beellama.cpp

Cela télécharge le dépôt BeeLlama.cpp et vous place dans le dossier du projet. Toutes les commandes de build de l’étape suivante se lancent depuis ce répertoire.

3. Compiler BeeLlama.cpp avec CUDA

Nous allons maintenant compiler BeeLlama.cpp avec le support CUDA afin d’exploiter correctement la RTX 4090.

Pour cette configuration, nous activons CUDA, Flash Attention, les optimisations CPU natives et les kernels de Flash Attention quantifiés. Comme nous utilisons une RTX 4090, nous définissons l’architecture CUDA sur 89.

cmake -B build -DGGML_CUDA=ON -DGGML_NATIVE=ON \
 -DGGML_CUDA_FA=ON -DGGML_CUDA_FA_ALL_QUANTS=ON \
 -DCMAKE_CUDA_ARCHITECTURES=89 \
 -DCMAKE_BUILD_TYPE=Release

cmake --build build -j

La compilation peut durer 20 minutes. Pendant le build, vous pouvez voir des avertissements liés à TurboQuant, TCQ ou aux déclarations CUDA de DFlash. Dans mon cas, il ne s’agissait que d’avertissements qui n’ont pas interrompu la compilation.

BeeLlama.cpp with CUDA build is complete

Enfin, copiez le binaire du serveur dans le dossier principal du projet pour le lancer plus facilement : 

cp ./build/bin/llama-server ./llama-server

4. Installer la CLI Hugging Face et télécharger les modèles

Nous devons maintenant télécharger deux fichiers GGUF : le modèle principal et le modèle de brouillon DFlash.

Le modèle principal produit la sortie finale. Le modèle de brouillon DFlash est beaucoup plus petit et sert uniquement à prédire des tokens en avance. Le modèle principal vérifie toujours les tokens générés : le brouillon accélère le décodage, il ne remplace pas le modèle principal.

Commencez par installer la CLI Hugging Face :

pip install -U huggingface_hub

Créez ensuite un dossier pour organiser les fichiers modèles :

mkdir -p models

Téléchargez le modèle principal Gemma 4 31B IT au format GGUF :

hf download unsloth/gemma-4-31B-it-GGUF \
gemma-4-31B-it-Q4_K_S.gguf \
--local-dir models

Téléchargez ensuite le modèle de brouillon DFlash :

hf download Anbeeld/gemma-4-31B-it-DFlash-GGUF \
gemma4-31b-it-dflash-Q5_K_M.gguf \
--local-dir models

Le modèle de brouillon DFlash est répertorié sur Hugging Face comme un modèle d’architecture dflash-draft, avec le fichier Q5_K_M d’environ 1,09 GB : il est donc bien plus petit que le 31B principal. C’est ce qui le rend pratique à charger aux côtés du modèle principal pour le décodage spéculatif. 

5. Exécuter Gemma 4 31B sans DFlash

Avant d’activer DFlash, lançons Gemma 4 31B en mode normal. Cela nous donne une base pour la vitesse de génération, l’usage de la VRAM et la qualité de sortie. Nous comparerons ensuite cette base avec l’exécution DFlash pour mesurer le gain réel.

Exécutez la commande suivante depuis le dossier beellama.cpp :

./llama-server \
 -m "models/gemma-4-31B-it-Q4_K_S.gguf"  \
--host 0.0.0.0  \
 --port 8910 \
-np 1 \
-ngl all \
-b 2048 -ub 512 \
--ctx-size 32768  \
--cache-type-k q5_0 \
--cache-type-v q4_1 \
--flash-attn on \
--jinja \
--metrics \
--log-timestamps \
--log-prefix \
--reasoning off \
--temp 0.7 \
--top-k 64 \
--top-p 0.95 \
--min-p 0.0

Cette commande démarre le serveur du modèle sur le port 8910. Comme nous avons exposé ce port lors de la création du pod RunPod, nous pouvons y accéder directement depuis le navigateur.

Une fois le modèle chargé en mémoire GPU, vous devriez voir un message indiquant que le serveur écoute sur : 0.0.0.0:8910.

The Gemma 4 31B Without DFlash inference serve is running locally.

Retournez maintenant sur le tableau de bord RunPod et cliquez sur le lien du port 8910. 

Access the 8910 port from the Runpod Dashboard

Cela ouvre l’interface web de llama.cpp, où vous pouvez tester le modèle dans une UI de chat simplifiée. 

Testing the Gemma 4 31B Without DFlash

À ce stade, posez quelques questions longues ou complexes pour observer la vitesse moyenne en tokens. Dans mon run de référence sans DFlash, j’étais autour de 41 tokens par seconde en moyenne. 

Testing the Gemma 4 31B Without DFlash

6. Évaluer le modèle de référence

Maintenant que le modèle de base tourne, il nous faut un moyen simple de mesurer sa vitesse de génération. Pour cela, nous utiliserons trois prompts orientés code et nous les enverrons au serveur local llama.cpp via l’endpoint de chat OpenAI‑compatible.

Le but n’est pas de créer une suite de benchmarks parfaite, mais d’obtenir une base cohérente afin de comparer ensuite les mêmes prompts avec DFlash activé.

Ouvrez un nouvel onglet Terminal Jupyter et créez un script de test :

cat > test_llm_prompts.sh <<'EOF'
#!/usr/bin/env bash

PORT="${1:-8910}"
MODEL="${2:-local-gemma}"
PREFIX="${3:-run}"

URL="http://localhost:${PORT}/v1/chat/completions"

PROMPTS=(
"Write a complete Python task store module. Include a Task dataclass, TaskStatus enum, TaskStore class, add_task, update_task, delete_task, search_tasks, filter_by_status, export_to_json, get_all_tasks, and 5 tests. Return only one complete Python file."

"Write a complete Python key-value report module. Include a KeyValueStore class, set, get, delete, exists, list_keys, filter_by_prefix, export_to_json, load_from_json, and a generate_report function that returns total keys, empty values, prefix counts, and largest value length. Include 5 tests. Return only one complete Python file."

"Write a complete Python doubly linked list module. Include a Node dataclass, DoublyLinkedList class, append, prepend, delete, find, reverse, to_list, from_list, clear, and 5 tests. Return only one complete Python file."
)

echo "Testing server: $URL"
echo "Model: $MODEL"
echo "Output prefix: $PREFIX"

for i in "${!PROMPTS[@]}"; do
  NUM=$((i+1))
  OUT="${PREFIX}_prompt_${NUM}.json"

  echo ""
  echo "Running prompt ${NUM}..."
  echo "Saving to ${OUT}"
  echo "--------------------------------"

  jq -n \
    --arg model "$MODEL" \
    --arg prompt "${PROMPTS[$i]}" \
    '{
      model: $model,
      messages: [
        {
          role: "user",
          content: $prompt
        }
      ],
      max_tokens: 1200,
      temperature: 0.7
    }' | curl -s "$URL" \
      -H "Content-Type: application/json" \
      -d @- | tee "$OUT" | jq '.timings'

  echo "Saved full result to ${OUT}"
done

echo ""
echo "Summary"
echo "--------------------------------"

for f in ${PREFIX}_prompt_*.json; do
  echo "$f"
  jq '{
    model: .model,
    prompt_tokens: .usage.prompt_tokens,
    completion_tokens: .usage.completion_tokens,
    total_tokens: .usage.total_tokens,
    generation_speed_tok_s: .timings.predicted_per_second,
    generation_time_sec: (.timings.predicted_ms / 1000),
    draft_tokens: .timings.draft_n,
    accepted_draft_tokens: .timings.draft_n_accepted
  }' "$f"
done
EOF

Sur macOS ou Linux, n’oubliez pas de rendre le script exécutable :

chmod +x test_llm_prompts.sh

Puis lancez‑le contre le modèle de référence : 

./test_llm_prompts.sh 8910 local-gemma-baseline baseline

Ce script envoie trois prompts de génération de code Python au modèle et enregistre chaque réponse complète dans un fichier JSON. Il affiche aussi des informations temporelles utiles : tokens de complétion, vitesse de génération, temps de génération et champs liés aux tokens de brouillon. 

La sortie complète est assez longue, voici donc un bref récapitulatif des résultats de base pour avoir une vue d’ensemble avant d’activer DFlash.

Prompt

Tokens de complétion

Vitesse de génération

Temps de génération

Prompt 1 : module de gestion de tâches

1124

40,66 tok/s

27,64 s

Prompt 2 : module de rapport key‑value

1200

40,67 tok/s

29,51 s

Prompt 3 : liste doublement chaînée

1200

40,72 tok/s

29,47 s

Sur les trois prompts, le modèle de référence est resté très stable autour de 40,68 tokens/s. Nous avons ainsi un point de comparaison clair avant d’activer DFlash.

7. Exécuter Gemma 4 31B avec DFlash

Maintenant que nous avons les résultats de base, relançons le même modèle avec DFlash activé.

Revenez au terminal où tourne le serveur de référence et arrêtez‑le avec Ctrl + C

Démarrez ensuite le serveur optimisé DFlash :

./llama-server \
-m "models/gemma-4-31B-it-Q4_K_S.gguf" \
--spec-draft-model "models/gemma4-31b-it-dflash-Q5_K_M.gguf" \
--spec-type dflash \
--spec-dflash-cross-ctx 1024 \
--host 0.0.0.0  \
 --port 8910 \
-np 1 \
--kv-unified \
-ngl all \
--spec-draft-ngl all \
-b 2048 -ub 512 \
--ctx-size 32768 \
--flash-attn on \
--cache-ram 0 \
--jinja \
--no-mmap \
--mlock \
--no-host \
--metrics \
--log-timestamps \
--log-prefix \
--reasoning off \
--temp 0.7 \
--top-k 64 \
--top-p 0.95 \
--min-p 0.0

Cette commande charge le même modèle principal Gemma 4 31B, mais ajoute cette fois le modèle de brouillon DFlash via --spec-draft-model.

Les options DFlash importantes sont :

Option

Rôle

--spec-draft-model

Charge le modèle de brouillon DFlash

--spec-type dflash

Active le décodage spéculatif DFlash

--spec-dflash-cross-ctx 1024

Définit la fenêtre de cross‑contexte utilisée par DFlash

--spec-draft-ngl all

Déporte les couches du modèle de brouillon sur le GPU

--kv-unified

Unifie la gestion du KV pour le couple modèle principal + brouillon

Le démarrage peut être un peu plus long cette fois, car il faut charger en mémoire le modèle principal et le modèle de brouillon.

Loading the Gemma 4 31B With DFlash in the GPU memory

Une fois le serveur complètement chargé, vous devriez de nouveau voir le serveur d’inférence sur : 0.0.0.0:8910.

Running the Gemma 4 31B With DFlash locally

8. Évaluer le modèle avec DFlash

Retournez dans le terminal Jupyter où nous avons créé le script de benchmark. Nous pouvons le relancer à l’identique, mais cette fois contre le serveur avec DFlash activé. 

./test_llm_prompts.sh 8910 local-gemma-dflash dflash

On réutilise les trois prompts de code du test de référence, ce qui rend la comparaison juste. La seule différence notable est que le serveur tourne maintenant avec le modèle de brouillon DFlash.

Comparer la vitesse d’inférence

La sortie complète est longue, voici donc un résumé des résultats de base et avec DFlash :

Prompt

Vitesse de base

Vitesse DFlash

Accélération

Temps de base

Temps DFlash

Temps gagné

Module de gestion de tâches

40,66 tok/s

130,96 tok/s

3,22×

27,64 s

8,23 s

19,41 s

Module de rapport key‑value

40,67 tok/s

145,68 tok/s

3,58×

29,51 s

8,24 s

21,27 s

Liste doublement chaînée

40,72 tok/s

153,04 tok/s

3,76×

29,47 s

7,84 s

21,63 s

Sur ces trois tâches de code, DFlash a fait passer la vitesse de environ 40 tok/s à 130–153 tok/s. On obtient ainsi une accélération de 3,2× à 3,8×, tout en réduisant le temps de génération de près de 30 secondes à environ 8 secondes par prompt. 

Vous pouvez également rouvrir le lien du port 8910 depuis le tableau de bord RunPod et tester le modèle via l’interface web.

Comparer la qualité de sortie

Puisque nous approchons une accélération ×4 sur des prompts de code, l’étape suivante est de vérifier la qualité. Pour cela, j’ai testé le modèle sur quelques tâches différentes.

D’abord, je lui ai demandé de générer un site portfolio pour « Abid ». Pour un modèle 31B local sur une seule RTX 4090, le résultat est impressionnant : une structure propre avec un HTML et un style exploitables. 

Website generated by Gemma 4

Ensuite, je lui ai demandé de générer un diagramme pour un pipeline MLOps complet. Le modèle a produit du code Mermaid avec libellés, couleurs et workflow abouti. Testé, il a fonctionné immédiatement. 

Testing the Gemma 4 31B With DFlash for the diagram generation.

Puis, je lui ai demandé d’écrire un article sur Mixture of Experts dans les LLM. La qualité est restée élevée, mais la vitesse a chuté à environ 95 tok/s. C’est toujours bien plus rapide que la référence, mais plus lent que sur les prompts de code. 

Testing the Gemma 4 31B With DFlash for blog writing.

Cela s’explique : DFlash donne le meilleur de lui‑même lorsque la sortie est plus prévisible. Les tâches de code suivent souvent des patrons clairs, le modèle de brouillon devine donc davantage de tokens. L’écriture créative ou les prompts de type recherche sont moins prévisibles, le taux d’acceptation baisse et le gain peut être moindre. 

Conclusion

Après ce test, je pense que le décodage spéculatif combiné à une meilleure gestion du cache KV est la vraie avancée pour l’inférence LLM en local.

Le bénéfice principal n’est pas que le gain théorique. C’est ce qu’il permet. Lorsqu’un modèle 31B peut générer du code à 130–150 tokens par seconde sur une seule RTX 4090, il devient réellement utilisable comme agent de code local. Vous pouvez l’utiliser pour créer des projets from scratch, le connecter à des serveurs MCP, lancer des outils bash, utiliser des compétences personnalisées et bâtir un flux de travail bien plus proche des agents premium.

Pour celles et ceux qui possèdent déjà une RTX 3090 ou 4090, c’est encore plus enthousiasmant. Plutôt que de payer chaque assistant de code ou de dépendre totalement du cloud, vous pouvez faire tourner une configuration locale puissante, rapide, privée et flexible. Cela ne remplacera pas tous les outils hébergés pour tout le monde, mais pour les passionnés d’IA locale, les développeurs et les makers, on s’en approche sérieusement.

Et ce n’est qu’un début. Beaucoup testent déjà des configurations similaires avec des modèles plus récents comme Qwen3.6‑27B et rapportent une qualité encore meilleure. À mesure que les modèles progressent, que les modèles de brouillon s’améliorent et que des moteurs d’inférence comme BeeLlama.cpp s’optimisent, l’IA locale gagnera encore en utilité.

Le meilleur dans tout cela, c’est la communauté. Beaucoup d’améliorations viennent d’enthousiastes de l’IA locale qui expérimentent, benchmarkent, améliorent les outils et partagent leurs résultats ouvertement. Cela nous permet à toutes et tous de reproduire la configuration et de profiter des mêmes gains de performance.

Sujets
Contenus associés

blog

Comprendre les TPU et les GPU dans l'IA : Un guide complet

L'essor du développement de l'intelligence artificielle (IA) a entraîné une augmentation notable de la demande en matière de calcul, d'où la nécessité de disposer de solutions matérielles robustes. Les unités de traitement graphique (GPU) et les unités de traitement tensoriel (TPU) sont devenues des technologies essentielles pour répondre à ces demandes.
Kurtis Pykes 's photo

Kurtis Pykes

9 min

blog

ROI de l'IA en 2026 : pourquoi les compétences des équipes déterminent le retour sur investissement

Seuls 21 % des dirigeants font état d'un retour sur investissement « significatif » de leurs investissements dans l'IA.
Lynn Heidmann's photo

Lynn Heidmann

blog

2022-2023 Rapport annuel DataCamp Classrooms

À l'aube de la nouvelle année scolaire, DataCamp Classrooms est plus motivé que jamais pour démocratiser l'apprentissage des données, avec plus de 7 650 nouveaux Classrooms ajoutés au cours des 12 derniers mois.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

8 min

blog

Les 20 meilleures questions d'entretien pour les flocons de neige, à tous les niveaux

Vous êtes actuellement à la recherche d'un emploi qui utilise Snowflake ? Préparez-vous à répondre à ces 20 questions d'entretien sur le flocon de neige pour décrocher le poste !
Nisha Arya Ahmed's photo

Nisha Arya Ahmed

15 min

cursor ai code editor

Tutoriel

Cursor AI : Un guide avec 10 exemples pratiques

Apprenez à installer Cursor AI sur Windows, macOS et Linux, et découvrez comment l'utiliser à travers 10 cas d'utilisation différents.

Tutoriel

Cache Python : Deux méthodes simples

Apprenez à utiliser des décorateurs tels que @functools.lru_cache ou @functools.cache pour mettre en cache des fonctions en Python.
Stephen Gruppetta's photo

Stephen Gruppetta

Voir plusVoir plus