Skip to content

Commit 515ff1f

Browse files
committed
Update on "[MoE][2/n]Move EP setup from trainer to config registry and add model_registry params"
## Summary Remove the `apply_ep()` call from `Trainer.__post_init__` and move EP-aware token dispatcher configuration to model config time. Previously, model configs always created a `LocalTokenDispatcher.Config` (EP=1 default), then `Trainer.__post_init__` would immediately replace it with the correct EP dispatcher via `apply_ep()`. This two-phase setup split EP concerns between the model config layer and the trainer, making it harder to reason about what dispatcher a model actually uses. Now: - `model_registry()` accepts `attn_backend` and `moe_comm_backend` params across all model families (llama3, llama4, deepseek_v3, gpt_oss, qwen3), so config registries can build the right dispatcher config upfront - `apply_ep()` and `find_pad_multiple` imports are removed from `trainer.py` - `ep_degree` is moved from `LocalTokenDispatcher.Config` (base) to `AllToAllTokenDispatcher.Config` and `DeepEPTokenDispatcher.Config` where it's actually used - Stale comment referencing removed `ExpertSequenceParallel` class is updated ## Test Plan Existing unit tests: `python -m pytest tests/unit_tests/test_expert_parallel.py -x` [ghstack-poisoned]
2 parents 3fd8a41 + 2ba1c7d commit 515ff1f

6 files changed

Lines changed: 101 additions & 79 deletions

File tree

torchtitan/models/common/config_utils.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -242,34 +242,6 @@ def make_token_dispatcher_config(
242242
)
243243

244244

245-
def apply_ep(
246-
layers: list,
247-
*,
248-
ep_size: int,
249-
sp_size: int = 1,
250-
moe_comm_backend: str = "standard",
251-
hybridep_non_blocking_expert_capacity_factor: float | None = None,
252-
pad_multiple: int | None = None,
253-
) -> None:
254-
"""Replace token dispatchers in MoE layers for expert parallelism.
255-
256-
Mutates layer configs in-place: for each MoE layer, replaces the
257-
token_dispatcher with the appropriate config based on EP settings.
258-
"""
259-
for layer_cfg in layers:
260-
if layer_cfg.moe is not None:
261-
td = layer_cfg.moe.experts.token_dispatcher
262-
layer_cfg.moe.experts.token_dispatcher = make_token_dispatcher_config(
263-
num_experts=td.num_experts,
264-
top_k=td.top_k,
265-
score_before_experts=td.score_before_experts,
266-
ep_size=ep_size,
267-
sp_size=sp_size,
268-
moe_comm_backend=moe_comm_backend,
269-
hybridep_non_blocking_expert_capacity_factor=hybridep_non_blocking_expert_capacity_factor,
270-
pad_multiple=pad_multiple,
271-
)
272-
273245

274246
def make_experts_config(
275247
*,

torchtitan/models/deepseek_v3/__init__.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import torch.nn as nn
1212
from torchtitan.components.loss import build_cross_entropy_loss
13+
from torchtitan.config import ParallelismConfig
1314
from torchtitan.components.optimizer import register_moe_load_balancing_hook
1415
from torchtitan.distributed.pipeline_parallel import pipeline_llm
1516
from torchtitan.models.common import Embedding, Linear, RMSNorm, RoPE, TransformerBlock
@@ -170,7 +171,8 @@ def _build_dsv3_layers(
170171
router_route_norm: bool = False,
171172
score_before_experts: bool = False,
172173
attn_backend: str = "sdpa",
173-
moe_comm_backend: str = "standard",
174+
parallelism: ParallelismConfig | None = None,
175+
pad_multiple: int | None = None,
174176
) -> list[TransformerBlock.Config]:
175177
"""Build the list of per-layer TransformerBlock configs.
176178
@@ -180,6 +182,8 @@ def _build_dsv3_layers(
180182
Router and expert inits are constructed per-layer so depth-scaled
181183
initializers are correct for each layer's position.
182184
"""
185+
if parallelism is None:
186+
parallelism = ParallelismConfig()
183187
layers = []
184188
for layer_id in range(n_layers):
185189
attn_cfg = _make_dsv3_attn_config(
@@ -225,7 +229,10 @@ def _build_dsv3_layers(
225229
top_k=router_top_k,
226230
param_init=_depth_experts_init(layer_id),
227231
score_before_experts=score_before_experts,
228-
moe_comm_backend=moe_comm_backend,
232+
moe_comm_backend=parallelism.expert_parallel_comm_backend,
233+
ep_size=parallelism.expert_parallel_degree,
234+
pad_multiple=pad_multiple,
235+
hybridep_non_blocking_expert_capacity_factor=parallelism.hybridep_non_blocking_expert_capacity_factor,
229236
),
230237
shared_experts=make_ffn_config(
231238
dim=dim,
@@ -251,7 +258,8 @@ def _build_dsv3_layers(
251258

252259
def _debugmodel(
253260
attn_backend: str = "sdpa",
254-
moe_comm_backend: str = "standard",
261+
parallelism: ParallelismConfig | None = None,
262+
pad_multiple: int | None = None,
255263
**kwargs,
256264
) -> DeepSeekV3Model.Config:
257265
dim = 256
@@ -284,7 +292,8 @@ def _debugmodel(
284292
router_score_func="softmax",
285293
score_before_experts=False,
286294
attn_backend=attn_backend,
287-
moe_comm_backend=moe_comm_backend,
295+
parallelism=parallelism,
296+
pad_multiple=pad_multiple,
288297
)
289298
return DeepSeekV3Model.Config(
290299
vocab_size=vocab_size,
@@ -315,7 +324,8 @@ def _debugmodel(
315324

316325
def _16b(
317326
attn_backend: str = "flex",
318-
moe_comm_backend: str = "standard",
327+
parallelism: ParallelismConfig | None = None,
328+
pad_multiple: int | None = None,
319329
**kwargs,
320330
) -> DeepSeekV3Model.Config:
321331
dim = 2048
@@ -348,7 +358,8 @@ def _16b(
348358
router_score_func="softmax",
349359
score_before_experts=False,
350360
attn_backend=attn_backend,
351-
moe_comm_backend=moe_comm_backend,
361+
parallelism=parallelism,
362+
pad_multiple=pad_multiple,
352363
)
353364
return DeepSeekV3Model.Config(
354365
vocab_size=vocab_size,
@@ -379,7 +390,8 @@ def _16b(
379390

380391
def _236b(
381392
attn_backend: str = "flex",
382-
moe_comm_backend: str = "standard",
393+
parallelism: ParallelismConfig | None = None,
394+
pad_multiple: int | None = None,
383395
**kwargs,
384396
) -> DeepSeekV3Model.Config:
385397
dim = 5120
@@ -416,7 +428,8 @@ def _236b(
416428
router_route_scale=16.0,
417429
score_before_experts=False,
418430
attn_backend=attn_backend,
419-
moe_comm_backend=moe_comm_backend,
431+
parallelism=parallelism,
432+
pad_multiple=pad_multiple,
420433
)
421434
return DeepSeekV3Model.Config(
422435
vocab_size=vocab_size,
@@ -447,7 +460,8 @@ def _236b(
447460

448461
def _671b(
449462
attn_backend: str = "flex",
450-
moe_comm_backend: str = "standard",
463+
parallelism: ParallelismConfig | None = None,
464+
pad_multiple: int | None = None,
451465
**kwargs,
452466
) -> DeepSeekV3Model.Config:
453467
dim = 7168
@@ -485,7 +499,8 @@ def _671b(
485499
router_route_norm=True,
486500
score_before_experts=False,
487501
attn_backend=attn_backend,
488-
moe_comm_backend=moe_comm_backend,
502+
parallelism=parallelism,
503+
pad_multiple=pad_multiple,
489504
)
490505
return DeepSeekV3Model.Config(
491506
vocab_size=vocab_size,
@@ -525,11 +540,13 @@ def _671b(
525540
def model_registry(
526541
flavor: str,
527542
attn_backend: str = "sdpa",
528-
moe_comm_backend: str = "standard",
543+
parallelism: ParallelismConfig | None = None,
544+
pad_multiple: int | None = None,
529545
) -> ModelSpec:
530546
config = deepseekv3_configs[flavor](
531547
attn_backend=attn_backend,
532-
moe_comm_backend=moe_comm_backend,
548+
parallelism=parallelism,
549+
pad_multiple=pad_multiple,
533550
)
534551
return ModelSpec(
535552
name="deepseek_v3",

torchtitan/models/deepseek_v3/config_registry.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from torchtitan.components.lr_scheduler import LRSchedulersContainer
99
from torchtitan.components.metrics import MetricsProcessor
1010
from torchtitan.components.optimizer import OptimizersContainer
11+
from torchtitan.components.quantization import find_pad_multiple
1112
from torchtitan.components.quantization.float8 import (
1213
Float8GroupedMMConverter,
1314
Float8LinearConverter,
@@ -64,9 +65,14 @@ def deepseek_v3_debugmodel_flex_attn() -> Trainer.Config:
6465

6566

6667
def deepseek_v3_16b() -> Trainer.Config:
68+
parallelism = ParallelismConfig(
69+
pipeline_parallel_schedule="Interleaved1F1B",
70+
expert_parallel_degree=8,
71+
expert_tensor_parallel_degree=1,
72+
)
6773
return Trainer.Config(
6874
hf_assets_path="./assets/hf/deepseek-moe-16b-base",
69-
model_spec=model_registry("16B"),
75+
model_spec=model_registry("16B", parallelism=parallelism),
7076
dataloader=HuggingFaceTextDataLoader.Config(
7177
dataset="c4",
7278
),
@@ -81,11 +87,7 @@ def deepseek_v3_16b() -> Trainer.Config:
8187
seq_len=4096,
8288
steps=1000,
8389
),
84-
parallelism=ParallelismConfig(
85-
pipeline_parallel_schedule="Interleaved1F1B",
86-
expert_parallel_degree=8,
87-
expert_tensor_parallel_degree=1,
88-
),
90+
parallelism=parallelism,
8991
checkpoint=CheckpointManager.Config(interval=10),
9092
activation_checkpoint=ActivationCheckpointConfig(
9193
mode="selective",
@@ -95,9 +97,15 @@ def deepseek_v3_16b() -> Trainer.Config:
9597

9698

9799
def deepseek_v3_671b() -> Trainer.Config:
100+
converters = [
101+
Float8LinearConverter.Config(filter_fqns=["output", "router.gate"]),
102+
Float8GroupedMMConverter.Config(fqns=["experts"]),
103+
]
98104
return Trainer.Config(
99105
hf_assets_path="./assets/hf/DeepSeek-V3.1-Base",
100-
model_spec=model_registry("671B"),
106+
model_spec=model_registry(
107+
"671B", pad_multiple=find_pad_multiple(converters)
108+
),
101109
dataloader=HuggingFaceTextDataLoader.Config(
102110
dataset="c4",
103111
),
@@ -123,10 +131,5 @@ def deepseek_v3_671b() -> Trainer.Config:
123131
mode="selective",
124132
),
125133
compile=CompileConfig(enable=True, components=["loss"]),
126-
model_converters=ModelConvertersContainer.Config(
127-
converters=[
128-
Float8LinearConverter.Config(filter_fqns=["output", "router.gate"]),
129-
Float8GroupedMMConverter.Config(fqns=["experts"]),
130-
],
131-
),
134+
model_converters=ModelConvertersContainer.Config(converters=converters),
132135
)

torchtitan/models/llama4/__init__.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import torch.nn as nn
1111
from torchtitan.components.loss import build_cross_entropy_loss
12+
from torchtitan.config import ParallelismConfig
1213
from torchtitan.components.optimizer import register_moe_load_balancing_hook
1314
from torchtitan.distributed.pipeline_parallel import pipeline_llm
1415
from torchtitan.models.common import (
@@ -84,14 +85,17 @@ def _build_llama4_layers(
8485
interleave_moe_layer_step: int = 1,
8586
fixed_attn_block_size: int = 8192,
8687
attn_backend: str = "flex",
87-
moe_comm_backend: str = "standard",
8888
shared_experts_hidden_dim: int | None = None,
89+
parallelism: ParallelismConfig | None = None,
90+
pad_multiple: int | None = None,
8991
) -> list[TransformerBlock.Config]:
9092
"""Build per-layer configs for a Llama4 model.
9193
9294
Handles iRoPE (NoPE on every N layers) and MoE interleaving. For each
9395
layer, depth-scaled inits are computed using the layer index.
9496
"""
97+
if parallelism is None:
98+
parallelism = ParallelismConfig()
9599
inner_attention, mask_type = get_attention_config(attn_backend)
96100
if every_n_layers_nope <= 1:
97101
raise ValueError("every_n_layers_nope must be greater than 1")
@@ -131,7 +135,10 @@ def _build_llama4_layers(
131135
num_experts=num_experts,
132136
top_k=router.top_k,
133137
param_init=_depth_experts_init(layer_id),
134-
moe_comm_backend=moe_comm_backend,
138+
moe_comm_backend=parallelism.expert_parallel_comm_backend,
139+
ep_size=parallelism.expert_parallel_degree,
140+
pad_multiple=pad_multiple,
141+
hybridep_non_blocking_expert_capacity_factor=parallelism.hybridep_non_blocking_expert_capacity_factor,
135142
)
136143
shared_experts = make_ffn_config(
137144
dim=dim,
@@ -176,7 +183,8 @@ def _build_llama4_layers(
176183

177184
def _debugmodel(
178185
attn_backend: str = "flex",
179-
moe_comm_backend: str = "standard",
186+
parallelism: ParallelismConfig | None = None,
187+
pad_multiple: int | None = None,
180188
**kwargs,
181189
) -> Llama4Model.Config:
182190
dim = 256
@@ -207,7 +215,8 @@ def _debugmodel(
207215
interleave_moe_layer_step=2,
208216
fixed_attn_block_size=256,
209217
attn_backend=attn_backend,
210-
moe_comm_backend=moe_comm_backend,
218+
parallelism=parallelism,
219+
pad_multiple=pad_multiple,
211220
),
212221
rope=RoPE.Config(
213222
dim=dim // n_heads,
@@ -223,7 +232,8 @@ def _debugmodel(
223232

224233
def _17bx16e(
225234
attn_backend: str = "flex",
226-
moe_comm_backend: str = "standard",
235+
parallelism: ParallelismConfig | None = None,
236+
pad_multiple: int | None = None,
227237
**kwargs,
228238
) -> Llama4Model.Config:
229239
dim = 5120
@@ -265,7 +275,8 @@ def _17bx16e(
265275
every_n_layers_nope=4,
266276
interleave_moe_layer_step=1,
267277
attn_backend=attn_backend,
268-
moe_comm_backend=moe_comm_backend,
278+
parallelism=parallelism,
279+
pad_multiple=pad_multiple,
269280
),
270281
rope=RoPE.Config(
271282
dim=dim // n_heads,
@@ -281,7 +292,8 @@ def _17bx16e(
281292

282293
def _17bx128e(
283294
attn_backend: str = "flex",
284-
moe_comm_backend: str = "standard",
295+
parallelism: ParallelismConfig | None = None,
296+
pad_multiple: int | None = None,
285297
**kwargs,
286298
) -> Llama4Model.Config:
287299
dim = 5120
@@ -323,7 +335,8 @@ def _17bx128e(
323335
every_n_layers_nope=4,
324336
interleave_moe_layer_step=1,
325337
attn_backend=attn_backend,
326-
moe_comm_backend=moe_comm_backend,
338+
parallelism=parallelism,
339+
pad_multiple=pad_multiple,
327340
),
328341
rope=RoPE.Config(
329342
dim=dim // n_heads,
@@ -345,11 +358,13 @@ def _17bx128e(
345358
def model_registry(
346359
flavor: str,
347360
attn_backend: str = "sdpa",
348-
moe_comm_backend: str = "standard",
361+
parallelism: ParallelismConfig | None = None,
362+
pad_multiple: int | None = None,
349363
) -> ModelSpec:
350364
config = llama4_configs[flavor](
351365
attn_backend=attn_backend,
352-
moe_comm_backend=moe_comm_backend,
366+
parallelism=parallelism,
367+
pad_multiple=pad_multiple,
353368
)
354369
return ModelSpec(
355370
name="llama4",

torchtitan/models/llama4/config_registry.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from torchtitan.components.lr_scheduler import LRSchedulersContainer
99
from torchtitan.components.metrics import MetricsProcessor
1010
from torchtitan.components.optimizer import OptimizersContainer
11+
from torchtitan.components.quantization import find_pad_multiple
1112
from torchtitan.components.quantization.float8 import Float8GroupedMMConverter
1213
from torchtitan.config import (
1314
ActivationCheckpointConfig,
@@ -57,10 +58,13 @@ def llama4_debugmodel() -> Trainer.Config:
5758

5859

5960
def llama4_debugmodel_fp8() -> Trainer.Config:
61+
converters = [Float8GroupedMMConverter.Config(fqns=["experts"])]
6062
return Trainer.Config(
6163
hf_assets_path="./tests/assets/tokenizer",
6264
metrics=MetricsProcessor.Config(log_freq=1),
63-
model_spec=model_registry("debugmodel"),
65+
model_spec=model_registry(
66+
"debugmodel", pad_multiple=find_pad_multiple(converters)
67+
),
6468
dataloader=HuggingFaceTextDataLoader.Config(
6569
dataset="c4_test",
6670
),
@@ -88,11 +92,7 @@ def llama4_debugmodel_fp8() -> Trainer.Config:
8892
mode="selective",
8993
),
9094
compile=CompileConfig(enable=True, components=["model", "loss"]),
91-
model_converters=ModelConvertersContainer.Config(
92-
converters=[
93-
Float8GroupedMMConverter.Config(fqns=["experts"]),
94-
],
95-
),
95+
model_converters=ModelConvertersContainer.Config(converters=converters),
9696
)
9797

9898

0 commit comments

Comments
 (0)