Repository navigation
🚨 deepgemm_megamoe EP implementation for DeepGEMM Mega MoE - #49606
IlyasMoutawwakil wants to merge 58 commits into
Conversation
…ers into unify-resolve-plan
This reverts commit 3f1e4ab.
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. Pages changed in this PR: |
passthrough expert-parallel strategy for DeepGEMM Mega MoEdeepgemm_megamoe expert-parallel strategy for DeepGEMM Mega MoE
1bfd600 to
6ca9df4
Compare
deepgemm_megamoe expert-parallel strategy for DeepGEMM Mega MoEdeepgemm_megamoe EP implementation for DeepGEMM Mega MoE
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| num_topk=num_top_k, | ||
| num_experts=num_global_experts, | ||
| num_max_tokens_per_rank=num_tokens, | ||
| num_max_tokens_per_rank=1 << (num_tokens - 1).bit_length(), |
There was a problem hiding this comment.
why do we have to do that but not before ?
There was a problem hiding this comment.
We don't strictly have to; it bounds the reallocations. Before, each experts module kept its own buffer, sized to the batch, so every new largest batch reallocated it, once per layer. Now every layer of an EP group shares one buffer per shape, and allocating it is a collective rendezvous over symmetric memory, so it's sized to the next power of two: a batch that grows (prompts of different lengths, more sequences) reallocates a few times instead of at every new size, for at most twice the memory.
| | :--- | :--- | :--- | | ||
| | `"all_to_all"`, see [token dispatch](#token-dispatch) | Works for any layout, including `ep_size > tp_size`. Only the routed tokens move. | Two all-to-all collectives and one host sync per layer, so it does not capture in a CUDA graph. | | ||
| | `"all_reduce"` | No tokens move and no host sync, so decode captures in a CUDA graph. | Requires `ep_size=tp_size`. Every rank runs its experts over the whole batch, so its cost grows with the batch. | | ||
| | `"deepgemm_megamoe"` | DeepGEMM Mega MoE fuses the dispatch, the experts and the combine in one kernel. Every layer of an EP group shares its symmetric-memory buffers. | Requires `ep_size=tp_size`, and FP8 activations with FP4 experts on SM100+. Inference only. | |
There was a problem hiding this comment.
how should we decide with auto which one to use at inference between all_reduce and deepgemm_megamoe ?
There was a problem hiding this comment.
deepgemm_megamoe ep impl is locked at load time if the model uses deepgemm_megamoe experts impl, it's not part of the auto dispatch
# DeepGEMM Mega MoE exchanges the tokens inside its kernel, through the `deepgemm_megamoe` implementation's buffers
distributed_config = getattr(model.config, "distributed_config", None)
if (
getattr(model.config, "_experts_implementation", None) == "deepgemm_megamoe"
and distributed_config is not None
):
if distributed_config.ep_implementation not in ("auto", "deepgemm_megamoe"):
raise ValueError(
"DeepGEMM Mega MoE exchanges tokens inside its kernel and only runs with "
f'`ep_implementation="deepgemm_megamoe"`, got '
f"`ep_implementation={distributed_config.ep_implementation!r}`."
)
distributed_config.ep_implementation = "deepgemm_megamoe"There was a problem hiding this comment.
yep shouldnt be a decision for auto only for specific usecases, something we can share as recipe for specific models
There was a problem hiding this comment.
update: moved this out of the quantizer, AutoEP now builds MegaMoeEP itself when the experts use deepgemm_megamoe. it's forced by the experts impl (they can't run any other way), not a perf choice, so it fits auto. an explicit other ep_implementation raises in install_forward
`AllReduceEP` had nothing to dispatch and `AutoEP` bypassed both steps, so the two-step contract didn't fit. An `EPImplementation` now implements `forward` and runs the local experts with a shared `run_experts` (local DTensor params, empty rows kept connected to backward). `AllToAllEP` keeps its two exchanges as private `_send` / `_receive` steps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every `EPImplementation` defines `__call__` (AutoEP already did), and the base class keeps `run_experts`, now owning the local DTensor params context. `_all_reduce_backward` is gone: its call sites check `torch.is_grad_enabled() and x.requires_grad` before `_AllReduceBackward.apply`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `EpDispatchExpertsParallel.ep_implementations` maps the three built-in names to their classes, replacing `EPImplementationInterface` / `ALL_EP_IMPLEMENTATIONS`; docs and the config docstring point to it. - `AllToAllEP`'s halves are `_dispatch_tokens` and `_combine_tokens` again. - `EpDispatchExpertsParallel.should_use_local_tensors` is back. - Tests, from review: one parametrized check per implementation and mode (train, inference, both checkpoint modes) against one process, a separate check of AutoEP's choice, and install_forward's refusals. Co-authored-by: Ferdinand Mom <47445085+3outeille@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`_same_ranks` had one caller; the comparison of the TP and EP groups' ranks now sits where `shares_batch` is set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ations` `deepgemm_megamoe` joins the dict on `EpDispatchExpertsParallel` that replaces `EPImplementationInterface`; its test keeps the new parametrized ones and uses local inputs. From review: the class is `MegaMoeEP`, and the DeepGEMM error says "implementation". Co-authored-by: Ferdinand Mom <47445085+3outeille@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Actual question but what is the benefit of keeping deepgemm? I would expect we switch to deep ep anyways and deepgemm is hard to maintain with lots of restrictions. Imo, it might be more worth it to drop hard restrictions like these? Or am i too eager to drop it lol |
|
deepgemm might still be the best way to serve w4a8 mxfp4 experts (dsv4), once we have deepEP and fused moe kernels, we can compare and drop it if it loses 🫣 |
|
ok fair enough, i just hate deepgemm atp (sorry not sorry 😂) |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…xperts class in tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
vasqu
left a comment
There was a problem hiding this comment.
Some small comments but overall fine
| | :--- | :--- | :--- | | ||
| | `"all_to_all"`, see [token dispatch](#token-dispatch) | Works for any layout, including `ep_size > tp_size`. Only the routed tokens move. | Two all-to-all collectives and one host sync per layer, so it does not capture in a CUDA graph. | | ||
| | `"all_reduce"` | No tokens move and no host sync, so decode captures in a CUDA graph. | Requires `ep_size=tp_size`. Every rank runs its experts over the whole batch, so its cost grows with the batch. | | ||
| | `"deepgemm_megamoe"` | DeepGEMM Mega MoE fuses the dispatch, the experts and the combine in one kernel. Every layer of an EP group shares its symmetric-memory buffers. | Requires `ep_size=tp_size`, and FP8 activations with FP4 experts on SM100+. Inference only. | |
There was a problem hiding this comment.
yep shouldnt be a decision for auto only for specific usecases, something we can share as recipe for specific models
| | `RouterParallelMegaMoe` | Router variant for DeepGEMM Mega MoE, which dispatches experts inside the kernel which wants the router output untouched. | | ||
| | `MoeTensorParalellMegaMoeExperts` | Inference-only experts layer for DeepGEMM Mega MoE. Skips the gradient syncs and passes the process group into the module so the kernel can set up its shared buffers on the first forward. | |
There was a problem hiding this comment.
breaking 🚨 but for good reasons
There was a problem hiding this comment.
yep, added 🚨 to the title and a breaking note in the description
| """ | ||
|
|
||
| # TODO: Mega MoE is built for ranks holding different batches (data-parallel attention + EP), where neither the | ||
| # slicing nor the gather is needed. Until inference supports data parallelism, it runs on the shared batch. |
There was a problem hiding this comment.
oh interesting so we can make this less restrictive under DP? guess we need to check the dp mesh additionally then (additional kwarg)
There was a problem hiding this comment.
yes, megamoe is built for dp attention + ep where each rank has its own batch, then neither the slice nor the gather is needed. inference has no dp yet, so it stays a todo until it does, and that's where the dp mesh check would go
| # slicing nor the gather is needed. Until inference supports data parallelism, it runs on the shared batch. | ||
| needs_shared_batch = True | ||
| # The kernel's symmetric-memory buffers, by EP group. They are slow to allocate, so every layer of a group shares | ||
| # them, as the layers run one after another. `MegaMoeEP.symm_buffers.clear()` frees them. |
There was a problem hiding this comment.
maybe a dedicated function, id expect deep ep to have something similar so anything that clears all buffers
There was a problem hiding this comment.
done, destroy_megamoe_buffers() in integrations/deepgemm.py, same as deepep's destroy_deepep_buffers(). the buffers live there now, per ep group, so MegaMoeEP doesn't hold them anymore
| with _use_local_dtensor_params(self.experts): | ||
| local_output = self.experts_forward( | ||
| hidden_states[rows], top_k_index[rows], top_k_weights[rows], ep_group, self.group_symm_buffers | ||
| ) |
There was a problem hiding this comment.
should we maybe just adjust the experts forward to allow
- rows
- arbitrary kwargs (like the buffers)
There was a problem hiding this comment.
partly: it now only passes process_group= by name, the megamoe forward looks up its buffers by group itself. i'd keep the other experts forwards as they are though, the extra arg only exists for the megamoe kernel, and the rows are just a slice of the inputs so nothing to add there
| getattr(model.config, "_experts_implementation", None) == "deepgemm_megamoe" | ||
| and distributed_config is not None | ||
| ): | ||
| if distributed_config.ep_implementation not in ("auto", "deepgemm_megamoe"): |
There was a problem hiding this comment.
should we be stricter and disallow auto?
There was a problem hiding this comment.
i'd keep auto: loading with experts_implementation="deepgemm_megamoe" should just work without also setting ep_implementation. AutoEP now builds MegaMoeEP itself for those experts (no more config rewrite in the quantizer), and any other explicit implementation raises when the plan is applied
…face registry, doc notes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y-rows case in `AllToAllEP` Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o ep-passthrough-strategy # Conflicts: # docs/source/en/expert_parallelism.md # src/transformers/distributed/expert_parallel.py
…_megamoe_buffers()` Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
deepgemm_megamoe EP implementation for DeepGEMM Mega MoEdeepgemm_megamoe EP implementation for DeepGEMM Mega MoE
# Conflicts: # docs/source/en/expert_parallelism.md # src/transformers/distributed/configuration_utils.py # src/transformers/distributed/expert_parallel.py # tests/expert_parallel/test_expert_parallel.py # tests/quantization/finegrained_fp8/test_fp8.py
|
[For maintainers] Suggested jobs to run (before merge) run-slow: finegrained_fp8 |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o longer rewrites `ep_implementation` Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Depends on #49429.
DeepGEMM Mega MoE fuses the token dispatch, the experts and the combine in one kernel. It needs global expert ids, unmasked routing weights and the EP process group. Until now it only got them through the
megamoe_routerandmegamoe_expertsstyles. On the defaultep_dispatch_expertsplan, which DeepSeek V4 ships, loading withexperts_implementation="deepgemm_megamoe"failed at the first forward (DeepGEMM Mega MoE requires a process_group).This PR adds a
"deepgemm_megamoe"EP implementation."auto"runs it for experts loaded withexperts_implementation="deepgemm_megamoe", since they can only run through it; another explicit implementation raises. It requiresep_size == tp_size, like the old styles.🚨 Breaking: the
megamoe_routerandmegamoe_expertsparallel styles are removed. A plan that names them should useep_dispatch_expertson the experts and drop the router rule; loading withexperts_implementation="deepgemm_megamoe"selects the implementation.How it runs
The kernel treats each rank's rows as that rank's own tokens. Here every rank holds the same batch.
Example with 4 tokens on 2 ranks:
Changes
distributed/expert_parallel.pyMegaMoeEP, registered as"deepgemm_megamoe". It passes the EP group to the experts asprocess_group.AutoEPbuilds it for Mega MoE experts.integrations/deepgemm.pyprocess_group.group_name) and shape, shared by every layer.destroy_megamoe_buffers()frees them, like DeepEP'sdestroy_deepep_buffers()(#49638).integrations/tensor_parallel.py,integrations/finegrained_fp8.pymegamoe_routerandmegamoe_expertsstyles, and the FP8 plan rewrites to them."deepgemm_megamoe"row in the EP implementation table. The two styles leave the parallel styles page.Tests
tests/expert_parallel, 2 ranks on gloo. The new Mega MoE test checks that"auto"runs it and"all_to_all"is refused, the padded slices, global ids, the EP group and the gathered output; the DeepGEMM kernel tests check the buffers are cached per EP group.🤖 Generated with Claude Code