[!NOTE] Traduction automatique Cet article a été traduit automatiquement depuis la version originale en anglais.
Échelle des grands modèles de langage : stratégies multi-GPU et multi-nœuds performantes en pratique
Les charges de travail liées aux grands modèles dépassent le cadre d’un seul GPU pour diverses raisons. Un job d’entraînement peut manquer de mémoire en raison de l’état de l’optimiseur, un autre en raison des activations de séquences longues, et même un modèle qui tient dans les ressources disponibles peut ne pas atteindre son objectif de débit. Chacun de ces problèmes exige une stratégie de partitionnement et un schéma de communication différents.
Il s’agit d’une présentation pratique des principales stratégies de parallélisme ainsi que des contraintes qui les sous-tendent, éclairée par les travaux de Hugging Face. Guide de mise en œuvre à très grande échelle. L’objectif est de montrer ce que chaque partition apporte, ce qu’elle transmet, et à quel moment des combinaisons deviennent nécessaires.
En résumé. Le parallélisme de données répliqué améliore le débit d’entraînement lorsque l’espace mémoire d’une réplique est suffisant. Le parallélisme de données entièrement shardé divise l’état du modèle, mais implique des opérations de collecte de tous les paramètres ainsi que des opérations de réduction et de dispersion des gradients. Le parallélisme tensoriel, pipeline, contextuel et d’expertise permet de séparer les calculs de couche, la profondeur, les séquences et les experts MoE. Il convient de les combiner uniquement après avoir identifié les contraintes liées à la mémoire ou aux communications.
Ce guide part du principe que vous maîtrisez déjà la rétropropagation, les couches Transformer ainsi qu’un cycle d’entraînement PyTorch standard.
Commencer avec deux budgets de mémoire
L’entraînement et l’inference n’ont pas la même empreinte en ressources.
training peak ≈ parameters
+ gradients
+ optimizer state
+ saved activations
+ temporary buffers
+ communication buffers
+ allocator headroom
inference peak ≈ resident weights
+ KV cache
+ runtime workspace
+ communication buffers
+ allocator headroom
Un modèle de 70 milliards de paramètres nécessite au moins 140 Go en format décimal rien que pour les poids de BF16. Ce chiffre ne dit pas grand-chose sur le processus d’entraînement, où les gradients, l’état de l’optimiseur, les poids maîtres et les activations peuvent jouer un rôle prédominant. De plus, il ne prend pas en compte la taille requise par serving, domaine où la politique de cache, la longueur des séquences, la concurrence entre lots et la quantification sont des facteurs déterminants.
Décrivez en détail l’architecture, le niveau de précision, la longueur de séquence, les micro-batches, l’optimiseur, la politique de sauvegarde des points de contrôle, ainsi que runtime. Notez également la mémoire allouée et réservée à leur pic, le nombre de tokens par seconde, le temps passé dans les noyaux de calcul, et le temps d’exécution lors des opérations collectives.
Chaque dimension parallèle implique un compromis
La question pertinente n’est pas « Quelle technique est la meilleure ? » mais plutôt « Quelle dimension du tenseur est divisée, quel état est répliqué, et quel collectif entre dans le chemin critique ? »
| Stratégie | Séparations | Relief primaire | Communication initiale introduite |
|---|---|---|---|
| Parallélisme de données répliquées | traitement par lots | taux de traitement des données d’entraînement | réduction gradiente globale |
| Parallélisme de données entièrement shardé | paramètres, gradients et état de l’optimiseur au sein d’un groupe DP | mémoire d’état du modèle | paramètre all-gather, réduction de gradient par scatter |
| Parallélisme des tenseurs | les dimensions de la matrice ou d’attention à l’intérieur des couches | pesées des couches et activations | les ensembles de neurones au sein des blocs Transformer |
| Pipeline parallélisme | groupes de couches | profondeur du modèle et état par étape | activations point à point associées aux bulles de planification |
| Parallélisme de contexte | dimension de séquence | mémoire d’activation à séquences longues | Échange de clé/valeur ou d’attention au sein du groupe de séquences |
| Parallélisme expert | MoE des experts et des tokens routés | Capacité d’expert par rang | affectation et combinaison de tokens, généralement de type tous-à-tous |
Le facteur de soulagement mémoire n’est pas un multiplicateur fixe. Il dépend du degré de shardage, de ce qui reste répliqué, de l’état temporaire non shardé, de la politique d’activation, des données de remplissage, des déséquilibres et des buffers.
Parallélisme de données répliquées : débit élevé sans contrainte de capacité
Le parallélisme de données distribué conserve une réplique complète d’entraînement sur chaque nœud du cluster. Chaque nœud traite un micro-ensemble de données distinct, et les gradients sont synchronisés avant l’exécution de l’étape d’optimisation.
Utilisez cette approche lorsque l’état d’entraînement complet peut être stocké avec une marge de sécurité suffisante, et que le lot global peut être augmenté ou que l’accumulation des gradients peut être ajustée. Ses principaux avantages résident dans sa sémantique simple ainsi que dans l’interaction éprouvée entre le calcul en sens inverse et la réduction des gradients par tranches.
L’ajout de rangs peut s’avérer problématique si le lot local devient trop petit, si le réseau ne parvient pas à masquer l’opération all-reduce, si la livraison des données d’entrée est retardée, ou encore si le lot d’optimisation souhaité ne permet pas une scalabilité suffisante.
Parallélisme de données entièrement shardé : mémoire d’état pour les collectifs
Le parallélisme de données entièrement shardé stocke les shards des paramètres, des gradients et de l’optimiseur au sein d’un groupe. Les paramètres d’une couche sont regroupés pour permettre le calcul, puis peuvent être à nouveau shardés ultérieurement ; les gradients, quant à eux, sont redistribués de manière réduite aux propriétaires respectifs.
La documentation actuelle PyTorch distingue les caractéristiques de FSDP2. fully_shard API provenant de la version plus ancienne FullyShardedDataParallel enveloppe. FSDP2 regroupe la communication par les modules auxquels fully_shard Cette approche est mise en œuvre et préconise une application bottom-up afin que les groupes de couches puissent superposer leurs opérations de communication et de calcul.
from torch.distributed.fsdp import fully_shard
# Apply bottom-up: each block becomes a communication group.
for block in model.transformer.blocks:
fully_shard(block)
# Shard remaining root parameters such as embeddings and output projection.
fully_shard(model)
# Construct the optimizer after parameters have become sharded DTensors.
optimizer = AdamW(model.parameters(), lr=learning_rate)
Il s’agit d’un schéma structurel et non d’un lanceur complet. Les réseaux de dispositifs, la précision mixte, le sauvegardage des points d’état, l’initialisation, l’état de l’optimiseur ainsi que le traitement distribué checkpoints doivent correspondre à l’environnement de formation.
Le shardage s’avère avantageux lorsque l’état du modèle constitue la contrainte principale et que le traitement par couches permet de masquer une partie suffisante du trafic collectif. Cependant, il peut représenter un mauvais compromis pour les modèles de petite taille, les liaisons lentes, les couches réduites, ou encore les architectures dont le groupe de shards dépasse une frontière de topologie inappropriée.
Parallélisme tensoriel : partitionnement de la mathématique des couches
Le parallélisme tensoriel divise les opérations d’algèbre linéaire au sein d’une couche, comme par exemple les projections en parallèle sur les colonnes ou sur les lignes. Les résultats partiels nécessitent des opérations collectives au sein des blocs transformateurs, ce qui rend la latence et la bande passante des facteurs critiques à chaque étape des passes avant et arrière.
Utilisez cette approche lorsque une couche ou ses activations ne conviennent pas, ou lorsque les produits matriciels sont suffisamment importants pour que des noyaux partitionnés offrent de meilleures performances qu’un seul rang. Affectez le groupe parallèle de tenseurs au domaine de communication le plus rapide disponible, puis effectuez des mesures. Un degré élevé peut réduire la taille de chaque matrice locale jusqu’à ce que l’efficacité du noyau diminue, tandis que la charge d’overhead collective augmente.
Le parallélisme séquentiel est fréquemment associé au parallélisme tensoriel afin d’éviter de répéter certaines opérations d’activation ; il diffère du parallélisme contextuel qui prend en compte l’ensemble de la séquence d’entrée du modèle.
Pipeline parallélisme : profondeur de partitionnement et temps d’planification
Le Pipeline permet de placer des groupes de couches distincts sur des étapes différentes et d’envoyer les activations entre celles-ci. Les micro-batchs assurent que les étapes fonctionnent en parallèle.
Il permet de libérer l’état du modèle à chaque étape et peut réduire le volume des communications traversant une frontière moins rapide par rapport aux collectifs de tenseurs par couche. Ses coûts incluent les bulles, les transferts d’activation, le déséquilibre entre les étapes, une planification plus complexe, ainsi qu’une récupération et des sauvegardes plus difficiles.
Pour un planning simple et équilibré de type GPipe avec p étapes et m Les micro-batchs : la fraction d’onde avant idéalisée est d’environ :
(p - 1) / (m + p - 1)
Les plannings réels peuvent recourir à des variantes « un-avant/un-arrière », « en alternance », ou « zéro bulle », et les coûts inégaux par couche peuvent avoir une influence prédominante sur la formule de calcul. Il convient de définir les limites entre les étapes en fonction du temps et de la mémoire mesurés, et non en se basant sur un nombre égal de couches.
Parallélisme de contexte : partitionnement des activations de séquences longues
Le parallélisme de contexte permet de distribuer la dimension séquentielle. Chaque nœud gère un morceau de séquence, tandis que la mécanique d’attention échange les informations nécessaires pour préserver la sémantique du contexte complet. Les implémentations peuvent recourir à des topologies en anneau point-à-point, à des opérations all-gather, all-to-all, ou à des combinaisons hiérarchisées.
Il diminue la mémoire d’activation nécessaire pour l’entraînement sur des contextes longs, mais reproduit les poids au sein du groupe de contexte et introduit une communication par attention. Les bénéfices dépendent du type d’attention, du masquage causal, de la longueur de la séquence, de la récomputation, ainsi que de la manière dont les groupes de contexte s’assemblent avec les groupes en parallèle tensoriel et de données.
Ne le sélectionnez pas à partir d’un seuil universel de 8 K, 32 K ou 100 K. Préservez la mémoire d’activation du profil ainsi que la communication d’attention adaptées à l’architecture réelle.
Parallélisme expert : uniquement pour une architecture MoE
Le parallélisme expert répartit les experts au sein des couches de mélange d’experts. Le routeur envoie des représentations de tokens aux experts sélectionnés et combine leurs résultats. Seuls les experts choisis effectuent des calculs pour chaque token, mais les poids totaux des experts nécessitent néanmoins un espace de stockage ainsi que leur serving.
Il ne s’agit pas d’un interrupteur d’optimisation destiné à un modèle dense. Il fait partie d’une architecture MoE et permet de gérer le équilibrage de charge, la capacité, les échanges de tokens entre tous les nœuds, les tokens supprimés ou complétés par des zéros, les pertes auxiliaires, ainsi que les déséquilibres liés aux pannes. Il est également possible de suivre le nombre de tokens par expert, l’entropie de routage, les débordements de capacité, le temps de communication, et la qualité du signal selon le chemin emprunté.
Composer un layout à partir de la topologie
Les systèmes de formation à grande échelle combinent différentes dimensions. La taille totale du monde suit généralement une forme de produit, comme par exemple :
world size = DP × TP × PP × CP
Le parallélisme expert peut partager ou plier les dimensions de manière différente ; il convient donc de vérifier la grille prise en charge par le framework avant d’effectuer des multiplications de façon aveugle.
Construisez le layout dans cet ordre :
- Dessiner les domaines de communication : des liens GPU vers GPU, des commutateurs, des limites NUMA, la structure des nœuds, le facteur d’oversubscription ainsi que le chemin de stockage.
- Placer les ensembles soumis à des latences élevées et fréquemment utilisés, généralement de type TP, dans le domaine le plus rapide qui convient.
- Sélectionner des FSDP ou des groupes DP répliqués en fonction de la capacité et de la bande passante restantes.
- Ajouter des PP lorsque cela améliore la disposition en profondeur ou le trafic inter-domaine, en équilibrant le temps d’exécution mesuré et l’utilisation de la mémoire.
- Ajouter des CP uniquement en raison d’une contrainte de séquence, et des EP uniquement pour tenir compte de la topologie spécialisée du modèle.
- Vérifier que les nombres de têtes, de dimensions cachées, de couches, d’experts, de lots et de séquences soient tous divisibles pour le maillage envisagé.
- Benchmark plusieurs maillages valables ; des heuristiques conscientes de la topologie permettent de sélectionner des candidats, mais pas nécessairement le meilleur d’entre eux.
Deux clusters présentant le même nombre de GPU peuvent adopter des configurations différentes, car la bande passante des liens, la hiérarchie des commutateurs, l’attachement CPU, ainsi que les conflits de réseau varient d’un cluster à l’autre.
L’entraînement et serving exigent des décisions distinctes
L’inférence ne transporte généralement ni gradients ni l’état de l’optimiseur ; par conséquent, les schémas d’entraînement de type FSDP ne se transmettent pas automatiquement.
Pour serving, demandez :
- Une seule réplique suffit-elle pour gérer les poids, KV cache, l’espace de travail ainsi que la concurrence cible ?
- Le débit est-il amélioré par davantage de répliques indépendantes ou par le shardage d’une seule réplique ?
- Le TP diminue-t-il suffisamment la charge sur les poids par rang et sur la mémoire cache pour compenser les coûts de communication entre couches ?
- Le PP est-il pris en charge de manière efficace par le moteur de modèle et le planificateur de requêtes ?
- En quoi prefill et le processus de décodage influencent-ils différemment la consommation de bande passante mémoire et les interactions interconnectées ?
- Que se passe-t-il avec la latence finale lorsque les requêtes présentent des longueurs prompt et de sortie différentes ?
Benchmark l’ensemble du serveur, y compris le planificateur, les mécanismes de quantification, la répartition des contextes, la politique de regroupement des requêtes et la modélisation de la charge de travail. Le nombre de tokens traités par seconde ne permet pas de prédire le serving temps nécessaire pour générer le premier token ni la latence entre les différents tokens.
Mesurer honnêtement un layout à échelle variable
Pour chaque candidat, enregistrer :
- le modèle, le code, runtime, les noyaux et l’identité de la topologie
- la distribution par lot global et local, ainsi que le comptage des séquences et des tokens
- la mémoire maximale par catégorie, le cas échéant
- le nombre de tokens utiles par seconde et l’utilisation des FLOP du modèle, lorsqu’ils sont calculés de manière cohérente
- le temps d’exécution dans les opérations all-reduce, all-gather, reduce-scatter, all-to-all et point-to-point
- les blocages d’entrée, le temps checkpoint, le comportement de redémarrage et la distribution des éléments en retard
- la perte de formation ou la parité sortie serving par rapport à la valeur de référence
Comparez délibérément l’échellenement faible et l’échellement fort. L’échellement faible augmente la charge totale en fonction du nombre de nœuds ; l’échellement fort maintient cette charge constante. Un pourcentage désigné comme « efficacité d’échellement » n’a aucun sens sans ce dénominateur et cette référence de base.
Conclusion
Le parallélisme consiste en une correspondance entre un goulot d’étranglement identifié et une dimension de tenseur ainsi qu’un schéma de communication. La réplication, le shardage, la partitionnement des couches, l’affichage temporaire des données, le partitionnement séquentiel et l’acheminement ciblé permettent chacun de soulager une contrainte différente et génèrent des modes de défaillance distincts.
Inventorier la charge de travail, dessiner la topologie, générer des maillages valides, et les profiler. La configuration optimale est celle qui intègre suffisamment d’espace de marge tout en minimisant les communications exposées pour le travail réellement exécuté.