onnxruntime
1e1f574c - QMoE: prepack int4/int8 expert weights in PrePack hook (symmetric with MatMulNBits) (#28749)

Commit
39 days ago
QMoE: prepack int4/int8 expert weights in PrePack hook (symmetric with MatMulNBits) (#28749) ## Summary This PR lets the CUDA `com.microsoft::QMoE` operator prepack **raw** int4/int8 expert weights into the CUTLASS `fpA_intB` layout **inside ORT's `PrePack()` hook**, instead of requiring callers to run the layout transform offline via `pack_weights_for_cuda_mixed_gemm`. This makes integer QMoE symmetric with `MatMulNBits::PrePack_B`, and lets exporters ship the schema-conformant `[E, N, K/pack]` quantized weights produced by `quantize_matmul_{4,8}bits` directly, with no offline pre-pack step. The behaviour is **opt-in and backward compatible**: a new `weights_prepacked` attribute is a tri-state and defaults to `-1` (auto), which the CUDA EP treats as "already CUTLASS-prepacked" (today's behaviour). `1` forces the prepacked interpretation explicitly, and only `weights_prepacked=0` triggers the new in-`PrePack` layout transform. ## What changed - **New `weights_prepacked` attribute** on the QMoE schema (tri-state, default `-1`/auto). `-1` lets each execution provider pick its own backward-compatible default; the CUDA EP treats auto as prepacked. `1` = the int4/int8 `fc1`/`fc2` initializers are already in the CUTLASS `fpA_intB` layout (today's behaviour). `0` = the initializers are raw `[E, N, K/pack]` tensors and the kernel runs the layout transform itself in `PrePack()`. - **`PrePackIntExpertWeights`** — loops over the `E` experts and applies the per-expert transpose + CUTLASS `fpA_intB` row-permutation / column-interleave / bias / pair-interleave transform on the GPU, mirroring `pack_weights_for_cuda_mixed_gemm`. Architecture-aware packing per `docs/contrib_ops/cuda/moe_qmoe.md` §7 (SM90 is its own layout group; all other supported arches share the SM80 layout; SM75+ required). - **`PrePack()` dispatch** for the int weight slots (2 and 5) when `quant_type == "int"` and `weights_prepacked == 0`. The source initializers are released after their shapes are cached (`fc1/fc2_weights_shape_`), so peak weight memory stays ~1×. - **`ComputeInternal`** prefers the prepacked GPU buffers when the PrePack hook populated them (gated on `int_weights_consumed_by_prepack`), and otherwise falls through to the raw initializer pointers (e.g. for sessions that set `session.disable_prepacking`). ## Schema note This **does add a schema attribute** (`weights_prepacked`) to QMoE. It is backward compatible because the default (`-1`/auto) is interpreted by the CUDA EP as prepacked, preserving the existing offline-prepacked behaviour, but it is a schema surface-area change. ## Diff scope | File | Change | |---|---| | `onnxruntime/core/graph/contrib_ops/contrib_defs.cc` | New `weights_prepacked` schema attribute + docs | | `onnxruntime/contrib_ops/cuda/moe/moe_quantization.h` | New private method + prepack buffer / cached-shape members | | `onnxruntime/contrib_ops/cuda/moe/moe_quantization.cc` | `PrePackIntExpertWeights` + PrePack dispatch + ComputeInternal hookup | | `onnxruntime/test/python/transformers/test_qmoe_cuda.py` | CUDA smoke test for the raw-weight `weights_prepacked=0` path | FP4 / FP8 / WFP4AFP8 paths are untouched, and there is no behaviour change for callers that pre-prepacked their weights. ## Testing - `onnxruntime_providers_cuda` builds and links cleanly (nvcc 13.2 / sm_90). - `TestQMoEIntPrePackSmoke` (`test_qmoe_cuda.py`) builds a QMoE graph with raw int4 weights and `weights_prepacked=0`, runs it through the CUDA kernel, and asserts the output is finite with a plausible magnitude. Verified on H200 (SM90); node placement confirmed on `CUDAExecutionProvider` via profiling. - Existing int4 QMoE parity tests (`phi3` / `swiglu`, fp16) pass on CUDA — no regression in the default `weights_prepacked=-1` (auto, prepacked) path. > Note: this is a smoke test, not a numerical parity check. The existing offline > pre-pack harness hardcodes `force_arch=80` and produces incorrect output on > SM≥90, so a bit-parity comparison against it is intentionally omitted until > that harness honours the runtime SM. --------- Signed-off-by: Justin Chu <11205048+justinchuby@users.noreply.github.com> Co-authored-by: Justin Chu <11205048+justinchuby@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Author
Parents
Loading