Prompt engineering

Accélérer l’inférence des grands modèles de langage : Techniques pour un déploiement efficace

mm
LLM Inference Speed up

Les grands modèles de langage (LLM) comme GPT-4, LLaMA, et PaLM poussent les limites de ce qui est possible avec le traitement automatique des langues. Cependant, le déploiement de ces modèles massifs dans des environnements de production présente des défis importants en termes d’exigences computationnelles, d’utilisation de la mémoire, de latence et de coût. Alors que les LLM continuent de grandir et de devenir plus capables, l’optimisation de leurs performances d’inférence est cruciale pour les applications du monde réel.

Dans cette plongée technique, nous allons explorer des techniques de pointe pour accélérer l’inférence des LLM, permettant des temps de réponse plus rapides, un débit plus élevé et une utilisation plus efficace des ressources matérielles. Nous allons couvrir des méthodes allant des techniques de précision numérique et de mécanismes d’attention novateurs à des innovations architecturales conçues spécifiquement pour une génération de texte efficace.

Commençons par comprendre pourquoi l’inférence des LLM est si difficile par rapport aux modèles de traitement automatique des langues traditionnels.

Le défi de l’inférence avec les grands modèles de langage

Avant l’avènement des LLM, le traitement automatique des langues reposait sur des modèles plus petits axés sur des tâches spécifiques comme la classification de texte, la reconnaissance d’entités nommées et l’analyse de sentiments. Même si ces modèles étaient déjà intensifs en termes de calcul, ils pouvaient être déployés sur un matériel modeste et suivaient des processus d’inférence relativement simples.

Les LLM, en revanche, représentent un changement de paradigme. Ces modèles sont formés sur des ensembles de données massifs en utilisant des milliards de paramètres, leur permettant de réaliser une large gamme de tâches de langage avec une remarquable compétence. Cependant, ce pouvoir est à l’origine d’un coût – des exigences computationnelles dramatiquement accrues pendant à la fois l’entraînement et l’inférence.

Un des principaux défis est la nature autorégressive de la génération de texte avec les LLM. Pour produire du texte ressemblant à celui des humains, ces modèles prédisent un jeton (mot ou sous-mot) à la fois, chaque nouveau jeton dépendant de la sortie générée précédemment. Cette dépendance séquentielle empêche une parallélisation efficace et entraîne des exigences computationnelles qui augmentent de manière polynomial avec la longueur de la séquence.

De plus, les LLM nécessitent souvent de longues séquences d’entrée (prompts) pour établir le contexte nécessaire à une génération de texte de haute qualité. Des longueurs d’entrée plus longues exigent plus de mémoire pour stocker les états intermédiaires et les matrices d’attention, ce qui sollicite davantage les ressources matérielles.

Avec ces défis uniques, les techniques d’optimisation traditionnelles comme la quantification et les graphiques de calcul statiques peuvent être insuffisantes, luttant pour maintenir les performances des LLM tout en offrant des accélérations significatives. Plongeons dans certaines des stratégies clés conçues spécifiquement pour accélérer l’inférence des LLM.

Techniques de précision numérique

De 32 bits à 16 bits de précision

De 32 bits à 16 bits de précision

Une voie pour accélérer l’inférence des LLM consiste à exploiter une précision numérique réduite pour les poids et les activations du modèle. Les cadres d’apprentissage automatique modernes comme PyTorch et TensorFlow emploient généralement une précision à virgule flottante de 32 bits (FP32) par défaut. Cependant, des recherches ont montré que les LLM peuvent souvent maintenir une grande précision même lorsqu’ils fonctionnent à des précisions plus faibles, comme 16 bits (FP16), 8 bits entiers (INT8) ou même 4 bits entiers (INT4).

La réduction de la précision numérique offre plusieurs avantages :

  • Empreinte mémoire réduite : Les représentations à faible précision nécessitent moins de mémoire, permettant ainsi à des modèles plus grands ou à des tailles de lots plus importantes de tenir dans les mêmes contraintes matérielles.
  • Calcul plus rapide : De nombreux processeurs et cartes graphiques modernes offrent des instructions et une accélération matérielle spécialisées pour l’arithmétique à faible précision, permettant ainsi des accélérations significatives.
  • Efficacité énergétique améliorée : Avec des exigences de mémoire plus faibles et des calculs plus rapides, l’inférence à faible précision peut se traduire par une consommation d’énergie réduite – un avantage crucial pour les déploiements sur le bord et les appareils mobiles.

Bien que puissante, la technique de précision numérique introduit une certaine perte de précision par rapport à l’opération FP32. La clé est de bien évaluer ce compromis entre les gains computationnels et la dégradation potentielle des performances pour votre cas d’utilisation spécifique.

Il existe deux approches principales de quantification avec les LLM :

Quantification après l’entraînement (PTQ) : Dans cette méthode, un LLM est d’abord entraîné en utilisant la précision FP32 standard. Après l’entraînement, les poids du modèle sont quantifiés (convertis) en un format de précision inférieure comme INT8 ou INT4. La PTQ est simple à mettre en œuvre mais peut entraîner une plus grande perte de précision.

Entraînement avec prise en compte de la quantification (QAT) : Avec le QAT, le processus de quantification est simulé pendant la phase d’entraînement elle-même. Cela permet au modèle d’apprendre à compenser les erreurs de quantification, minimisant ainsi la dégradation de la précision lorsque le modèle quantifié final est déployé. Le QAT est plus complexe mais donne souvent de meilleurs résultats que la PTQ.

Pour une application pratique, on pourrait utiliser des modèles pré-quantifiés disponibles sur des plateformes comme Hugging Face, qui héberge une variété de modèles optimisés via différentes méthodes de quantification. Par exemple, si un modèle quantifié en utilisant Auto-GPTQ est souhaité, les utilisateurs peuvent facilement le charger en utilisant la bibliothèque de transformateurs de Hugging Face. De plus, pour quantifier un modèle, des outils comme AutoGPTQ peuvent être utilisés, qui s’intègrent sans effort aux bibliothèques existantes pour compresser le modèle de manière efficace.

Voici un exemple de chargement d’un modèle Llama-2-7b pré-quantifié en utilisant la bibliothèque de transformateurs de Hugging Face :

from transformers import AutoModelForCausalLM, AutoTokenizer

model_id = "TheBloke/Llama-2-7b-Chat-GPTQ"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
Et pour une quantification personnalisée, on pourrait suivre ces étapes en utilisant l'outil AutoGPTQ :

from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig

model_id = "llama-2-7b-original"
tokenizer = AutoTokenizer.from_pretrained(model_id)
quantization_config = GPTQConfig(bits=4, dataset="votre-ensemble-de-données", tokenizer=tokenizer)
model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quantization_config)

N’oubliez pas que la quantification peut nécessiter un affinage post-quantification ou une ingénierie de prompt pour maintenir la qualité du modèle. Pour une nouvelle quantification, vous pouvez contribuer à la communauté en poussant vos modèles quantifiés vers des plateformes comme Hugging Face.

Assurez-vous toujours de trouver un équilibre entre la taille du modèle, les exigences computationnelles et les performances lors de la sélection de la stratégie de quantification pour votre cas d’utilisation spécifique.

 

L’algorithme d’attention Flash

Le mécanisme d’attention multi-tête est un composant essentiel des LLM basés sur les transformateurs, permettant au modèle de capturer des dépendances à longue portée et des représentations contextualisées. Cependant, cette opération d’attention est inefficace sur le plan computationnel pour la génération de texte autorégressive, car elle nécessite de recalculer de nombreuses valeurs pour chaque nouveau jeton.

L’algorithme d’attention Flash, introduit dans le document FlashAttention, fournit une approche plus efficace en termes de mémoire et plus favorable à la parallélisation pour l’opération d’attention. Au lieu de recalculer les valeurs d’attention pour chaque jeton, l’algorithme d’attention Flash met en cache et réutilise les matrices clé/valeur intermédiaires, évitant ainsi les calculs redondants.

Cette optimisation ne réduit pas seulement la charge computationnelle mais améliore également les modèles d’accès à la mémoire, conduisant à une meilleure utilisation de la bande passante de la mémoire GPU et du parallélisme.

Même si les détails de l’algorithme d’attention Flash sont assez complexes, l’idée de base est de décomposer l’opération d’attention en deux phases :

  1. Intégration d’incrustation de préfixe : Cette phase calcule et met en cache les incrustations clé/valeur pour tous les jetons d’entrée, permettant ainsi une réutilisation efficace pendant la génération.
  2. Attention causale : L’opération d’attention réelle, maintenant optimisée pour exploiter les incrustations clé/valeur mises en cache de la première phase.

En séparant ces phases, l’algorithme d’attention Flash peut tirer parti des opérations parallèles sur GPU à haute performance, accélérant ainsi de manière significative le goulet d’étranglement de l’attention dans l’inférence des LLM.

Voici une brève illustration conceptuelle de la mise en œuvre de l’algorithme d’attention Flash avec un LLM :

from transformers import AutoModelForCausalLM
import torch
from flash_attention import flash_attention

# Charger un LLM comme OctoCoder
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder")

# Exemple de prompt système qui guide le modèle pour qu'il soit un meilleur assistant de codage
system_prompt = "« ... (détails du prompt système) ... »"

# Préparation d'une entrée plus longue avec le prompt système
long_prompt = system_prompt + "Question : Écrivez une fonction en Python qui transforme des octets en gigaoctets."

# Conversion du modèle pour l'optimisation Flash Attention
model.to_bettertransformer()

# Exécution du modèle avec Flash Attention
start_time = time.time()
with torch.backends.cuda.sdp_kernel(enable_flash=True):
result = model.generate(long_prompt, max_new_tokens=60)
print(f"Généré en {time.time() - start_time} secondes.")

Même si l’algorithme d’attention Flash offre des gains de performance impressionnants, il fonctionne dans l’architecture de transformateur existante. Pour libérer pleinement le potentiel de l’inférence accélérée des LLM, nous devons explorer les innovations architecturales conçues spécifiquement pour cette tâche.

Élagage des LLM

L’élagage des LLM est une technique pour réduire la taille du modèle tout en maintenant sa fonctionnalité. Il utilise un estimateur de l’importance des poids basé sur des approximations de la matrice de Hesse. L’élagage consiste à supprimer les groupes de poids les moins importants, puis le modèle est affiné pour récupérer la précision. Le package LLM-Pruner propose des scripts pour l’élagage avec différentes stratégies prises en charge. L’élagage inclut la découverte des dépendances, l’estimation des contributions de groupe et une phase de récupération impliquant un court entraînement postérieur.

Voici un exemple simplifié de code Python démontrant l’utilisation de LLM-Pruner pour un modèle LLaMa :

from transformers import AutoModelForSequenceClassification
from pruning import LLMPruner

# Charger le modèle LLaMa pré-entraîné
model = AutoModelForSequenceClassification.from_pretrained("llama-base")

# Initialiser l'élagueur avec la configuration souhaitée
pruner = LLMPruner(
model,
pruning_ratio=0.25,
block_mlp_layers=(4, 30),
block_attention_layers=(4, 30),
pruner_type='taylor'
)

# Exécuter l'élagage
pruned_model = pruner.prune()

# Affiner le modèle élagué
pruned_model.fine_tune(données_d'entraînement)

Ce croquis de code représente le chargement d’un modèle LLaMa pré-entraîné, la configuration de l’élagueur avec des paramètres spécifiques (comme les couches à élaguer et le type d’élagueur), l’exécution du processus d’élagage, puis l’affinage du modèle élagué.

Notez que pour une mise en œuvre réelle, vous devriez remplir les détails tels que le nom spécifique du modèle, les chemins d’accès aux données, et des paramètres supplémentaires pour le processus d’affinage. De plus, soyez conscient que ce code est une représentation conceptuelle, et la syntaxe réelle peut varier en fonction de la bibliothèque et des versions utilisées.

Innovations architecturales pour une génération de texte efficace

L’architecture de transformateur, bien qu’extrêmement efficace pour les tâches de modélisation de langage, a été conçue comme un modèle de séquence à séquence généraliste. Lors du déploiement des LLM pour des tâches de génération de texte avec des contextes d’entrée longs, les chercheurs ont constaté que des architectures plus spécialisées peuvent améliorer considérablement l’efficacité d’inférence sans sacrifier la qualité.

Voici certaines des innovations architecturales clés permettant une inférence des LLM plus rapide :

Alibi : L’architecture Alibi, introduite dans le document PAL-Instruction, sépare la modélisation du contexte d’entrée long de la génération de texte elle-même. Elle utilise une représentation compressée du contexte d’entrée (l'”alibi”) pour initialiser le processus de génération, évitant ainsi le besoin de traiter la séquence d’entrée complète à plusieurs reprises pendant la génération autorégressive.

Incrustations rotatives : Au lieu d’utiliser des incrustations de position standard, la technique d’incrustation rotative emploie des matrices de rotation pour encoder l’information de position de manière plus efficace. Cette approche a été montrée pour améliorer les performances et permettre le traitement de séquences d’entrée plus longues.

Attention multi-requête (MQA) : Dans l’attention traditionnelle, chaque jeton de sortie fait attention à toute la séquence d’entrée, ce qui entraîne des calculs redondants. La MQA reformule l’opération d’attention pour partager les calculs entre plusieurs jetons de sortie, réduisant ainsi la complexité globale.

Attention multi-requête

Attention multi-requête

Attention regroupée-requête (GQA) : En s’appuyant sur la MQA, la GQA regroupe les jetons de sortie en clusters et calcule l’attention conjointement pour chaque cluster. Cette approche réduit encore les exigences computationnelles tout en maintenant une génération de texte de haute qualité.

Même si ces innovations architecturales sont encore en cours de recherche et de développement, elles ont déjà démontré des accélérations impressionnantes pour les tâches d’inférence des LLM, en particulier lorsqu’elles sont combinées avec des techniques comme Flash Attention et l’optimisation de la précision numérique.

Considérations de déploiement dans le monde réel

Au-delà des algorithmes et des architectures de base, il existe plusieurs considérations pratiques et compromis à naviguer lors du déploiement des LLM dans des environnements de production :

Accélération matérielle : Même si les processeurs peuvent gérer l’inférence des LLM, les cartes graphiques et d’autres accélérateurs comme les TPUs de Google sont essentiels pour atteindre un débit élevé et une faible latence. Le choix du matériel approprié et l’optimisation de l’utilisation de la mémoire sont cruciaux.

Batching et parallélisme : Pour exploiter pleinement le parallélisme matériel, des stratégies comme l’inférence par lots (traitement de plusieurs entrées simultanément) et le parallélisme de modèle (distribution d’un LLM sur plusieurs appareils) peuvent considérablement augmenter le débit.

Compromis entre quantification et qualité : Le degré de quantification (8 bits, 4 bits, etc.) aura un impact direct sur la vitesse d’inférence et l’utilisation de la mémoire, mais affectera également la qualité de sortie. Ce compromis doit être soigneusement évalué pour chaque cas d’utilisation.

Distillation de modèle : Une alternative à la quantification, les techniques de distillation de modèle peuvent compresser de grands LLM en modèles étudiants plus petits et plus efficaces tout en conservant une grande précision.

Mise en cache et exécution optimisée : Des exécutions d’apprentissage automatique optimisées comme NVIDIA TensorRT et des cadres conçus pour le service des LLM (par exemple, MosaicML’s Composable Inference Suite) peuvent fournir des améliorations de performances significatives grâce à des techniques comme la fusion d’opérateurs, l’optimisation de noyau et des stratégies de mise en cache intelligentes.

Le chemin vers un déploiement optimal des LLM implique souvent de combiner plusieurs techniques tout en considérant soigneusement les exigences spécifiques de votre application, les contraintes d’infrastructure et les objectifs de performance.

Conclusion

Alors que les grands modèles de langage continuent leur évolution rapide, accélérer leurs performances d’inférence devient de plus en plus crucial pour permettre des applications du monde réel et démocratiser l’accès à ces puissantes capacités d’IA.

Dans ce guide technique, nous avons exploré des techniques de pointe allant de l’optimisation de la précision numérique à de nouveaux algorithmes d’attention comme Flash Attention et des innovations architecturales conçues pour une génération de texte efficace. Même si chaque approche offre ses propres avantages, le véritable pouvoir réside souvent dans la combinaison de plusieurs stratégies tout en naviguant dans les compromis complexes entre vitesse, utilisation de la mémoire et qualité de sortie.

En regardant vers l’avenir, nous pouvons nous attendre à une poursuite de la recherche et du développement dans ce domaine, alimentée par la demande insatiable de LLM plus capables et plus accessibles. Des accélérateurs matériels à la compression de modèles et à de nouvelles architectures, la quête d’une inférence efficace des LLM reste un domaine passionnant dans le monde du traitement automatique des langues et de l’intelligence artificielle.

J'ai passé les cinq dernières années à me plonger dans le monde fascinant de l'apprentissage automatique et de l'apprentissage profond. Ma passion et mon expertise m'ont conduit à contribuer à plus de 50 projets de génie logiciel divers, avec un accent particulier sur l'IA/ML. Ma curiosité permanente m'a également attiré vers le traitement automatique des langues, un domaine que je suis impatient d'explorer plus en détail.