Illustration vectorielle plate représentant des blocs de poids de modèle abstraits entrant dans un rack de serveur moderne, symbolisant l'optimisation de l'inférence.

vLLM propose des niveaux d’optimisation pour le temps de démarrage

Les développeurs qui font tourner des modèles de langage en production ont désormais une granularité bien plus fine pour gérer la complexité du démarrage des serveurs d’inférence. L’annonce de github.com sur vLLM présente quatre niveaux d’optimisation (-O0 à -O3) qui permettent de scinder le compromis classique entre un temps de démarrage rapide et la performance soutenue en régime permanent.

Si l’on choisit le niveau -O0, on obtient le temps de lancement le plus court, au prix d’une performance plus faible. À l’inverse, le niveau par défaut, -O2, intègre des compilations et des fusions supplémentaires, tandis que -O3 propose une approche plus agressive, bien que son contenu soit actuellement équivalent à -O2.

Au-delà de ces niveaux de compilation, d’autres leviers permettent d’éviter de refaire tout le travail à chaque redémarrage. On peut, par exemple, réutiliser le cache de compilation de torch.compile en persistant les artefacts sous le répertoire VLLM_CACHE_ROOT. Cela permet de transférer ce cache entre machines ou de l’intégrer directement dans une image conteneur, ce qui est un gain de temps notable.

Collage illustratif en papier découpé montrant une interface numérique avec des cartes de configuration superposées, symbolisant le réglage fin des paramètres d'inférence.

Il existe aussi des méthodes pour alléger le démarrage en évitant les mesures de profilage de la mémoire KV (Key-Value Cache) en utilisant le flag --kv-cache-memory. Toutefois, attention, cette astuce demande une précision chirurgicale : la taille du cache est fixée au lieu d’être mesurée, ce qui peut soit plafonner la concurrence des lots, soit provoquer un échec d’allocation si la valeur est trop optimiste.

La gestion de la mémoire n’est pas qu’une question de démarrage ; elle impacte directement la robustesse du système. L’architecture auto-régressive des transformeurs signifie que, si le cache KV est saturé, vLLM peut préempter des requêtes. Ces requêtes sont ensuite re-calculées lorsque de l’espace se libère, ce qui, si cela devient fréquent, vient impacter la latence globale. Pour contrer ce phénomène, l’outil suggère d’augmenter gpu_memory_utilization, de baisser le nombre maximal de séquences ou de tokens par lot, ou encore d’augmenter tensor_parallel_size pour répartir les poids sur plus de GPU.

Les subtilités de la planification des requêtes

L’implémentation utilise par défaut le chunked prefill, qui permet de traiter les longues étapes de pré-remplissage par morceaux, les intégrant avec les requêtes de décodage. Ce mécanisme vise à équilibrer les tâches gourmandes en calcul (préfill) et celles dépendant de la mémoire (décodage). La politique privilégie les requêtes de décodage, ce qui améliore la latence inter-token (ITL). Pour optimiser le temps de première token (TTFT), il est recommandé de régler max_num_batched_tokens à une valeur supérieure à 8192, en particulier pour les modèles plus petits tournant sur de grosses cartes.

Parallèlement à ces optimisations d’exécution, d’autres acteurs du domaine travaillent sur la persistance de l’état. SGLang, par exemple, propose plusieurs formats de chargement, allant du safetensors au layered, et intègre des mécanismes comme le sharded state pour les modèles à très grande échelle. Ces outils, en parallèle de ceux de vLLM, montrent une tendance forte à vouloir sauvegarder et réutiliser l’état initialisé, que ce soit les poids chargés ou les artefacts compilés.

L’architecture de chargement des poids

Le processus par lequel les poids arrivent dans le moteur d’inférence est un domaine de recherche à part entière. SGLang fournit un éventail de formats de chargement sophistiqués. On trouve le format instanttensor, qui utilise un chargement distribué et un préchargement par pipeline, ou encore le runai_streamer pour charger directement depuis des systèmes de stockage objet comme S3 ou GCS. Ces méthodes affectent directement comment les poids sont traités avant d’être disponibles pour le moteur.

Ces mécanismes de chargement sont distincts des caches de compilation de vLLM. Alors que vLLM se concentre sur la réutilisation des résultats de compilation GPU, SGLang s’attache davantage à l’efficacité de la lecture des fichiers sur le stockage sous-jacent. Il est intéressant de noter que les deux écosystèmes convergent vers une vision où le temps de démarrage n’est plus vu comme une simple séquence d’étapes, mais comme un ensemble de couches de travail pouvant être pré-calculées, stockées, et réutilisées.

La question qui reste entière, c’est comment intégrer ces différentes formes de persistance — cache de compilation, poids préchargés, état de moteur sauvegardé — dans un workflow de production stable et interopérable.

Sources