Compétence Sélection de Stratégie de Parallélisme
Pour un arrière-plan stable sur chaque type de parallélisme, voir :
- @docs/parallelisms.md
- @skills/perf-parallelism-strategies/card.yaml
Décision par Taille de 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. Puisque seule une fraction des paramètres est active par token, TP peut souvent rester à 1 ou 2 — le fragment de paramètre actif tient déjà sur un seul GPU. EP est la dimension d'échelle 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 |
| Moonlight 16B / 3B | 2 | 1 | 8 | petit TP pour couches partagées |
| DeepSeek-V2 236B / 21B | 1 | 4 | 32 | pas de TP du tout |
| GLM-4.5 Air 106B / 12B | 1 | 4 | 8 | pas de TP du tout |
| Qwen3 30B-A3B | 4 | 2 | 4 | |
| GLM-4.5 355B / 32B | 2 | 8 | 16 | |
| Qwen3 235B-A22B | 4 | 16 | 8 | CP=2 pour préentraînement |
| DeepSeek-V3 671B / 37B | 2 | 16 | 64 | TP=2, pas 8 |
| Kimi-K2 1T | 2 | 16 | 32 |
Motifs clés :
- TP est dimensionné par paramètres actifs, pas paramètres totaux. Une MoE 671B avec 37B actifs nécessite beaucoup moins de TP qu'un modèle dense 70B.
- EP s'échelle avec le nombre d'experts. Courant : 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. Toujours profiler la première itération pour vérifier la mémoire et la communication.
Décision par Topologie du Matériel
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 : garder TP dans un seul domaine NVLink. Utiliser PP ou DP pour l'échelle entre nœuds. TP entre nœuds est presque toujours une perte de performance.
Décision par 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, considérer a2a+p2p pour grand CP |
Activation de 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 (par 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 (par 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 Minimum de GPUs
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 chemin dense utilise une maille TP*CP et le chemin MoE utilise une maille EP*ETP, et dans chaque étage PP ces deux mailles partagent le même ensemble de GPUs — elles se chevauchent, elles ne se multiplient pas. Seuls les étages PP se multiplient (ce sont des tranches disjointes du modèle). Donc :
min_gpus = PP * max(TP * CP, EP * ETP)
Simplification courante (FAUSSE) : PP * TP * CP * EP * ETP. Cela sur-alloue les GPUs et apparaît dans de nombreux READMEs et tables de dimensionnement slurm. Ne la propagez pas.
Le découplage du parallélisme attention et MoE (formes de maille différentes pour les chemins dense et expert partageant les mêmes GPUs d'étage PP) est détaillé dans Pangu Ultra MoE (arXiv:2504.14960).
Exemples
| Config | Faux (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)) |
Échelle au-delà du minimum
Ajouter des GPUs met à l'échelle DP et/ou EDP (le world_size doit satisfaire les deux équations simultanément). À min_gpus le côté maille plus grande a DP (ou EDP) = 1 et le côté plus petit absorbe le jeu.
Exemple — TP=2, CP=1, EP=8, ETP=1, PP=1 :
- 8 GPUs (
min_gpus) : denseDP = 8/2 = 4, MoEEDP = 8/8 = 1 - 16 GPUs : dense
DP = 8, MoEEDP = 2→ 2× batch global - 32 GPUs : dense
DP = 16, MoEEDP = 4→ 4× batch global
Lors du dimensionnement des scripts slurm, calculer --nodes à partir de min_gpus (ou un multiple pour plus de débit via DP/EDP).
Estimation de Mémoire
Sans parallélisme (modèle 70B, FP16) :
paramètres : 140 GB
gradients : 140 GB
états optimizer : 280 GB (Adam)
activations : 48 GB (batch=1, seq=4K)
total : 608 GB
Avec TP=4, PP=4, DP=4 (64 GPUs) :
paramètres : 8,75 GB par GPU
gradients : 8,75 GB par GPU
états optimizer : 17,50 GB par GPU
activations : 3,00 GB par GPU
total : ~38 GB par GPU
Ancrages 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 câble le parallélisme dans les 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
-
TP entre nœuds détruit le débit. Toujours garder TP dans un seul domaine NVLink.
-
PP sans entrelacement a de grandes bulles pipeline. Utiliser
virtual_pipeline_model_parallel_sizequand possible. -
SP requiert
tensor_model_parallel_size > 1. Activer SP seul sans TP est une erreur de config. -
CP requiert
seq_length % (2 * context_parallel_size) == 0. -
EP est uniquement pour modèles MoE. Définir
expert_model_parallel_sizesur un modèle dense est un no-op ou erreur. -
La table taille-de-modèle-à-parallélisme ci-dessus est une heuristique de démarrage. Toujours profiler la première itération pour vérifier mémoire et communication.
-
CUDA_DEVICE_MAX_CONNECTIONSet les variables env connexes interagissent avec les paramètres d'overlap. Voir @skills/perf-tp-dp-comm-overlap/SKILL.md. -
Le nombre minimum de GPUs pour une config MoE est
PP * max(TP*CP, EP*ETP), pas le produit de toutes les dimensions. La maille denseTP*CPet MoEEP*ETPpartagent les mêmes GPUs dans chaque étage PP. Voir section « Nombre Minimum de GPUs » ci-dessus.
Vérification
Vérification rapide que le parallélisme combiné initialise correctement en utilisant la plus petite recette disponible avec parallélisme remplacé :
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 (par ex.
lm loss: 1.003808E+01) - log affiche layout TP=2 PP=2 DP=1 avec 4 rangs