Aide

Besoin d’aide ?

Posez votre question sur le Discord de MiniLab, dans le salon de cette page :

#questions-generation

Ouvrir le salon ↗

Pas encore membre ? Rejoindre le Discord, puis revenez sur ce bouton.

Ma progression

Sauvegarder ma progression

Chargement…

Votre progression est enregistrée dans ce navigateur, pour cette adresse seulement. Gardez ce code : il la restaure dans un autre navigateur, sur un autre ordinateur, ou si les données du site ont été effacées.

MINILAB-0-1C
Mentions légales
Affichage

Personnaliser l’affichage

Ce réglage s’applique à la vue côte à côte.
LEÇON 15LE VOYAGE D’UNE REQUÊTE

Cache KV et vitesse.

Dans la leçon précédente, le serveur a assemblé toute la conversation et l’a envoyée au modèle. Comment le modèle traite-t-il ce long prompt d’un coup, puis génère-t-il la réponse token après token sans tout recalculer ? Rappelez-vous la boucle de génération : il calcule une distribution (leçon 08), choisit un token (leçon 09), l’ajoute au texte, puis recommence. Mais à chaque tour, le texte à relire s’allonge. Si le modèle refaisait tout le calcul de l’attention (leçon 06) depuis le début à chaque token, une longue réponse deviendrait d’une lenteur insupportable. Tous les modèles en production utilisent donc une astuce simple et puissante : le cache KV. Cette leçon explique aussi les mots que l’on entend dès qu’on parle de vitesse : prefill, decode, délai du premier token et tokens par seconde.

01

Le travail refait pour rien

Imaginez que vous écriviez une lettre et qu’avant chaque nouveau mot, vous relisiez toute la lettre depuis le début. Au dixième mot, vous auriez relu 45 mots ; au centième, près de 5 000. C’est exactement ce qui se passerait sans précaution.

Rappelez-vous la leçon 06 : chaque token calcule une requête Q, une clé K et une valeur V, puis sa requête est comparée aux clés de tous les tokens précédents. Quand on ajoute un nouveau token, les tokens déjà présents ne changent pas : grâce au masque causal, ils ne voient jamais l’avenir. Leurs clés et leurs valeurs restent donc exactement les mêmes d’un tour à l’autre. Les recalculer, c’est du travail refait pour rien.

02

Garder les clés et les valeurs : le cache KV

L’idée du cache KV (KV cache, pour key-value cache) est de mettre de côté les clés et les valeurs de chaque token, dans chaque couche, dès qu’elles sont calculées. À chaque nouveau token, il suffit alors de :

Une étape de génération avec le cache
1. calculer q, k, v pour le seul nouveau token
2. ajouter k et v au cache
3. comparer q à toutes les clés du cache (softmax)
4. faire la somme pondérée de toutes les valeurs du cache

Pourquoi garder K et V, mais pas Q ? Parce que la requête d’un ancien token ne sert plus jamais : elle a déjà produit la sortie de ce token. Seul le nouveau token pose une question ; tous les autres ne font que répondre, avec leur clé et leur valeur. Le résultat est identique au calcul complet : le cache ne change rien à la réponse, il évite seulement de refaire des calculs.

03

Deux phases : prefill et decode

Une génération se déroule en deux temps bien distincts. D’abord, le prefill (le pré-remplissage) : le modèle lit tout le prompt d’un coup. Comme tous ses tokens sont connus, il les traite en parallèle, comme pendant l’entraînement, et remplit le cache avec leurs clés et leurs valeurs.

Ensuite vient le decode (le décodage) : le modèle produit la réponse un token à la fois, car chaque token dépend du précédent. Chaque étape ne traite qu’un seul nouveau token et s’appuie sur le cache.

Attention au double sens du mot « décodage ». La stratégie de décodage de la leçon 09 désigne la façon de choisir un token (glouton ou sampling). La phase de decode dont nous parlons ici désigne le moment où le modèle génère la réponse token par token, après avoir lu tout le prompt d’un coup pendant le prefill. Les deux se combinent : à chaque étape du decode, une stratégie de décodage choisit le token.

Dans le laboratoire, avec le prompt « Phileas Fogg »
prefill : 13 tokens du prompt, en une seule étape
decode  : 8 tokens générés, « et de la », un par étape

projections Q, K, V calculées
sans cache : 13 + 14 + 15 + … + 21 = 153
avec cache : 13 + 1 + 1 + … + 1     =  21

Pour une réponse de 1 000 tokens, l’écart devient énorme : sans cache, il faudrait environ 500 fois plus de projections. Le cache transforme un coût qui grandit comme le carré de la longueur en un coût qui grandit simplement avec elle.

04

Le prix à payer : la mémoire

Rien n’est gratuit : le cache occupe de la mémoire sur la carte graphique (le GPU), et il grandit avec chaque token. Pour chaque token, il faut garder une clé et une valeur de d_model nombres, dans chaque couche.

Combien pèse un nombre ? En informatique, la mémoire se compte en octets. Pour économiser de la place, les modèles en production stockent généralement chaque nombre à virgule sur 2 octets (un format dit « 16 bits »). C’est cette valeur que nous utilisons ci-dessous.

La taille du cache KV
mémoire = 2 × n_layer × d_model × nombre de tokens × octets par nombre

GPT-2 (12 couches, d_model = 768, nombres de 2 octets) :
par token      : 2 × 12 × 768 × 2 = 36 864 octets ≈ 36,9 Ko
1 024 tokens   : ≈ 37,7 Mo, pour une seule conversation

Pour un grand modèle, avec des dizaines de couches, des milliers de dimensions, de très longs contextes et des centaines d’utilisateurs à la fois, le cache peut peser plus lourd que le modèle lui-même. D’où une astuce. Dans la formule, d_model compte toutes les têtes à la fois : les 768 dimensions de GPT-2 regroupent ses 12 têtes d’attention de 64 dimensions chacune (d_model = n_head × d_k, soit 12 × 64 = 768). Souvenez-vous de l’attention multi-têtes de la leçon 06 : chaque tête a ses propres clés et valeurs, comme un carnet de notes personnel, qu’il faut garder dans le cache. Avec 12 ou 32 têtes, cela fait 12 ou 32 carnets par couche. Les modèles récents, comme Llama, font plutôt partager un même carnet K et V à plusieurs têtes : chacune garde sa propre question Q, mais elles consultent les mêmes notes. Si quatre têtes partagent un carnet, il ne reste que 3 carnets de 64 dimensions au lieu de 12 : la dimension gardée dans le cache passe de 768 à 192, et le cache est divisé par quatre. Cette technique s’appelle l’attention à requêtes groupées (grouped-query attention, ou GQA).

05

Mesurer la vitesse

Les deux phases ont des profils très différents, et on les mesure séparément. Le délai du premier token (time to first token, ou TTFT) est le temps entre l’envoi de la requête et l’apparition du premier token : il dépend surtout du prefill, donc de la longueur du prompt.

Ensuite, le débit se mesure en tokens par seconde, ou par son inverse, le temps entre deux tokens (inter-token latency). Il dépend du decode.

Pourquoi ces deux phases vont-elles à des vitesses si différentes ? Imaginez un cuisinier. Pendant le prefill, tous les ingrédients sont déjà sur le plan de travail : la carte graphique a tous les tokens du prompt sous la main et calcule à plein régime. Sa limite, c’est sa vitesse de calcul : on dit que cette phase est limitée par la puissance de calcul (compute-bound).

Pendant le decode, c’est l’inverse. Pour écrire un seul token, la carte graphique doit relire les millions de poids du modèle et tout le cache, rangés dans sa mémoire. Le calcul lui-même est vite fait ; c’est l’aller-retour qui prend du temps, comme un cuisinier qui retournerait au garde-manger pour chaque ingrédient. On dit que cette phase est limitée par la bande passante mémoire (memory-bound), c’est-à-dire par la vitesse à laquelle on peut lire la mémoire.

06

Réutiliser le cache d’une requête à l’autre

Beaucoup de requêtes commencent par le même texte : les mêmes instructions, le même long document, le même historique de conversation. Les fournisseurs d’API en profitent : si le début d’un prompt a déjà été traité récemment, ils réutilisent son cache au lieu de refaire le prefill. Chez OpenAI, ce mécanisme s’appelle le prompt caching : il s’applique automatiquement aux longs prompts et rend les tokens d’entrée déjà en cache plus rapides et moins chers.

Conséquence pratique, très utile pour un développeur : placez les parties fixes d’un prompt (instructions, exemples) au début, et les parties qui changent à la fin. Le cache ne fonctionne que sur un début de texte strictement identique.

07

Observez par vous-même

Dans le laboratoire, tapez Phileas Fogg (avec l’espace final). Le laboratoire génère 8 tokens avec le décodage glouton, puis rejoue toute la génération avec la tête d’attention de la leçon 06.

Faites défiler les étapes avec le curseur : le prefill remplit le cache d’un coup, puis chaque étape de decode ajoute une seule ligne. Regardez le compteur : 153 projections sans cache, 21 avec. Et vérifiez la dernière ligne : l’écart entre les deux méthodes est exactement nul.

08

Les limites de notre exemple

Notre laboratoire n’a qu’une tête et une couche, sur 3 dimensions : le cache tient en quelques dizaines de nombres. Les tokens générés viennent du modèle par comptage, et l’attention du Transformer non entraîné des leçons précédentes. Les calculs de mémoire, eux, utilisent les vrais chiffres de GPT-2. Et nous ne mesurons pas de vrais temps : sur un processeur, avec si peu de nombres, tout est instantané.

Le modèle a maintenant généré sa réponse… sous forme d’identifiants de tokens. Il reste le chemin du retour : comment ces identifiants redeviennent-ils du texte, et pourquoi la réponse s’affiche-t-elle mot après mot au lieu d’arriver d’un bloc ? C’est le sujet de la dernière leçon : du modèle à l’écran, avec la détokenisation et le streaming SSE.

À retenir

Grâce au masque causal, un token ne regarde jamais l’avenir : ses clés et ses valeurs ne changent donc plus une fois calculées. Le cache KV les garde de côté, couche par couche, et chaque nouveau token ne calcule plus que ses propres q, k et v. Le résultat est identique au calcul complet, mais beaucoup plus rapide.

Une génération se fait en deux temps. Le prefill lit tout le prompt en parallèle : sa durée fixe le délai du premier token (TTFT). Le decode écrit ensuite la réponse un token à la fois : sa vitesse se mesure en tokens par seconde.

Le cache échange de la mémoire contre de la vitesse : pour GPT-2, il pèse environ 36,9 Ko par token, et des techniques comme GQA le réduisent. Pour un développeur, l’astuce pratique est le prompt caching : placer les parties fixes au début du prompt permet de réutiliser le cache d’une requête à l’autre.

Prompt caching · OpenAI ↗
Caching · Hugging Face Transformers ↗

VÉRIFIER SES CONNAISSANCES

Valider cette étape

Répondez aux trois questions pour débloquer la suite. Vous pouvez réessayer autant de fois que nécessaire.

Chargement de la progression…

Mise en ligne le

ESPACE DE PRATIQUE

Le laboratoire

Regardez le cache se remplir, token après token.

● EN DIRECT
01

Votre texte

MODIFIABLE

Génération en cours…

À retenir

Le prefill lit tout le prompt en parallèle et remplit le cache ; chaque étape de decode n’ajoute ensuite qu’une ligne, celle du nouveau token, dont la requête parcourt toutes les clés du cache. Le résultat est identique au calcul complet.

Ce laboratoire utilise la tête d’attention de la leçon 06, sur 3 dimensions et une seule couche, et des tokens générés par le modèle par comptage. Le calcul de mémoire utilise les vrais chiffres de GPT-2.

06

Pour aller plus loin

Le cache KV et la latence sont au cœur du coût et de la vitesse des LLM en production. Ces ressources officielles montrent comment ils sont gérés.