Accueil / Articles / Optimisation de l’inférence des LLM : préremplissage, décodage et LLMOps d’entreprise

Optimisation de l’inférence des LLM : préremplissage, décodage et LLMOps d’entreprise

Goulets d’étranglement liés au préremplissage et à la décodage, lotification continue, FlashAttention, quantification, PagedAttention, décodage spéculatif, préremplissage par blocs et fourniture désagrégée.

1809 mots

Concevoir des systèmes de service pour les LLM à haute performance et économiques signifie tenir compte des limites réelles du matériel — et non pas simplement envelopper une API en espérant que les GPU restent occupés.

À l’origine, les budgets des entreprises consacrés à l’intelligence artificielle générative se concentraient sur l’entraînement et le fine-tuning. Une fois les applications sorties du laboratoire, la situation change : des inférences continues gênées par les GPU et des pics de latence impossibles à prédire.

L’échelle impose des compromis tant sur le plan physique que financier. Les systèmes rapides et économes examinent au-delà des couches superficielles pour comprendre comment les inférences s’exécutent réellement sur le silicium.

1. Deux phases, deux goulets d’étranglement

Chaque demande d’inférence se divise en phase de préremplissage et en phase de décodage. Chacune de ces phases rencontre des limites matérielles différentes.

Prefill (généralement lié aux capacités de calcul)

Prefill ingère tous les tokens de la requête en même temps et crée des activations clé-valeur (KV) en parallèle. Les requêtes suffisamment longues entraînent des multiplications de matrices volumineuses qui saturent les ressources de calcul, ce qui rend cette étape limitée par les capacités de traitement. Les requêtes courtes ou des lots très petits peuvent inverser la situation : il n’y a pas assez d’opérations arithmétiques pour masquer la consommation mémoire, ce qui fait que Prefill devient limité par la mémoire. Le temps de précharge correspond au premier temps d’attente de l’utilisateur.

Décodage (généralement limité par la bande passante mémoire)

Lorsque la requête est entrée, les tokens arrivent un par un. À chaque étape, les poids complets du modèle ainsi que l’historique KV en cours de construction sont transférés depuis la mémoire à large bande passante (HBM) vers la SRAM de la GPU. Lorsque les tailles de lot sont faibles, ce transfert s’effectue si fréquemment que la GPU attend en raison de la bande passante plutôt que des capacités de calcul.

Une nuance unique guide le reste de la conception. L’augmentation de la taille des lots permet d’amortir la même opération de chargement du poids sur de nombreuses séquences, et le décodage revient vers une approche limitée par les capacités de calcul. C’est précisément ce point de basculement qui justifie l’existence du lotage continu : il fait en sorte que le décodage s’effectue dans un régime où les unités arithmétiques restent occupées.

Équation de la latence

La latence totale d’une requête se divise en deux parties : le préremplissage et le décodage :

T_total  =  TTFT  +  (N_tokens − 1) × TPOT
  • TTFT (temps jusqu’au premier token) correspond au préremplissage complet du prompt ainsi qu’au premier token de sortie — ce qui influence la perception initiale par l’utilisateur quant à la rapidité de réponse.
  • TPOT (temps par token de sortie), ou latence entre tokens, représente le coût constant de chaque étape de décodage ultérieure.
  • N_tokens indique la longueur totale du texte généré.

Le facteur (N − 1) est intentionnel : le premier token se trouve déjà à l’intérieur de TTFT, donc seuls les autres sont multipliés par TPOT. Mélanger le calcul préalable brut avec TTFT est une erreur courante. TTFT est destiné à l’utilisateur et doit inclure cette première étape de décodage.

2. Entrée avant que les GPU ne voient le trafic

Le trafic maximal épuisera les GPU à moins que l’entrée ne nettoie, n’évalue et ne filtre d’abord les données. Un parcours typique : passerelle API → cache sémantique multicouche → en cas d’échec, un routeur intelligent qui évalue la complexité et envoie le travail dans une file d’attente de modèle standard ou dans une file d’attente de modèle avancé.

Éléments clés :

  • Cachage sémantique multicouche : correspondance exacte clé-valeur ainsi que similarité vectorielle avec cos θ ≥ τ. Les répétitions n’affectent jamais le modèle ; les coûts et la latence diminuent en même temps.
  • Affectation intelligente des modèles : un classificateur léger envoie les informations de classification et de formatage aux petits modèles, réservant les modèles avancés pour des raisonnements complexes ou l’utilisation de outils en plusieurs étapes.
  • 3. Moteur d’exécution : lotification continue et flux mémoire

    Après l’affectation, le travail passe au moteur d’exécution. La lotification statique gaspille des ressources : tout le lot attend la séquence la plus longue. Les systèmes de production utilisent une lotification continue (planification au niveau des itérations) afin que les slots restent occupés et que les séquences terminées soient libérées dès qu’elles envoient le signal de fin de séquence.

    La lotification continue ne concerne pas seulement le débit. Elle permet également de passer d’un régime limité par la mémoire à un régime limité par les capacités de calcul, permettant ainsi à la GPU d’effectuer des opérations arithmétiques sans devoir attendre le HBM.

    4. Cibler directement les goulots d’étranglement de la phase

    Prefill : FlashAttention

    Le coût du préremplissage augmente avec le carré de la longueur du prompt lorsque l’attention classique génère une matrice de scores complète N×N dans la HBM. FlashAttention est un noyau en tuiles conscient des opérations d’entrée/sortie qui calcule l’attention avec précision en transmettant les tuiles via la SRAM intégrée, réduisant ainsi le trafic vers la HBM sans approximer les calculs. Résultat exact et temps de traitement plus court pour des prompts longs. Il est par défaut dans la plupart des stacks de traitement et s’accompagne d’un préremplissage en chunks ainsi que d’une désagrégation ultérieure.

    Quantification

    Décoder entraîne des coûts liés au transfert des poids de la HBM vers la SRAM. La quantification réduit la taille des poids — de FP16 à FP8, INT8 ou 4 bits (AWQ, GPTQ) — de sorte que chaque token occupe moins d’octets. La bande passante effective augmente et davantage de séquences peuvent tenir en mémoire. On s’attend à une légère perte en précision, que vous devrez valider par vos propres tests d’évaluation.

    Mémoire cache KV paginée (PagedAttention)

    Les clés/valeurs historiques agrandissent le texte token par token, ce qui entraîne une utilisation importante de la mémoire en temps réel. L’allocation contiguë crée des fragments et oblige à une provisionnement excessif. PagedAttention stocke les données KV en blocs de taille fixe, à l’instar de la mémoire virtuelle du système d’exploitation, ce qui élimine les fragments et permet des tailles de lots plus importantes sur le même matériel. Associez-le à un agrégation continue pour obtenir une forte concurrence.

    Décodage spéculatif

    Le décodage séquentiel, limité par la mémoire, laisse le processeur inactif entre les lectures. Le décodage spéculatif utilise ce temps mort : un petit module propose une séquence courte de tokens ; le réseau principal vérifie cette séquence en une seule étape de calcul. Les tokens acceptés coûtent environ une étape correspondant à un modèle de grande taille.

    La correction est préservée : les préfixes correspondants restent inchangés ; la première incohérence entraîne un troncature et le modèle cible effectue un rééchantillonnage à partir d’une distribution corrigée. Avec le décodage gourmand, les tokens correspondent exactement au modèle cible ; avec l’échantillonnage, la distribution correspond de manière statistique. L’accélération dépend du taux d’acceptation des brouillons, ce qui montre l’importance de la qualité de ces derniers.

    5. Planification des deux phases : préremplissage par blocs et désagrégation

    Le préremplissage et le décodage nécessitent des ressources matérielles opposées. Le partage d’un pool de GPU permet à un préremplissage long de monopoliser les ressources de calcul, ce qui augmente la latence entre tokens pour toutes les autres requêtes. Deux solutions complémentaires sont proposées.

    Préremplissage par blocs

    Au lieu d’un seul chargement préalable massif, divisez la requête en segments et mélangez-les (en les superposant) avec des étapes de décodage dans le même lot (Sarathi / Sarathi-Serve). Cela atténue les pics de charge pour les requêtes voisines et combine les tâches gourmandes en calcul avec celles gourmandes en mémoire. Le lotage continu choisit quelles requêtes partagent une étape ; le chargement préalable en blocs décide comment un chargement préalable important peut s’effectuer sans entraver le décodage.

    Servir de manière désagrégée

    Le chargement préalable en blocs réduit les interférences ; la désagrégation les élimine en plaçant différentes phases sur des matériels distincts (DistServe, Splitwise). Le chargement préalable est traité par des groupes optimisés pour le calcul, tandis que le décodage l’est par des groupes optimisés pour la bande passante, les données KV étant transmises via l’interconnexion. Chaque phase s’échelle en fonction du silicium adapté à son goulot d’étranglement.

    Les compromis sont réels : le transfert KV devient un nouveau goulot d’étranglement, et les poids doivent exister dans les deux bases de données. À grande échelle, on constate que l’allocation spécifique à chaque phase est plus avantageuse face à ces surcoûts. Les sites plus petits se contentent souvent uniquement d’un préremplissage par blocs.

    6. Impact systémique et compromis

    Les modèles de production sacrifient les performances au profit du risque opérationnel et des coûts d’infrastructure. Les chiffres varient en fonction du matériel, du modèle, du trafic et des paramètres de configuration — évaluez vos propres charges de travail plutôt que de copier des pourcentages génériques.

    Cachage sémantique multicouche — KV exact ainsi que similarité vectorielle. Les réponses trouvées évitent complètement l’utilisation du modèle. Coût : recherche vectorielle (de quelques millisecondes à une dizaine de millisecondes), avec des réponses obsolètes ou partiellement correctes si τ est trop bas.

    Encadrement intelligent — un classificateur de complexité dirige les tâches simples vers de petits modèles. Cela réduit le coût moyen par token ; une mauvaise orientation nuit à la qualité.

    Grouper les données de manière continue — jointure au niveau des itérations pendant la génération. Meilleure utilisation et débit en situation de concurrence ; les requêtes individuelles peuvent être mises en file d’attente pendant l’assemblage. Le groupage statique convient toujours aux tâches à débit hors ligne.

    Quantification — des poids à précision réduite diminuent les transferts de HBM vers SRAM. Plus de concurrence par GPU ; il faut valider la précision ; le support des noyaux varie.

    KV paginé — des blocs fixes éliminent la fragmentation. Tailles de lots plus grandes ; nécessite une gestion des blocs et un noyau d’attention compatible.

    Décodage spéculatif — un petit proposeur fait une suggestion ; le grand modèle vérifie conjointement. Plusieurs tokens par étape importante ; sensibilité au second modèle et au taux d’acceptation.

    Lorsque vous avez besoin de données précises sur la latence ou les coûts, obtenez-les à partir d’essais reproductibles du travail de charge cible (études de déploiement publiées ou tests de charge internes), et non à partir de pourcentages marketing fixes.

    7. Fermer le cycle

    Passer du prototype à la production signifie concevoir en fonction du matériel. Séparez le préremplissage de la décodage, observez comment la taille des lots influence le passage de la décodage entre régimes limités par la mémoire et ceux limités par le calcul, mettez en cache les requêtes prévisibles, dirigez les tâches simples vers de petits modèles, et regroupez les tokens par lot continu. Ensuite, attaquez le problème de la décodage grâce à la quantification, aux tables KV paginées et à une décodage spéculative, et atténuez les interférences de phase grâce à un préremplissage par blocs et à une désagrégation. Ensemble, ces éléments permettent d’absorber les pics de charge sans épuiser les GPU.

    Liste de contrôle pour la planification des capacités

    Lorsque TTFT augmente, vérifiez les distributions de longueur des prompts, le taux d’atteinte du cache sémantique, la disponibilité de FlashAttention, ainsi que le fait que les prompts longs continuent de monopoliser la GPU en une seule opération de précharge. Lorsque TPOT augmente en situation de concurrence, examinez la taille effective des lots, le temps d’occupation des mémoires KV, le niveau de quantification, et déterminez si la décodage est retombée dans un régime limité par la mémoire.

    Une revue hebdomadaire pratique pose trois questions : stockons-nous des requêtes prévisibles en cache ? Dirigeons-nous le travail trivial vers des modèles moins performants ? Organisons-nous la décodage de manière à ce que les GPU effectuent des calculs plutôt que d’attendre l’accès à la mémoire HBM ? Des réponses positives permettent généralement d’éviter l’achat d’un nouvel équipement avant d’avoir optimisé la pile de services.

    La décomposition ne doit figurer dans le plan que lorsque le préremplissage par blocs et l’agrégation continue ont déjà prouvé leur efficacité. Le trafic d’interconnexion et les poids dupliqués représentent des coûts réels ; il faut les prendre en compte lorsque les groupes spécifiques à chaque phase surpassent clairement une flotte partagée dans votre configuration.

    Décrivez la taille du lot de croisement mesurée où le décodage devient limité par les capacités de calcul de votre matériel. Ce seul chiffre permet d’ajuster plus précisément les objectifs liés à l’agrégation continue que n’importe quel graphique générique publié sur un blog.

    Notes pour les opérateurs

    Les caches sémantiques nécessitent une révision de leur TTL et de leur τ ; un τ trop faible entraîne des réponses partiellement correctes. Les routeurs ont besoin de données sur la complexité étiquetées, sinon ils envoient par erreur des requêtes complexes à de petits modèles. L’agrégation continue exige des objectifs de latence de file d’attente afin que « un débit plus élevé » ne masque pas les problèmes d’interactivité. Le décodage spéculatif requiert des tableaux de bord d’acceptation provisoire — si l’acceptation diminue, vous avez payé pour un deuxième modèle sans aucun gain de vitesse.

    Considérez les articles comme des preuves de mécanismes, et non comme des promesses de pourcentages applicables partout. Reproduisez les résultats sur vos GPU, avec les longueurs de prompts et le niveau de concurrence que vous utilisez, avant d’affirmer des économies financières.

    Références

    Articles principaux derrière ces mécanismes (les numéros correspondent à ceux des auteurs, pas aux vôtres) :

    1. Orca distributed transformer serving — Yu et al., OSDI 2022 (USENIX).
    2. PagedAttention memory management — Kwon et al., SOSP 2023 (arXiv:2309.06180).
    3. GPTQ post-training quantization — Frantar et al., 2022 (arXiv:2210.17323).
    4. AWQ activation-aware weight quantization — Lin et al., 2023 (arXiv:2306.00978).
    5. FlashAttention IO-aware exact attention — Dao et al., NeurIPS 2022 (arXiv:2205.14135).
    6. Speculative decoding for fast transformer inference — Leviathan, Kalman, Matias, ICML 2023 (arXiv:2211.17192).
  • Sarathi / Sarathi-Serve : précharges en blocs avec décodage par piggybacking — Agrawal et al., 2023–2024 (arXiv:2308.16369).
  • DistServe : désagrégation des précharges et du décodage — Zhong et al., OSDI 2024 (USENIX).
  • Splitwise : séparation en phases pour l’inférence générative — Patel et al., ISCA 2024 (arXiv:2311.18677).