Comment j'ai multiplié par 10 le contexte de mes modèles locaux avec Flash Attention et KV Cache q8_0

Deux variables d'environnement Ollama suffisent pour passer gemma4 de 10k à 32k tokens et qwen3.5 de 8k à 80k tokens — sans perte de vitesse

Tout est parti d'une vidéo YouTube.

Je regardais une présentation sur l'optimisation du KV cache avec Flash Attention — le genre de vidéo qui passe un dimanche soir quand on n'arrive pas à décrocher. Le présentateur expliquait comment la quantification du cache clé-valeur pouvait libérer de la VRAM sans impact perceptible sur la qualité. En théorie, c'était propre. Mais est-ce que ça marchait vraiment sur ma config ?

Du coup, j'ai passé la journée à tester. Gemma4, Qwen3.5, ma RTX 3050 6 Go, Ollama 0.23.1. Résultat : x3 de contexte sur gemma4 (10k → 32k), x10 sur qwen3.5 (8k → 80k), avec un gain de vitesse de 5 à 10 %. Le tout sans changer de matériel.


Avant de continuer de lire la suite de l'article, je vous invite à vous inscrire à ma newsletter, pour connaître en avant première les futurs sujets traités chaque semaine.


Le problème : pourquoi votre contexte est bridé sans que vous le sachiez

Quand vous lancez un modèle sur Ollama, deux choses consomment votre VRAM :

  1. Les poids du modèle (weights) — fixes, dépendent du nombre de paramètres et de la quantification
  2. Le KV cache — dynamique, il grandit avec chaque token de contexte

Sur une RTX 3050 6 Go, gemma4:e4b en Q4_K_M pèse déjà ~4,7 GiB rien qu'en poids. Le KV cache en précision FP16 standard gruge le reste. Résultat : à 10k tokens de contexte, vous êtes déjà au taquet. Au-delà, Ollama décharge des couches sur le CPU — et les performances s'effondrent.

Le pire, c'est que la plupart des gens ne savent même pas que c'est réglable. Ollama utilise FP16 pour le KV cache par défaut. Et FP16, c'est 2 octets par élément, pour chaque tête d'attention, pour chaque couche. Sur un modèle à 4 milliards de paramètres avec 32 têtes et 16 couches, ça chiffre vite.


La solution tient en deux variables d'environnement

Deux flags dans la configuration systemd d'Ollama changent tout :

Variable Valeur Ce qu'elle fait
OLLAMA_FLASH_ATTENTION 1 Active le tiling de l'attention — réduit les écritures en mémoire GPU (HBM) et optimise la bande passante
OLLAMA_KV_CACHE_TYPE q8_0 Quantifie le cache clé-valeur en 8 bits au lieu de 16 bits — divise par deux la consommation VRAM du KV cache

Flash Attention, c'est l'algorithme de Tri Dao (Stanford, 2022) qui a révolutionné l'attention des transformers. Au lieu de calculer la matrice d'attention complète N×N — qui explose en O(N²) — il la découpe en tuiles et fusionne les opérations pour éviter d'écrire les résultats intermédiaires dans la mémoire principale. Moins d'écritures = moins de bande passante consommée = plus de place pour le contexte.

La quantification q8_0, elle, s'attaque directement au stockage : chaque élément du cache passe de 16 bits à 8 bits. La précision baisse, mais les benchmarks montrent que l'impact sur la qualité est négligeable pour les modèles de 4B+ paramètres.

Le combo des deux est redoutable. Flash Attention évite le gaspillage mémoire pendant le calcul, q8_0 réduit le stockage permanent.


Ma configuration de test

Avant de vous donner les chiffres, voici le matériel et la config :

  • GPU : NVIDIA RTX 3050 6 Go Laptop (WSL2 Ubuntu, compute capability 8.6 — Ampere)
  • Ollama : 0.23.1
  • Modèles testés :
  • gemma4:e4b — Q4_K_M, 43 couches, text-only pruned (Handyfff)
  • qwen3.5:4b — Q4_K_M, contexte 8k

La configuration appliquée dans /etc/systemd/system/ollama.service.d/port.conf :

Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"
Environment="OLLAMA_CONTEXT_LENGTH=32768"

Pour gemma4, j'ai aussi créé un Modelfile avec PARAMETER num_ctx 32768 pour forcer le contexte maximum GPU-only. Sans ça, Ollama utilise son contexte par défaut (2048 tokens).


Résultat 1 — gemma4:e4b : de 10k à 32k sans changer de GPU

Voici les relevés VRAM pour chaque palier de contexte, avec la config FA + q8_0 :

Contexte VRAM GPU Layers Status
4 096 ~5 233 MiB 43/43 100 % GPU
8 192 ~5 405 MiB 43/43 100 % GPU
16 384 ~5 529 MiB 43/43 100 % GPU
24 576 ~5 511 MiB 43/43 100 % GPU
32 768 ~5 623 MiB 43/43 100 % GPU — MAX
36 864+ ~3 200-3 700 42/43 Output layer → CPU

Le seuil critique est à 32 768 tokens. Au-delà, la couche de sortie bascule sur CPU et les performances chutent de 10-15 %. Mais 32k, c'est déjà trois fois plus que ce que j'avais avant (10k en FP16). Et tout tient dans les 6 Go de la RTX 3050.

Le coût du KV cache q8_0 est remarquablement linéaire : environ 36 MiB par tranche de 4k tokens supplémentaires. À 32k, le cache complet ne consomme que ~400 MiB de plus qu'à 4k.


Résultat 2 — qwen3.5:4b : le vrai gagnant, x10 de contexte

C'est sur qwen3.5:4b que la différence est la plus spectaculaire.

Sans optimisation, mon qwen3.5:4b calait à environ 8 192 tokens avant de déborder. Avec FA + q8_0, je l'ai poussé jusqu'à 80 000 tokens sans offload CPU. C'est un facteur 10.

Modèle Avant (FP16) Après (FA + q8_0) Gain
gemma4:e4b ~10 240 tokens 32 768 tokens x3
qwen3.5:4b ~8 192 tokens 80 000 tokens x10

Pourquoi une telle différence entre les deux modèles ? qwen3.5:4b est plus léger en poids (~2,5 GiB en Q4_K_M contre ~4,7 GiB pour gemma4) — il reste donc beaucoup plus de marge pour le KV cache. La quantification libère une bande passante que le modèle peut entièrement convertir en contexte supplémentaire.


Résultat 3 — la vitesse ne baisse pas, elle augmente

C'est le résultat le plus contre-intuitif : non seulement le contexte s'élargit, mais la vitesse de génération augmente de 5 à 10 %.

gemma4:e4b — 4K vs 32K

Contexte TPS moyen VRAM Différence
4 096 44,9 t/s 5 248 MiB
32 768 44,2 t/s 5 640 MiB -0,7 t/s (-1,5 %)

La différence est imperceptible : -1,5 % de TPS pour 8× plus de contexte. Et comparé à mon benchmark d'avril 2026 où gemma4 tournait à 38 t/s en config standard, c'est +16 % de TPS avec Flash Attention activé.

Test de stabilité — 5 minutes continues

Pour vérifier que le gain n'est pas un artefact de bench court, j'ai fait tourner gemma4 en continu pendant 5 minutes :

Métrique Valeur
TPS moyen 40,8 t/s
TPS stable (6/7 runs) 42-45 t/s
Température GPU 63-75 °C
VRAM stable ~5 640 MiB

Aucun throttling thermique. La 3050 tient la charge sans broncher.

Pour qwen3.5:4b, le TPS est passé d'environ 55 t/s à 60-62 t/s — un gain de 8-10 %. Le modèle est plus à l'aise avec le cache quantifié, probablement parce que la réduction de la pression mémoire permet au GPU de mieux paralléliser.


Pourquoi ça marche : explication technique

Le gain n'est pas magique — il découle de trois mécanismes distincts :

1. La quantification du KV cache réduit la pression mémoire. En passant de FP16 à q8_0, chaque élément du cache occupe 1 octet au lieu de 2. À 32k tokens, sur gemma4, ça représente environ 400 MiB d'économisés — exactement la marge qui permet de ne pas déborder des 6 Go.

2. Flash Attention fusionne les opérations pour éviter les écritures intermédiaires. L'attention standard écrit la matrice N×N complète en HBM avant de la normaliser. Flash Attention fait le calcul par tuiles en SRAM (on-chip), sans jamais écrire la matrice complète en mémoire externe. Résultat : moins de bande passante consommée, plus de place pour le contexte.

3. Sur GPU Ampere (compute 8.6), la SRAM est bien dimensionnée pour cette technique. La RTX 3050 a 2 Mo de L2 cache et 64 Ko de SRAM par SM — assez pour que le tiling de Flash Attention soit efficace sans overflow. Ollama 0.23.1 gère correctement le support Ampere, ce qui n'était pas le cas des versions antérieures.

Le résultat concret : les poids du modèle restent la consommation dominante (~4,5 GiB sur 5,2-5,6 GiB), le KV cache quantifié ajoute un coût marginal linéaire (~36 MiB/4k tokens), et la génération reste compute-bound plutôt que memory-bandwidth-bound.


Comment appliquer ça chez vous

La mise en place prend cinq minutes :

# 1. Créer un modèle avec le contexte souhaité (optionnel mais recommandé)
cat > /tmp/gemma4-32k.Modelfile << 'EOF'
FROM hf.co/Handyfff/Gemma-4-E4B-it-uncensored-pruned-TextOnly-EnglishOnly-GGUF:Q4_K_M
PARAMETER num_ctx 32768
EOF
ollama create gemma4:e4b-32k -f /tmp/gemma4-32k.Modelfile

# 2. Éditer la configuration systemd d'Ollama
sudo mkdir -p /etc/systemd/system/ollama.service.d
sudo tee /etc/systemd/system/ollama.service.d/port.conf << 'EOF'
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"
Environment="OLLAMA_CONTEXT_LENGTH=32768"
EOF

# 3. Redémarrer le service
sudo systemctl daemon-reload
sudo systemctl restart ollama

# 4. Vérifier que c'est bien activé
journalctl -u ollama -n 5

Vous devez voir dans les logs une ligne du type :

FlashAttention:Enabled KvSize:32768 KvCacheType:q8_0
GPULayers:43[ID:GPU-xxx Layers:43(0..42)]
offloaded 43/43 layers to GPU

Si vous ne voyez pas FlashAttention:Enabled ou KvCacheType:q8_0, vérifiez que les variables sont bien dans le fichier de configuration systemd (pas dans un .env à côté — Ollama en service systemd ne lit pas les fichiers .env sauf si le service est configuré pour).


Ce qu'il faut retenir

Après une journée de benchmarks, trois leçons :

1. Le KV cache q8_0 est le facteur décisif, pas Flash Attention. La quantification du cache libère bien plus de VRAM que l'optimisation de l'algorithme d'attention. Flash Attention aide, mais c'est q8_0 qui permet de passer de 10k à 32k (ou 80k).

2. Pas besoin d'un modèle « court » et d'un modèle « long » séparés. La pénalité de vitesse entre 4k et 32k est de 1,5 % — négligeable en pratique. Un seul modèle configuré au max de ce que votre GPU peut tenir, et vous avez le meilleur des deux mondes.

3. 32k est le sweet spot GPU-only sur 6 Go. Au-delà, la couche de sortie tombe sur CPU et les performances chutent. Si vous avez 8 Go ou plus, vous pouvez viser plus haut — le principe reste le même : FA + q8_0, et pousser le contexte jusqu'au seuil de basculement CPU.

Est-ce que vous avez testé Flash Attention et le KV cache q8_0 sur votre config ? Quel gain de contexte avez-vous obtenu ? Dites-moi en commentaire — et si vous avez des résultats sur d'autres modèles (llama, mistral, deepseek), je suis preneur.


Pour aller plus loin

Sources et références externes :
- FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness — papier original de Tri Dao et al. (Stanford, 2022)
- Ollama GPU documentation — configuration des variables d'environnement GPU
- Ollama releases — support Flash Attention ajouté dans les versions récentes

Articles liés sur ce blog :
- Gemma 4 e2b et e4b : ce que j'ai appris après des heures de benchmark sur des modèles locaux
- J'ai benchmarké Qwen3 sur GPQA et HLE — les résultats m'ont surpris
- Benchmark de 30 modèles locaux — le classement définitif (avril 2026)


Qui suis je ?

Je suis Mathieu GRENIER, CTO d'Easystrat une startup de Montpellier, en France. Je manage une équipe d'une dizaine d'ingénieurs (Graphistes, IA, frontend, backend, devOps, AWS) en remote depuis le Japon.

J'ai aussi mon activité de freelance, où je conseille des entrepreneurs dans leurs projets d'application.

Avec mon expérience personnelle de plus de 15 ans en ESN, j'ai pu travailler pour un large panel d'entreprises de différentes tailles. Ma compréhension des problèmes métiers est une de mes grandes forces et permet à mes clients de pouvoir se projeter plus facilement.

L'essentiel de mon travail consiste à canaliser l'énergie des entrepreneurs sur l'essence même de leur projet.

La technologie, les méthodes, le management sont le cœur de mes compétences.

Vous pouvez me faire confiance sur ces points là.

Si vous voulez me parler d'un de vos projets, n'hésitez pas à m'envoyer un email avec vos disponibilités à : contact@mathieugrenier.fr

Je documente en public ce que je construis en privé. Abonnez-vous pour ne pas manquer les prochains articles sur l'IA locale, les agents autonomes et l'architecture de systèmes LLM.


Tous les articles de ce blog sont écrits par moi, même si je peux m'aider de l'IA pour illustrer mes propos. Mais jamais je ne fournis d'articles 100 % IA.

Mathieu Grenier 15 mai 2026
Partager cet articlE