đ Table des matiĂšres
Cliquez sur une section pour y accéder directement
đ Pipeline
Vue d'ensemble du flux
âïž Tokenizer
Texte â IDs
đ Embedding
IDs â Vecteurs
đïž Transformer
Architecture d'une couche
đïž Attention
Q, K, V expliqués
đ§ FFN
Le "cerveau" du modĂšle
đ Layers
80 couches en profondeur
đ Logits
Vecteur â ProbabilitĂ©s
đČ Sampling
Température, top-p
đŸ KV Cache
Ăviter les recalculs
đ§© MoE
Mixture of Experts
đ§ Functions
Tool calling, MCP
đ§ Reasoning
o1, R1, CoT
đą PrĂ©cision
FP16, INT8, INT4
đŸ MĂ©moire
Calculs VRAM
đ Training
SFT, RLHF, DPO
⥠Optim
Flash Attention, vLLM
đ Pipeline Complet
Le chemin du texte à la réponse générée
"Le chat mange" â PREFILL (parallĂšle) â "sa" â DECODE (sĂ©quentiel) â "pĂątĂ©e." â <EOS>
Prefill = traiter tout le prompt en parallÚle, GPU saturé (compute-bound). Decode = générer un token à la fois, on recharge 140 GB de poids par token (memory-bound). Le goulot d'étranglement n'est pas le calcul mais la bande passante mémoire (~3 TB/s sur H100).
đ Les 9 Ă©tapes du pipeline
"Le chat mange" (user)
â
1. TOKENIZER : texte â IDs [2356, 7541, 64867]
â
2. EMBEDDING : IDs â vecteurs [3 Ă 8192]
â
3. POSITIONAL : + position (RoPE)
â
4. PREFILL (parallĂšle, compute-bound) :
ââ 80 couches Ă [Attention â FFN]
ââ Stocke K,V dans le cache
â
5. LOGITS : dernier vecteur â 128K scores
â
6. SOFTMAX : scores â probabilitĂ©s
â
7. SAMPLING : top-p + tempĂ©rature â "sa"
â
8. DECODE (séquentiel, memory-bound) :
ââ "sa" traverse 80 couches
ââ KV cache rĂ©utilisĂ© (pas recalculĂ©)
ââ K,V de "sa" ajoutĂ©s au cache
ââ â "pĂątĂ©e" â "." â <EOS>
â
9. DETOKENIZER : IDs â "sa pĂątĂ©e."
⥠Pourquoi le decode est lent (memory-bound)
Pour générer 1 seul token, il faut :
âą Charger 140 GB de poids (70B Ă 2 bytes) âą Faire trĂšs peu de calcul (1 token Ă 8192 dims) Ratio calcul/transfert trĂšs faible ! H100 : 3 TB/s bande passante â 140 GB / 3 TB/s â 47 ms minimum par token â ~21 tokens/sec thĂ©orique (1 batch) Avec batching (8 requĂȘtes) : â MĂȘme 140 GB chargĂ©s, 8Ă plus de calcul â ~168 tokens/sec (8 Ă 21)
Le batching amortit le coĂ»t mĂ©moire â c'est pour ça que vLLM bat llama.cpp en throughput.
âïž Tokenization
Transformer le texte en nombres
"Le chat mange" â ["Le", "chat", "mange"] â [2356, 7541, 64867]
Le tokenizer dĂ©coupe le texte en sous-mots (tokens) via l'algorithme BPE (Byte Pair Encoding). Chaque token reçoit un ID unique dans un vocabulaire de 128K entrĂ©es. Un mot peut devenir 1 ou plusieurs tokens : "aujourd'hui" â 3-4 tokens, "the" â 1 token.
đ·ïž Tokens spĂ©ciaux
En plus des tokens de texte, il existe des tokens de contrĂŽle :
| Token | RĂŽle | Exemple |
|---|---|---|
| <BOS> | Begin Of Sequence | Démarre la génération |
| <EOS> | End Of Sequence | ArrĂȘte la gĂ©nĂ©ration |
| <PAD> | Padding | Remplissage pour batch |
| <UNK> | Unknown | Token inconnu (rare) |
| [INST]...[/INST] | Instruction | Délimite user/assistant |
<EOS> est crucial : c'est lui qui dit au modĂšle de s'arrĂȘter. Sans lui, le modĂšle continuerait indĂ©finiment.
đ«đ· Pourquoi le français consomme ~1.5Ă plus de tokens ?
Les tokenizers sont entraßnés sur des corpus majoritairement anglais.
"hello" â 1 token "bonjour" â 2 tokens (bon+jour) "today" â 1 token "aujourd'hui" â 3-4 tokens
ConsĂ©quence : contexte 8K tokens â 6000 mots anglais mais ~4000 mots français.
đ Embedding
Transformer les IDs en vecteurs sémantiques
[2356, 7541, 64867] â table[ID] â 3 vecteurs de 8192 dimensions
L'embedding est une simple lookup dans une table : table[ID] = vecteur. Chaque token devient un vecteur de 8192 dimensions. Les mots similaires ont des vecteurs proches dans cet espace. On ajoute le positional encoding (RoPE) pour que le modĂšle sache l'ordre des mots.
đŻ Pourquoi pas juste les IDs ?
Les IDs sont arbitraires : "chat" = 7541, "chien" = 9871 â aucune relation mathĂ©matique !
Avec embeddings : "chat" â [0.8, 0.3, -0.2, ...] â "chien" â [0.7, 0.4, -0.1, ...] â PROCHES ! "voiture"â [-0.5, 0.9, 0.2, ...] LOIN
Le fameux : roi - homme + femme â reine
đïž Architecture Transformer
La structure d'une couche
Matrice [3Ă8192] â 80 couches identiques (Attention+FFN) â Matrice [3Ă8192] transformĂ©e
Une couche = Attention â FFN, toujours dans cet ordre. L'Attention permet aux tokens de communiquer entre eux (20% des params). Le FFN transforme chaque token individuellement â c'est lĂ que sont stockĂ©es les "connaissances" (80% des params). La connexion rĂ©siduelle (+) prĂ©serve l'info originale Ă travers les 80 couches.
đïž MĂ©canisme d'Attention
Comment les tokens se regardent
"mange" cherche son sujet â score Ă©levĂ© avec "chat" (85%) â rĂ©cupĂšre l'info de "chat"
Q (Query) = ce que le token cherche. K (Key) = l'Ă©tiquette de chaque token. V (Value) = le contenu Ă rĂ©cupĂ©rer. Le score Q Ă K dĂ©termine "qui regarde qui". Softmax transforme en probabilitĂ©s. RĂ©sultat = somme pondĂ©rĂ©e des V. Le causal mask empĂȘche de voir les tokens futurs.
đ§ Multi-Head Attention
Plusieurs "tĂȘtes" regardent en parallĂšle, chacune spĂ©cialisĂ©e :
TĂȘte 1 : Relations sujet-verbe TĂȘte 2 : CorĂ©fĂ©rences (sa â chat) TĂȘte 3 : ProximitĂ© syntaxique LLaMA 70B : 64 tĂȘtes Ă 128 dimensions
⥠GQA : Grouped-Query Attention
| Type | Q heads | KV heads | KV Cache |
|---|---|---|---|
| MHA | 64 | 64 | 100% |
| GQA | 64 | 8 | 12.5% |
| MQA | 64 | 1 | 1.5% |
GQA = compromis optimal, utilisé par LLaMA 2+.
đ§ Feed-Forward Network (FFN)
Le "cerveau" qui stocke les connaissances
Vecteur "mange" [8192] â expansion [28672] â SwiGLU â contraction [8192] enrichi
Le FFN expand la dimension Ă3.5 (8192 â 28672), applique l'activation SwiGLU, puis contracte. Chaque token passe individuellement (pas de communication). C'est lĂ que sont stockĂ©es les "connaissances" : chaque neurone encode un micro-concept (capitales, syntaxe Python, termes mĂ©dicaux...).
đ§ Que font les neurones ?
Chaque neurone de la couche cachée est un détecteur de patterns :
Neurone 4821 : s'active sur "capitale de..." Neurone 12045 : s'active sur du code Python Neurone 8923 : s'active sur des termes médicaux Neurone 15678 : s'active sur des négations
Le modÚle a appris ces patterns pendant le pre-training. C'est pourquoi le FFN représente 80% des paramÚtres : c'est la "mémoire" du modÚle.
âïž SwiGLU vs ReLU
SwiGLU (Swish-Gated Linear Unit) est l'activation moderne :
ReLU(x) = max(0, x) â coupe les nĂ©gatifs SwiGLU(x) = swish(xWâ) â (xWâ) â gate + smooth âą Plus expressif que ReLU âą Meilleure propagation du gradient âą UtilisĂ© par LLaMA, Mistral, Gemma
đ Calcul des paramĂštres FFN
LLaMA 70B FFN (par couche) : W1 (gate) : 8192 Ă 28672 = 235M params W2 (down) : 28672 Ă 8192 = 235M params W3 (up) : 8192 Ă 28672 = 235M params Total FFN : 705M params/couche 80 couches Ă 705M = 56B params (80% du total)
đ TraversĂ©e des 80 Couches
Spécialisation en profondeur
"Le chat mange" traverse 80 couches : syntaxe â grammaire â sĂ©mantique â raisonnement
Les couches se spécialisent : les basses traitent la syntaxe, les hautes le raisonnement. L'info circule via le residual stream : chaque couche ajoute son Πsans perdre l'info précédente. Sortie finale = accumulation de contributions, pas remplacement.
đ Le Residual Stream = une riviĂšre
Imagine le flux d'information comme une riviĂšre qui traverse 80 villages (couches) :
âââââââââââ
Embedding ââââââââââ¶â Couche 1ââââŹâââââââââââââââ¶
(source) â Attn+FFNâ â +Îâ (affluent)
âââââââââââ â
âŒ
âââââââââââ
ââââââ¶â Couche 2ââââŹâââââââââââââââ¶
â Attn+FFNâ â +Îâ (affluent)
âââââââââââ â
âŒ
...80 couches...
â
âŒ
Logits
Chaque couche est comme un affluent qui enrichit la riviÚre sans remplacer ce qui coule déjà . La riviÚre principale (residual) transporte l'info originale + toutes les contributions.
đ Pourquoi c'est crucial ?
Sans connexions résiduelles, l'info de l'embedding serait perdue aprÚs quelques couches (vanishing gradient). Avec elles :
âą L'info originale traverse directement âą Chaque couche AJOUTE au lieu de REMPLACER âą Gradient stable pour le training âą Le modĂšle peut "skip" des couches inutiles
đ Ce que fait chaque "zone" de couches
| Couches | RĂŽle | Exemple |
|---|---|---|
| 1-20 | Syntaxe locale | "le" â article, nom attendu |
| 20-40 | Structure grammaticale | "chat" = sujet de "mange" |
| 40-60 | SĂ©mantique | "mange" â contexte nourriture |
| 60-80 | Raisonnement haut niveau | Qu'est-ce qui suit logiquement ? |
đ Logits & Softmax
Du vecteur aux probabilités
Vecteur "mange" [8192] â LM Head â 128K logits â softmax â "sa": 62%
Le dernier vecteur est projetĂ© vers 128K scores bruts (logits) â un par token du vocabulaire. Softmax transforme ces scores en probabilitĂ©s (somme = 100%). Gros scores â grosses probas, petits â quasi-zĂ©ro. Puis vient le sampling pour choisir.
đČ Sampling
Choisir le prochain token
Probas [62%, 18%, 12%...] â tempĂ©rature 0.7 â top-p 0.9 â tirage â "sa" â
TempĂ©rature : ajuste les Ă©carts. Basse (0.2) = dĂ©terministe, haute (1.5) = crĂ©atif/risquĂ©. Top-p (nucleus) : garde les tokens jusqu'Ă p% cumulĂ©, Ă©limine les absurditĂ©s. Ensemble : tempĂ©rature redistribue, top-p filtre â crĂ©atif mais pas fou.
đïž Combinaisons recommandĂ©es
| Usage | Température | Top-p |
|---|---|---|
| Code / Maths | 0.0 - 0.3 | 0.9 |
| Assistants | 0.7 | 0.9 |
| Créatif | 1.0 - 1.3 | 0.95 |
đŸ KV Cache
Ăviter les recalculs pendant la gĂ©nĂ©ration
Prefill : Kâââ, Vâââ stockĂ©s â gĂ©nĂšre "sa" â ajoute Kâ, Vâ â gĂ©nĂšre "pĂątĂ©e"...
Pour gĂ©nĂ©rer le token N, l'attention regarde les tokens 1 Ă N-1. Sans cache : recalculer K,V pour TOUS (O(NÂČ)). Avec cache : K,V stockĂ©s, on calcule seulement pour le nouveau (O(N)). On stocke K et V, pas Q (le nouveau gĂ©nĂšre sa propre Q).
đ Calcul de la taille
LLaMA 70B, contexte 4K : Par token : 2 Ă 80 Ă 8 Ă 128 Ă 2 = 327 KB 4096 tokens : 327 KB Ă 4096 â 1.3 GB 8 requĂȘtes batch : 1.3 GB Ă 8 â 10 GB
đ§© Mixture of Experts (MoE)
Plus de paramĂštres, mĂȘme compute
"mange" â Router choisit Expert 2 + Expert 5 â 0.7ĂE2 + 0.3ĂE5 â output
Au lieu d'un seul gros FFN, on a 8 experts spĂ©cialisĂ©s. Un router sĂ©lectionne les 2 meilleurs pour chaque token. Avantage : plus de paramĂštres (47B) mais mĂȘme compute (13B actifs). InconvĂ©nient : tous les poids en VRAM quand mĂȘme.
đ§ Function Calling, Tools, MCP & Agents
Le LLM qui interagit avec le monde
"MĂ©tĂ©o Ă Paris ?" â LLM gĂ©nĂšre JSON â systĂšme appelle API â rĂ©sultat â LLM rĂ©pond
Tool = une fonction que le LLM peut appeler. Function Calling = le LLM génÚre un JSON structuré pour déclencher un tool. MCP = protocole standardisé pour exposer des tools. Agent = LLM + tools + boucle d'exécution autonome.
đ ïž Tool (Outil)
Un Tool est simplement une fonction que le LLM peut décider d'utiliser :
Exemples de tools : âą get_weather(city) â API mĂ©tĂ©o âą search_web(query) â Moteur de recherche âą run_python(code) â ExĂ©cution de code âą read_file(path) â Lecture de fichier âą send_email(to, subject, body) â Envoi d'email
Le tool est décrit au LLM (nom, paramÚtres, description) mais exécuté par le systÚme hÎte.
đ Function Calling
Function Calling = la capacité du LLM à générer un appel de fonction structuré :
User : "Quelle météo à Paris demain ?"
LLM génÚre (au lieu de texte) :
{
"function": "get_weather",
"arguments": {
"city": "Paris",
"date": "2025-01-02"
}
}
â Le systĂšme exĂ©cute get_weather("Paris", "2025-01-02")
â RĂ©sultat renvoyĂ© au LLM
â LLM formule la rĂ©ponse finale
C'est un mode de sortie du LLM, pas une exécution. Le LLM ne fait que générer du JSON.
đ MCP â Model Context Protocol
MCP (Anthropic) est un protocole standardisé pour exposer des tools :
Avant MCP : âą Chaque app dĂ©finit ses tools diffĂ©remment âą IntĂ©gration custom Ă chaque fois âą Pas de rĂ©utilisation Avec MCP : âââââââââââââââ âââââââââââââââ â Claude.ai ââââââ¶â MCP Server ââââ¶ Google Drive â ou autre â â (standard) ââââ¶ Slack â client â â ââââ¶ GitHub âââââââââââââââ ââââââââââââââââââ¶ Base de donnĂ©es âą Un serveur MCP = N tools exposĂ©s âą Un client MCP = peut utiliser N serveurs âą Protocol JSON-RPC standardisĂ©
Analogie : MCP est aux tools ce que USB est aux pĂ©riphĂ©riques â un standard de connexion.
đ€ Agent
Un Agent = LLM + Tools + Boucle autonome :
Agent vs Chatbot simple :
CHATBOT :
User â LLM â RĂ©ponse (1 tour)
AGENT :
User â LLM â "Je dois chercher X"
â
Tool: search(X)
â
LLM â "Maintenant je dois lire Y"
â
Tool: read(Y)
â
LLM â "J'ai assez d'info, voici la rĂ©ponse"
â
Réponse finale
L'agent décide seul quels tools utiliser et dans quel ordre. Il boucle jusqu'à avoir la réponse.
đ Comparaison rĂ©sumĂ©e
| Concept | C'est quoi ? | Qui l'exécute ? |
|---|---|---|
| Tool | Une fonction disponible | Le systĂšme hĂŽte |
| Function Call | JSON généré par LLM | LLM génÚre, systÚme exécute |
| MCP | Protocole standard | Serveur MCP |
| Agent | LLM + tools + boucle | Autonome (multi-tours) |
đ Exemple concret d'Agent
User : "Trouve les 3 meilleurs restos italiens prĂšs de chez moi
et réserve une table pour 2 demain soir"
Agent (Claude Code, Cursor, etc.) :
1. đ§ "Je dois d'abord localiser l'utilisateur"
â Tool: get_location() â "Paris 11Ăšme"
2. đ§ "Maintenant chercher les restos"
â Tool: search_restaurants("italien", "Paris 11")
â [Lista Ristorante, Ober Mamma, Pink Mamma...]
3. đ§ "Je dois vĂ©rifier les notes"
â Tool: get_reviews(["Lista", "Ober Mamma", "Pink Mamma"])
â Scores et avis
4. đ§ "Maintenant rĂ©server"
â Tool: book_table("Ober Mamma", "2025-01-02", "20:00", 2)
â Confirmation #12345
5. đ§ "J'ai tout, je peux rĂ©pondre"
â "J'ai rĂ©servĂ© chez Ober Mamma demain 20h pour 2.
Confirmation #12345. Bon appétit !"
5 appels de tools, décidés autonomement par l'agent.
đ§ Reasoning
Les modÚles qui "réfléchissent" (o1, R1)
"17Ă28 ?" â <think> 17Ă30-17Ă2 = 510-34 </think> â "476" â
Les modĂšles reasoning gĂ©nĂšrent une chaĂźne de pensĂ©e (CoT) avant de rĂ©pondre. Plus de tokens gĂ©nĂ©rĂ©s = plus de "compute Ă l'infĂ©rence" = meilleures rĂ©ponses sur des problĂšmes complexes. Le CoT peut ĂȘtre visible (R1) ou cachĂ© (o1). C'est une nouvelle dimension de scaling.
đą Formats de PrĂ©cision
FP32, FP16, INT8, INT4...
70B params Ă 2 bytes (FP16) = 140 GB | Ă 0.5 byte (INT4) = 35 GB
FP16/BF16 : standard pour l'inférence (2 bytes/param). INT8 : divise par 2 avec peu de perte. INT4/NF4 : divise par 4, perte qualité mesurable mais 70B tourne sur 2à RTX 4090 ! La quantization est un trade-off mémoire vs qualité.
đŸ MĂ©moire GPU
Combien de VRAM faut-il ?
LLaMA 70B FP16 : 140 GB poids + ~10 GB KV cache (8 req Ă 4K) = ~150 GB VRAM
Poids = params Ă bytes (70B Ă 2 = 140 GB, pas 70 !). KV Cache grandit avec contexte Ă batch. Solutions : Quantization (INT4 â 35 GB), Tensor Parallelism (split sur N GPUs), Offloading (CPU/disk).
đ VRAM selon prĂ©cision
| Précision | Bytes/param | 70B | 13B |
|---|---|---|---|
| FP32 | 4 | 280 GB | 52 GB |
| FP16/BF16 | 2 | 140 GB | 26 GB |
| INT8 | 1 | 70 GB | 13 GB |
| INT4 | 0.5 | 35 GB | 6.5 GB |
đ Training & Fine-tuning
Du pre-training au déploiement optimisé
Pre-train â SFT â RLHF/DPO â LoRA (optionnel) â Merge â AWQ/GPTQ â Deploy
Pre-training : prĂ©dire le token suivant sur TB de texte. SFT : fine-tuning instructionârĂ©ponse. RLHF/DPO : aligner sur prĂ©fĂ©rences humaines. LoRA : adapter sans toucher les poids. Quantization : compresser pour le dĂ©ploiement.
đ§ LoRA â Low-Rank Adaptation
ProblĂšme : Fine-tuner 70B params = modifier 70 milliards de poids â impossible en mĂ©moire.
Solution : Ajouter des petites matrices (adapters) sans toucher les poids originaux :
W' = W + ÎW = W + (A Ă B) W : poids originaux (frozen) A : matrice (d Ă r) â r = rang (64-128) B : matrice (r Ă d)
Pour une couche 4096Ă4096 = 16.7M params :
| Approche | Params entraßnés | Ratio |
|---|---|---|
| Full fine-tune | 16.7M | 100% |
| LoRA r=64 | 524K | 3% |
Pourquoi ça marche ? Les modifications pour adapter un LLM vivent dans un sous-espace de faible dimension.
⥠QLoRA â Quantized LoRA
Charge le modĂšle base en 4-bit (frozen) + adapters LoRA en FP16 (trainable) :
MĂ©moire = Base(4-bit frozen) + LoRA(FP16 trainable) 70B en QLoRA â 35-40 GB (vs 140+ GB full fine-tune)
â Fine-tuner LLaMA 70B sur 1Ă A100 80GB devient possible !
đ Quantization â Compresser pour l'inference
RĂ©duire FP16 â INT4 divise la mĂ©moire par 4, mais quantization naĂŻve = perte de qualitĂ©.
Observation clé : tous les poids ne sont pas égaux. Certains ont un impact énorme sur les activations, d'autres trÚs peu.
đŻ AWQ â Activation-aware Weight Quantization
Identifie les poids saillants via les activations sur un dataset de calibration :
Saillance(w) = |w| Ă ||activation||
Les poids importants (~1%) sont protégés de la quantization agressive.
Processus : 1. Charger modÚle FP16 2. Passer dataset de calibration 3. Mesurer activations par couche 4. Identifier poids saillants 5. Quantifier en préservant les importants 6. Sauvegarder INT4
â ïž Calibration importante : utiliser des samples reprĂ©sentatifs de ton use-case !
âïž GPTQ â Post-Training Quantization
Quantifie couche par couche avec compensation d'erreur (méthode OBQ/OBS) :
Pour chaque couche : 1. Quantifier un groupe de poids 2. Mesurer l'erreur introduite 3. Ajuster les poids restants pour compenser 4. Répéter
Plus lent à générer qu'AWQ, mais souvent légÚrement meilleure qualité.
đ Comparaison AWQ vs GPTQ
| Aspect | AWQ | GPTQ |
|---|---|---|
| Vitesse quantization | Rapide | Lent |
| Qualité | TrÚs bonne | Excellente |
| Inference speed | Optimisé batch | Standard |
| Calibration | Critique | Moins critique |
| Support vLLM | Natif (GEMM) | Natif |
Recommandation : AWQ pour vLLM en production, GPTQ si qualité max requise.
đ Pipeline complet fine-tune + deploy
ModĂšle base (FP16, 140GB)
â
⌠QLoRA fine-tuning
âââââââââââ
â LoRA â â EntraĂźne adapters sur ta tĂąche
â adaptersâ Base frozen en 4-bit
ââââââŹâââââ
â
⌠Merge
âââââââââââ
â Merge â â Fusionne adapters dans le modĂšle
ââââââŹâââââ
â
⌠Quantization
âââââââââââ
â AWQ â â Avec calibration sur ton domaine
ââââââŹâââââ
â
âŒ
ModĂšle final (INT4, 35GB)
â
⌠Serving
âââââââââââ
â vLLM â â Inference optimisĂ©e
âââââââââââ
⥠Optimisations
Techniques pour aller plus vite
Flash Attention (2-4Ă) | Speculative Decode (2-3Ă) | Paged Attention (+24Ă throughput) | Continuous Batching
⥠Flash Attention
Calcul par blocs en SRAM, Ă©vite matrice NĂN en HBM. 2-4Ă plus rapide, contextes plus longs.
đź Speculative Decode
Petit modÚle "devine" K tokens, gros vérifie en batch. 2-3à speedup, qualité identique.
đ Paged Attention
KV Cache par pages (comme mémoire virtuelle). +24à throughput via vLLM.
đŠ Continuous Batching
Insertion dynamique dĂšs qu'une requĂȘte finit. GPU toujours occupĂ©.
đŸ GQA
Partage K,V entre tĂȘtes Q. KV Cache Ă·4 Ă Ă·8, qualitĂ© ~identique.
đ Quantization
GPTQ, AWQ, NF4. Mémoire ÷2 à ÷8, trade-off qualité.
L'inférence est memory-bound (on attend les données). Les optimisations ciblent : réduire les accÚs mémoire (Flash Attention), paralléliser la vérification (Speculative), mieux gérer la mémoire (Paged), maximiser l'utilisation GPU (Continuous Batching).
⥠Le problĂšme : la matrice NĂN
L'attention standard calcule une matrice Q à Kᔠde taille N à N (N = longueur séquence) :
Contexte 32K tokens : Matrice attention = 32K Ă 32K = 1 milliard de floats En FP16 = 2 GB juste pour cette matrice ! â Doit ĂȘtre stockĂ©e en HBM (lent) â Limite la longueur de contexte
đĄ La solution : calcul par blocs
Flash Attention ne matérialise jamais la matrice complÚte :
Au lieu de : 1. Calculer toute la matrice QĂKá” (NĂN en HBM) 2. Appliquer softmax 3. Multiplier par V Flash Attention : 1. Charger un bloc de Q, K, V en SRAM (20MB, ultra-rapide) 2. Calculer attention sur ce bloc 3. Accumuler le rĂ©sultat 4. Passer au bloc suivant â Jamais plus de quelques MB en mĂ©moire â 2-4Ă plus rapide â Contextes 100K+ possibles
đ HiĂ©rarchie mĂ©moire GPU
| Type | Taille | Bande passante | Usage |
|---|---|---|---|
| Registres | ~KB | ~20 TB/s | Calculs immédiats |
| SRAM | 20 MB | ~19 TB/s | Flash Attention |
| HBM | 80 GB | ~3 TB/s | Poids, KV Cache |
Flash Attention exploite le SRAM (6Ă plus rapide que HBM) en ne gardant que des blocs.
đ Le problĂšme : fragmentation du KV Cache
Sans Paged Attention, chaque requĂȘte rĂ©serve un bloc contigu de mĂ©moire pour son KV Cache :
RequĂȘte A : [ââââââââââââââââ________] 16K allouĂ©s, 12K utilisĂ©s RequĂȘte B : [ââââââââ____] 12K allouĂ©s, 8K utilisĂ©s RequĂȘte C : [ââââââââââââââââââââ____] 20K allouĂ©s, 18K utilisĂ©s â Gaspillage Ă©norme (fragmentation interne) â Impossible de servir plus de requĂȘtes
đĄ La solution : mĂ©moire virtuelle pour LLM
Paged Attention alloue le KV Cache par pages (comme un OS) :
Pages de 16 tokens chacune : RequĂȘte A : page 0 â page 3 â page 7 â page 12 RequĂȘte B : page 1 â page 5 â page 8 RequĂȘte C : page 2 â page 4 â page 6 â page 9 â page 11 â Pas de fragmentation â Allocation dynamique â Pages libĂ©rĂ©es dĂšs que la requĂȘte finit â +24Ă throughput vs naĂŻf !
đ vLLM = Paged Attention + Continuous Batching
Continuous Batching : âą RequĂȘte A finit â sa place est immĂ©diatement rĂ©utilisĂ©e âą Nouvelle requĂȘte D s'insĂšre sans attendre le batch llama.cpp : 1 requĂȘte Ă la fois (simple, CPU-friendly) vLLM : N requĂȘtes en parallĂšle (optimisĂ© serveur) Pour du self-hosting en production â vLLM Pour du dev local â llama.cpp / Ollama