Moins de latence et plus de débit avec DeepSeek multi-nœuds

Le déploiement multi-GPU booste les performances des modèles MoE

AuteursPerplexity Research

Dans la plupart des systèmes, la latence et le débit sont souvent des objectifs contradictoires qui nécessitent des compromis lors de la conception et du déploiement. Par exemple, dans les grands modèles de langage denses, l'augmentation de la taille des lots peut améliorer le débit, mais elle accroît également la latence ; l'augmentation du parallélisme des tenseurs au sein d'une même machine peut réduire la latence, mais diminue le nombre de répliques, ce qui entraîne une baisse du débit.

Les modèles de type Mixture of Experts (MoE), comme DeepSeek-V3/R1, ont récemment démontré d'excellentes capacités de modèle et une grande efficacité opérationnelle. Par exemple, le modèle DeepSeek-V3/R1 possède un total de 671 milliards de paramètres, mais chaque jeton n'utilise que 37 milliards de paramètres lors de l'inférence. Cette architecture de modèle présente à la fois des défis et des opportunités pour les systèmes d'inférence.

Cet article démontre que, contrairement aux systèmes conventionnels, les modèles MoE tels que DeepSeek-V3/R1 peuvent atteindre simultanément un débit plus élevé et une latence plus faible en utilisant davantage de GPU dans des déploiements multi-nœuds dans la plupart des scénarios.

Architectures de déploiement

Déploiement sur un seul nœud via NVLink, avec une attention et un calcul expert répartis sur plusieurs GPU.
Déploiement multi-nœuds via InfiniBand, avec des groupes de GPU connectés à l’intérieur des nœuds et entre eux.

En raison du grand nombre de petits experts que possède le modèle, les déploiements doivent être répartis sur plusieurs dispositifs. Nous avons envisagé à la fois des déploiements sur un seul nœud avec 8 GPU H200 et des déploiements multi-nœuds sur des GPU 8xH100.

Les deux architectures de déploiement tirent parti du parallélisme de données, orchestré par notre programmateur de requêtes interne. L'implémentation du parallélisme de données implique le lancement de plusieurs instances de moteur d'inférence, chacune fonctionnant indépendamment pour traiter et maintenir les requêtes. Le programmateur de requêtes, qui interagit avec le moteur via GRPC, est chargé de répartir les requêtes aussi uniformément que possible, tout en facilitant la réutilisation de la KV Cache, en envoyant les requêtes ayant des préfixes partiels correspondants aux serveurs contenant le cache. Les instances de moteur ne s'étendent pas sur plusieurs nœuds. Elles peuvent éventuellement utiliser le parallélisme de tenseurs pour fragmenter l'attention sur plusieurs dispositifs. Les instances sont interconnectées via NVLink dans le cas d'un seul nœud ou InfiniBand pour le cas multi-nœuds, répartissant et collectant les experts.

La configuration de déploiement sur un seul nœud offre une latence supérieure avec de petites tailles de lots ; cependant, les performances se dégradent rapidement dans des conditions de charge accrue.

Pour déployer le moteur de service, nous lançons un pod par nœud hébergeant plusieurs instances de moteur. PyTorch est responsable de la mise en place de la communication distribuée et de la négociation de l'initialisation de NVSHMEM. Pour la communication, nous nous appuyons sur des noyaux CUDA personnalisés décrits dans un article de blog précédent. L'implémentation des deux déploiements est pratiquement identique, le modèle choisissant les noyaux corrects à utiliser en fonction de la structure implémentant le parallélisme des experts.

Techniques de parallélisation

Avant d'aborder nos comparaisons de performances, il est essentiel de comprendre les stratégies de parallélisation clés qui rendent possible le déploiement de modèles MoE massifs tels que DeepSeek-V3/R1.

Parallélisme des tenseurs

Dans l'inférence des LLM, le parallélisme des tenseurs (TP) est généralement utilisé pour réduire l'utilisation de la mémoire et les calculs par GPU, réduisant ainsi la latence. Habituellement, nous pouvons fragmenter les Linear Projections dans les couches d'attention et MLP selon les dimensions des lignes ou des colonnes, et fragmenter les opérations d'attention selon la dimension des têtes d'attention.

Avec le TP, l'architecture Llama-3 n'a aucun calcul dupliqué pour les opérations Linear Projection et Attention entre les GPU, ce qui est une méthode de fragmentation idéale. Cependant, dans les modèles DeepSeek-V3/R1, le TP ne peut pas atteindre cet objectif.

Les modèles DeepSeek-V3/R1 utilisent l'attention multi-latente (MLA). Une couche MLA utilise d'abord une Linear Projection kv_a_proj pour calculer le vecteur latent, puis utilise une autre Linear Projection kv_b_proj pour le transformer dans l'Espace de chaque tête d'attention. Comme toutes les têtes d'attention partagent le même vecteur latent, le TP ne peut pas fragmenter le vecteur latent ; par conséquent, tous les rangs TP doivent répliquer les paramètres et les calculs de kv_a_proj et kv_b_proj. De même, comme la MLA stocke le vecteur latent dans la KV Cache, chaque rang TP stocke une copie identique de la KV Cache.

Malgré une certaine duplication dans la MLA, le parallélisme des tenseurs permet toujours une réduction partielle des besoins en calcul, ce qui le rend précieux pour les scénarios nécessitant des vitesses de sortie élevées.

Parallélisme des experts

Les modèles DeepSeek-V3/R1 remplacent les couches MLP par des couches MoE. Une couche MoE dispose de 256 experts routés et d'un expert partagé. Chaque jeton est envoyé à 8 experts routés différents pour le calcul, et les résultats sont sommés par pondération. Chaque jeton effectue également des calculs dans l'expert partagé, et le résultat est ajouté au résultat provenant des experts routés.

Le parallélisme des experts (EP) sert d'approche de fragmentation typique pour les couches MoE, chaque GPU gérant 256 / EP experts routés tout en conservant une copie de l'expert partagé. Comparé au TP, l'avantage de l'EP est qu'il peut distribuer les calculs sur davantage de GPU, réduisant ainsi l'utilisation du calcul et de la mémoire par GPU.

Avant d'effectuer les calculs des experts, tous les GPU doivent effectuer une communication AllToAll pour distribuer les jetons aux GPU où se trouvent les experts correspondants ; après le calcul des experts, une autre communication AllToAll est nécessaire pour collecter les résultats des calculs à partir de divers GPU et effectuer une sommation pondérée. Nous avons implémenté une version optimisée de ces deux noyaux de communication AllToAll, Dispatch et Combine, en utilisant NVSHMEM. Dans notre précédent article de blog, nous avons détaillé l'implémentation, et nos noyaux ont été mis en open-source sur GitHub.

Parallélisme de données

Avec l'EP, nous pouvons distribuer les calculs MoE sur 128 GPU ou plus. Cependant, les calculs MLA ne peuvent pas être partitionnés avec l'EP. À ce stade, nous pouvons introduire le parallélisme de données (DP). Chaque groupe DP possède une copie complète de la couche MLA. Chaque groupe DP accepte des entrées différentes et effectue les calculs de la couche MLA indépendamment.

Le DP et le TP de la couche MLA peuvent être combinés, un groupe DP étant divisé en plusieurs rangs TP. L'EP de la couche MoE peut être combiné avec le DP/TP de la couche MLA. EP = DP * TP. Par exemple, sur 16 machines, EP128 DP32 TP4 signifie distribuer les experts routés sur 128 GPU, chaque groupe de 4 GPU formant un groupe DP, pour un total de 32 groupes DP indépendants.

Déploiement sur un seul nœud vs multi-nœuds

Les 671 milliards de paramètres de DeepSeek dépassent la capacité de mémoire d'une seule machine H100 à 8 GPU (80 Go * 8), mais une seule machine H200 à 8 GPU peut entièrement accueillir le modèle complet (141 Go * 8). En utilisant la configuration EP8 DP8 TP1, le modèle utilise environ 100 Go de mémoire par GPU, laissant environ 40 Go pour la KV Cache et d'autres résultats intermédiaires. Un jeton occupe 70 272 octets de KV Cache. En supposant que chaque requête a 5 000 jetons, chaque GPU peut accueillir environ 100 requêtes.

Nous voulions comprendre les différences de performance entre les déploiements sur un seul nœud et les déploiements multi-nœuds selon différentes configurations. Nous avons utilisé une machine H200 pour le déploiement sur un seul nœud et jusqu'à 16 machines H100 pour les déploiements multi-nœuds. Pour chaque environnement de déploiement, nous avons utilisé des combinaisons de TP 1, 2, 4, 8 et des tailles de lots par GPU de 1, 2, 4, 8, 16, 32, 64, 128. Nous avons supposé que chaque requête avait une longueur de KV Cache de 5 000 jetons. Nous avons également supposé que la prédiction multi-jetons (MTP) prédit 1 jeton supplémentaire (c'est-à-dire que la longueur de requête de chaque requête est de 2), et avons supposé de manière conservatrice un taux d'acceptation de 60 %. La figure ci-dessous montre le débit et la vitesse de sortie pour différentes configurations.

Frontières de Pareto latence-débit pour différentes configurations de parallélisme expert.

L'axe horizontal représente la vitesse de sortie par requête en jetons/s. L'axe vertical utilise une échelle logarithmique pour montrer le débit par machine en jetons/s. Nous avons marqué la frontière de Pareto pour chaque configuration EP avec des lignes de couleurs différentes.

Dans les scénarios avec des exigences de vitesse de sortie extrêmement élevées, l'utilisation de l'EP8 DP1 TP8 sur un seul nœud avec une taille de lot de 1 peut atteindre une vitesse de sortie supérieure à 100 jetons/s, mais le débit est extrêmement faible, équivalent à la vitesse de sortie. Dans ce scénario, le lot entier ne contient que 2 jetons, qui peuvent être envoyés à au plus 2*8=16 experts, activant un total d'au plus 57 milliards de paramètres.

Dans la plage de vitesse de sortie de 80-40 jetons/s, à mesure que le débit augmente, la vitesse de sortie diminue de manière significative. En revanche, l'EP128 a un débit environ 5 fois plus élevé que le déploiement sur un seul nœud à la même vitesse de sortie.

Ce phénomène peut s'expliquer en examinant le comportement des déploiements sur un seul nœud : l'augmentation de la taille du lot est directement corrélée à une augmentation du nombre d'experts activés. Lorsque la taille du lot est de 1, le nombre moyen d'experts activés par GPU est de 2 * 8 / 8 = 2. Lorsque le lot est suffisamment grand, tous les experts sont activés, ce qui signifie que chaque GPU active 256 / 8 = 32 experts. Activer plus d'experts signifie que le GPU doit lire plus de paramètres depuis la mémoire, ce qui augmente considérablement la pression sur la bande passante mémoire. Étant donné que la phase de décodage des grands modèles de langage est déjà limitée par la bande passante mémoire plutôt que par les performances de calcul, l'augmentation de la taille du lot dans le déploiement sur un seul nœud réduit considérablement la vitesse de sortie.

La comparaison des quatre configurations de déploiement multi-nœuds (EP16, EP32, EP64 et EP128) révèle que des valeurs EP plus élevées déplacent la frontière de Pareto vers des améliorations simultanées du débit et de la vitesse de sortie.

Utiliser un nombre EP plus élevé signifie que chaque GPU se voit allouer moins d'experts. Par exemple, EP128 signifie que chaque GPU est responsable de 256 / 128 = 2 experts, de sorte que la pression sur la bande passante mémoire est considérablement réduite. En d'autres termes, en utilisant un nombre EP plus grand, nous gagnons effectivement plus de bande passante mémoire. Lorsque la taille du lot par GPU est inférieure à 64, l'augmentation de la taille du lot n'affecte pas de manière significative la vitesse de calcul des experts, car l'augmentation du nombre d'entrées n'augmente pas significativement la pression sur la bande passante mémoire. Par conséquent, nous observons que lors de l'utilisation de l'EP128, l'augmentation de la taille du lot n'affecte pas la vitesse de sortie de manière aussi significative.

Fait intéressant, sur des tailles de lots plus grandes (64 requêtes par GPU), nous avons observé un nouveau phénomène : le débit du déploiement sur un seul nœud est légèrement supérieur à celui du déploiement multi-nœuds. Cela s'explique en partie par le fait que l'NVLink intra-nœud a une bande passante plus élevée que l'InfiniBand inter-nœuds. Une autre partie est due aux limitations de notre implémentation. Nous analyserons ce phénomène plus en détail ultérieurement.

En raison des limitations de capacité mémoire, la configuration EP8 DP8 TP1 ne peut pas atteindre une taille de lot de 128 par GPU, le déploiement multi-nœuds reste donc un meilleur choix dans les scénarios visant un débit plus élevé.

Chevauchement du calcul et de la communication

Comme brièvement présenté ci-dessus concernant le parallélisme des experts, les GPU sont inactifs pendant la communication de la couche MoE. Pour réduire le gaspillage et abaisser la latence, nous devons trouver des tâches de calcul indépendantes des données pour occuper ce temps d'inactivité.

Ordonnancements du calcul et de la communication sans chevauchement, avec chevauchement de l’envoi et un pipeline à cinq étapes.

La partie supérieure de la figure ci-dessus montre le flux de calcul d'une couche. Le calcul MoE dépend du Dispatch, et le calcul de la couche suivante dépend du résultat du Combine.

Nous plaçons l'expert partagé sur chaque GPU. De cette façon, le calcul de l'expert partagé ne nécessite pas de communication AllToAll. Par conséquent, nous pouvons effectuer le calcul de l'expert partagé immédiatement après l'envoi du Dispatch, puis attendre que la réception du Dispatch soit terminée. Nous appelons ce schéma de chevauchement « Dispatch Overlap ».

Le Dispatch Overlap offre une implémentation simple et une large applicabilité. Cette technique masque le temps de calcul de l'expert partagé pour toutes les tailles d'EP et de lots.

Pour augmenter encore davantage le chevauchement du calcul et de la communication, nous avons utilisé le micro-lotissement mentionné dans le rapport technique de DeepSeek pour briser la dépendance aux données. Comme le montre la partie inférieure de la figure, nous avons divisé le calcul d'une couche Transformer en 5 étapes :

Étape 1 : InputNorm, QKVProj, AppendKV, BMM

Étape 2 : BMM, Attn, OProj, PostNorm, Gate

Étape 3 : Dispatch Send, Expert partagé

Étape 4 : Dispatch Recv, MoE, Combine Send

Étape 5 : Combine Recv

Dans les 3 premières couches Dense Transformer, nous utilisons le lot complet. Dans les 58 couches MoE Transformer suivantes, nous divisons uniformément le lot en deux micro-lots. Les deux micro-lots s'exécutent alternativement, avec un décalage de 3 étapes. Comme il n'y a pas de dépendance aux données entre ces deux micro-lots, nous pouvons passer au calcul d'un autre micro-lot après l'envoi du Dispatch et après l'envoi du Combine.

Répartition de la latence

Ensuite, nous comparons les effets du chevauchement à travers une expérience, et comparons les différences de performance entre le déploiement sur un seul nœud EP8 et le déploiement multi-nœuds EP128. Pour faciliter la comparaison, nous avons utilisé des GPU H100 pour l'expérience suivante. Nous avons utilisé TP1, une taille de lot de 128 par GPU, une longueur de requête de 2 par requête et une longueur de KV Cache de 5 000.

Latence par couche et par noyau pour les configurations de parallélisme expert et de chevauchement comparées.

La figure ci-dessus montre le temps total passé sur une couche MoE Transformer et la proportion de latence de différents types de noyaux. À l'exception de Dispatch, Combine et GroupGEMM, le temps d'exécution des autres noyaux devrait être égal dans les séries EP8, EP128 NoOverlap et EP128 DispatchOverlap car la taille du lot est la même.

Chevauchement

Comparons d'abord les effets des trois méthodes de chevauchement. NoOverlap a pris 2 667 µs au total, DispatchOverlap a pris 2 651 µs, économisant 16 µs soit seulement 0,6 %. MicroBatch a montré une amélioration très significative, prenant 1 896 µs, une accélération de 29 %. Le temps de Dispatch et de Combine a été considérablement réduit. Dispatch a diminué de 593 µs à 367 µs, et Combine de 1 012 µs à 237 µs.

Notez que pour les noyaux de calcul, diviser un lot de taille 128 en deux lots de taille 64 augmente le temps d'exécution total. Par conséquent, bien que le temps passé sur la communication ait été réduit de 1 001 µs, le temps total n'a été réduit que de 771 µs. Nous expliquerons la raison en utilisant le modèle Roofline dans la section suivante.

Pour cette raison, le micro-lotissement n'améliore pas toujours les performances.

Évolution de la vitesse de sortie et du débit par nœud avec le micro-batching, tracée en fonction de la taille de lot par GPU.

La figure ci-dessus montre l'amélioration des performances de Microbatch par rapport à DispatchOverlap pour des tailles de lots de 4 à 128. Lorsque la taille du lot est inférieure à 32, Microbatch diminue les performances de 5 % à 40 %. Lorsque la taille du lot est supérieure ou égale à 32, Microbatch peut améliorer les performances de 10 % à 35 %.

EP8 vs EP128

Revenons à la figure précédente et comparons EP8 et EP128 Microbatch. EP8 a pris 1 802 µs au total, légèrement moins que les 1 896 µs d'EP128. Outre l'augmentation du temps d'exécution des noyaux apportée par Microbatch mentionnée ci-dessus, les principales différences se situent au niveau de GroupGEMM utilisé pour le calcul MoE, et des deux noyaux de communication, Dispatch et Combine.

Le GroupGEMM d'EP8 a pris 555 µs, tandis que le GroupGEMM d'EP128 a pris 270 µs, soit une réduction de moitié. C'est l'avantage essentiel du déploiement multi-nœuds.

Malheureusement, le temps passé sur la communication a augmenté de 213 µs, ce qui a largement compensé l'avantage de GroupGEMM. Dans des tests de performance séparés de nos noyaux de communication, nous avons constaté qu'ils ne peuvent atteindre que la moitié de la bande passante Infiniband. Nous continuerons à optimiser nos noyaux de communication.

Un autre noyau qui accuse un retard significatif est GEMM. Microbatch a augmenté le GEMM de 95 µs. Nous analyserons le GEMM plus en profondeur dans la section Roofline ci-dessous. Nous pensons que l'implémentation actuelle de GEMM n'a pas encore atteint des performances optimales.

Roofline

Le modèle Roofline est un bon outil pour analyser les performances des noyaux. Son axe horizontal est l'intensité arithmétique, le rapport entre les FLOP et les octets d'E/S mémoire. La valeur de l'axe horizontal peut être calculée directement à partir de la sémantique du noyau. L'axe vertical représente les performances atteintes, calculées en divisant les FLOP par la latence de référence.

La limite théorique supérieure de la performance du noyau est directement déterminée par les spécifications du GPU. La performance de crête FP8 du H100 est de 1 979 TFLOP/s, représentée par une ligne horizontale dans le modèle Roofline. La bande passante mémoire du H100 est de 3,35 To/s, représentée par la pente d'une ligne passant par l'origine. Les deux lignes donnent les limites de performance pour les noyaux liés au calcul et liés à la mémoire, respectivement.

Ci-dessous, nous discutons des performances des noyaux GroupGEMM et GEMM.

GroupGEMM

Le noyau GroupGEMM dans MoE effectue le calcul suivant : Il y a g groupes au total, le i-ème groupe a m_i jetons, effectuant une multiplication de matrice de [m_i, k] x [k, n] -> [m_i, n]. Dans les tests de performance, nous supposons que le nombre de jetons dans chaque groupe est le même, noté m_i = m. Alors le nombre de FLOP pour GroupGEMM est 2 * g * m * k * n, et les octets d'E/S mémoire sont g * (m * k + n * k + m * n).

Dans le modèle DeepSeek-V3/R1, il y a 256 experts, et chaque jeton est envoyé à 8 experts pour le calcul. En supposant une taille de lot de 128, une longueur de requête de 2, en utilisant la configuration EP128 DP128, le nombre moyen de jetons reçus par chaque expert (c'est-à-dire m) est 128 * 2 * 8 * 128 / 256 = 1 024. De même, nous pouvons calculer m pour d'autres configurations et tailles de lots.

Nous avons utilisé l'implémentation GroupGEMM de DeepGEMM pour les tests de performance. Les points de test couvraient des combinaisons de configurations EP8, EP16, EP32, EP64, EP128 avec TP1 et des tailles de lots de 1 à 128.

Performance de GroupGEMM par rapport aux limites théoriques de calcul et de bande passante mémoire.

La figure ci-dessus montre le modèle Roofline pour GroupGEMM sous différentes configurations EP. Différents EP correspondent à différents nombres de groupes. La figure illustre des lignes de performance presque superposées, indiquant que la performance de GroupGEMM est principalement déterminée par le nombre total de jetons (représenté par g * m).

Les étoiles marquent les points de données correspondant à une taille de lot de 128 par GPU pour chaque configuration EP. En comparant ces points de données étoilés, nous pouvons voir qu'à mesure que l'EP augmente (et que le DP augmente de manière synchrone), le nombre de jetons par expert m augmente également. À l'EP8, m=128, tandis qu'à l'EP128, m=2 048.

À mesure que m augmente, l'intensité arithmétique augmente également. Dans la plupart des configurations, GroupGEMM est limité par la bande passante mémoire, donc l'augmentation de m améliore les performances.

GEMM

Le noyau GEMM correspond aux Linear Projections dans le modèle, telles que la projection Q/K/V/O. Pour une multiplication de matrice de [m, k] x [k, n] -> [m, n], le nombre de FLOP est 2 * m * k * n, et les octets d'E/S mémoire sont m * k + n * k + m * n. Nous pouvons également tester la latence pour des tailles de lots de 1 à 128.

Performance de GEMM par rapport aux limites théoriques de calcul et de bande passante mémoire.

La figure ci-dessus montre le modèle Roofline pour GEMM sous différentes configurations EP. Nous pouvons voir que les performances de GEMM sont limitées par la bande passante mémoire. À mesure que la taille du lot augmente, l'intensité arithmétique augmente également, améliorant ainsi les performances.

Microbatch

Lors de l'utilisation du micro-lotissement, nous divisons le lot uniformément en deux parties. À partir des deux figures ci-dessus, nous pouvons voir que lorsque m devient m/2, l'efficacité de la multiplication de matrice diminue. Par conséquent, l'exécution de deux multiplications de matrice de taille m/2 prend plus de temps que l'exécution d'une multiplication de matrice de taille m.

Prédiction multi-jetons

Tout au long de cet article, nous avons supposé l'utilisation de la prédiction multi-jetons (MTP) pour le décodage spéculatif. La MTP fait passer la longueur de la requête par requête de 1 à 2. Pour la multiplication de matrice, cela équivaut à changer m en m * 2, augmentant ainsi l'efficacité de la multiplication de matrice. D'un autre côté, si nous dessinions le modèle Roofline pour MLA, nous constaterions que l'augmentation de la longueur de la requête augmente considérablement l'efficacité du noyau MLA.

Par conséquent, l'utilisation de la MTP joue un rôle important dans l'efficacité du modèle.

Implémentation & optimisations

Dans cette section, nous présenterons quelques détails d'implémentation et d'optimisation pour notre modèle DeepSeek-V3/R1.

Quantification

DeepSeek-V3/R1 a été nativement entraîné sur FP8 en utilisant un schéma de quantification par bloc, avec des poids quantifiés de manière statique et des activations quantifiées à la volée. Au lieu de calculer un facteur d'échelle par canal ou par matrice de manière statique, les facteurs d'échelle sont calculés sur des vecteurs de 128 éléments pour les activations et des tuiles de 128x128 éléments pour les matrices, limitant la dégradation de la précision due à la quantification.

Chez Perplexity, nous nous appuyons sur un mélange de noyaux CUDA et Triton pour prendre en charge l'inférence, CUDA étant utilisé pour les noyaux les plus sensibles aux performances et les moins fréquemment modifiés (tels que l'attention et GEMM), Triton implémentant une large gamme de noyaux d'activation, de normalisation et utilitaires. Triton nous a permis d'adapter rapidement les noyaux au schéma de quantification par bloc.

Pour les couches linéaires et MoE, nous mélangeons les noyaux Deep GEMM avec nos propres noyaux Triton GEMM, car nous avons remarqué que pour certaines dimensions de matrice et de petites tailles de lots, Split-K offre une latence plus faible. Si la couche non quantifiée effectue une multiplication (M, K) x (K, N), elle nécessite un facteur d'échelle (M x ceil_div(K, 128)) x (ceil_div(K, 128), ceil_div(N, 128)) pour la quantification par bloc. Pour la quantification par bloc, les facteurs d'échelle pour les activations sont calculés à la volée, au lieu d'être pré-calibrés. Étant donné que les facteurs d'échelle d'activation ne sont agrégés que le long de la dimension K et non le long de la dimension M, les noyaux ne nécessitent que de légères modifications pour prendre en charge le schéma.

Calcul groupé de SiLU et de multiplication, montrant les tenseurs d’entrée des experts, les tenseurs de sortie et les facteurs d’échelle.

La fonction d'activation SiLU utilisée par DeepSeek-V3/R1 a nécessité des modifications substantielles pour prendre en charge les graphes CUDA, la quantification par bloc et le nombre de jetons routés dynamiquement. La quantification par bloc peut être problématique car elle introduit des réductions horizontales, cependant le noyau découpait déjà les activations le long de leur dimension cachée en blocs de 1 024 éléments. Au sein d'un bloc, le tenseur à quantifier était davantage découpé en blocs de 128 pour calculer la plus grande valeur absolue, avec Triton générant des réductions maximales inter-warp efficaces, ajoutant un surcoût minimal.

Pour prendre en charge le routage MoE sous les graphes CUDA, les noyaux doivent être conscients des informations de routage indiquant le nombre de jetons par expert, au lieu de planifier le travail en fonction de la taille des tampons qui ont été alloués pour contenir la limite supérieure du nombre de jetons. Nous ne pouvons pas diviser le problème en fonction des dimensions du tenseur d'entrée, nous lançons donc un nombre fixe de noyaux persistants qui lisent les informations de routage pour déterminer combien de jetons sont peuplés et divisent dynamiquement le travail de traitement des activations entre eux.

Nous avons déjà intégré certains de nos noyaux dans le projet FlashInfer et, à l'avenir, nous mettrons en open-source davantage de notre code.

Couche MLA

Nous utilisons FlashInfer pour le calcul MLA. FlashInfer prend en charge des paramètres de table de pages flexibles et des performances extrêmement élevées.

Nous avons fusionné q_a_proj et kv_a_proj en un seul qkv_a_proj. La latence a diminué de 15,4 µs + 14,8 µs = 30,2 µs à 16,7 µs.

Nous avons décomposé kv_b_proj en deux matrices, k_b_proj et v_b_proj. Nous avons écrit un noyau BMM quantifié par bloc FP8 pour les calculs liés à ces deux matrices.

Cuda Graph

Cuda Graph peut réduire considérablement le surcoût de lancement du noyau, ce qui est crucial pour les performances. Nous créons un Cuda Graph pour chaque taille de lot.

Avant de développer notre noyau AllToAll, nous utilisions torch.all_to_all_single() pour la communication AllToAll. Cette opération nécessite que tous les GPU utilisent la même taille de lot. Cependant, différents groupes DP peuvent exécuter des tailles de lots différentes.

Pour garantir que all_to_all_single() est compatible avec différents groupes DP utilisant des tailles de lots différentes, nous avons d'abord utilisé une opération allreduce() avant chaque exécution du modèle pour obtenir la taille de lot maximale parmi tous les groupes DP. Ensuite, nous avons fait en sorte que tous les groupes DP utilisent cette taille de lot pour s'exécuter.

Bien que cette approche garantisse que nous pouvons utiliser Cuda Graph, elle présente trois inconvénients. Premièrement, elle nécessite une opération allreduce() supplémentaire. Deuxièmement, les groupes DP avec des tailles de lots plus petites sont forcés de remplir. Troisièmement, cela rend notre code d'implémentation complexe.

Après avoir implémenté notre propre noyau AllToAll, nous n'exigeons plus que tous les GPU utilisent la même taille de lot. Par conséquent, nous n'avons plus besoin d'effectuer d'opérations allreduce() supplémentaires ni de remplir les tailles de lots.

MoE Router

Le routeur MoE est implémenté dans Triton, s'appuyant sur un tri modifié dérivé de la bibliothèque standard qui suit également les indices des éléments triés. L'implémentation est partagée entre tous les modèles MoE, car le routage Mixtral est un cas particulier des routes DeepSeek où le groupe Top-K est le même que le groupe de tous les experts. Les noyaux clairsemés consomment directement les indices et les scores Top-K, tandis que les schémas de dispatch/combine denses reposant sur le tout-à-tout nécessitent que les informations de routage soient agrégées par expert plutôt que par jeton.

Travaux futurs

Dans les travaux futurs, nous prévoyons d'optimiser davantage les performances du modèle DeepSeek.

La prochaine optimisation la plus importante est la désagrégation du préremplissage. La phase de préremplissage et la phase de décodage du modèle DeepSeek-V3/R1 ont des caractéristiques de calcul très différentes. Les deux peuvent utiliser différentes stratégies d'optimisation et schémas de déploiement.

Pour la couche MLA, dans la phase de décodage, nous utilisons l'absorption de matrice pour réduire le nombre de FLOP du calcul MLA. Dans la phase de préremplissage, projeter d'abord le vecteur latent dans l'Espace K/V, puis effectuer le calcul sous forme d'attention multi-têtes (MHA) serait plus performant.

Si le préremplissage et le décodage s'exécutent sur le même GPU, pour réduire l'impact du préremplissage sur la vitesse de sortie du décodage, nous utilisons généralement un préremplissage découpé pour diviser la requête en plusieurs segments pour le préremplissage. Comme la KV Cache stocke le vecteur latent, il devient difficile de convertir MLA sous forme MHA.

Pour la couche MoE, dans la phase de décodage, nous utilisons un EP et un DP aussi grands que possible pour augmenter le nombre de jetons d'entrée par expert, améliorant ainsi les performances de GroupGEMM. Dans la phase de préremplissage, comme le nombre de jetons est déjà suffisamment grand, GroupGEMM est déjà limité par le calcul. Par conséquent, pour le préremplissage, nous pouvons utiliser un EP et un DP plus petits.

Si le préremplissage et le décodage s'exécutent sur le même GPU, tant qu'un groupe DP effectue un préremplissage, la latence des couches MoE sur tous les GPU augmentera, affectant considérablement la vitesse de sortie du décodage.

Outre la désagrégation du préremplissage, nous prévoyons également d'optimiser les aspects suivants :

Performances AllToAll : Notre noyau AllToAll ne peut actuellement atteindre qu'un tiers de la bande passante Infiniband. Nous continuerons à optimiser ce noyau.

Décodage spéculatif de style EAGLE : Dans les données ci-dessus, nous avons supposé l'utilisation du décodage spéculatif pour prédire 1 jeton. EAGLE peut utiliser une structure en arbre pour prédire plusieurs jetons, améliorant la longueur d'acceptation, ce qui peut augmenter considérablement la vitesse de sortie.

Noyau GEMM : Dans le modèle Roofline montré précédemment, nous pouvons constater que l'efficacité du noyau GEMM est encore loin de la limite théorique. Nous continuerons à optimiser ce noyau.

GB200 NVL72 : Dans la dernière solution GB200 NVL72 de NVIDIA, 72 GPU Blackwell sont interconnectés via NVLink haut débit. Pour les modèles d'architecture MoE, c'est une très grande opportunité et un défi.

Conclusion

Le déploiement multi-nœuds des modèles DeepSeek MoE permet d'atteindre ce qui est généralement impossible avec les LLM denses : améliorer simultanément le débit et la latence. En distribuant les experts sur davantage de GPU, nous réduisons la pression sur la bande passante mémoire par dispositif, permettant un traitement plus rapide et un débit système plus élevé. Nos expériences montrent que les configurations EP128 atteignent un débit jusqu'à 5 fois supérieur à des vitesses de sortie équivalentes par rapport aux déploiements sur un seul nœud.

Les techniques de chevauchement calcul-communication comme le micro-lotissement réduisent considérablement le surcoût de communication multi-nœuds, notre implémentation montrant une accélération allant jusqu'à 40 %. Nos noyaux de communication AllToAll personnalisés et nos implémentations de noyaux optimisées ont permis un déploiement efficace du modèle à 671 milliards de paramètres.

Alors que les architectures MoE gagnent en popularité pour leurs capacités, ces stratégies de déploiement fournissent des informations précieuses pour mettre à l'échelle de tels modèles de manière efficace.

Références

Rapport technique DeepSeek-V3

Vue d'ensemble du système d'inférence DeepSeek-V3/R1

Megatron-LM : Entraînement de modèles de langage à plusieurs milliards de paramètres en utilisant le parallélisme de modèle

EAGLE : L'échantillonnage spéculatif nécessite de repenser l'incertitude des caractéristiques

Citation

BibTeX
@online{perplexity2025LowerLatencyAndHigherThroughputWithMultiNodeDeepseekDeployment,
  author = {{Perplexity} and Lequn Chen and Nandor Licker and Erin McKnight},
  title = {{Lower latency and higher throughput with multi-node DeepSeek deployment}},
  date = {2025-04-18},
  url = {https://perplexity.coolkeypoint.com/hub/blog/lower-latency-and-higher-throughput-with-multi-node-deepseek-deployment}
}