# Batching continu

Le batch continu maximise l'utilisation du GPU en réorganisant dynamiquement le lot à chaque étape de génération. À mesure que les requêtes se terminent, de nouvelles requêtes rejoignent immédiatement le lot au lieu d'attendre la fin de l'ensemble. Le GPU reste saturé et le débit reste élevé.

> [!TIP]
> Pour les déploiements en production, utilisez [transformers serve](./serve-cli/serving_optims#continuous-batching). Il s’appuie sur [ContinuousBatchingManager](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager) et expose un point de terminaison HTTP compatible OpenAI.

## generate_batch

Le batch continu est pris en charge via [generate_batch()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousMixin.generate_batch). Transmettez une liste de prompts tokenisés et récupérez les résultats pour l’ensemble une fois leur traitement terminé. `generate_batch` gère l’ordonnancement en interne et bloque jusqu’à l’achèvement de toutes les requêtes.

Pour les cas d’usage de service et de diffusion en continu, utilisez directement [ContinuousBatchingManager](#continuousbatchingmanager) pour gérer les requêtes.

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.generation import ContinuousBatchingConfig, GenerationConfig

model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen3-4B",
    attn_implementation="flash_attention_2",
    device_map="auto",
    dtype=torch.bfloat16,
)
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-4B")

prompts = [
    "What's up?",
    "Name a cat breed.",
    "Write a detailed history of quantum mechanics.",
]
inputs = [tokenizer.encode(p) for p in prompts]

generation_config = GenerationConfig(
    max_new_tokens=64,
    eos_token_id=tokenizer.eos_token_id,
)

outputs = model.generate_batch(inputs=inputs, generation_config=generation_config)

for request_id, output in outputs.items():
    text = tokenizer.decode(output.generated_tokens, skip_special_tokens=True)
    print(f"[{request_id}] {text}")
```

## ContinuousBatchingManager

[ContinuousBatchingManager](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager) exécute un thread en arrière-plan et vous permet de soumettre des requêtes et de récupérer les résultats de manière indépendante. À chaque étape de génération, il vérifie les requêtes terminées et planifie de nouvelles requêtes pour rejoindre le lot. Cela est utile pour le streaming, le service en temps réel ou la soumission de requêtes à mesure qu’elles arrivent.

Utilisez [continuous_batching_context_manager()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousMixin.continuous_batching_context_manager) pour démarrer et arrêter le gestionnaire en toute sécurité. L'exemple ci-dessous contient des entrées de longueurs variables. Dès qu'un prompt le plus court est terminé, il quitte le lot tandis que les prompts plus longs continuent de générer. Avec un lot statique, vous devriez les rembourrer tous à la même longueur. Le lot continu libère le prompt terminé afin que vous puissiez commencer immédiatement le traitement du prompt suivant.

```py
with model.continuous_batching_context_manager(generation_config=generation_config) as manager:
    manager.add_request(
        input_ids=tokenizer.encode("Write a detailed history of quantum mechanics."),
        request_id="long",
        max_new_tokens=512,
    )
    manager.add_request(
        input_ids=tokenizer.encode("What's up?"),
        request_id="short_0",
        max_new_tokens=32,
    )
    manager.add_request(
        input_ids=tokenizer.encode("Name a cat breed."),
        request_id="short_1",
        max_new_tokens=32,
    )

    for result in manager:
        text = tokenizer.decode(result.generated_tokens, skip_special_tokens=True)
        print(f"[{result.request_id}] {text}")
```

Vous pouvez également appeler [init_continuous_batching()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousMixin.init_continuous_batching) pour gérer le cycle de vie vous-même.

```py
manager = model.init_continuous_batching(generation_config=generation_config)
manager.start()

# submit and retrieve requests...
```

### Arrêt du gestionnaire

Le manager exécute un thread en arrière-plan et détient des ressources distribuées. L’arrêt s’effectue en deux étapes afin que vous puissiez choisir comment traiter le travail en cours.

Appel [stop()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager.stop) pour arrêter le thread en arrière-plan. Par défaut, le gestionnaire cesse d’accepter de nouvelles soumissions et attend la fin des demandes en file d’attente et actives avant que le thread ne se termine.

```py
manager.stop()
```

Passez `hard_stop=True` pour abandonner immédiatement le travail en attente. Les demandes en file d’attente et actives échouent avec une `RuntimeError` au lieu de se terminer.

```py
manager.stop(hard_stop=True)
```

Une fois que `stop` est appelé, [add_request()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager.add_request) et [add_requests()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager.add_requests) ignorent les nouvelles soumissions et affichent un avertissement. Vous pouvez toujours rappeler `start` pour exécuter une autre session de génération avec le même gestionnaire.

Appel de [destroy()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager.destroy) pour libérer les ressources distribuées. `destroy` arrête d'abord le gestionnaire s'il est encore en cours d'exécution, et le gestionnaire ne peut pas être redémarré par la suite. Utilisez-le lorsque vous avez terminé avec le lotissement continu pour la durée de vie du processus.

```py
manager.destroy()
```

[continuous_batching_context_manager()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousMixin.continuous_batching_context_manager) gère ce processus. Il appelle `stop` à la sortie et `destroy`, sauf si vous passez `persistent_manager=True` pour mettre le gestionnaire en cache sur le modèle pour la session suivante.

### Ajout de requêtes

[add_request()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager.add_request) soumet une requête unique. Fournissez un `request_id` ou laissez le gestionnaire en générer un automatiquement.

```py
manager.add_request(input_ids=input_ids, request_id="my_request")
```

[add_requests()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager.add_requests) soumet un lot en une seule fois. Il trie automatiquement les entrées afin de maximiser les correspondances du cache de préfixe lorsque le partage de blocs est activé.

```py
manager.add_requests(inputs=inputs)
```

Annuler une requête avec [cancel_request()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager.cancel_request).

```py
manager.cancel_request(request_id="my_request")
```

### Paramètres d'échantillonnage par requête

Activez `per_request_processors` pour appliquer `temperature`, `top_k` et `top_p` de manière indépendante pour chaque requête au sein d'un même passage avant, afin de permettre des paramètres d'échantillonnage différents pour différentes requêtes (par exemple, des sorties créatives à haute température par opposition à des sorties précises à basse température).

```py
cb_config = ContinuousBatchingConfig(per_request_processors=True)

# each request gets its own sampling parameters
manager.add_request(input_ids=inputs_a, temperature=0.9, top_p=0.95)
manager.add_request(input_ids=inputs_b, temperature=0.1, top_k=10)
```

Chaque paramètre de [GenerationConfig](/docs/transformers/main/fr/main_classes/text_generation#transformers.GenerationConfig) doit avoir une valeur non par défaut afin de créer le processeur de logits associé à l'exécution. Par exemple, définissez `temperature` sur une valeur autre que `None` ou `1` pour prendre en charge le contrôle de la température par requête. Les requêtes avec une température de `1` peuvent toujours être créées par la suite.

### Récupération des résultats

Itérez sur le manager pour recevoir les résultats à mesure qu'ils arrivent.

```py
for result in manager:
    print(tokenizer.decode(result.generated_tokens, skip_special_tokens=True))
```

[get_result()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager.get_result) récupère le résultat suivant de la file de sortie. Transmettez un `request_id` pour filtrer une requête spécifique. Si le résultat suivant dans la file ne correspond pas, il est remis en file et la méthode renvoie `None`.

```py
# next available result
result = manager.get_result()

# filter for a specific request
result = manager.get_result(request_id="my_request")
```

### Streaming

Définissez `streaming=True` sur une requête, puis utilisez [request_id_iter()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousBatchingManager.request_id_iter) pour itérer sur les sorties partielles au fur et à mesure que les jetons sont générés.

```py
from transformers.generation.continuous_batching import RequestStatus

manager.add_request(input_ids=input_ids, request_id="streamed", streaming=True)

for chunk in manager.request_id_iter(request_id="streamed"):
    token = tokenizer.decode(chunk.generated_tokens[-1:], skip_special_tokens=True)
    print(token, end="", flush=True)
    if chunk.status == RequestStatus.FINISHED:
        break
```

## ContinuousBatchingConfig

[ContinuousBatchingConfig](/docs/transformers/main/fr/main_classes/continuous_batching#transformers.ContinuousBatchingConfig) contrôle le cache KV, l’ordonnancement, les graphes CUDA, l’utilisation de la mémoire et bien plus encore. Transmettez-le à `generate_batch` ou à [init_continuous_batching()](/docs/transformers/main/fr/main_classes/text_generation#transformers.ContinuousMixin.init_continuous_batching) via l’argument `continuous_batching_config`, indépendamment de [GenerationConfig](/docs/transformers/main/fr/main_classes/text_generation#transformers.GenerationConfig). Les deux configurations décrivent des aspects distincts. [GenerationConfig](/docs/transformers/main/fr/main_classes/text_generation#transformers.GenerationConfig) est centrée sur le modèle et contient les paramètres d’échantillonnage et d’arrêt, tandis que [ContinuousBatchingConfig](/docs/transformers/main/fr/main_classes/continuous_batching#transformers.ContinuousBatchingConfig) est centrée sur le matériel et contient les paramètres de mémoire et d’ordonnancement.

> [!WARNING]
> Définir `continuous_batching_config` sur un [GenerationConfig](/docs/transformers/main/fr/main_classes/text_generation#transformers.GenerationConfig) est obsolète, émet un `FutureWarning` et sera supprimé dans la v5.19.

Par défaut, `max_batch_tokens` est `8192`, limité par la mémoire GPU disponible et jamais inférieur à `256`, tandis que `num_blocks` remplit la mémoire restante. Utilisez le tableau ci-dessous pour vous aider à choisir les fonctionnalités appropriées.

| Fonctionnalité | Mémoire | Débit | Latence |
|---|---|---|---|
| `max_memory_percent` / `page_size` | ✓ contrôle le budget KV | | |
| `max_batch_tokens` | ↑ tampons d'entrée plus grands | ✓ lots de préférence plus volumineux | ✓ TTFT lorsque le prétraitement est le facteur limitant |
| `scheduler` | | ✓ politique de planification | ✓ TTFT |
| Graphes CUDA | ↑ stockage du graphe | ✓ moins de surcharge de dispatch | ✓ |
| Batching asynchrone | ↑ ~2× tampons d'E/S | ✓ chevauchement CPU/GPU | |
| Compilation | ↑ warmup-time uniquement | ✓ passages en avant plus rapides | ✓ |
| Chemin rapide de décodage | ↑ table de blocs par requête | ✓ étapes de décodage uniquement plus rapides | ✓ |
| Déchargement sur CPU | ↑ mémoire CPU verrouillée | ✓ ignore certains re-prefills | |
| Mise en cache des préfixes | ↓ blocs KV partagés | ✓ ignore le préremplissage redondant | ✓ TTFT |
| Attention paginée | ↓ aucune fragmentation | ✓ appartenance dynamique au lot | |
| Fenêtre glissante | ↓ KV borné par couche | | |
| Processeurs par requête | | ✓ paramètres d'échantillonnage mixtes par lot | |
| `max_requests_per_batch` | ↓ plafonne le tampon de logits | ✓ limite la taille du lot | |
| `safety_margin` | | | ✓ protège la latence de décodage |

```py
from transformers.generation import ContinuousBatchingConfig

cb_config = ContinuousBatchingConfig(
    max_memory_percent=0.8,
    page_size=256,           # KV cache page size in tokens
    scheduler_type="fifo",        # "fifo" or "prefill_first"
)

outputs = model.generate_batch(
    inputs=inputs,
    generation_config=generation_config,
    continuous_batching_config=cb_config,
)
```

### Taille de page du cache KV

`page_size` définit le nombre de jetons de KV qu’une page d’attention complète contient pour une couche. Il doit être d’au moins `4`, sinon l’initialisation lève une `ValueError`. La valeur par défaut `256` convient à la plupart des charges de travail.

> [!NOTE]
> Le paramètre `block_size` est obsolète et remplacé par `page_size`.

Une taille de page plus importante réduit le suivi, mais gaspille de l’espace lorsqu’une séquence s’arrête en milieu de page. Des pages plus petites gaspillent moins d’espace, mais nécessitent un suivi plus important. Il n’est généralement pas nécessaire de régler `page_size`. Si votre charge de travail comporte de nombreuses requêtes courtes, essayez une valeur plus petite. S’il comporte quelques requêtes très longues, essayez une valeur plus grande. Consultez [Gestion de la mémoire](./continuous_batching_architecture#memory-management) pour comprendre comment les pages, les blocs et les fragments s’articulent.

```py
cb_config = ContinuousBatchingConfig(page_size=128)
```

### Taille du lot de préremplissage

`max_batch_tokens` définit le budget de jetons pour un seul passage avant, c’est-à-dire le nombre maximal de jetons de requête que le modèle traite simultanément. Un budget plus élevé permet d’insérer davantage de jetons de prompt dans chaque préremplissage, ce qui augmente le débit de préremplissage et réduit le temps jusqu’au premier jeton sur les charges de travail riches en prompts. L’ordonnanceur répartit les prompts qui dépassent le budget sur plusieurs étapes. Consultez [chunked prefill](./continuous_batching_architecture#chunked-prefill) pour savoir comment les prompts trop volumineux sont gérés.

Par défaut, `max_batch_tokens` vaut `8192`. Cette valeur est limitée par la mémoire GPU disponible afin que les tenseurs d'entrée par lot n'évictent pas le cache KV, et elle ne descend jamais en dessous de `256`. Sur un GPU avec peu de mémoire libre, la limite l'abaisse en dessous de `8192`.

`max_batch_tokens` et `num_blocks` puisent dans le même budget mémoire, ils sont donc en concurrence l’un avec l’autre. Un budget de jetons plus important alloue des tampons d’entrée plus volumineux et laisse moins de blocs de cache KV pour les requêtes concurrentes ou longues. Augmentez `max_batch_tokens` pour accroître le débit de préremplissage si vous disposez de plus de mémoire, et réduisez-le pour libérer de la mémoire afin d’ajouter des blocs KV ou pour éviter les erreurs de mémoire insuffisante.

```py
cb_config = ContinuousBatchingConfig(max_batch_tokens=16384)
```

### Limites de lot et de planification

`max_requests_per_batch` limite le nombre de requêtes exécutées lors d'un seul passage avant. Le modèle génère un tenseur de logits dont la taille est déterminée par le nombre de jetons du lot et la taille du vocabulaire, et il est converti en `fp32` pour l'échantillonnage, ce qui double l'empreinte mémoire. Chaque requête n'a besoin que d'une prédiction de jeton suivant, donc une limite plus faible maintient ce tenseur plus petit et évite les erreurs de mémoire insuffisante sur les lots dominés par la préremplissage avec de grands vocabulaires. Par défaut, il est défini au nombre de prompts soumis, avec une valeur de repli de 1024, puis limité pour s'adapter à `max_batch_tokens` et `num_blocks`.

```py
cb_config = ContinuousBatchingConfig(max_requests_per_batch=256)
```

`safety_margin` réserve une fraction de la capacité libre du cache pour les requêtes actives. Lorsque la capacité libre passe sous le seuil de `safety_margin` (une fraction de la taille totale du cache), le planificateur cesse d’admettre de nouveaux prefills et ne poursuit que le décodage des requêtes déjà en cours. Cette approche privilégie l’achèvement du travail actif par rapport au démarrage de nouvelles requêtes, ce qui protège la latence de décodage et retarde le [offloading](./continuous_batching_architecture#offloading). La valeur doit se situer entre `0` et `1`, où `0` désactive la marge.

```py
cb_config = ContinuousBatchingConfig(safety_margin=0.15)
```

La valeur par défaut dépend de l'ordonnanceur. Pour l'ordonnanceur FIFO, elle est de `0.15` et pour `prefill_first`, elle est de `0.0`. Consultez [Admission](./continuous_batching_architecture#admission) pour comprendre comment la marge interagit avec l'ordonnancement.

### Probabilités logarithmiques

[ContinuousBatchingConfig](/docs/transformers/main/fr/main_classes/continuous_batching#transformers.ContinuousBatchingConfig) renvoie la log-probabilité de chaque jeton généré lorsque `return_logprobs=True`. Cela est utile pour le RL, où les logprobs constituent une entrée de certaines boucles d'entraînement.

```py
cb_config = ContinuousBatchingConfig(return_logprobs=True)

# generate_batch()

for request_id, output in outputs.items():
    for token_id, log_prob in zip(output.generated_tokens, output.logprobs):
        token = tokenizer.decode([token_id])
        print(f"{token} | logprob: {log_prob}")
```

### Graphes CUDA

Les graphes CUDA éliminent le surcoût de dispatch CPU en enregistrant le graphe d’exécution GPU une seule fois, puis en le rejouant pour des lots dont les formes correspondent. Activez-les explicitement avec `use_cuda_graph=True`.

```py
cb_config = ContinuousBatchingConfig(use_cuda_graph=True)
```

Lorsqu’il est actif, le gestionnaire remplit les longueurs des requêtes et des paires clé-valeur jusqu’à des intervalles fixes afin que les formes se répètent et que les graphes soient réutilisés. Des valeurs plus petites de `q_padding_interval_size` et `kv_padding_interval_size` réduisent le calcul gaspillé sur le remplissage, mais cela signifie qu’il y a plus de formes uniques que le graphe doit enregistrer et stocker, ce qui coûte davantage de mémoire.

```py
cb_config = ContinuousBatchingConfig(
    use_cuda_graph=True,
    q_padding_interval_size=64,
    kv_padding_interval_size=16384,
)
```

### Batching asynchrone

Le lot asynchrone superpose la planification CPU du lot suivant au calcul GPU du lot actuel. Il nécessite des graphes CUDA et double approximativement la VRAM utilisée pour les tenseurs d'entrée.

```py
cb_config = ContinuousBatchingConfig(
    use_cuda_graph=True,
    use_async_batching=True,
)
```

### Compilation

`default_compile_level` applique `torch.compile` aux passes avant du modèle. La compilation échange un coût de mise en route unique contre des passes avant plus rapides lors de la génération. Des niveaux plus élevés exécutent des optimisations plus agressives, ce qui améliore le débit mais allonge la mise en route. Maintenez le niveau bas pour les tests et l’itération des benchmarks, et augmentez-le pour les charges de travail de service de longue durée où le coût de mise en route est amorti sur de nombreuses requêtes.

Le niveau varie de `0` à `3`. Le niveau `0` est la valeur par défaut et ignore entièrement la compilation.

| Niveau | `mode` | `dynamic` | Compromis |
|---|---|---|---|
| 0 | — | — | Aucune compilation (par défaut), démarrage le plus rapide |
| 1 | `default` | `True` | Légère accélération, échauffement court |
| 2 | `max-autotune-no-cudagraphs` | `True` | Plus d'accélération, échauffement plus long |
| 3 | `max-autotune-no-cudagraphs` | `False` | Meilleur débit, phase de préchauffement la plus longue |

```py
cb_config = ContinuousBatchingConfig(default_compile_level=1)
```

Le niveau fournit une configuration [CompileConfig](/docs/transformers/main/fr/internal/generation_utils#transformers.CompileConfig) par défaut aux chemins d'exécution varlen et decode. Il ne s'applique qu'à un chemin qui n'a pas de configuration explicite, de sorte que `varlen_compile_config` et `decode_compile_config` ont la priorité lorsqu'ils sont définis. Sous FlashAttention, le chemin varlen ignore la compilation car `max_length_k` déclenche des recompilations fréquentes, si bien que le niveau n'affecte que le chemin decode dans ce cas.

### Chemin rapide de décodage

Lorsqu’un lot ne contient que des requêtes de décodage (un jeton de requête par séquence), le gestionnaire peut dispatcher vers le noyau `flash_attn_with_kvcache` au lieu du noyau à longueur variable. C’est plus rapide que le chemin varlen car le noyau lit et écrit le cache KV paginé sur place via un tableau de blocs, plutôt que de passer par une mise à jour manuelle. Consultez [Paged attention](./paged_attention) pour les détails au niveau du noyau.

Le chemin rapide est dimensionné par `max_blocks_per_request`, qui détermine la taille de la table de blocs par requête. Par défaut, cette valeur est inférée automatiquement. Si `max_prompt_length` et `max_generated_length` sont définis sur le gestionnaire, la table de blocs est dimensionnée pour accueillir la longueur de séquence maximale. Sinon, une valeur par défaut de repli (32 blocs par requête) est utilisée.

Définissez `max_blocks_per_request` sur une valeur spécifique pour dimensionner explicitement la table de blocs. Cela est utile lorsque vous connaissez la longueur de séquence maximale par requête et souhaitez limiter le coût mémoire de la table de blocs.

```py
cb_config = ContinuousBatchingConfig(max_blocks_per_request=64)
```

Définissez `max_blocks_per_request=0` pour désactiver le chemin rapide et forcer le passage de chaque lot par le noyau varlen. Cela restaure le comportement par défaut antérieur et est utile lorsque le chemin rapide n'est pas disponible pour votre implémentation d'attention (le gestionnaire le désactive également automatiquement lorsque le noyau sous-jacent ne peut pas être utilisé).

```py
cb_config = ContinuousBatchingConfig(max_blocks_per_request=0)
```

Le chemin rapide repose sur le noyau `flash_attn_with_kvcache`, qui est disponible pour deux combinaisons de périphérique et d’implémentation de l’attention.

| Appareil | `attn_implementation` |
|---|---|
| CUDA | `flash_attention_2` ou `flash_attention_3` |
| XPU | [flash_attention_2](https://huggingface.co/kernels-community/flash-attn2) |

Pour toute autre combinaison, ou lorsque le noyau ne peut pas être importé, le gestionnaire bascule sur le chemin varlen. Il n’affiche un avertissement que lorsque vous définissez explicitement `max_blocks_per_request`.

L’attention complète prend en charge les tables de blocs de noyau, mais l’attention glissante ne le fait pas. Si le modèle comporte des couches d’attention glissante, y compris les modèles hybrides qui utilisent également l’attention complète, l’initialisation force `max_blocks_per_request` à `0`, et toute valeur non nulle que vous définissez est écrasée. Le gestionnaire enregistre alors que le chemin rapide de décodage n’est pas disponible, car certains types d’attention du modèle ne prennent pas en charge les tables de blocs de noyau.

### Déchargement sur CPU

Le déchargement sur CPU copie les blocs de cache KV évacués vers un tampon CPU épinglé préalloué lorsque le cache KV du GPU est plein. Une fois de l’espace disponible dans le cache, le gestionnaire recopie les blocs sur le GPU et reprend la requête sans recalculer son prompt ni les jetons générés.

Définissez `cpu_offload_space` sur l'espace d'échange CPU en GiB. La valeur par défaut, `0.0`, désactive le déchargement sur CPU.

```py
cb_config = ContinuousBatchingConfig(cpu_offload_space=8.0)
```

Par défaut, `cpu_offload_space_safety_threshold=0.8` limite l'espace demandé à 80 % de la RAM système disponible lorsque `psutil` est installé. Définissez `cpu_offload_space=None` pour dimensionner le pool d'échange à partir du seuil de sécurité.

### Délai d'attente du parallélisme de tenseurs

Sous le parallélisme de tenseurs, le gestionnaire crée un groupe de communication CPU pour coordonner les soumissions, les annulations et l’arrêt des requêtes entre les rangs. `cpu_group_timeout` limite la durée pendant laquelle une opération collective sur ce groupe peut bloquer avant que le processus ne plante. Si un rang se fige, le délai d’attente empêche les autres d’attendre indéfiniment.

Définissez un délai d’attente plus long pour les charges de travail qui émettent des collectives peu fréquentes, ou passez `None` pour le désactiver.

```py
cb_config = ContinuousBatchingConfig(cpu_group_timeout=600.0)
```

### Mise en cache des préfixes

Lorsque plusieurs requêtes partagent un préfixe commun, comme un prompt système, le gestionnaire réutilise leurs blocs de cache KV au lieu de les recalculer. `allow_block_sharing` est défini par défaut sur `True`. Le partage de préfixe n’est actif que si tous les allocateurs de type d’attention prennent en charge le partage, si bien que seuls les modèles à attention complète l’utilisent. Les modèles purement glissants et hybrides le désactivent même lorsque `allow_block_sharing` est `True`.

```py
cb_config = ContinuousBatchingConfig(
    allow_block_sharing=True,  # default
)
```

## Choisir un backend d'attention

Le batch continu prend en charge FlashAttention, SDPA et `"paged|eager"`. Définissez `attn_implementation` lors du chargement du modèle.

| Backend | `attn_implementation` | Prérequis |
|---|---|---|
| FlashAttention 2 | "flash_attention_2" | le package `flash-attn` ou `kernels` |
| FlashAttention 3 | "flash_attention_3" | le package `flash-attn-3` ou `kernels` |
| SDPA (natif PyTorch) | "sdpa" | Aucun |
| Eager | "paged&#124;eager" | Aucun |

```py
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen3-4B",
    attn_implementation="flash_attention_2",
    device_map="auto",
    dtype=torch.bfloat16,
)
```

Le continuous batching est plus rapide avec FlashAttention qu'avec eager ou SDPA, principalement parce que FlashAttention n'a pas besoin de masque d'attention. Si le modèle prend en charge FlashAttention, un modèle chargé avec `"eager"` ou `"sdpa"` bascule sur FlashAttention 3, ou sur FlashAttention 2 si FlashAttention 3 n'est pas installé, et un avertissement est journalisé. Si aucune des deux versions n'est installée, le backend ne change pas.

Pour conserver eager ou SDPA, par exemple lors de tests, définissez `auto_switch_to_flash=False` dans [ContinuousBatchingConfig](/docs/transformers/main/fr/main_classes/continuous_batching#transformers.ContinuousBatchingConfig). Chaque fois que le backend reste `"eager"`, le continuous batching exécute `"paged|eager"` à la place.

## Parallélisme de tenseurs

Pour les modèles trop volumineux pour tenir sur un seul GPU, répartissez les poids sur plusieurs appareils au moyen du parallélisme de tenseurs. Définissez le nombre d’appareils avec `DistributedConfig(tp_size=N)`. Le lotissement continu lit la taille du parallélisme de tenseurs depuis le modèle afin de dimensionner le cache KV paginé par fragment. Consultez [Tensor parallelism](./tensor_parallelism) pour la liste des architectures prises en charge et le fonctionnement de la répartition.

```py
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, DistributedConfig
from transformers.generation import ContinuousBatchingConfig, GenerationConfig

distributed_config = DistributedConfig(tp_size=4)
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen3-32B",
    attn_implementation="flash_attention_2",
    distributed_config=distributed_config,
)
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-32B")

inputs = [tokenizer.encode(p) for p in ["What's up?", "Name a cat breed."]]
generation_config = GenerationConfig(max_new_tokens=64, eos_token_id=tokenizer.eos_token_id)

outputs = model.generate_batch(inputs=inputs, generation_config=generation_config)
```

Lancez le script avec `torchrun` en définissant `--nproc-per-node` sur le nombre de GPU sur lesquels vous souhaitez répartir le sharding.

```shell
torchrun --nproc-per-node 4 cb_tp.py
```

La taille du parallélisme des tenseurs doit diviser le nombre de `num_key_value_heads` du modèle (vérifiez la configuration du modèle). Sinon, le cache paginé lève une erreur au démarrage ; choisissez donc une valeur appropriée pour `--nproc-per-node`.

> [!WARNING]
> Ne définissez pas `device_map` avec `distributed_config`. Les deux sont en conflit, car `device_map` place des modules entiers sur des GPU spécifiques, tandis que le parallélisme de tenseurs répartit ces mêmes paramètres sur tous les GPU.

## Attention à fenêtre glissante

Les modèles avec attention à fenêtre glissante (Mistral, Gemma 2) fonctionnent avec le lotissement continu. Les couches glissantes utilisent `SlidingAttentionCacheAllocator`, qui ne conserve qu'une fenêtre fixe de jetons récents en recyclant un petit ensemble de pages. Le type d'attention provient de `layer_types` ou `sliding_window` du modèle, et non de [ContinuousBatchingConfig](/docs/transformers/main/fr/main_classes/continuous_batching#transformers.ContinuousBatchingConfig).

```py
from transformers import AutoConfig, AutoModelForCausalLM

config = AutoConfig.from_pretrained("google/gemma-2-2b")
config.sliding_window = 4096

model = AutoModelForCausalLM.from_pretrained(
    "google/gemma-2-2b",
    config=config,
    attn_implementation="sdpa",
    device_map="auto",
    dtype=torch.bfloat16,
)
```

[Prefix caching](#prefix-caching) et le [decode fast path](#decode-fast-path) sont désactivés dès lors que l’attention glissante est présente, y compris dans les modèles hybrides qui comportent également des couches d’attention complète.

## Étapes suivantes

- L’article de blog [Continuous batching](https://huggingface.co/blog/continuous_batching) aborde la mise en cache KV, le préremplissage par morceaux et la planification dynamique, avec des chiffres de référence de performance.
- Pour une analyse plus approfondie du fonctionnement du système de batch continu, consultez le document [Architecture du batch continu](./continuous_batching_architecture).

