Intelligence artificielle
Optimiser le déploiement de LLM : vLLM PagedAttention et l’avenir du service d’IA efficace

Les modèles de langage à grande échelle (LLM) déployés sur des applications du monde réel présentent des défis uniques, notamment en termes de ressources computationnelles, de latence et de rentabilité. Dans ce guide complet, nous allons explorer le paysage du service LLM, avec un focus particulier sur vLLM (modèle de langage vectoriel), une solution qui révolutionne la façon dont nous déployons et interagissons avec ces modèles puissants.
Les défis du service de modèles de langage à grande échelle
Avant de plonger dans des solutions spécifiques, examinons les défis clés qui rendent le service LLM une tâche complexe :
Ressources computationnelles
Les LLM sont notoires pour leur nombre énorme de paramètres, allant de milliards à des centaines de milliards. Par exemple, GPT-3 compte 175 milliards de paramètres, tandis que des modèles plus récents comme GPT-4 sont estimés avoir encore plus. Cette taille considérable se traduit par des exigences computationnelles significatives pour l’inférence.
Exemple :
Considérez un LLM relativement modeste avec 13 milliards de paramètres, comme LLaMA-13B. Même ce modèle nécessite :
– Environ 26 Go de mémoire pour stocker simplement les paramètres du modèle (en supposant une précision 16 bits)
– De la mémoire supplémentaire pour les activations, les mécanismes d’attention et les calculs intermédiaires
– Une puissance de calcul GPU substantielle pour l’inférence en temps réel
Latence
Dans de nombreuses applications, telles que les chatbots ou la génération de contenu en temps réel, une faible latence est cruciale pour une bonne expérience utilisateur. Cependant, la complexité des LLM peut entraîner des temps de traitement significatifs, en particulier pour les séquences plus longues.
Exemple :
Imaginez un chatbot de service client alimenté par un LLM. Si chaque réponse prend plusieurs secondes à générer, la conversation semblera peu naturelle et frustrante pour les utilisateurs.
Coût
Le matériel nécessaire pour exécuter les LLM à grande échelle peut être extrêmement coûteux. Des GPU ou des TPU de haute gamme sont souvent nécessaires, et la consommation d’énergie de ces systèmes est substantielle.
Exemple :
L’exécution d’un cluster de GPU NVIDIA A100 (souvent utilisés pour l’inférence LLM) peut coûter des milliers de dollars par jour en frais de calcul cloud.
Approches traditionnelles de service LLM
Avant d’explorer des solutions plus avancées, résumons brièvement certaines approches traditionnelles de service LLM :
Déploiement simple avec Hugging Face Transformers
La bibliothèque Hugging Face Transformers offre une façon simple de déployer des LLM, mais elle n’est pas optimisée pour un service à haut débit.
Exemple de code :
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
model_name = "meta-llama/Llama-2-13b-hf"
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_name)
def generate_text(prompt, max_length=100):
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_length=max_length)
return tokenizer.decode(outputs[0], skip_special_tokens=True)
print(generate_text("L'avenir de l'IA est"))
Bien que cette approche fonctionne, elle n’est pas adaptée aux applications à trafic élevé en raison de son utilisation inefficace des ressources et du manque d’optimisations pour le service.
Utilisation de TorchServe ou de frameworks similaires
Des frameworks comme TorchServe offrent des capacités de service plus robustes, notamment l’équilibrage de charge et la gestion des versions de modèles. Cependant, ils n’abordent pas spécifiquement les défis du service LLM, tels que la gestion efficace de la mémoire pour les grands modèles.
Comprendre la gestion de la mémoire dans le service LLM
La gestion efficace de la mémoire est cruciale pour le service de modèles de langage à grande échelle (LLM) en raison des ressources computationnelles considérables requises. Les images suivantes illustrent divers aspects de la gestion de la mémoire, qui sont essentiels pour optimiser les performances LLM.
Mémoire segmentée vs. mémoire paginée
Ces deux diagrammes comparent les techniques de gestion de la mémoire segmentée et paginée, couramment utilisées dans les systèmes d’exploitation (SE).
- Mémoire segmentée : Cette technique divise la mémoire en différents segments, chacun correspondant à un programme ou processus différent. Dans le contexte du service LLM, des segments différents pourraient être alloués à divers composants du modèle, tels que la tokenisation, l’incrustation et les mécanismes d’attention. Chaque segment peut grandir ou diminuer indépendamment, offrant de la flexibilité mais pouvant potentiellement conduire à la fragmentation si les segments ne sont pas gérés correctement.
- Mémoire paginée : Ici, la mémoire est divisée en pages de taille fixe, qui sont mappées sur la mémoire physique. Les pages peuvent être échangées au besoin, permettant une utilisation efficace des ressources de mémoire. Dans le service LLM, cela peut être crucial pour gérer les grandes quantités de mémoire nécessaires pour stocker les poids du modèle et les calculs intermédiaires.
Gestion de la mémoire dans le système d’exploitation vs. vLLM
Cette image contraste la gestion traditionnelle de la mémoire du système d’exploitation avec l’approche de gestion de la mémoire utilisée dans vLLM.
- Gestion de la mémoire du système d’exploitation : Dans les systèmes d’exploitation traditionnels, les processus (par exemple, Processus A et Processus B) sont alloués des pages de mémoire (Page 0, Page 1, etc.) dans la mémoire physique. Cette allocation peut conduire à la fragmentation au fil du temps à mesure que les processus demandent et libèrent de la mémoire.
- Gestion de la mémoire vLLM : Le framework vLLM utilise un cache Key-Value (KV) pour gérer la mémoire de manière plus efficace. Les demandes (par exemple, Demande A et Demande B) sont allouées des blocs du cache KV (Bloc KV 0, Bloc KV 1, etc.). Cette approche aide à minimiser la fragmentation et à optimiser l’utilisation de la mémoire, permettant un service de modèle plus rapide et plus efficace.
Mécanisme d’attention dans les LLM
Le mécanisme d’attention est un composant fondamental des modèles de transformateurs, qui sont couramment utilisés pour les LLM. Ce diagramme illustre la formule d’attention et ses composants :
- Requête (Q) : Un nouveau jeton à l’étape de décodage ou le dernier jeton que le modèle a vu.
- Clé (K) : Le contexte précédent auquel le modèle doit prêter attention.
- Valeur (V) : Somme pondérée sur le contexte précédent.
La formule calcule les scores d’attention en prenant le produit scalaire de la requête avec les clés, en réduisant par la racine carrée de la dimension de la clé, en appliquant une fonction softmax, et enfin en prenant le produit scalaire avec les valeurs. Ce processus permet au modèle de se concentrer sur les parties pertinentes de la séquence d’entrée lors de la génération de chaque jeton.
Comparaison du débit de service
Cette image présente une comparaison du débit de service entre différents frameworks (HF, TGI et vLLM) en utilisant des modèles LLaMA sur différents ensembles de matériel.
- LLaMA-13B, A100-40GB : vLLM atteint un débit 14 à 24 fois supérieur à celui de HuggingFace Transformers (HF) et 2,2 à 2,5 fois supérieur à celui de HuggingFace Text Generation Inference (TGI).
- LLaMA-7B, A10G : Des tendances similaires sont observées, avec vLLM surpassant nettement à la fois HF et TGI.
vLLM : Une nouvelle architecture de service LLM
vLLM, développé par les chercheurs de l’UC Berkeley, représente un grand pas en avant dans la technologie de service LLM. Explorons ses fonctionnalités clés et ses innovations :
PagedAttention
Au cœur de vLLM se trouve PagedAttention, un algorithme d’attention novateur inspiré de la gestion de la mémoire virtuelle dans les systèmes d’exploitation. Voici comment cela fonctionne :
– Partitionnement du cache Key-Value (KV) : Au lieu de stocker l’ensemble du cache KV de manière contiguë dans la mémoire, PagedAttention le divise en blocs de taille fixe.
– Stockage non contigu : Ces blocs peuvent être stockés de manière non contiguë dans la mémoire, permettant une gestion de la mémoire plus flexible.
– Allocation à la demande : Les blocs sont alloués uniquement lorsqu’ils sont nécessaires, réduisant les pertes de mémoire.
– Partage efficace : Plusieurs séquences peuvent partager des blocs, permettant des optimisations pour des techniques comme l’échantillonnage parallèle et la recherche en faisceau.
Illustration :
“`
Cache KV traditionnel :
[Token 1 KV][Token 2 KV][Token 3 KV]…[Token N KV]
(Allocation de mémoire contiguë)
Cache KV PagedAttention :
[Bloc 1] -> Adresse physique A
[Bloc 2] -> Adresse physique C
[Bloc 3] -> Adresse physique B
…
(Allocation de mémoire non contiguë)
“`
Cette approche réduit considérablement la fragmentation de la mémoire et permet une utilisation beaucoup plus efficace de la mémoire GPU.
Batching continu
vLLM met en œuvre le batching continu, qui traite dynamiquement les demandes à mesure qu’elles arrivent, plutôt que d’attendre de former des lots de taille fixe. Cela conduit à une latence plus faible et à un débit plus élevé.
Exemple :
Imaginez un flux de demandes entrantes :
“`
Temps 0ms : Demande A arrive
Temps 10ms : Début du traitement de la Demande A
Temps 15ms : Demande B arrive
Temps 20ms : Début du traitement de la Demande B (en parallèle avec A)
Temps 25ms : Demande C arrive
…
“`
Avec le batching continu, vLLM peut commencer à traiter chaque demande immédiatement, plutôt que d’attendre de les regrouper en lots prédéfinis.
Échantillonnage parallèle efficace
Pour les applications qui nécessitent plusieurs échantillons de sortie par invite (par exemple, des assistants de rédaction créative), les capacités de partage de mémoire de vLLM brillent. Il peut générer plusieurs sorties tout en réutilisant le cache KV pour les préfixes partagés.
Exemple de code en utilisant vLLM :
from vllm import LLM, SamplingParams
llm = LLM(model="meta-llama/Llama-2-13b-hf")
prompts = ["L'avenir de l'IA est"]
# Générer 3 échantillons par invite
sampling_params = SamplingParams(n=3, temperature=0.8, max_tokens=100)
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
print(f"Invite : {output.prompt}")
for i, out in enumerate(output.outputs):
print(f"Échantillon {i + 1} : {out.text}")
Ce code génère efficacement plusieurs échantillons pour l’invite donnée, en exploitant les optimisations de vLLM.
Benchmarking des performances de vLLM
Pour vraiment apprécier l’impact de vLLM, regardons quelques comparaisons de performances :
Comparaison du débit
Sur la base des informations fournies, vLLM surpasse nettement les autres solutions de service :
– Jusqu’à 24 fois plus de débit par rapport à Hugging Face Transformers
– 2,2 à 3,5 fois plus de débit que Hugging Face Text Generation Inference (TGI)
Illustration :
“`
Débit (jetons/seconde)
|
| ****
| ****
| ****
| **** ****
| **** **** ****
| **** **** ****
|————————
HF TGI vLLM
“`
Efficacité de la mémoire
Le PagedAttention de vLLM aboutit à une utilisation de la mémoire presque optimale :
– Seulement environ 4 % de perte de mémoire, par rapport à 60-80 % dans les systèmes traditionnels
– Cette efficacité permet de servir des modèles plus grands ou de gérer plus de demandes simultanées avec le même matériel
Commencer avec vLLM
Maintenant que nous avons exploré les avantages de vLLM, décomposons le processus de mise en place et d’utilisation dans vos projets.
6.1 Installation
L’installation de vLLM est straightforward en utilisant pip :
!pip install vllm
6.2 Utilisation de base pour l’inférence hors ligne
Voici un exemple simple d’utilisation de vLLM pour la génération de texte hors ligne :
from vllm import LLM, SamplingParams
# Initialiser le modèle
llm = LLM(model="meta-llama/Llama-2-13b-hf")
# Préparer les invites
prompts = [
"Écrivez un court poème sur l'intelligence artificielle :",
"Expliquez l'informatique quantique en termes simples :"
]
# Définir les paramètres d'échantillonnage
sampling_params = SamplingParams(temperature=0.8, max_tokens=100)
# Générer des réponses
outputs = llm.generate(prompts, sampling_params)
# Imprimer les résultats
for output in outputs:
print(f"Invite : {output.prompt}")
print(f"Texte généré : {output.outputs[0].text}\n")
Ce script démontre comment charger un modèle, définir des paramètres d’échantillonnage et générer du texte pour plusieurs invites.
6.3 Configuration d’un serveur vLLM
Pour le service en ligne, vLLM fournit un serveur d’API compatible OpenAI. Voici comment le configurer :
1. Démarrez le serveur :
python -m vllm.entrypoints.openai.api_server --model meta-llama/Llama-2-13b-hf
2. Interrogez le serveur en utilisant curl :
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{"model": "meta-llama/Llama-2-13b-hf", "prompt": "L'avenir de l'IA est", "max_tokens": 100, "temperature": 0.7}'
Cette configuration vous permet de servir votre LLM avec une interface compatible avec l’API OpenAI, facilitant ainsi l’intégration dans des applications existantes.
Sujets avancés sur vLLM
Bien que vLLM offre des améliorations significatives dans le service LLM, il existe des considérations et des sujets avancés à explorer :
7.1 Quantification du modèle
Pour un service encore plus efficace, notamment sur du matériel à mémoire limitée, des techniques de quantification peuvent être employées. Bien que vLLM lui-même ne prenne pas en charge la quantification, il peut être utilisé conjointement avec des modèles quantifiés :
from transformers import AutoModelForCausalLM, AutoTokenizer import torch # Charger un modèle quantifié model_name = "meta-llama/Llama-2-13b-hf" model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", load_in_8bit=True) tokenizer = AutoTokenizer.from_pretrained(model_name) # Utiliser le modèle quantifié avec vLLM from vllm import LLM llm = LLM(model=model, tokenizer=tokenizer)
7.2 Inférence distribuée
Pour des modèles extrêmement grands ou des applications à trafic élevé, l’inférence distribuée sur plusieurs GPU ou machines peut être nécessaire. Bien que vLLM ne prenne pas en charge cela de manière native, il peut être intégré dans des systèmes distribués en utilisant des frameworks comme Ray :
import ray
from vllm import LLM
@ray.remote(num_gpus=1)
class DistributedLLM:
def __init__(self, model_name):
self.llm = LLM(model=model_name)
def generate(self, prompt, params):
return self.llm.generate(prompt, params)
# Initialiser des LLM distribués
llm1 = DistributedLLM.remote("meta-llama/Llama-2-13b-hf")
llm2 = DistributedLLM.remote("meta-llama/Llama-2-13b-hf")
# Les utiliser en parallèle
result1 = llm1.generate.remote("Invite 1", sampling_params)
result2 = llm2.generate.remote("Invite 2", sampling_params)
# Récupérer les résultats
print(ray.get([result1, result2]))
7.3 Surveillance et observabilité
Lors du service de LLM en production, la surveillance est cruciale. Bien que vLLM ne fournisse pas de surveillance intégrée, vous pouvez l’intégrer avec des outils comme Prometheus et Grafana :
from prometheus_client import start_http_server, Summary
from vllm import LLM
# Définir des métriques
REQUEST_TIME = Summary('request_processing_seconds', 'Temps passé à traiter la demande')
# Initialiser vLLM
llm = LLM(model="meta-llama/Llama-2-13b-hf")
# Exposer les métriques
start_http_server(8000)
# Utiliser le modèle avec surveillance
@REQUEST_TIME.time()
def process_request(prompt):
return llm.generate(prompt)
# Votre boucle de service ici
Cette configuration vous permet de suivre des métriques comme le temps de traitement de la demande, qui peuvent être visualisées dans des tableaux de bord Grafana.
Conclusion
Le service de modèles de langage à grande échelle de manière efficace est une tâche complexe mais cruciale à l’ère de l’IA. vLLM, avec son algorithme d’attention innovant PagedAttention et sa mise en œuvre optimisée, représente un grand pas en avant dans le déploiement de LLM plus accessible et rentable.
En améliorant considérablement le débit, en réduisant les pertes de mémoire et en permettant des options de service plus flexibles, vLLM ouvre de nouvelles possibilités pour intégrer des modèles de langage puissants dans une large gamme d’applications. Que vous construisiez un chatbot, un système de génération de contenu ou toute autre application alimentée par le NLP, comprendre et exploiter des outils comme vLLM sera clé pour le succès.














