Skip to content

Add MORI as a Token Dispatcher#135

Merged
sudhu2k merged 65 commits into
rocm_devfrom
sudhu/mori_deepseek_qwen
Jul 9, 2026
Merged

Add MORI as a Token Dispatcher#135
sudhu2k merged 65 commits into
rocm_devfrom
sudhu/mori_deepseek_qwen

Conversation

@sudhu2k

@sudhu2k sudhu2k commented May 25, 2026

Copy link
Copy Markdown
Collaborator

Add MORI as a Token Dispatcher

Summary

This PR integrates MORI EP as a new MoE token-dispatch/combine backend for the flex token dispatcher, giving AMD/ROCm GPUs an optimized expert-parallel all-to-all path alongside the existing DeepEP and HybridEP backends. It also adds the supporting padding-aware routing fixes, argument plumbing, example training scripts, container build steps, and unit-test coverage needed to run DeepSeek-V3 and Qwen3 MoE models with MORI.

Enable it with:

--moe-token-dispatcher-type flex --moe-flex-dispatcher-backend mori

Motivation

The flex dispatcher previously only supported deepep and hybridep. MORI provides a ROCm-native dispatch/combine kernel set. This PR wires MORI into Megatron's flex-dispatcher abstraction so MoE training on AMD hardware gets efficient, overlap-capable expert parallelism without changing the model code.

What's included

New MORI backend (megatron/core/transformer/moe/fused_a2a.py)

  • MoriDispatch / MoriCombine autograd.Functions implementing the forward/backward all-to-all via MORI's EpDispatchCombineOp.
  • Process-wide op caching (get_mori_op), shmem lifecycle management (init_mori_shmem / finalize_mori_shmem / reset_mori_op), and a dedicated high-priority CUDA comm stream so dispatch/combine can overlap non-dependent compute (mirrors DeepEP's async_finish / allocate_on_comm_stream contract).
  • Kernel-type auto-selection by world size (IntraNode for ≤8 ranks, InterNodeV1 otherwise) and optional FP8 dispatch support.
  • Adapts MORI's global-expert-id output to Megatron's DeepEP-style contract (local expert space with -1 sentinels), with sync-free per-expert token counting.

Dispatcher manager (token_dispatcher.py)

  • New _MoriManager(_DispatchManager) mirroring the DeepEP workflow (setup_metadatadispatch → permute → combine), including multihot conversion (with permute_fusion support), FP8 quantization padding, and a deferred-sync prefetch of per-expert counts to keep host reads off the critical path.
  • MoEFlexTokenDispatcher now constructs the MORI manager when moe_flex_dispatcher_backend == "mori".

Config & args

  • transformer_config.py: add mori to moe_flex_dispatcher_backend, plus new moe_mori_kernel_type and moe_mori_max_tokens_per_rank fields, with validation (MORI requires the flex dispatcher and is mutually exclusive with DeepEP).
  • arguments.py: auto-derive --moe-mori-max-tokens-per-rank in validate_args from micro_batch_size, seq_length, TP/SP, and CP when not explicitly set.

Examples & build

  • Dockerfile_rocm.ci: install MORI (pinned commit) and its libpci-dev / libibverbs-dev dependencies.
  • DeepSeek-V3 and Qwen3 train/proxy scripts: add ENABLE_MORI toggle and the corresponding moe_options.

Tests

  • test_token_dispatcher.py: parametrize flex dispatcher tests over ["deepep", "hybridep", "mori"] (skipping when MORI isn't available) and add a TestMoriSharedOp suite stressing process-wide op reuse across layers/steps.
  • conftest.py: proper MORI shmem/op teardown between parametrized cases to isolate EP state.
  • test_moe_layer_discrepancy.py: relax tolerances to account for floating-point accumulation noise.

How to test

  • Build the ROCm CI image (now includes MORI) and run the MoE unit tests; MORI-specific cases are auto-skipped when the library is absent.
  • Train DeepSeek-V3 / Qwen3 with ENABLE_MORI=true using the provided example scripts.

Notes / follow-ups

  • moe_mori_max_tokens_per_rank is auto-derived; pass an explicit value only to over-provision the symmetric SHMEM heap for variable-batch scenarios.

sudhu2k added 30 commits April 28, 2026 18:52
- Introduced `train_qwen2.sh` and `train_qwen3.sh` scripts for pretraining Qwen2 and Qwen3 models, respectively, with detailed configuration options.
- Added `readme.md` files for both Qwen2 and Qwen3, outlining dataset preparation, model training processes, and environment setup.
- Included instructions for single-node and multi-node training setups, along with customizable parameters for model size and training iterations.
…node runs

- Updated `train_qwen3.sh` to include FP8 recipe options for improved precision handling during training.
- Added a new script `1P1G_AAI_proxy_mi355x_qwen3_235B_A22B.sh` for smaller Qwen3-235B-style MoE proxy configurations, allowing for single-node and single-GPU smoke runs.
- Improved environment variable handling for model size, layers, and experts in the training scripts to facilitate easier customization.
- Adjusted default values and added comments for clarity on tunable parameters.
…ation

- Modified `train_deepseekv3.sh` to disable legacy grouped GEMM when using FP8, ensuring compatibility with TE grouped GEMM requirements.
- Updated `1P1G_AAI_proxy_mi355x_qwen3_235B_A22B.sh` to set `MOE_USE_LEGACY_GROUPED_GEMM` to false for improved performance.
- Enhanced `train_qwen3.sh` to include automatic handling of `--moe-router-padding-for-fp8` for MXFP8 configurations, streamlining the training process for FP8 models.
- Added informative logging to clarify changes in grouped GEMM settings based on FP8 configurations.
…bgroup

MORI's symmetric-heap allocation (hipExtMallocWithFlags, 32 GB+) collides
with TransformerEngine's HIP runtime init and aborts with glibc
`free(): invalid size`. Initialize MORI shmem in pretrain_gpt.py as the
first statement of the entry point, before any megatron/TE imports, against
a dedicated gloo subgroup registered as "mori" (mirrors vLLM's
MoriAll2AllManager). World group stays pure NCCL.

- pretrain_gpt.py: inline early bootstrap (no-op without --moe-enable-mori)
- fused_a2a.py: drop now-dead init_mori_shmem and its lazy call site
- training/initialize.py: pass device_id to init_process_group for eager
  NCCL init (required by MORI)
- examples/{qwen3,deepseek_v3}/train_*.sh: ulimit -l unlimited (libibverbs
  pin), force MORI_SHMEM_HEAP_SIZE=32G, --moe-mori-max-tokens-per-rank=32768
- MoriDispatch.forward: rebase op.dispatch's global expert ids to local
  ids with -1 sentinels (DeepEP contract) so _indices_to_multihot stops
  writing OOB and triggering HSA_STATUS_ERROR_EXCEPTION 0x1016. Fix
  tokens_per_expert via the is_local mask.

- _MoriManager.combine and MoriDispatch.backward: pass receiver-side
  dispatched_probs ([total_recv, topk]) to op.combine instead of
  sender-side token_probs ([N, topk]). The IntraNode kernel indexes
  weightsBuf by totalRecvTokenNum, so the sender buffer caused a
  ~1.1 MiB OOB read and a delayed Memory access fault.

- Slice op.combine's [max_num_inp_token_per_rank, hidden_dim] output
  down to num_tokens in MoriCombine.forward and MoriDispatch.backward
  so view(hidden_shape) and dx match the original input.

Also drop the double reset_mori_op() (call_reset=True already resets),
remove triage prints, and lower qwen3's --moe-mori-max-tokens-per-rank
from 32768 to 8192.
- Introduced a process-wide CUDA stream for MORI dispatch/combine operations to allow concurrent execution with non-dependent work.
- Implemented `_get_mori_comm_stream` to lazily allocate and cache the communication stream with high priority.
- Updated `_run_mori_op_on_stream` to execute MORI operations on the dedicated stream when specified, enhancing performance by overlapping communication and computation.
- Modified `MoriDispatch` and `MoriCombine` classes to support new parameters for asynchronous execution and stream allocation, ensuring compatibility with existing functionality.
- Adjusted `_MoriManager` to pass the new flags for async operations during token dispatching and combining, improving overall efficiency in the MORI framework.
and auto calculate -moe-mori-max-tokens-per-rank
…side global indices are used for backward operations. Updated `MoriDispatch` and `MoriCombine` to save and pass the correct indices, preventing incorrect summation in the kernel. Improved documentation for clarity on input expectations and added receiver-side caches in `_MoriManager` for better integration with MORI's operations.
…f bug and adding a helper function to ensure non-empty weights for MORI operations. This change prevents potential issues with zero-row tensors during dispatch and improves the robustness of the MORI dispatch and combine functionality.
…reset_mori_op` functions. The `get_mori_op` now ensures a resolved kernel type is used and clarifies the operator's lifecycle in the documentation. The `reset_mori_op` function has been updated to clear the global MORI operator reference, preventing stale handles during tests. Additionally, the test suite has been modified to call `reset_mori_op` in the teardown method, ensuring a fresh state for each test case.
Drop the `recv_num_token[0].item()` host sync in `MoriDispatch.forward`
and the matching slice in `MoriCombine.backward` in favor of working on
the full `[max_num_tokens_per_rank, ...]` padded buffers and masking
the tail with `masked_fill` (0/`-1`/0), threading the live
`recv_num_token` tensor through `_MoriManager` into `MoriCombine` so
both backwards can re-mask without re-syncing. Replace `torch.bincount`
(internal `.max().item()`) and the `recv_token_indices[is_local]`
boolean gather with a fixed-size `scatter_add_` + `torch.where`. Remove
the now-unused `_ensure_combine_weights_non_empty` workaround. Clamp
fused-permute's `num_out_tokens` to `>= 1` to keep TE's unpermute
backward from raising `AttributeError` on cold ranks. Full
`tests/.../test_forward_backward[mori-*]` matrix passes.
Enhance the _MoriManager class by introducing a sync-free caching mechanism for tokens per expert. The new implementation allows for efficient retrieval of token counts without GPU-CPU synchronization, leveraging CPU and lazy-allocated GPU tensors. This change improves performance during expert layer operations and reduces unnecessary host syncs, particularly benefiting the Triton GroupedGEMM path. Additionally, new methods for computing fixed target per expert and padding routing maps have been added to streamline the token management process.
Introduce the MOE_PERMUTE_FUSION environment variable to control the fused token permute/unpermute behavior in the training script. Update the MoE options section to conditionally include the --moe-permute-fusion flag based on the new variable. This enhancement allows for more flexible configuration of the MoE training process, improving usability and performance tuning.
…zation lazy to call it just before combine or dispatch ops
…ver distinctions. Updated argument naming conventions in `MoriCombine` to include `sender_` and `recv_` prefixes, enhancing code readability and preventing potential bugs related to argument misalignment. Improved documentation to detail the expected shapes and roles of input tensors, addressing issues that led to backward gradient errors. Additionally, ensured correct handling of probabilities and indices for both forward and backward passes in the MORI operations.
This commit introduces the MORI installation steps in the Dockerfile. It also updates the comments for argument validation logic.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR integrates ROCm/MORI as an additional backend for Megatron-Core’s flex MoE token dispatcher, enabling MORI-based expert-parallel dispatch/combine alongside existing DeepEP and HybridEP paths. It also adds padding-aware routing behavior, argument/config plumbing for MORI sizing, ROCm container install steps, and expands unit tests and example scripts to exercise the new backend.

Changes:

  • Add MORI dispatch/combine implementation + lifecycle helpers (op caching, shmem init/finalize, comm stream) and wire it into the flex token dispatcher.
  • Propagate/handle padding masks in routing and fine-grained GPT execution, and adjust test tolerances/coverage for the new communication path.
  • Add MORI-related config/args fields and update ROCm container + example training scripts to enable MORI.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
megatron/core/transformer/moe/fused_a2a.py Adds MORI EP dispatch/combine autograd functions, op caching, shmem lifecycle, comm-stream execution helpers.
megatron/core/transformer/moe/token_dispatcher.py Introduces _MoriManager and wires MORI as a flex dispatcher backend.
megatron/core/transformer/moe/router.py Masks router outputs for padding tokens (so padding doesn’t participate in routing/dispatch).
megatron/core/transformer/transformer_config.py Adds MORI backend option + MORI-specific config fields and validation.
megatron/training/arguments.py Auto-derives --moe-mori-max-tokens-per-rank when MORI backend is selected.
megatron/core/models/gpt/fine_grained_callables.py Passes padding mask into MoE routing in fine-grained execution path.
tests/unit_tests/transformer/moe/test_token_dispatcher.py Parametrizes flex tests over MORI + adds MORI shared-op stress tests and teardown hooks.
tests/unit_tests/transformer/moe/conftest.py Adds MORI shmem teardown safety net between tests.
tests/unit_tests/transformer/moe/test_moe_layer_discrepancy.py Relaxes allgather vs alltoall tolerance (fp32 accumulation-order noise).
tests/unit_tests/models/test_mamba_moe_model.py Updates expected config keys to include MORI fields.
run_unit_tests.sh Adjusts marker expression (now includes internal tests by default).
Dockerfile_rocm.ci Installs MORI + build deps into ROCm CI container image.
examples/qwen3/train_qwen3.sh Adds ENABLE_MORI toggle + MORI flex-dispatcher flags.
examples/qwen3/proxy_mi355x_qwen3_235B_A22B.sh Enables MORI by default for this proxy script.
examples/deepseek_v3/train_deepseekv3.sh Adds ENABLE_MORI toggle + MORI flex-dispatcher flags.
examples/deepseek_v3/proxy_mi355x_deepseekv3_671B.sh Enables MORI by default for this proxy script.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread megatron/core/transformer/moe/router.py
Comment thread megatron/core/transformer/moe/token_dispatcher.py Outdated
Comment thread megatron/core/transformer/transformer_config.py
Comment thread megatron/core/transformer/moe/fused_a2a.py
Comment thread megatron/core/transformer/moe/fused_a2a.py
Comment thread run_unit_tests.sh
Comment thread tests/unit_tests/transformer/moe/test_token_dispatcher.py
Comment thread megatron/core/transformer/transformer_config.py
- Added validation to ensure `moe_mori_max_tokens_per_rank` is set when using the MORI EP backend, raising a ValueError if not.
- Updated process group registration methods in `fused_a2a.py` to use the correct namespace for improved compatibility.
- Introduced a new function `_resolve_mori_kernel_type` to determine the MORI kernel type based on world size or user input, enhancing flexibility in kernel selection.
- Adjusted the `dispatch` method in `_MoriManager` to utilize the new `kernel_type` parameter for better control over dispatch operations.
- Refined the routing logic in `router.py` to use bitwise operations for masking, improving performance and clarity.
- Cleaned up imports in the test file `test_token_dispatcher.py` by removing unnecessary lines.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.

Comment thread megatron/training/arguments.py
Comment thread megatron/core/transformer/moe/router.py
Comment thread megatron/core/transformer/moe/fused_a2a.py
Comment thread megatron/core/transformer/moe/fused_a2a.py
Comment thread tests/unit_tests/transformer/moe/test_token_dispatcher.py
Comment thread tests/unit_tests/transformer/moe/test_token_dispatcher.py
Comment thread megatron/core/transformer/moe/router.py
Comment thread megatron/core/transformer/transformer_config.py
Comment thread megatron/core/transformer/moe/fused_a2a.py Outdated
Comment thread megatron/core/transformer/moe/fused_a2a.py
Comment thread megatron/core/transformer/moe/token_dispatcher.py Outdated
Comment thread megatron/core/transformer/moe/fused_a2a.py
@wenchenvincent

Copy link
Copy Markdown
Collaborator

does EpDispatchCombineOp double-buffer its staging region per outstanding routing handle, or is there one shared region?

sudhu2k added 5 commits July 1, 2026 07:25
- Introduced `enable_mori` flag in `fine_grained_callables.py` to manage memory freeing logic for the MORI backend.
- Updated `MoriDispatch` class in `fused_a2a.py` to improve gradient handling and memory management during backward passes.
- Added new test cases in `test_cuda_graphed_schedule_chunk_1f1b.py` and `test_schedule_chunk_1f1b.py` to validate MORI functionality, including proper teardown procedures to prevent state leakage between tests.
- Enhanced comparison utilities to accommodate floating-point tolerance for MORI, ensuring accurate test results across different backends.
- Updated `MoriDispatch` in `fused_a2a.py` to eliminate unnecessary defensive cloning of dispatch output, enhancing memory management during backward passes.
- Introduced `_permute_by_experts` method in `_MoriManager` to fuse the expert permute operation within the dispatch node, streamlining the token processing flow.
- Adjusted floating-point comparison tolerances in `utils.py` to accommodate accumulation noise, ensuring accurate results across different backends.
- Updated `MoriCombine.backward` in `fused_a2a.py` to eliminate unnecessary cloning of the dispatch output, allowing for direct use of the gradient view without defensive copies.
- Enhanced `_MoriManager` in `token_dispatcher.py` to fuse the expert unpermute operation into the combine node, ensuring serialized execution on the same communication stream and improving efficiency during backward passes.
… functionality

- Updated test cases in `test_schedule_chunk_1f1b.py` and `test_schedule_layer_1f1b.py` to utilize the new `get_valid_token_dispatcher_types()` function, streamlining dispatcher type handling.
- Enhanced `reinitialize_model_parallel_for_mori()` in `utils.py` to allow for independent tensor model parallel size configuration, improving flexibility in test setups.
- Removed deprecated dispatcher configuration functions to simplify the codebase and reduce redundancy.
…n floating-point evaluations. Adjusted `MORI_COMPARE_ATOL` to 1.5e-1 and `MORI_COMPARE_RTOL` to 5e-2, reflecting improved handling of accumulation noise across different backends.
@sudhu2k

sudhu2k commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator Author

does EpDispatchCombineOp double-buffer its staging region per outstanding routing handle, or is there one shared region?

One shared staging region per op, so we cannot have 2 dispatch/combine calls from the same op in flight at the same time.

@sudhu2k
sudhu2k requested a review from wenchenvincent July 6, 2026 04:48
sudhu2k added 3 commits July 7, 2026 06:48
- Introduced `MORI_EP_LAUNCH_CONFIG_MODE` environment variable to control the launch configuration mode for MORI, defaulting to "AUTO".
- Removed FP8 dispatch integration and updated the dispatch configuration to use the standard data type and a scale dimension of zero
@sudhu2k

sudhu2k commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

While CI is having issues, all the tests passed locally.

@sudhu2k
sudhu2k merged commit 26912eb into rocm_dev Jul 9, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants