nemo-mbridge-perf-parallelism-strategies

Par nvidia · skills

Guide opérationnel pour choisir et combiner les stratégies de parallélisme dans Megatron Bridge, incluant les règles de dimensionnement, le mappage de topologie matérielle et la configuration du parallélisme combiné.

npx skills add https://github.com/nvidia/skills --skill nemo-mbridge-perf-parallelism-strategies

Compétence de Sélection de Stratégie de Parallélisme

Pour des informations stables sur chaque type de parallélisme, voir :

  • @docs/parallelisms.md
  • @skills/nemo-mbridge-perf-parallelism-strategies/card.yaml

Décision selon la Taille du Modèle

Modèles denses

Taille du modèle GPUs Point de départ recommandé
< 1B 1-8 DP uniquement
1-10B 8-16 TP=2-4 + DP
10-70B 16-64 TP=4-8 + PP=2-4 + DP
70-175B 64-256 TP=8 + PP=4-8 + DP
175-500B 256-1024 TP=8 + PP=8-16 + CP=2 + DP

Modèles MoE

Le parallélisme MoE diffère des modèles denses. Comme seule une fraction des paramètres sont actifs par token, TP peut souvent rester à 1 ou 2 — le fragment de paramètres actifs tient déjà sur une seule GPU. EP est la dimension de scaling primaire, avec PP gérant la distribution des couches entre nœuds.

Modèle (total / actif) TP PP EP Notes
OLMoE 7B / 1B 1 1 8 EP uniquement, tient sur un nœud unique
Moonlight 16B / 3B 2 1 8 petit TP pour les couches partagées
DeepSeek-V2 236B / 21B 1 4 32 aucun TP
GLM-4.5 Air 106B / 12B 1 4 8 aucun TP
Qwen3 30B-A3B 4 2 4
GLM-4.5 355B / 32B 2 8 16
Qwen3 235B-A22B 4 16 8 CP=2 pour pretrain
DeepSeek-V3 671B / 37B 2 16 64 TP=2, pas 8
Kimi-K2 1T 2 16 32

Motifs clés :

  • TP est dimensionné par les paramètres actifs, non les paramètres totaux. Un MoE 671B avec 37B actifs nécessite bien moins de TP qu'un modèle dense 70B.
  • EP évolue avec le nombre d'experts. Commun : EP = num_experts ou num_experts / experts_per_gpu.
  • PP gère la profondeur. Les grands modèles MoE utilisent PP=8-16 entre nœuds.
  • ETP (expert tensor parallelism) est rarement utilisé. Llama 4 est une exception (ETP=4).

Ce sont des points de départ, pas des règles strictes. Profilez toujours la première itération pour vérifier la mémoire et la communication.

Décision selon la Topologie Matérielle

Nœud unique avec NVLink :

cfg.model.tensor_model_parallel_size = 8

Plusieurs nœuds avec InfiniBand :

cfg.model.tensor_model_parallel_size = 8
cfg.model.pipeline_model_parallel_size = N

Réseau limité (Ethernet) :

cfg.model.tensor_model_parallel_size = 4
cfg.model.pipeline_model_parallel_size = M

La règle stable est : gardez TP dans un seul domaine NVLink. Utilisez PP ou DP pour le scaling entre nœuds. TP entre nœuds est presque toujours une perte de performance.

Décision selon la Longueur de Séquence

Longueur de séquence Recommandation
< 2K TP + PP + DP standard
2K-8K ajouter SP (sequence_parallel=True)
8K-32K ajouter CP=2
32K+ ajouter CP=4-8, envisager a2a+p2p pour CP large

Activation du Parallélisme Combiné

Parallélisme 3D (TP + PP + DP) :

cfg.model.tensor_model_parallel_size = 4
cfg.model.pipeline_model_parallel_size = 4
cfg.model.sequence_parallel = True

Parallélisme 4D (TP + PP + CP + DP) :

cfg.model.tensor_model_parallel_size = 8
cfg.model.pipeline_model_parallel_size = 8
cfg.model.context_parallel_size = 2
cfg.model.sequence_parallel = True

MoE avec EP + PP (ex. DeepSeek-V2 236B sur 128 GPUs) :

cfg.model.tensor_model_parallel_size = 1
cfg.model.pipeline_model_parallel_size = 4
cfg.model.expert_model_parallel_size = 32
cfg.model.sequence_parallel = False

MoE avec petit TP + PP + EP (ex. DeepSeek-V3 671B sur 256 GPUs) :

cfg.model.tensor_model_parallel_size = 2
cfg.model.pipeline_model_parallel_size = 16
cfg.model.expert_model_parallel_size = 64
cfg.model.sequence_parallel = True

La taille DP est toujours implicite :

data_parallel_size = world_size / (TP * PP * CP)        # dense path
expert_data_parallel_size = world_size / (PP * EP * ETP) # MoE path

Nombre de GPUs Minimum

Le nombre minimum de GPUs nécessaires pour exécuter une config (c.-à-d. avec DP=1, EDP=1) n'est pas le produit de toutes les dimensions de parallélisme. Le dense path utilise une TP*CP-mesh et le MoE path utilise une EP*ETP-mesh, et au sein de chaque étape PP ces deux meshes partagent le même ensemble de GPUs — elles chevauchent, elles ne se multiplient pas. Seules les étapes PP se multiplient (ce sont des tranches disjointes du modèle). Donc :

min_gpus = PP * max(TP * CP, EP * ETP)

Simplification courante (INCORRECTE) : PP * TP * CP * EP * ETP. Cela sur-alloue les GPUs et apparaît dans de nombreux READMEs et tableaux de dimensionnement slurm. Ne la propagez pas.

Le découplage entre le parallélisme attention et MoE (formes de mesh différentes pour les paths dense et expert partageant les mêmes GPUs de PP-stage) est détaillé dans Pangu Ultra MoE (arXiv:2504.14960).

Exemples

Config Incorrect (PP·TP·CP·EP·ETP) Correct (PP·max(TP·CP, EP·ETP))
PP=1, TP=2, CP=1, EP=8, ETP=1 16 8 (1 nœud)
PP=1, TP=4, CP=1, EP=8, ETP=1 32 8 (max(4, 8))
PP=1, TP=2, CP=2, EP=8, ETP=1 32 8 (max(4, 8))
PP=1, TP=2, CP=4, EP=8, ETP=1 64 8 (max(8, 8))
PP=2, TP=2, CP=1, EP=8, ETP=1 32 16 (2 · max(2, 8))
PP=1, TP=2, CP=1, EP=4, ETP=2 16 8 (max(2, 8))

Scaling au-delà du minimum

Ajouter des GPUs fait évoluer DP et/ou EDP (la world_size doit satisfaire les deux équations simultanément). À min_gpus le côté mesh plus grand a DP (ou EDP) = 1 et le côté plus petit absorbe le slack.

Exemple — TP=2, CP=1, EP=8, ETP=1, PP=1 :

  • 8 GPUs (min_gpus) : dense DP = 8/2 = 4, MoE EDP = 8/8 = 1
  • 16 GPUs : dense DP = 8, MoE EDP = 2 → 2× batch global
  • 32 GPUs : dense DP = 16, MoE EDP = 4 → 4× batch global

Lors du dimensionnement des scripts slurm, calculez --nodes à partir de min_gpus (ou un multiple de celui-ci pour un throughput plus élevé via DP/EDP).

Estimation de Mémoire

Sans parallélisme (modèle 70B, FP16) :

parameters:       140 GB
gradients:        140 GB
optimizer states: 280 GB (Adam)
activations:       48 GB (batch=1, seq=4K)
total:            608 GB

Avec TP=4, PP=4, DP=4 (64 GPUs) :

parameters:        8,75 GB par GPU
gradients:         8,75 GB par GPU
optimizer states: 17,50 GB par GPU
activations:       3,00 GB par GPU
total:           ~38    GB par GPU

Ancres de Code

Dimensions de parallélisme définies dans le fournisseur de modèle :

model_config = GPTModelProvider(
    tensor_model_parallel_size=2,
    # ... other model parameters
)

Calcul de la taille DP :

data_parallel_size = world_size / (tensor_model_parallel_size × pipeline_model_parallel_size × context_parallel_size)

L'initialisation Bridge relie le parallélisme aux groupes de processus :

parallel_state.initialize_model_parallel(
    tensor_model_parallel_size=model_config.tensor_model_parallel_size,
    pipeline_model_parallel_size=model_config.pipeline_model_parallel_size,
    ...
    context_parallel_size=model_config.context_parallel_size,
    hierarchical_context_parallel_sizes=model_config.hierarchical_context_parallel_sizes,
    expert_model_parallel_size=model_config.expert_model_parallel_size,
    ...
)

Pièges

  1. TP entre nœuds détruit le throughput. Gardez toujours TP dans un seul domaine NVLink.

  2. PP sans entrelacement a de grandes bulles pipeline. Utilisez virtual_pipeline_model_parallel_size si possible.

  3. SP nécessite tensor_model_parallel_size > 1. Activer SP seul sans TP est une erreur de config.

  4. CP nécessite seq_length % (2 * context_parallel_size) == 0.

  5. EP est uniquement pour les modèles MoE. Définir expert_model_parallel_size sur un modèle dense est un no-op ou une erreur.

  6. Le tableau modèle-size-to-parallelism ci-dessus est une heuristique de départ. Profilez toujours la première itération pour vérifier la mémoire et la communication.

  7. CUDA_DEVICE_MAX_CONNECTIONS et les variables env associées interagissent avec les paramètres de chevauchement. Voir @skills/nemo-mbridge-perf-tp-dp-comm-overlap/SKILL.md.

  8. Le nombre minimum de GPUs pour une config MoE est PP * max(TP*CP, EP*ETP), non le produit de toutes les dimensions. La dense TP*CP-mesh et MoE EP*ETP-mesh partagent les mêmes GPUs dans chaque PP stage. Voir la section « Nombre de GPUs Minimum » ci-dessus.

Vérification

Vérification rapide que le parallélisme combiné s'initialise correctement en utilisant la plus petite recette disponible avec parallélisme surchargé :

CUDA_VISIBLE_DEVICES=0,1,2,3 uv run python -m torch.distributed.run --nproc_per_node=4 \
  scripts/training/run_recipe.py \
  --recipe llama32_1b_pretrain_config \
  model.tensor_model_parallel_size=2 \
  model.pipeline_model_parallel_size=2 \
  model.sequence_parallel=True \
  train.train_iters=3 train.global_batch_size=8 train.micro_batch_size=1 \
  scheduler.lr_warmup_iters=0 \
  validation.eval_iters=0 validation.eval_interval=0 \
  checkpoint.save_interval=0 \
  logger.log_interval=1

Critères de succès :

  • code de sortie 0
  • perte finie à l'itération 3 (ex. lm loss: 1.003808E+01)
  • log affiche layout TP=2 PP=2 DP=1 avec 4 ranks

Skills similaires