Chapitre 7 — Stratégies de batching avancées
Septième billet de la tournée chapitre par chapitre de LLM Primer VI : Mettre à l'échelle les systèmes IA. Le chapitre qui montre pourquoi le batching n'est pas une optimisation mais le mouvement porteur qui rend le décodage limité par la bande passante tractable — et pourquoi le batch est un verbe, non un nom.
Pourquoi ce chapitre existe
Un seul pas de décodage lit des dizaines de gigaoctets de poids depuis la HBM pour produire un token. Si le GPU diffuse ces poids de toute façon, il peut produire un token pour de nombreuses requêtes dans la même étape à un coût marginal presque nul. Le batching n'est donc pas une optimisation au sens ordinaire — c'est le seul moyen de rendre le décodage économiquement viable sur du matériel limité par la bande passante mémoire. Mais la manière évidente de batcher s'effondre au contact du monde réel, car les requêtes ont des longueurs différentes et finissent à des moments différents. Le Chapitre 7 parcourt le trajet du schéma naïf qui fonctionne presque au planificateur au niveau itération que les moteurs de production font tourner, et nomme la dette que ce planificateur crée pour le Chapitre 8.
7.1 Le batching statique est vaincu par le problème du plus rapide à finir
Le batching statique est ce que tout le monde écrit d'abord : rassembler des requêtes jusqu'à une taille B ou un délai, faire le préremplissage sur le batch entier à la longueur S_max, faire tourner une boucle de décodage jusqu'à ce que chaque séquence du batch ait émis EOS. Les deux coûts sont catastrophiques en combinaison. Le padding — le prompt de 50 tokens dans le même batch qu'un prompt de 4 000 tokens paie 80× le travail de préremplissage dont il a besoin. Le plus rapide à finir — la boucle de décodage tourne jusqu'à ce que chaque séquence finisse, donc un batch avec une requête de 20 tokens et une de 2 000 passe 99 pour cent de son temps avec 31 slots à produire des tokens qui seront jetés. Le débit moyen paraît acceptable et la latence de queue est dominée par la longue requête présente dans le batch. Le batching dynamique (délai variable, autorisation d'arrivées tardives dans le batch en attente) adoucit l'attente mais ne change pas le schéma fondamental ; il hérite du même problème du plus rapide à finir une fois le décodage lancé.
7.2 Le batching continu ordonnance par itération, non par requête
Le batching continu — l'ordonnancement au niveau itération d'Orca, l'in-flight batching de NVIDIA, « l'astuce centrale » de vLLM et TGI — est le changement de variable. Au lieu d'engager un batch pour la durée de la génération, le planificateur revisite la composition du batch à chaque pas de décodage. Après chaque pas : les séquences terminées quittent leurs slots et libèrent leur KV ; de nouvelles séquences de la file entrent dans les slots libérés ; le pas de décodage conjoint tourne sur le nouvel ensemble actif. Deux propriétés du décodage LLM rendent cela possible. Chaque pas de décodage est structurellement la même opération — le kernel ne se soucie pas de savoir quelle séquence occupe le slot 7 ou le slot 11. Et chaque séquence porte son propre cache KV indépendamment, donc sa mémoire redevient simplement disponible à son départ. L'unité d'équité devient l'itération, non la requête : une requête de 20 tokens se termine après environ 20 itérations quels que soient les autres, et une requête de 2 000 tokens occupe un slot aussi longtemps qu'il le faut sans prendre les autres en otage. Sur le trafic réel à queue longue — mélanges de courts tours de chat et de longues complétions RAG — l'utilisation GPU sur un modèle 70B grimpe de la fourchette 10–20 pour cent typique du batching statique à 60–80 pour cent, et la latence p99 se resserre nettement.
7.3 Le préremplissage par tronçons unifie préremplissage et décodage sur la même puce
Le batching continu laisse encore une tension. Les nouveaux arrivants ont besoin de préremplissage, qui est limité par le calcul et préfère de longues séquences par passe. Les séquences en vol ont besoin de décodage, qui est limité par la bande passante mémoire et préfère de larges batches. Faire tourner un préremplissage complet sur un prompt frais de 4 000 tokens dans la même passe avant que le pas de décodage de trente séquences en cours retarde soit les décodes en cours (mauvais TTFT pour les utilisateurs existants), soit le préremplissage du nouvel arrivant (mauvais TTFT pour le nouvel utilisateur). Le préremplissage par tronçons découpe le préremplissage en morceaux — disons 512 tokens à la fois — et entrelace ces tronçons avec les pas de décodage des séquences actives. La passe avant unique porte désormais un peu de travail de préremplissage sur un nouveau prompt et un peu de travail de décodage en cours simultanément, et les deux phases partagent les mêmes flux de poids. Le caractère limité par le calcul du préremplissage absorbe l'arithmétique ; la demande de bande passante du décodage est amortie sur plus de travail utile par octet. Les deux phases cessent d'être antagonistes sur une même puce. Le cas restant — assez de trafic pour qu'elles se battent encore — est la mise en place du service désagrégé au Chapitre 12.
Ce que prépare le Chapitre 7
Le batching continu fait son travail et, ce faisant, expose le cache KV comme la contrainte qui lie la concurrence. Chaque séquence active porte son propre KV, dimensionné selon sa longueur actuelle ; des séquences entrent et sortent à chaque pas ; le moteur ne peut pas connaître d'avance leur longueur. Une disposition naïve d'une tranche par slot rend la plus grande partie du gain de batching. Le Chapitre 8 porte la solution des systèmes d'exploitation : diviser le cache en petits blocs physiques, les découpler des positions logiques de tokens avec une table de pages, et laisser une politique d'éviction récupérer ou partager des blocs entre séquences. PagedAttention est le mouvement qui rend le problème KV du batching continu tractable.
Prochaine étape — Chapitre 8 : Gestion nouvelle génération du cache KV. PagedAttention, éviction H2O, InfiniGen et l'économie du cache de préfixe.