Repository navigation
[CUDA] Add fast INT3 QMoE kernels and offline SM80 INT2/INT4 prepack support - #33569
Merged
David Fan (jiafatom) merged 6 commits intoOct 25, 2026
Merged
Conversation
…support
- Add CUDA QMoE execution for INT3 and mixed-width {2,3,4}x{2,3,4} projections
(FusedFc1FastKernel with aligned uint32 __ldg + __funnelshift_r unpacking and
shared-memory input staging, parallel-route Fc2RouteFastKernel, and
FinalizeRoutesFastKernel) with one-time validation caching for CUDA Graph capture.
- Support offline SM80 fpA_intB prepacked weights (weights_prepacked=1) and
block_size=32 2-scale GEMV dequantization for INT2 and mixed INT2/INT4 QMoE
up to 512 experts, top_k=10, and expanded_num_rows <= 64.
- Ensure QMoE PrePack helpers fall back to the kernel GPU allocator when the
supplied initializer allocator is on CPU.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved scale-validation, packed-layout fallback, and numerical-consistency defects can cause out-of-bounds reads or incorrect results.
7 open issues
Validate scale shapes before offline-packed dispatch · New Reject offline-packed inputs without a packed execution path · New Revalidate mutable zero-point and scale inputs per run · New Track selected experts for INT3 execution · New Round dequantized weights before accumulation · New Add offline-packed SM80 layout parity tests · New Add fast-path coverage for aligned INT3 shapes · New
What changed in this PR
This PR extends CUDA QMoE execution with INT3 and mixed-width kernels, plus offline SM80-prepacked INT2/INT4 support for lower-memory MoE inference.
Changes:
- Adds direct INT3 projection kernels, dispatch, and content validation.
- Expands packed INT2/INT4 execution to block-size-32 dequantization, larger routing configurations, and offline-packed weights.
- Adds CUDA test cases and documents supported layouts and execution paths.
| File | Description |
|---|---|
onnxruntime/test/contrib_ops/moe_test.cc |
Adds block-size-32 and INT3 mixed-width tests. |
onnxruntime/contrib_ops/cuda/moe/qmoe_kernels.h |
Declares INT3 parameters and launch interfaces. |
onnxruntime/contrib_ops/cuda/moe/qmoe_kernels.cu |
Implements INT3 scalar, optimized, and validation kernels. |
onnxruntime/contrib_ops/cuda/moe/moe_quantization.h |
Adds INT3 dispatch and validation state. |
onnxruntime/contrib_ops/cuda/moe/moe_quantization.cc |
Integrates INT3 execution and offline-packed INT2/INT4 handling. |
onnxruntime/contrib_ops/cuda/llm/moe_gemm/moe_gemv.h |
Raises the expanded-row dispatch threshold to 64. |
onnxruntime/contrib_ops/cuda/llm/moe_gemm/moe_gemv.cu |
Adds two-scale block-size-32 INT2 dequantization. |
docs/contrib_ops/cuda/moe_qmoe.md |
Documents INT3 and offline-packed integer support. |
Review effort: Balanced
Tianlei Wu (tianleiwu)
marked this pull request as draft
October 23, 2026 22:22
- Validate block-wise scale shapes for offline-prepacked INT2/mixed weights by caching the shape before PrePack releases the scales. - Reject offline-prepacked inputs that fall to the dense dequantize fallback. - Cache INT3 content validation only for constant initializers so runtime-fed scales/zero points are always validated. - Record expert-selection statistics on the INT3 path. - Round each dequantized weight to T before accumulation in the fast INT3 kernels to match the scalar path. - Add INT3 fast-path parity, invalid zero-point, INT3 tiled-log, and weights_prepacked=1 INT2/mixed-width parity and malformed-scale tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ing to 8 rows - Raise kMaxProfiledExpandedRows from 64 to 80 in moe_gemv.h so 8-row (S=8, 7-draft DFlash2) verification with top_k=10 uses the fast MoE decode GEMV kernel. - Widen kFusedRouteMaxRows from 4 to 8 (kFusedRouteThreads=256) in qmoe_fused_route.cuh so single-CTA FusedSoftmaxTopKMapsKernel handles up to 8 rows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tianlei Wu (tianleiwu)
added a commit
that referenced
this pull request
Oct 24, 2026
…2 QMoE, and PR cleanups - Extend FoldMid2/FoldTail to head_rows<=8 and pack tokens[4..7] into ring record words 1, 2, 3, and 5. - Add state_update_capacity (0..8) support to CausalConvWithState and enable state_update_capacity > 0 in QwenS2 GatedDeltaNetDecodeWarpKernel. - Raise kMaxProfiledExpandedRows to 80 in moe_gemv.h and kFusedRouteMaxRows to 8 in qmoe_fused_route.cuh; add fast INT3 and offline SM80 INT2/INT4 prepack QMoE support. - Eliminate pq[8][ROWS] local register array in HcUpPreKernel and sync PR cleanups (#33469, #33470, #33471, #33472, #33474, #33548, #33569). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add dequantize_and_dot_f32 for AccT==float && CtaM==1 in moe_gemv_kernel, moe_gemv_fused_finalize_kernel, and moe_gemv_interleaved_swiglu_kernel to eliminate the 128-register tile_w_pack2 array and pack_to_vec2 scalar permutations, reducing register usage from 127 to 96 regs (4->5 blocks/SM) in FC1 and 80 to 72 regs (6->7 blocks/SM) in FC2 (-536 us/cycle at S=8). - Dispatch CtaNLargeM/2 (CtaN=2) at M=8 for small-N (N<=2560) Int4 GEMV. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Restore the original import order in test_qmoe_cuda.py so ruff passes. - Gate the fpA_intB GEMV M=8 small-N dispatch to the measured fp16 INT4 SM80-interleaved configuration, consistent with the adjacent wave-aware block. - Fix QMoECudaInt3TiledLogHasOneCounterUpdate to use the swiglu FC1 shapes that INT3 requires; the test previously failed shape inference. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tianlei Wu (tianleiwu)
marked this pull request as ready for review
October 24, 2026 23:18
David Fan (jiafatom)
approved these changes
Oct 25, 2026
David Fan (jiafatom)
deleted the
tlwu/20261023/qmoe-int3-int2-prepack-cuda
branch
October 25, 2026 01:09
This was referenced Oct 25, 2026
Tianlei Wu (tianleiwu)
added a commit
that referenced
this pull request
Nov 2, 2026
### Description Based on `main` after #33452 and #33450 merged (with already-merged #33569 commits dropped): 1. **SM80-Prepacked INT4 & Raw INT3 Offload Admission (`moe_quantization.cc`)**: Admits SM80-prepacked INT4 (`quant_type="int", expert_weight_bits=4, weights_prepacked=1, block_size=32`) and raw INT3 (`quant_type="int", expert_weight_bits=3, weights_prepacked=0, block_size in {32, 64, 128}`) `com.microsoft::QMoE` nodes into the v4 MoE offload pipeline. 2. **GPU `Int3MoeParams` Cold-Slot Skipping (`qmoe_kernels.{h,cu}`)**: Extends `FusedFc1FastKernel`, `Fc2RouteFastKernel`, and `LaunchInt3Typed` to skip negative cold-miss slots (`expert < 0`), support `source_route_ids` (`hit_ids`) indirection, and emit `wave_output` partials. 3. **`int4_bank_mode_` & `int3_bank_mode_` in `QMoEOffload` (`qmoe_offload.{h,cc}`)**: Adds INT4 and INT3 offload support across doorbell hybrid decode, adaptive promotion, byte-preserving `FileExpertStore` host caching (`scales_are_block_major = false` on CPU), and wave-streaming prefill, along with `test_v4_int4_and_int3_offload_modes_and_numerical_parity` in `test_qmoe_offload_v4.py`. ### PR stack Merge in this order: 1. #33575 - INT4/INT3 QMoE CPU/GPU offload (base: `main`) 2. #33622 - INT4 offload prefill/decode and S=8 doorbell optimizations (base: #33575) 3. #33629 - Grouped INT3 offload prefill and S=8 streaming optimizations (base: #33622) 4. #33731 - Tensor-core INT3/INT4 offload decode/prefill (base: #33629) Prerequisites #33452, #33450, #33689, and #33650 have merged into `main`. Retarget each dependent PR to `main` after its predecessors merge. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
Adds fast CUDA execution kernels for$S \le 8$ , 7-draft DFlash2 speculative decoding).
INT3and mixed-width(FC1, FC2) ∈ {2, 3, 4} × {2, 3, 4}com.microsoft::QMoEprojections, and extends the SM80 (fpA_intB) packedINT2and mixedINT2/INT4execution paths (moe_gemvdecode andRunInt2MoePrefillgrouped GEMM prefill) and single-CTA fused routing to support offline prepacked weights (weights_prepacked = 1),block_size = 322-scale GEMV dequantization,num_experts <= 512,k = 10,expanded_num_rows <= 80, andkFusedRouteMaxRows = 8(Summary of Changes
Fast
INT3& Mixed-WidthQMoECUDA Kernelsonnxruntime/contrib_ops/cuda/moe/qmoe_kernels.hInt3Projection,Int3MoeParams,LaunchInt3Moe, andValidateInt3MoeContent.onnxruntime/contrib_ops/cuda/moe/qmoe_kernels.cuUnpack8CenteredCodes/Unpack8CenteredCodes128(aligned 32-bit__ldg+ hardware__funnelshift_r24-bit 8-elementINT3unpacking),FusedFc1FastKernel(shared-memorys_inputstaging + 2-column(gate, up)register reuse per warp),Fc2RouteFastKernel(parallel-routegridDim.y = rows * top_klaunch + shared-memorys_actstaging + 16-lane half-warp 2-column tiling), andFinalizeRoutesFastKernel.onnxruntime/contrib_ops/cuda/moe/moe_quantization.hComputeInt3,has_int3_, and per-instanceint3_content_validated_atomic flag.onnxruntime/contrib_ops/cuda/moe/moe_quantization.ccexpert_weight_bitsandfc{1,2,3}_expert_weight_bitsin{2, 3, 4, 8}, dispatchesINT3projections toComputeInt3, and caches one-time content validation while skipping host synchronization during CUDA Graph capture.Offline SM80$S \le 8$ Routing
INT2/ MixedINT2/INT4Prepacking (weights_prepacked = 1),block_size = 32Decodemoe_gemv, &onnxruntime/contrib_ops/cuda/llm/moe_gemm/moe_gemv.hkMaxProfiledExpandedRowsfrom8to80soexpanded_num_rows <= 80) dispatches tomoe_gemv.onnxruntime/contrib_ops/cuda/moe/qmoe_fused_route.cuhkFusedRouteMaxRowsfrom4to8(kFusedRouteThreads = 256,s_sorted[256]) so single-CTAFusedSoftmaxTopKMapsKernelhandles up to 8 rows (onnxruntime/contrib_ops/cuda/llm/moe_gemm/moe_gemv.cudequantize_and_pack_to_vec2<Details, GroupSize, TypeA>andscales_iterator_hiacross all 4moe_gemvkernels soInt2DetailsW(StepK = 64) supports 2-scaleGroupSize == 32dequantization alongsideGroupSize == 64and128.onnxruntime/contrib_ops/cuda/moe/moe_quantization.ccweights_prepacked = 1forINT2((2, 2)) and mixedINT2/INT4((2, 4),(4, 2)), consuming offline SM80fpA_intBweight tensors directly in-place (packed_int_fc1,packed_int_fc2) forblock_size ∈ {32, 64, 128},num_experts <= 512, andk ∈ {1, 2, 4, 6, 8, 10}while releasing untransposed[E, N, K_blocks]scales inPrePack.docs/contrib_ops/cuda/moe_qmoe.mdINT3QMoE CUDA execution and offline SM80-prepackedINT2/ mixedINT2/INT4support.onnxruntime/test/contrib_ops/moe_test.ccQMoETest_MixedWidthCudaPackedDecodeBlock32andQMoETest_Int3AndMixedWidthCudaSwiGLUunit tests.Testing
QMoETest_MixedWidthCudaPackedDecodeBlock32andQMoETest_Int3AndMixedWidthCudaSwiGLUacross(3, 3),(3, 4),(4, 3),(2, 3),(2, 4),(4, 2), and(2, 2)withblock_size ∈ {32, 64}andnum_rows ∈ {1, 4, 64}.QMoEmodel packages on the full 800-sample MMLU-Pro benchmark (max_new = 8192) on NVIDIA H200 GPUs (361.14 tok/smedian,411.32 tok/sP90,453.30 tok/smax at