Skip to content

feat(moe): add unified block-scale FP8 support - #4026

Merged
aleozlx merged 8 commits into
flashinfer-ai:mainfrom
feih-nv:feih/mxfp8-moe-unified-api-pr1
Jul 22, 2026
Merged

aleozlx merged 8 commits into
flashinfer-ai:mainfrom
feih-nv:feih/mxfp8-moe-unified-api-pr1

Conversation

@feih-nv

@feih-nv feih-nv commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

📌 Description

Adds first-class DeepSeek FP8 and MXFP8 block-scale execution through the unified MoELayer API. These formats previously existed in the configuration schema and legacy flat APIs, but were not executable through MoELayer.

Fixed one issue in tests/moe_ep/test_split_fused_moe_kernel_vs_reference.py.

What changed

  • Added TrtllmFp8BlockRunner to the unified MoELayer API with:
    • DeepSeek FP8 and MXFP8 block-scale execution
    • Precomputed and in-kernel routing
    • Local expert offsets, autotuning, and CUDA graphs
  • Added format-aware weight and activation preparation:
    • DeepSeek FP8: FP32 128-element/128x128 block scales
    • MXFP8: UE8M0 32-element scales with shuffled MajorK weights
  • Fixed DeepSeek FP8 to preserve caller-provided activation scales.
  • Restricted unified block-FP8 support to the validated SM100 family (SM100 and SM103).
  • Added independent-reference, routing-replay, CUDA graph, and unified-fuzzer coverage.

🔍 Scope and follow-up

Unified FP8 support is split into two PRs because block-scale and per-tensor FP8 have distinct scaling and execution contracts. This PR covers block-scale FP8.

Follow-up work for per-tensor FP8

  • Add TrtllmFp8PerTensorRunner
  • Add per-tensor weight and scalar-scale preparation
  • Register QuantVariant.FP8PerTensor with MoELayer
  • Initially support FromLogits, matching the legacy API
  • Add independent conformance, CUDA-graph, tactic, fuzzer, and model-profile coverage

Additional future work

  • FP8 expert-parallel integration
  • do_finalize=False
  • Routing replay
  • LoRA and fused shared experts
  • OA parameters
  • Non-SwiGLU activations

Existing legacy tests remain under the Mirror → Bridge → Prune policy. The legacy flat APIs are unchanged. The unified runner delegates to the existing TRTLLM MoERunner and kernel entry points.

🚀 Pull Request Checklist

✅ 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.

🧪 Tests

Validated on SM100:

  • 11 passed — unified block-FP8 conformance suite
  • 19 passed — unified API validation subset
  • 2 passed — curated DeepSeek FP8 and MXFP8 fuzzer cases with production autotuning
  • 1 passed — existing FP4 FromLogits fuzzer confirmation on SM100

Summary by CodeRabbit

  • New Features
    • Added unified TRT-LLM block-FP8 MoE support for DeepSeek FP8 and MXFP8.
    • Added variant-aware block-FP8 weight/activation preparation and a new public block-FP8 runner.
    • Enabled both pre-routed and logits-based routing (including expert offsets), with CUDA graph capture/replay support.
  • Bug Fixes
    • Tightened block-FP8 backend SM support to explicitly allowed targets.
    • Corrected FP8 block activation/scale handling for accurate kernel dispatch.
  • Tests
    • Expanded block-FP8 conformance and fuzz coverage; updated backend support/validation expectations.

Expose DeepSeek FP8 and MXFP8 through MoELayer with format-aware preparation, routing-mode support, and focused conformance/fuzz coverage. AI-assisted implementation and validation.
@coderabbitai

coderabbitai Bot commented Jul 17, 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

Adds unified TRTLLM FP8 block MoE support for DeepSeek FP8 and MXFP8, including variant-aware preparation, runner dispatch, scale handling, architecture gating, routing support, and conformance and fuzz coverage.

Changes

TRTLLM FP8 Block MoE

Layer / File(s) Summary
FP8 contracts and preparation
flashinfer/fused_moe/__init__.py, flashinfer/fused_moe/api.py, flashinfer/fused_moe/prepare.py
Exports the FP8 block runner, adds variant-aware preparation APIs and activation-layout documentation, and implements DeepSeek FP8 and MXFP8 tensor preparation with validation, scaling, and permutation caching.
Runner and kernel integration
flashinfer/fused_moe/layer.py, flashinfer/fused_moe/runners.py, flashinfer/fused_moe/core.py
Registers the backend, validates routing and FP8 tensor contracts, constructs TRTLLM inputs, and forwards activation scales to the FP8 block kernel.
FP8 backend conformance tests
tests/moe/test_unified_moe.py, tests/moe/test_unified_moe_fp8.py, tests/moe_ep/test_split_fused_moe_kernel_vs_reference.py
Covers architecture support, executable variants, numerical results, weight layouts, logits routing, DeepSeekV3 routing, expert offsets, CUDA graph replay, and updated activation-pack routing fields.
FP8 fuzz and autotune coverage
tests/moe/test_unified_moe_fuzz.py
Adds FP8 references, generated and curated cases, variant-aware preparation, determinism coverage, and adjusted cache-coherence sweeps.

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

Sequence Diagram(s)

sequenceDiagram
  participant Input
  participant MoELayer
  participant TrtllmFp8BlockRunner
  participant MoERunner
  participant FP8BlockKernel
  Input->>MoELayer: provide BF16 activations and routing inputs
  MoELayer->>TrtllmFp8BlockRunner: select FP8 block backend
  TrtllmFp8BlockRunner->>MoERunner: pack routing, quantized tensors, and scales
  MoERunner->>FP8BlockKernel: execute FP8 block-scale MoE
  FP8BlockKernel-->>MoELayer: return computed output
Loading

Possibly related PRs

Suggested labels: run-ci, op: moe

Suggested reviewers: yzh119, jiahanc, aleozlx, djmmoss

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.04% 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 accurately summarizes the main change: adding unified block-scale FP8 support for MoE.
Description check ✅ Passed The description is mostly complete, covering changes, scope, checklist, and tests, with only the optional related issues section omitted.
✨ 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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request adds support for TRTLLM block-FP8 MoE (covering DeepSeek FP8 and MXFP8 quantization variants) on Blackwell SM100+ architectures. It introduces the TrtllmFp8BlockRunner adapter, weight and activation preparation utilities, and comprehensive unit and fuzz tests. The feedback suggests ensuring that act.topk_weights is contiguous before calling .view(torch.int16) in runners.py to prevent potential runtime crashes on non-contiguous tensors.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread flashinfer/fused_moe/runners.py
feih-nv added 3 commits July 20, 2026 01:05
Tighten calibrated conformance bounds, pin MXFP8 weight permutations, and track the shared DeepSeekV3 FromLogits wrong-answer path until its routing fix lands.
Select a deterministic curated seed that exercises production autotuning and document why block-FP8 preparation requires an explicit quant variant.
Use empty routing placeholders so the FP8 launcher consumes logits, reject unsupported SM110 early, and verify grouped routing selections exactly through replay.
@feih-nv
feih-nv marked this pull request as ready for review July 20, 2026 11:40

@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.

🧹 Nitpick comments (2)
tests/moe/test_unified_moe_fuzz.py (1)

469-498: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

prepare_weights result is unused for the MxFp8 path.

view is computed unconditionally at Line 469 but only referenced in the DeepSeekFp8 branch (Lines 480-485); the MxFp8 branch (Lines 486-498) rebuilds weights via _mxfp8_quant_matrix and discards view. Guarding the call avoids a redundant GPU weight preparation per MxFp8 reference call and removes a misleading dead computation.

♻️ Move prepare_weights into the DeepSeekFp8 branch
-    view = TrtllmFp8BlockConfig.prepare_weights(
-        w1,
-        w2,
-        variant=variant,
-        num_local_experts=w1.shape[0],
-        hidden_size=x.shape[1],
-        intermediate_size=intermediate_size,
-        device=x.device,
-    )
     x32 = _block_fp8_dequant(x_q, x_sf, variant)
     if variant is QuantVariant.DeepSeekFp8:
+        view = TrtllmFp8BlockConfig.prepare_weights(
+            w1,
+            w2,
+            variant=variant,
+            num_local_experts=w1.shape[0],
+            hidden_size=x.shape[1],
+            intermediate_size=intermediate_size,
+            device=x.device,
+        )
         w1_32 = _block_fp8_dequant(
             view["gemm1_weights"], view["gemm1_weights_scale"], variant
         )
         w2_32 = _block_fp8_dequant(
             view["gemm2_weights"], view["gemm2_weights_scale"], variant
         )
🤖 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 `@tests/moe/test_unified_moe_fuzz.py` around lines 469 - 498, Move the
TrtllmFp8BlockConfig.prepare_weights call into the DeepSeekFp8 branch, where its
result is consumed by view["gemm1_weights"] and view["gemm2_weights"]. Leave the
MxFp8 branch using _mxfp8_quant_matrix directly without computing or retaining
view.
tests/moe/test_unified_moe_fp8.py (1)

35-44: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use flashinfer.utils arch-support helpers instead of a manual arch tuple.

_is_trtllm_fp8_arch() hardcodes major*10+minor in (100, 103, 120, 121) and adds a torch.cuda.is_available() guard. Path instructions for tests/**/*.py call for using canonical helpers like is_sm100a_supported()/is_sm120a_supported() for arch gating, and this repo's tests assume CUDA is always available (no CPU guard needed in fixtures/skip helpers).

♻️ Suggested refactor
-def _is_trtllm_fp8_arch() -> bool:
-    if not torch.cuda.is_available():
-        return False
-    major, minor = get_compute_capability(torch.device("cuda"))
-    return major * 10 + minor in (100, 103, 120, 121)
+def _is_trtllm_fp8_arch() -> bool:
+    device = torch.device("cuda")
+    return is_sm100a_supported(device) or is_sm120a_supported(device)

As per path instructions, "Skip tests on unsupported CUDA architectures using flashinfer.utils functions like is_sm90a_supported(), is_sm100a_supported(), etc." Based on learnings, tests in this repo assume CUDA is available and avoid CPU-only guards outside of explicitly non-CUDA contexts.

🤖 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 `@tests/moe/test_unified_moe_fp8.py` around lines 35 - 44, Update
_is_trtllm_fp8_arch() to use the canonical flashinfer.utils architecture-support
helpers, such as is_sm100a_supported() and is_sm120a_supported(), instead of
computing and comparing a hardcoded capability tuple. Remove the
torch.cuda.is_available() guard and preserve support for the architectures
required by the test skip condition.

Sources: Path instructions, Learnings

🤖 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.

Nitpick comments:
In `@tests/moe/test_unified_moe_fp8.py`:
- Around line 35-44: Update _is_trtllm_fp8_arch() to use the canonical
flashinfer.utils architecture-support helpers, such as is_sm100a_supported() and
is_sm120a_supported(), instead of computing and comparing a hardcoded capability
tuple. Remove the torch.cuda.is_available() guard and preserve support for the
architectures required by the test skip condition.

In `@tests/moe/test_unified_moe_fuzz.py`:
- Around line 469-498: Move the TrtllmFp8BlockConfig.prepare_weights call into
the DeepSeekFp8 branch, where its result is consumed by view["gemm1_weights"]
and view["gemm2_weights"]. Leave the MxFp8 branch using _mxfp8_quant_matrix
directly without computing or retaining view.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 06bf879c-c6c7-48f7-8e15-9514665ee57e

📥 Commits

Reviewing files that changed from the base of the PR and between 17228c6 and 2aa9e15.

📒 Files selected for processing (9)
  • flashinfer/fused_moe/__init__.py
  • flashinfer/fused_moe/api.py
  • flashinfer/fused_moe/core.py
  • flashinfer/fused_moe/layer.py
  • flashinfer/fused_moe/prepare.py
  • flashinfer/fused_moe/runners.py
  • tests/moe/test_unified_moe.py
  • tests/moe/test_unified_moe_fp8.py
  • tests/moe/test_unified_moe_fuzz.py

Describe BF16, NVFP4, DeepSeek FP8, and MXFP8 payload/scale layouts and reflect block-FP8 FromLogits support.
@feih-nv

feih-nv commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run tests/moe

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

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

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

[FAILED] Pipeline #58765989: 8/20 passed

feih-nv added 2 commits July 20, 2026 19:07
Avoid launching unsupported sm100f BMM cubins on SM120/121, align tests with the validated architecture family, and remove redundant MXFP8 reference preparation.
Resolve flashinfer-ai#3983 overlap by adopting runner-owned support validation and retaining b12x alongside the TRTLLM block-FP8 runner.

@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.

🧹 Nitpick comments (1)
flashinfer/fused_moe/layer.py (1)

109-113: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move runner instantiation inside the try block.

Moving runner = runner_cls(config, device=self.device) inside the try block provides defense-in-depth. If a backend runner intentionally or inadvertently throws a validation error (ValueError, NotImplementedError, or RuntimeError) during its __init__ phase, it will be safely caught and skipped instead of crashing the entire layer initialization.

♻️ Proposed refactor
-            runner = runner_cls(config, device=self.device)
             try:
+                runner = runner_cls(config, device=self.device)
                 runner.check_support()
             except (NotImplementedError, ValueError, RuntimeError):
                 continue
🤖 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/layer.py` around lines 109 - 113, Move the runner
instantiation in the runner-selection loop inside the existing try block that
calls runner.check_support(), so ValueError, NotImplementedError, and
RuntimeError raised by runner_cls initialization are caught and skipped with
unsupported backends.
🤖 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.

Nitpick comments:
In `@flashinfer/fused_moe/layer.py`:
- Around line 109-113: Move the runner instantiation in the runner-selection
loop inside the existing try block that calls runner.check_support(), so
ValueError, NotImplementedError, and RuntimeError raised by runner_cls
initialization are caught and skipped with unsupported backends.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ff745c83-d8a9-4d4b-af18-38e8a21ffd78

📥 Commits

Reviewing files that changed from the base of the PR and between 20700a6 and 1c0f1bc.

📒 Files selected for processing (7)
  • flashinfer/fused_moe/__init__.py
  • flashinfer/fused_moe/api.py
  • flashinfer/fused_moe/core.py
  • flashinfer/fused_moe/layer.py
  • flashinfer/fused_moe/prepare.py
  • flashinfer/fused_moe/runners.py
  • tests/moe/test_unified_moe.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • flashinfer/fused_moe/init.py
  • flashinfer/fused_moe/core.py
  • flashinfer/fused_moe/runners.py
  • flashinfer/fused_moe/api.py
  • flashinfer/fused_moe/prepare.py

Use the renamed unified routing fields so split BF16 and NVFP4 conformance tests execute again, and document the DeepSeek FP8 scale exception.
@feih-nv
feih-nv requested a review from Anerudhan as a code owner July 21, 2026 08:35
@feih-nv

feih-nv commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run tests/moe

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

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

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

[SUCCESS] Pipeline #58896568: 14/20 passed

@aleozlx
aleozlx merged commit b7cd951 into flashinfer-ai:main Jul 22, 2026
32 checks passed
@feih-nv
feih-nv deleted the feih/mxfp8-moe-unified-api-pr1 branch July 22, 2026 03:07
aleozlx pushed a commit that referenced this pull request Jul 24, 2026
## 📌 Description

Add TRTLLM per-tensor FP8 execution to the unified `MoELayer` API.

Also fixes the MXFP8 scale-layout issue reported in #4087.

### What changed

* Added `TrtllmFp8PerTensorRunner` to the unified `MoELayer` API with:
  * `FromLogits` in-kernel routing
  * SM100 and SM103 support
  * Autotuning and CUDA graphs
  * Llama4 routing-scale-on-input behavior
* Added per-tensor FP8 weight and activation preparation:
  * Per-expert E4M3 weight quantization
  * Calibrated per-tensor activation quantization
  * TRTLLM gated-row reorder and shuffled MajorK weights
  * Per-expert GEMM1 linear/gate and GEMM2 epilogue scales
* Registered `QuantVariant.FP8PerTensor` with `MoELayer`.
* Added independent-reference, routing-replay, CUDA-graph,
architecture-gating, and unified-fuzzer coverage.
* Fixed unified MXFP8 block-scale preparation by converting row-permuted
GEMM1/GEMM2 scale tensors into TRTLLM’s required 128×4 interleaved
layout.

## 🔍 Scope and follow-up

Unified quantized MoE support is split into separate PRs because the
formats use different kernels, scaling conventions, architectures, and
execution contracts:
* PR 1: block-scale DeepSeek FP8 and MXFP8 — merged in #4026
* PR 2: per-tensor FP8 — this PR
* PR 3: CUTLASS W4A8 — follow-up

This PR keeps per-tensor FP8 `FromLogits`-only, matching the existing
TRTLLM kernel entry point. The legacy flat APIs remain unchanged.

## 🚀 Pull Request Checklist

### ✅ Pre-commit Checks

* I have installed `pre-commit` by running `pip install pre-commit` (or
used my 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.

## 🧪 Tests

Validated on SM100:

* `18 passed` — unified block-FP8 and per-tensor-FP8 conformance suites
* `7 passed` — focused unified API/config validation
* `1 passed` — curated per-tensor FP8 fuzzer profile with production
autotuning
* `1 passed` — MXFP8 seed `900013` regression, including valid-tactic
coverage
* `1 passed` — exact reported MXFP8 seed-100 configuration, including
valid-tactic coverage

### MXFP8 #4087 validation

The fuzzer and legacy MXFP8 references agree to within `1.16e-10`.
Unified and legacy weight payloads were identical, but the unified scale
tensors were missing the 128×4 physical interleave.

With the corrected scale preparation:

```text
before: 110 / 524288 elements over tolerance
after:  0 / 524288 elements over tolerance
```

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added TensorRT-LLM FP8 per-tensor quantization for Mixture-of-Experts,
including integration into the cross-backend MoE layer.
* Exposed a new FP8 per-tensor runner via the public API (FromLogits
routing).
* Added calibrated global scaling support for FP8 weights and
activations.
* **Bug Fixes**
* Tightened FP8/MXFP8 preparation validation for MXFP8 and clarified the
FP8 layout constraints.
* Refined hardware support to SM100 family values (supported: 100/103;
unsupported: 90/120).
* **Tests**
* Expanded FP8 per-tensor correctness and replay coverage, plus new
negative/behavioral tests.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
feih-nv added a commit that referenced this pull request Jul 29, 2026
Expose the existing TRTLLM-gen `MxFP4xMxFP8` (W4A8) and `MxFP4xBf16`
(W4A16) kernels through the unified MoE API.

## 📌 Description

This is PR 3 in the unified MoE quantization series for FP8 support:
1. #4026 — unified block-scale FP8 (merged)
2. #4091 — unified per-tensor FP8 (merged)
3. This PR — unified TRTLLM MXFP4×MXFP8/W4A8 and MXFP4×BF16/W4A16

### Changes
- Generalize `TrtllmFp4RoutedRunner` beyond NVFP4:
  - `QuantVariant.MXFP4`: `MxE2m1` weights × `MxE4m3` activations
  - `QuantVariant.W4A16`: `MxE2m1` weights × BF16 activations
- Add variant-aware TRTLLM FP4 preparation:
  - MXFP4 weights with 32-element UE8M0 scales
  - MXFP8 activation preparation for W4A8
  - BF16 activation preparation for W4A16
- Add shape, dtype, and scale-layout validation.
- Add unified conformance and fuzzer coverage for packed and
`FromLogits` routing.

### Support matrix
- NVFP4 and MXFP4/W4A8: SM100, SM103
- W4A16: SM100 only (remains disabled on SM103, matching upstream xfail
#1754)
- SM120/121: separate b12x backends where available
- SM107 is unsupported after #4171 

### Scope
- No CUDA/C++ kernel changes; both modes already exist in the TRTLLM
flat API.
- CUTLASS W4A8 is out of scope.

## 🚀 Pull Request Checklist

### ✅ Pre-commit Checks

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

## 🧪 Tests

SM100, CUDA 13 CI container:
- `tests/moe/test_unified_moe_mxfp4.py`
  - 21 passed
- Unified fuzzer, packed routing:
  - seeds `900017,900018`
  - 2 passed
- Unified fuzzer, `FromLogits`:
  - seeds `900019,900020`
  - 2 passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants