Optimisation Avancée des LLM : Architecture Interne et Stratégies de Performance en Production
Plongez dans les mécanismes internes des transformers et maîtrisez les techniques d'optimisation critiques pour déployer des LLM performants en production. Ce cours décortique l'architecture, révèle les goulots d'étranglement et fournit des stratégies éprouvées pour maximiser l'efficacité.
1. Anatomie Interne des Transformers : De l'Embedding à la Génération
Définition
L'architecture transformer repose sur un mécanisme d'attention auto-régressive qui traite les séquences de tokens en parallèle pendant l'entraînement, puis de façon autorisatrice durant l'inférence. Chaque couche contient des têtes d'attention multi-heads, des réseaux feed-forward avec activations non-linéaires, et des mécanismes de normalisation critiques pour la stabilité.
Analogie Pédagogique
Imaginez une équipe de traducteurs simultanés (heads d'attention) dans une salle. Chacun se concentre sur certains mots et leurs relations (queries, keys, values). Ils travaillent en parallèle, puis un superviseur (feed-forward) reformule les insights combinés avant de passer à l'équipe suivante. La chaîne complète crée progressivement une compréhension nuancée du texte.
Tableau Comparatif : Composants et Responsabilités
| Composant | Fonction Primaire | Coût Mémoire | Coût Computationnel | Optimisabilité |
|---|---|---|---|---|
| Embedding Layer | Conversion token→vecteur | O(V×d) | O(1) par token | Basse (fixe) |
| Multi-Head Attention | Modélisation des dépendances | O(n×d) | O(n²×d) | Très haute |
| Feed-Forward Networks | Non-linéarité et expansion | O(d×d_ff) | O(n×d×d_ff) | Haute |
| Layer Normalization | Stabilité numérique | O(d) | O(n×d) | Faible |
| Positional Encoding | Information positionnelle | O(n×d) | O(1) | Moyenne |
Astuce d'Expert
Exploitez la détection des "attention heads mortes" - certaines têtes convergent vers des patterns statiques. Identifier et analyser ces têtes révèle souvent des optimisations possibles : vous pouvez les supprimer (pruning) ou les recycler pour d'autres tâches. Utilisez les statistiques d'entropie des distributions d'attention pour quantifier ce phénomène.
⚠️ Attention Critique
Le coût quadratique de l'attention O(n²) n'est jamais vraiment éliminé - seul le contexte de la fenêtre peut être réduit. Les variantes "linéarisant" l'attention (linear attention, kernel-based) modifient les propriétés mathématiques de la convergence. Vérifiez toujours la capacité d'expressivité avant d'optimiser agressivement.
2. Quantization et Compression : Réduire Sans Casser
Définition
La quantization convertit les poids et activations de précision flottante (float32, float16) vers des représentations entières de plus basse précision (int8, int4, bfloat16). La post-training quantization (PTQ) s'applique après entraînement, tandis que la quantization-aware training (QAT) intègre les effets de la quantization durant l'apprentissage pour une plus grande fidélité.
Analogie Pédagogique
Pensez à la quantization comme la compression d'une image haute résolution en JPEG. Vous réduisez les données brutes, mais les détails critiques doivent survivre. Un JPEG agressif crée des artefacts visibles ; une compression intelligente préserve les contours importants. De même, quantizer intelligemment préserve les "contours" décisionnels du modèle.
Tableau Détaillé : Schémas de Quantization
| Schéma | Précision | Perte Typique (Accuracy) | Compression | Use Case | Complexité |
|---|---|---|---|---|---|
| PTQ Int8 Asymétrique | int8 | 0.5-2% | 4× | Inférence CPU/edge | Basse |
| PTQ Int4 Groupwise | int4 | 1-3% | 8× | Mobile, embeddings | Moyenne |
| QAT Mixed-Precision | int8/int4 | 0.1-0.5% | 6× | Critique performance | Haute |
| GPTQ (Quantization-aware) | int4 (groupé) | 0.2-0.8% | 8× | LLM 7B-13B | Haute |
| Activation Quantization | int8 activations | 1-5% | 2× | Réduction mémoire | Moyenne |
Astuce d'Expert
Utilisez la "calibration par percentile" plutôt que par min-max pour les outliers. Identifiez les activations qui ont des queues de distribution longues (tokens rares, gradients expliquant) ; quantizez-les séparément. Pour GPTQ spécifiquement, calculez l'ordre de Hessian Schur pour prioriser les poids critiques lors de la quantization groupe par groupe.
⚠️ Attention Critique
Les couches early (embedding, premières couches d'attention) sont souvent plus sensibles à la quantization que les couches finales. Ne compressez jamais uniformément. Les activations sont plus difficiles à quantizer que les poids ; les approches dynamiques (per-batch) augmentent la latence d'inférence. Testez systématiquement sur des benchmarks représentatifs de votre domaine applicatif.
3. KV-Cache, Paging et Optimisation Mémoire en Inférence
Définition
Le KV-cache (Key-Value cache) stocke les clés et valeurs pré-calculées des tokens précédents pour éviter de les recalculer durant l'inférence autoégressive. Cela réduit le coût de chaque pas de décodage de O(n²×d) à O(1×d) asymptotiquement, mais introduit une pression mémoire croissante O(n×d×num_layers×batch_size). Le paging (comme dans vLLM) traite le KV-cache comme de la mémoire virtuelle paginée pour fragmenter et réutiliser efficacement l'espace.
Analogie Pédagogique
Imaginez un scénario de restaurant : lors du premier appel (requête initiale), le serveur écoute chaque client entièrement (attention complète). Ensuite, il prend note (KV-cache) des commandes précédentes. Pour les appels suivants, il ne consulte que ses notes au lieu de réécouter. Le paging est comme utiliser un cahier au lieu de mémoriser : vous pouvez utiliser un cahier partagé par plusieurs tables (batch), paginé sur le disque si nécessaire.
Tableau Comparatif : Stratégies de Gestion Mémoire
| Stratégie | Pic Mémoire | Latence Token | Utilisation GPU | Fragmentation | Scalabilité Batch |
|---|---|---|---|---|---|
| KV-Cache Standard | O(n×d×L×B) | Basse (très) | Très haute | Moyenne | Faible (OOM rapide) |
| KV-Cache avec Recompute | O(√(n)×d×L×B) | Moyenne | Haute | Basse | Moyenne |
| Paging (vLLM) | O(n×d×L×B/page_size) | Basse+ | Très haute | Très basse | Très élevée |
| Ring Buffer KV | O(context_window×d×L×B) | Basse | Très haute | Nulle | Très élevée |
| Sparse Attention KV | O(sparse_ratio×n²×d×L) | Basse/Moyenne | Moyenne | Faible | Élevée |
Astuce d'Expert
Implémentez un "scheduler de paging" adaptatif : au lieu d'utiliser une taille de page fixe, ajustez dynamiquement la granularité du paging en fonction du ratio hit-rate du cache. Si vous générez des batches hétérogènes (longueurs d'entrée/sortie variées), utilisez le "continuous batching" avec préemption : les séquences courtes terminent rapidement et libèrent la mémoire pour les longues. Mesurez le "effective batch size" (tokens/seconde) plutôt que le nombre brut de séquences.
⚠️ Attention Critique
Le paging introduit des accès mémoire non-contiguës, réduisant potentiellement la bande passante effective. Les latences de swap disque (si débordement GPU→CPU) peuvent devenir dominantes. Le "batch reordering" (traiter d'abord les courtes séquences) crée une variance importante en latence pour les utilisateurs. Documentez toujours le "latency SLA" vs "throughput trade-off" que votre architecture impose.
4. Fine-tuning Efficace : LoRA, Adapters et Mixing of Experts Dynamiques
Définition
Le fine-tuning pleine dimension met à jour tous les paramètres du LLM, consommant énormément de mémoire et de temps. Les méthodes efficaces (LoRA, adapters) introduisent des modules paramétrés supplémentaires de dimension réduite. LoRA (Low-Rank Adaptation) décompose les mises à jour de poids en produits de deux matrices de rang faible : ΔW = AB^T où A∈ℝ^(d×r) et B∈ℝ^(d×r) avec r << d. Les Mixture-of-Experts dynamiques ajoutent une couche de routage pour activer sélectivement des experts spécialisés.
Analogie Pédagogique
Imaginez un système de tuteurs spécialisés. Au lieu de réentraîner chaque tuteur (fine-tuning complet), vous envoyez des "instructions de correction" minimalistes (LoRA) à leurs notes existantes. Ces corrections capturent les principes essentiels de votre domaine sans reécrire les manuels entiers. Pour les Mixture-of-Experts, certains tuteurs se spécialisent en mathématiques, d'autres en langues ; un superviseur (router) dirige chaque étudiant vers l'expert approprié.
Tableau Comparatif : Méthodes de Fine-tuning
| Méthode | Params Trainables | Mémoire GPU | Vitesse Training | Flexibilité | Qualité Finale |
|---|---|---|---|---|---|
| Full Fine-tuning | 100% | Très haute | Basse | Très haute | Excellente |
| LoRA (r=8) | 0.1-0.5% | Basse | Très haute | Haute | Très bonne |
| LoRA (r=64) | 1-2% | Basse-Moyenne | Très haute | Très haute | Excellente |
| Adapter Modules | 1-5% | Basse | Haute | Moyenne | Bonne |
| Prefix-tuning | 0.1-1% | Basse | Très haute | Basse | Acceptable |
| MoE Dynamique | 10-30% (selon routing) | Haute | Moyenne | Très haute | Excellente (tâches mixtes) |
Astuce d'Expert
Pour LoRA, le rang r = 8 est souvent un sweet spot, mais mesurez la "intrinsic dimensionality" du fine-tuning en calculant les valeurs singulières des mises à jour de poids sur un petit subset. Utilisez des "LoRA blocks" spécialisés : applicatifs seulement à certaines couches (attention + dernière couche feed-forward typiquement). Pour les MoE dynamiques, implémentez l'"expert load balancing" via une perte auxiliaire qui pénalise les déséquilibres de routage, sinon tous les tokens convergent vers 1-2 experts.
⚠️ Attention Critique
LoRA suppose une faible intrinsèque dimensionnalité des mises à jour - faux pour les changements de domaine drastiques. Un adapter avec 5% de paramètres peut dépasser LoRA à rang 8 sur certaines tâches. Les MoE introduisent une variance importante (dropout stochastique du routage) ; nécessitent une regularization délicate. Le "catastrophic forgetting" revient même avec ces méthodes - utilisez systématiquement des techniques de replay ou continual learning si fine-tunez séquentiellement sur plusieurs tâches.
5. Debugging et Profiling : Identifier les Bottlenecks en Production
Définition
Le debugging de LLM en production requiert une instrumentation profonde des trois dimensions : computationnelle (où le temps CPU/GPU est dépensé), mémoire (pics et fuites), et comportementale (sorties dégradées, mode collapse). Le profiling collecte des traces exécution précises ; l'analyse révèle les goulots. Les outils modernes (PyTorch Profiler, TensorRT, Triton Inference Server) exposent les kernels GPU critiques et les stalls de mémoire.
Analogie Pédagogique
Déboguer un LLM est comme diagnostiquer un patient compliqué. Vous ne voyez que les symptômes (latence élevée, mémoire saturée, outputs bizarres). Vous devez tester systématiquement : scanner (profiling) révèle où les problèmes se concentrent. Une latence élevée vient-elle de l'I/O réseau, du compute GPU, ou de la congestion mémoire ? Chaque cause exige un traitement différent.
Tableau de Diagnostic : Symptômes et Root Causes
| Symptôme Observé | Root Causes Probables | Outils de Debug | Solution Typique |
|---|---|---|---|
| Latence élevée (p99) | Queuing batch, TTFT > 500ms | Triton metrics, vLLM logs | Augmenter batch_size ou ajouter instances |
| Crête GPU mémoire soudaine | KV-cache non-libéré, mémoire fragment | nvidia-smi, torch.cuda.memory_allocated() | Réduire max_tokens_per_batch ou impl streaming |
| Throughput réduisant (>24h) | Fuite mémoire, accumulateurs de gradients | Memory Profiler, torch.utils.checkpoint | Vérifier delete() explicite des tensors |
| Mode Collapse (rép. répétées) | Temperature=0, beam_search défectueux | Logits histogrammes, sequence analysis | Augmenter temperature, ajouter penalties |
| Divergence output vs baseline | Quantization non-calibrée, opérateurs fondus | Layer-wise activation comparison | Recalibrer quantization sur données réelles |
| Variance inter-infos (même prompt) | Seed non-controllé, ordre d'exécution GPU | Fixer seed + redémarrer GPU state | torch.manual_seed() + gpu memset |
Astuce d'Expert
Implémentez un "heartbeat profiler" : collectez toutes les 1000 tokens générés les métriques clés (peak_memory, compute_time, memory_allocated). Plottez les timeline pour identifier les patterns. Utilisez "activation checkpointing" (recompute) sur les couches suspectes une à une pour isoler les outliers. Enfin, profilez avec des données réelles en production (shadowing) : les benchmark synthétiques masquent souvent des patterns pathologiques d'utilisation réelle.
⚠️ Attention Critique
Le profiling introduit un overhead non négligeable (5-20% en général). N'activez jamais le profiling complet sur 100% du trafic production ; échantillonnez (ex: 1% des requêtes). Les outils GPU (nvprof, nsys) génèrent des fichiers énormes ; comprimez et streamez vers stockage distant. Les problèmes mémoire sont souvent "intermittents" (ex: OOM seulement après N heures) ; testez les scenarios de long-running avec des boucles synthétiques. Enfin, distinguez clairement : latency variance due aux ressources partagées (réseau, CPU) vs latency dus au modèle lui-même.