Skip to content

feat(moe): support shared expert fusion for trtllm-gen fp4 moe - #4239

Merged
aleozlx merged 5 commits into
flashinfer-ai:mainfrom
Aneureka:hiki/moe/shared_expert_fusion
Jul 31, 2026
Merged

aleozlx merged 5 commits into
flashinfer-ai:mainfrom
Aneureka:hiki/moe/shared_expert_fusion

Conversation

@Aneureka

@Aneureka Aneureka commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

📌 Description

Follow-up work for #2625 to add shared-expert fusion for trtllm-gen FP4 MoE.

🔍 Related Issues

#2551

🚀 Pull Request Checklist

Thank you for contributing to FlashInfer! Before we review your pull request, please make sure the following items are complete.

✅ Pre-commit Checks

  • I have installed pre-commit by running pip install pre-commit (or used your preferred method).
  • I have installed the hooks with pre-commit install.
  • I have run the hooks manually with pre-commit run --all-files and fixed any reported issues.

If you are unsure about how to set up pre-commit, see the pre-commit documentation.

🧪 Tests

  • Tests have been added or updated as needed.
  • All tests are passing (unittest, etc.).

Reviewer Notes

Summary by CodeRabbit

  • New Features
    • Added num_fused_shared_experts support for FP4 block-scale fused-shared-expert MoE, including DeepSeek-V3 routing, dispatcher plumbing, and updated trace/template inputs.
  • Bug Fixes
    • Updated routing/workspace sizing and tensor shape validation to correctly account for fused shared experts.
    • Improved routing replay compatibility checks, rejecting unsupported fused-shared-expert replay layouts and incompatible routing modes.
  • Tests
    • Added SM100 fused-shared-experts autotune smoke coverage for FP4 (varying fused expert counts) and expanded host-side validation/rejection tests.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

FP4 and FP8 TensorRT-LLM MoE paths now propagate fused shared-expert counts, expand routing and workspace sizing, enforce DeepSeek-V3 and replay constraints, and add trace, autotuning, integration, and validation coverage.

Changes

Fused shared-expert MoE support

Layer / File(s) Summary
API propagation and validation
flashinfer/fused_moe/core.py, flashinfer/fused_moe/runners.py
Public FP4 APIs, runners, fake operators, and dispatch paths accept and forward num_fused_shared_experts, while validating routing modes, expert-parallel settings, and replay buffers.
CUDA routing and tactic sizing
csrc/trtllm_fused_moe_kernel_launcher.cu
FP4 routing shapes, workspaces, scaling counts, tensor validation, and tactic resolution use fused expert totals; FP4 and FP8 launchers reject incompatible replay layouts.
Reference routing and trace contracts
flashinfer/trace/templates/moe.py, tests/trace/...json
DeepSeek-V3 reference routing appends fused experts with unit weights, expands expert execution, and exposes fused shared-expert inputs in trace schemas.
Autotuning and validation coverage
tests/autotuner/*, tests/moe/*
Tests cover FP4 fused shared-expert autotuning, CUDA-graph configuration, expert-parallel restrictions, replay rejection, routing-method restrictions, tensor shapes, and compatible implementations.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

  • flashinfer-ai/flashinfer#2551: Covers shared-expert fusion across FP4/FP8 routing, dispatch, validation, tracing, and tests.

Possibly related PRs

Suggested reviewers: aleozlx, samuellees, yzh119, dhiraj113, sricketts

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant MoERunner
  participant FP4Launcher
  participant DSReference
  Caller->>MoERunner: provide num_fused_shared_experts
  MoERunner->>FP4Launcher: dispatch fused routing parameters
  DSReference->>FP4Launcher: append shared expert ids and unit weights
  FP4Launcher-->>Caller: execute fused FP4 MoE
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately reflects the main change: shared-expert fusion support for trtllm-gen FP4 MoE.
Description check ✅ Passed The description follows the template with description, related issues, checklist, and tests sections filled in sufficiently; reviewer notes are optional.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
csrc/trtllm_fused_moe_kernel_launcher.cu (1)

1924-1944: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider mirroring the EP defense-in-depth pattern for UnpackedPrecomputed + fused shared experts.

The EP restriction (num_fused_shared_experts > 0 requires no sharding) is enforced at both the Python wrapper and here in C++ (init_common, Lines 706-725). The UnpackedPrecomputed + num_fused_shared_experts > 0 restriction, however, is only asserted in the Python op (core.py Lines 2761-2763) — check_routing() here has no equivalent guard, relying solely on the generic numel mismatch to eventually fail if this combination is ever reached directly.

🛡️ Optional defensive check
     if (routing_input_mode_ == RoutingInputMode::UnpackedPrecomputed) {
       TVM_FFI_ICHECK_EQ(topk_ids.dtype(), dl_int32)
           << "topk_ids must be int32 for unpacked precomputed routing.";
       TVM_FFI_ICHECK(topk_weights.dtype() == dl_bfloat16 || topk_weights.dtype() == dl_float32)
           << "topk_weights must be bfloat16 or float32 for unpacked precomputed routing.";
+      TVM_FFI_ICHECK(args->num_fused_shared_experts == 0)
+          << "num_fused_shared_experts > 0 is not supported with UnpackedPrecomputed routing.";
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@csrc/trtllm_fused_moe_kernel_launcher.cu` around lines 1924 - 1944, Update
check_routing() to explicitly reject the combination of
RoutingInputMode::UnpackedPrecomputed and args->num_fused_shared_experts > 0,
mirroring the existing Python validation. Add the guard alongside the
routing-mode and fused-shared-expert checks, with a clear validation message;
preserve the existing dtype and numel validations for supported combinations.
flashinfer/fused_moe/core.py (1)

4120-4135: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated EP/DeepSeekV3-only validation between FP8 and FP4 wrappers.

trtllm_fp8_block_scale_moe (Lines 4120-4135) and trtllm_fp4_block_scale_moe (Lines 4574-4594) implement identical EP-rejection and DeepSeekV3-only enforcement logic, differing only in local variable naming (nfse vs nsfe) and message wording. This duplication has already begun to drift; extracting a shared helper (e.g. _validate_fused_shared_experts_config(num_fused_shared_experts, local_expert_offset, local_num_experts, num_experts, routing_method_type)) would prevent the two paths from silently diverging further.

♻️ Proposed shared helper
+def _validate_fused_shared_experts_config(
+    num_fused_shared_experts: int,
+    local_expert_offset: int,
+    local_num_experts: int,
+    num_experts: int,
+    routing_method_type: int,
+) -> None:
+    if num_fused_shared_experts > 0 and (
+        local_expert_offset != 0 or local_num_experts != num_experts
+    ):
+        raise ValueError(
+            "Fused shared experts (num_fused_shared_experts > 0) do not yet support "
+            "expert parallelism: require local_expert_offset == 0 and "
+            "local_num_experts == num_experts. Got "
+            f"num_fused_shared_experts={num_fused_shared_experts}, "
+            f"local_expert_offset={local_expert_offset}, "
+            f"local_num_experts={local_num_experts}, num_experts={num_experts}."
+        )
+    if num_fused_shared_experts > 0 and routing_method_type != RoutingMethodType.DeepSeekV3:
+        raise ValueError(
+            "Fused shared experts (num_fused_shared_experts > 0) are only supported "
+            f"with DeepSeekV3 routing; got routing_method_type={routing_method_type}."
+        )

Then both trtllm_fp8_block_scale_moe and trtllm_fp4_block_scale_moe call _validate_fused_shared_experts_config(nfse, local_expert_offset, local_num_experts, num_experts, routing_method_type) followed by _validate_routing_replay_out(...).

Also applies to: 4574-4594

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@flashinfer/fused_moe/core.py` around lines 4120 - 4135, Extract the
duplicated fused shared-expert validation from trtllm_fp8_block_scale_moe and
trtllm_fp4_block_scale_moe into a shared _validate_fused_shared_experts_config
helper accepting num_fused_shared_experts, local_expert_offset,
local_num_experts, num_experts, and routing_method_type. Preserve both existing
checks and their error behavior in the helper, then have both wrappers call it
before _validate_routing_replay_out.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@tests/trace/fi_trace_out/moe_fp4_block_scale_ds_routing_topk8_e32_h7168_i2048_ng8_kg4.json`:
- Line 239: Regenerate the trace JSON artifact from the current moe.py template
so the embedded _trtllm_fp4_block_scale_moe_ds_routing_reference matches it
exactly, including the **activation_kwargs parameter, nsfe naming, and current
docstring. Preserve the activation-related inputs and do not manually edit the
embedded reference.

---

Nitpick comments:
In `@csrc/trtllm_fused_moe_kernel_launcher.cu`:
- Around line 1924-1944: Update check_routing() to explicitly reject the
combination of RoutingInputMode::UnpackedPrecomputed and
args->num_fused_shared_experts > 0, mirroring the existing Python validation.
Add the guard alongside the routing-mode and fused-shared-expert checks, with a
clear validation message; preserve the existing dtype and numel validations for
supported combinations.

In `@flashinfer/fused_moe/core.py`:
- Around line 4120-4135: Extract the duplicated fused shared-expert validation
from trtllm_fp8_block_scale_moe and trtllm_fp4_block_scale_moe into a shared
_validate_fused_shared_experts_config helper accepting num_fused_shared_experts,
local_expert_offset, local_num_experts, num_experts, and routing_method_type.
Preserve both existing checks and their error behavior in the helper, then have
both wrappers call it before _validate_routing_replay_out.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c34c898-0d05-49fc-a201-824bd92775a1

📥 Commits

Reviewing files that changed from the base of the PR and between 92274ba and 7c8056205a7485054c30a728f4e5b1fdc5b3dc87.

📒 Files selected for processing (8)
  • csrc/trtllm_fused_moe_kernel_launcher.cu
  • flashinfer/fused_moe/core.py
  • flashinfer/fused_moe/runners.py
  • flashinfer/trace/templates/moe.py
  • tests/autotuner/test_trtllm_fused_moe_autotuner_integration.py
  • tests/moe/test_trtllm_gen_fused_moe.py
  • tests/moe/trtllm_gen_fused_moe_utils.py
  • tests/trace/fi_trace_out/moe_fp4_block_scale_ds_routing_topk8_e32_h7168_i2048_ng8_kg4.json

@Aneureka
Aneureka force-pushed the hiki/moe/shared_expert_fusion branch from 7c80562 to 2874b4c Compare July 29, 2026 10:00
@Aneureka

Copy link
Copy Markdown
Collaborator Author

/bot run tests/moe

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

GitLab MR !1073 has been created, and the CI pipeline #60109719 is currently running. I'll report back once the pipeline job completes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@csrc/trtllm_fused_moe_kernel_launcher.cu`:
- Line 2808: Before assigning args->num_fused_shared_experts in init_common(),
validate that every expert-major weight, scale, and optional per-expert tensor
has an expert dimension of at least local_num_experts + nFusedShared, matching
the fused-ID mapping; reject undersized routed-only inputs with a host-side
error before launch.
- Around line 2702-2725: Validate that the optional num_fused_shared_experts
value is non-negative before using it in the dimension and scale-count
calculations in the exported launcher. Reject negative values with a clear
validation error, while preserving value_or(0) behavior when the option is
absent.
- Around line 1935-1942: Scope the expanded topk_ids and topk_weights size
checks in the num_fused_shared_experts block to routing_input_mode_ ==
RoutingInputMode::UnpackedPrecomputed. Preserve the existing validation for
unpacked precomputed inputs while allowing FromLogits and PackedPrecomputed to
use their respective buffer contracts.

In `@tests/moe/test_trtllm_gen_fused_moe.py`:
- Line 1964: Update the pytest.raises call in the relevant test to use a raw
regex string for the match pattern, preserving the existing ValueError assertion
and regex behavior while resolving Ruff RUF043.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 29ed239c-e566-42e8-9182-8bca19246682

📥 Commits

Reviewing files that changed from the base of the PR and between 7c8056205a7485054c30a728f4e5b1fdc5b3dc87 and 2874b4cf77755e3394a87e95ff327d3f37d0491b.

📒 Files selected for processing (8)
  • csrc/trtllm_fused_moe_kernel_launcher.cu
  • flashinfer/fused_moe/core.py
  • flashinfer/fused_moe/runners.py
  • flashinfer/trace/templates/moe.py
  • tests/autotuner/test_trtllm_fused_moe_autotuner_integration.py
  • tests/moe/test_trtllm_gen_fused_moe.py
  • tests/moe/trtllm_gen_fused_moe_utils.py
  • tests/trace/fi_trace_out/moe_fp4_block_scale_ds_routing_topk8_e32_h7168_i2048_ng8_kg4.json
🚧 Files skipped from review as they are similar to previous changes (6)
  • tests/moe/trtllm_gen_fused_moe_utils.py
  • tests/autotuner/test_trtllm_fused_moe_autotuner_integration.py
  • flashinfer/fused_moe/runners.py
  • flashinfer/trace/templates/moe.py
  • tests/trace/fi_trace_out/moe_fp4_block_scale_ds_routing_topk8_e32_h7168_i2048_ng8_kg4.json
  • flashinfer/fused_moe/core.py

Comment thread csrc/trtllm_fused_moe_kernel_launcher.cu
Comment thread csrc/trtllm_fused_moe_kernel_launcher.cu
Comment thread csrc/trtllm_fused_moe_kernel_launcher.cu
Comment thread tests/moe/test_trtllm_gen_fused_moe.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@csrc/trtllm_fused_moe_kernel_launcher.cu`:
- Around line 2046-2066: Extend the fused shared-expert validation block around
check_per_expert_scale to validate non-null gemm1_bias and gemm2_bias tensors
before constructing MoERunnerArgs. Require each bias to have totalLocalExperts
rows and preserve the existing expected trailing-dimension checks, then include
routed-only and fused-expert bias cases in the regression matrix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4007a634-9773-4323-8538-13dd6979430c

📥 Commits

Reviewing files that changed from the base of the PR and between 2874b4cf77755e3394a87e95ff327d3f37d0491b and 43df9633c007334be61803f02c665469f65b0f5b.

📒 Files selected for processing (2)
  • csrc/trtllm_fused_moe_kernel_launcher.cu
  • tests/moe/test_trtllm_gen_fused_moe.py

Comment thread csrc/trtllm_fused_moe_kernel_launcher.cu
@Aneureka
Aneureka force-pushed the hiki/moe/shared_expert_fusion branch from b313efa to 6c2fa53 Compare July 29, 2026 16:42
@Aneureka

Copy link
Copy Markdown
Collaborator Author

/bot run tests/moe

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

GitLab MR !1073 has been updated with latest changes, and the CI pipeline #60154826 is currently running. I'll report back once the pipeline job completes.

Comment thread tests/autotuner/test_trtllm_fused_moe_autotuner_integration.py Outdated

@aleozlx aleozlx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

one comment about testing organization. rest looks good

Aneureka added 5 commits July 29, 2026 20:25
Signed-off-by: Haobin Guo <haobing@nvidia.com>
Signed-off-by: Haobin Guo <haobing@nvidia.com>
Signed-off-by: Haobin Guo <haobing@nvidia.com>
Signed-off-by: Haobin Guo <haobing@nvidia.com>
Signed-off-by: Haobin Guo <haobing@nvidia.com>
@Aneureka
Aneureka force-pushed the hiki/moe/shared_expert_fusion branch from 6c2fa53 to b31860e Compare July 30, 2026 03:26
@Aneureka

Copy link
Copy Markdown
Collaborator Author

/bot run tests/moe

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

GitLab MR !1073 has been updated with latest changes, and the CI pipeline #60237310 is currently running. I'll report back once the pipeline job completes.

@Aneureka
Aneureka requested a review from aleozlx July 30, 2026 05:10
@flashinfer-bot

Copy link
Copy Markdown
Collaborator

[FAILED] Pipeline #60237310 — 17/18 executed test jobs passed

Compared with nightly #59923506.

Unit Tests

GPU CUDA 12.9 CUDA 13.0 Notes
5090 ✅ Pass ✅ Pass
B300 ✅ Pass ✅ Pass
GB200 ✅ Pass ✅ Pass
GB300 ✅ Pass ✅ Pass
H100 ✅ Pass ✅ Pass
RTX Pro 6000 Blackwell ✅ Pass ✅ Pass

✅ Pass · 🟡 Old failure · ❌ New failure · ⏱ Test timeout · ⚠️ Infrastructure · ❔ Unknown or unclassified · — Not run

Multi-GPU and Multi-Node Tests — 5/6 passed

GPU CUDA 12.9 CUDA 13.0 Notes
B300 (multi-GPU) ⚠️ Infra ✅ Pass Infrastructure: CI infrastructure failure (1 job; CUDA 12.9)
GB200 (multi-node) ✅ Pass ✅ Pass
GB300 (multi-node) ✅ Pass ✅ Pass
Failure details

Timeouts, infrastructure, or incomplete jobs

@Aneureka Aneureka self-assigned this Jul 31, 2026

@aleozlx aleozlx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants