Repository navigation
[CUDA] Add GatherPacked, MatMulPacked, and MoEPacked contrib ops for block-packed weights - #33953
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical defects can cause initialization crashes, invalid memory reads, CUDA launch failures, and incorrect or undefined packed-operator outputs.
11 open issues
Reject empty vocabularies before gathering rows · New Reject top-k values greater than the expert count · New Handle shared-memory requests above CUDA's default limit · New Gate BF16 Tensor Core dispatch on hardware support · New Reject packed formats without a supported decoder · New Keep all warp lanes active in partial-tile MMA · New Regenerate and commit contrib operator documentation · New Stage device initializers into owned CPU tensors · New Decode external weights into native-endian float storage · New Disable CPU fallback in the CUDA decoder test · New Compare MoEPacked outputs against a numerical reference · New
What changed in this PR
Adds block-packed weight support to ONNX Runtime through three contrib operators, enabling embedding lookup, matrix multiplication, and mixture-of-experts execution without offline weight repacking.
Changes:
- Registers GatherPacked for CPU/CUDA and MatMulPacked and MoEPacked for CUDA.
- Adds CUDA dequantization, decode, prefill, and expert-routing kernels with Python tests.
- Extends external-initializer buffer borrowing and device reuse, with loading tests and documentation.
| File | Description |
|---|---|
onnxruntime/test/shared_lib/test_model_loading.cc |
Adds direct-buffer session-loading coverage. |
onnxruntime/test/python/transformers/test_gguf_packed_ops.py |
Tests packed formats and decode/prefill paths. |
onnxruntime/test/framework/inference_session_test.cc |
Tests initializer copying and pointer reuse. |
onnxruntime/core/session/inference_session.cc |
Passes the direct-buffer option to graph injection. |
onnxruntime/core/graph/graph.cc |
Extends external-initializer buffer retention. |
onnxruntime/core/graph/contrib_ops/ms_opset.h |
Adds the three operators to the Microsoft opset. |
onnxruntime/core/graph/contrib_ops/contrib_defs.cc |
Defines schemas and shape inference. |
onnxruntime/core/framework/tensorprotoutils.cc |
Extends in-memory serialization to small device tensors. |
onnxruntime/core/framework/session_state_utils.cc |
Reuses graph initializers on their planned device. |
onnxruntime/contrib_ops/cuda/quantization/matmul_packed.h |
Declares packed matrix-multiplication interfaces. |
onnxruntime/contrib_ops/cuda/quantization/matmul_packed.cu |
Implements decode kernels and cuBLAS prefill. |
onnxruntime/contrib_ops/cuda/quantization/matmul_packed.cc |
Validates inputs and dispatches CUDA computation. |
onnxruntime/contrib_ops/cuda/quantization/gguf_quant_cuda.cuh |
Adds shared CUDA decoders and BF16 Tensor Core helpers. |
onnxruntime/contrib_ops/cuda/quantization/gather_packed.h |
Declares CUDA packed-gather interfaces. |
onnxruntime/contrib_ops/cuda/quantization/gather_packed.cu |
Implements gathered-row dequantization. |
onnxruntime/contrib_ops/cuda/quantization/gather_packed.cc |
Registers and validates CUDA GatherPacked. |
onnxruntime/contrib_ops/cuda/moe/moe_packed.h |
Defines expert-routing parameters and interfaces. |
onnxruntime/contrib_ops/cuda/moe/moe_packed.cu |
Implements routing, expert computation, and output accumulation. |
onnxruntime/contrib_ops/cuda/moe/moe_packed.cc |
Validates expert tensors and chunks execution. |
onnxruntime/contrib_ops/cuda/cuda_contrib_kernels.cc |
Registers the three CUDA operators. |
onnxruntime/contrib_ops/cpu/quantization/gather_packed.cc |
Implements threaded CPU GatherPacked. |
onnxruntime/contrib_ops/cpu/cpu_contrib_kernels.cc |
Registers CPU GatherPacked variants. |
include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h |
Documents expanded direct-buffer option behavior. |
include/onnxruntime/core/graph/graph.h |
Adds the graph-injection borrowing parameter. |
docs/Model_Loading_Performance.md |
Describes external-buffer borrowing and device reuse. |
Review effort: Balanced
993adf6 to
ad04a04
Compare
…block-packed weights Add com.microsoft::GatherPacked (CPU and CUDA), com.microsoft::MatMulPacked (CUDA), and com.microsoft::MoEPacked (CUDA) contrib operators that consume 2D/3D block-packed quantized weight blobs (such as GGUF IQ1/IQ2/IQ3/IQ4/Q2_0/Q4/Q5/Q6_K/Q8_0) directly without offline repacking or split scale tensors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Disallow output-type split-K reductions in MatMulPacked prefill so FP32 compute cannot silently round intermediate sums to BF16 or FP16. This addresses the Windows A10 packed-operator parity failures while retaining Tensor Core execution. Preserve the caller's cuBLAS math mode, propagate mode-update failures, and add FP16/BF16 cancellation coverage with a documented prefill numerical contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
320084a to
0051ca2
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved critical CUDA alignment, dimension-range, and BF16 dispatch defects can cause faults or silently incorrect results, while full-matrix dequantization can exhaust device memory.
16 open issues
Range-check MoE dimensions before narrowing casts · New Use scalar finalize for misaligned output pointers · New Validate K and grid limits before CUDA launches · New Make packed decoder reads safe for unaligned weights · New Handle BF16 dispatch when only older PTX was compiled · New Reject dimensions that overflow device index types · New Tile large prefill dequantization to limit scratch memory · New Handle misaligned FP16/BF16 activation loads · New Decode GGUF values explicitly as little-endian · New Add large-M numerical coverage for chunking and workspace reuse · New Preserve ggml copyright and MIT notices for copied tables · New Document negative-index behavior and format block requirements · New Gate BF16 tests on SM80 capability · New Add independent CPU known-answer decoder tests · New Cover FP16, prefill, and runtime-M GEMV paths · New Add MoE tests for lookup formats and mixed weight pairs · New
11 resolved since last review
Stage device initializers into owned CPU tensors Regenerate and commit contrib operator documentation Keep all warp lanes active in partial-tile MMA Reject packed formats without a supported decoder Gate BF16 Tensor Core dispatch on hardware support Handle shared-memory requests above CUDA's default limit Reject top-k values greater than the expert count Reject empty vocabularies before gathering rows Compare MoEPacked outputs against a numerical reference Disable CPU fallback in the CUDA decoder test Decode external weights into native-endian float storage
Review effort: Max
Validate dimensions before narrowing, support unaligned packed and activation buffers, and bound MatMulPacked prefill scratch. Check compiled BF16 capability, preserve endian-safe decoding and ggml notices, and extend CPU/CUDA regression coverage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Unchecked CPU row-size arithmetic can overflow, and CUDA FP16 prefill can produce infinite outputs even when the correct result is finite.
11 open issues
Check row-size multiplication for int64 overflow · New Avoid FP16 overflow when converting large prefill weights · New Avoid per-row heap allocations when gathering low-precision output · New Clarify GGUF loading claims or implement mapped-buffer access · New Probe CUDA function attributes on the configured device · New Validate complete quantization blocks during construction · New Fall back to SIMT when Tensor Core code is unavailable · New Validate output dtype before narrowing to 32 bits · New Test BF16 staging-buffer reuse with larger MoE dimensions · New Test large-N BF16 decode across quantized formats · New Add independent known-answer tests for quantized formats · New
16 resolved since last review
Handle misaligned FP16/BF16 activation loads Tile large prefill dequantization to limit scratch memory Reject dimensions that overflow device index types Handle BF16 dispatch when only older PTX was compiled Make packed decoder reads safe for unaligned weights Validate K and grid limits before CUDA launches Use scalar finalize for misaligned output pointers Range-check MoE dimensions before narrowing casts Add MoE tests for lookup formats and mixed weight pairs Cover FP16, prefill, and runtime-M GEMV paths Add independent CPU known-answer decoder tests Gate BF16 tests on SM80 capability Document negative-index behavior and format block requirements Preserve ggml copyright and MIT notices for copied tables Add large-M numerical coverage for chunking and workspace reuse Decode GGUF values explicitly as little-endian
Review effort: Max
Resolve the generated operator documentation conflicts by retaining both MoEGroupRouter and the packed operators. Validation: CUDA 13.0 rebuild; 22 packed-operator tests, 14 focused C++ tests, 19 documentation tests; merged registration lint. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reject oversized packed rows and invalid output types during initialization. Keep FP16 prefill finite, preserve BF16 SIMT fallback on forward-compatible builds, and avoid per-row CPU conversion allocations. Add independent known answers and multi-block GPU regressions, and clarify packed-weight device-memory requirements. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The JNI-only ORT AAR does not reference legacy support libraries. Avoid loading its large Debug native libraries into Jetifier, which failed NNAPI CI with Java heap space, while retaining Jetifier for other Android test dependencies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Baiju Meswani (baijumeswani)
left a comment
There was a problem hiding this comment.
What this PR does
This adds GatherPacked on CPU/CUDA and MatMulPacked and MoEPacked on CUDA. They read native block-packed weights without requiring a separate repacking step or separate scale tensors. That is useful for loading existing GGUF models without keeping an expanded copy of their weights. CUDA still needs device memory for the packed weights; host-buffer borrowing and hybrid CPU/GPU offload are separate parts of the wider work.
What looks good
The current version addresses several earlier concerns: dimension and byte-size checks, unaligned buffers, compiled BF16 capability checks and fallback, bounded MatMul prefill scratch, and FP16 prefill overflow. The tests now have independent known answers for all 15 accepted formats, and CUDA sessions disable CPU fallback. These are meaningful improvements, not just comparisons between two new implementations that could share the same mistake.
What remains before approval
Please fix the CPU GatherPacked global-type-reduction failure described inline and add a regression. The public format contract and the decode/prefill precision differences should also be documented clearly before models start depending on these schemas. The inline comments include two further improvement suggestions: reducing empty MoE launches and broadening the independent IQ fixtures.
For the stack as a whole, please restack and test the actual final candidate. Against this head, I reproduced 16 conflicting paths when combining #33962, including validation, decoders, kernels, schemas and tests. The upper branch contains an older copy of the packed implementation, so conflict resolution needs to preserve the newer fixes here as well as the precision/routing additions. #33991 is explicitly test-only and uses an older bottom snapshot; it does not establish that the current merge stack works together.
Before settling the public operator surface, I would also like a clear comparison with #33940's existing-operator approach. Native packed storage is a reasonable requirement; I am not asking for repacking merely to reuse an operator name, or assuming that the alternative covers every GGUF format here. The question is which new public contracts are necessary, while keeping decoding, routing and expert execution reusable.
Reviewed f5f7aee with three independent reviewers. I reproduced the registration filtering failure, the numerical example and tile-bound calculations, and checked the stack conflicts. I did not run a full ORT build, GPU runtime tests, sanitizers or latency benchmarks.
Preserve GatherPacked output/index pairs in reduced builds and bound MoE launches by the route count without changing workspace layout. Define stable public packed layouts and decode/prefill rounding behavior, with independent IQ known answers and dispatch-boundary regressions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Addressed the five inline items in 9beea24119: pair-aware GatherPacked reduction, the MoE launch clamp, explicit rounding boundaries, a stable packed-format contract, and independent high-index IQ fixtures. Validation of this lower candidate
Comparison with #33940
These are not strict supersets: this lower PR does not implement NVFP4 or the Bolt-specific routing contract. Offset-UINT8 Q8 also must not be equated with native Q8_0's signed bytes and interleaved scale. I agree that native storage does not mathematically require new operator names or repacking merely to reuse existing names. The necessary public contracts are the byte codec/layout and dimensions, activation/output types and rounding, and MoE activation/routing semantics. Those need explicit, stable definitions under either operator surface. #33940 demonstrates the alternative of adding guarded fixed profiles to existing schemas; the three names here expose a uniform native-block interface. Private decoding, routing, and expert execution should remain reusable rather than being separated merely by the public names. Upper-stack qualification remains outstandingRe-running read-only Rui Ren (@rui-ren): #33962 needs replaying/restacking onto |
iOS device runs have stalled during cold simulator setup before app installation. Reset only the simulator selected by the Detox configuration, then wait for boot and app services without restarting the global CoreSimulator service. Keep app reinstallation, device assertions, and the existing Detox setup deadline unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Final maintenance verification at The native reviewer fixes in The subsequent exactccea React Native42622402833 genuinely executed three cases: MNIST/Basic Types passed, then EPContext reload failed after a native signal11 in the The identical original39a header has an independently reproduced post-dispatch UAF: resolve/reject dispatch can release the last worker owner before the background lambda subsequently accesses raw Fresh local validation on actual Packed69a/f58:640 real pinned-Hermes/JSI ASan+LSan lifetime scenarios in two independent processes, covering resolve/reject/cancellation/Env invalidation/dispatch exceptions, with compiler dependencies verifying the actual checkout header; all five focused EPContext component tests; configured native policy1/1; and scoped configured C++ formatting, repository TSX ESLint and repository-locked Prettier checks. This is native lifecycle validation, not a claim that the complete optional Packed/device matrix ran locally. Decisive fresh device proof: exact69a React Native42634651129 completed SUCCESS. Android artifact13684063653 and iOS artifact13686716401 each explicitly identify that run/head and contain exactly three actual passing MNIST, Basic Types and EPContext cases, no failures/errors/skips, and the unchanged14/14 checks passed assertion in device logs/traces. The originally failing iOS EPContext case now passes on the repaired current head. All other current-head integrations, including Windows CUDA42634651253 and the final WebGPU packaging/static-plugin gates, have also succeeded. No tests, tolerances, runtime assertions or teardown checks were bypassed. |
Run the native completion hook before dispatch can release the final worker reference. Preserve exactly-once completion when dispatch throws, and assert completion at promise settlement in the EPContext bridge regressions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Merge pinned main 3bde254 (23 commits ahead of the previous merge base 548473f, the #33953 merge). Conflict resolution: js/react_native/e2e/test/OnnxruntimeModuleExample.test.js took main's version. Main already selects the EPContext button on iOS via testID/by.id (e2a328f). The branch's by.label selector matches two nested views on iOS ("Multiple elements found"), so the branch no longer touches the React Native e2e test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
## Description Extends `com.microsoft::MatMulPacked` (CUDA) with the scaling and operand-precision contract needed by Nemotron Bolt, without repacking native weights. The optional scalar FP32 NVFP4 `global_scale` is applied after FP32 accumulation and before the output cast. Complete decoded weights now round to the activation dtype **by default**. The precision policy is session-only: `ep.cuda.matmul_packed_allow_unrounded_gemv="0"` (or unset) retains rounding, while `"1"` permits eligible GEMV kernels to skip it. Tensor-core kernels may still round. GEMM/prefill always rounds, including with FP32 scratch buffers. Only `"0"`/`"1"` are accepted; invalid values fail kernel/session initialization. The `dequantize_to_activation_dtype` node attribute is removed. Existing exports carrying that attribute must remove it or be regenerated; it is no longer an operator attribute. The BF16 decode path preserves contiguous K partitions and MMA operand ordering. Tensor Core dispatch checks compiled-image support as well as GPU capability so compute_75-only PTX correctly uses SIMT on newer GPUs. Prefill retains bounded tiled dequantization/GEMM, including the FP16 FP32-accumulation path. **Dependency:** first follow-up to merged #33953; this PR now targets `main`. Part of [native stack #33967](https://github.com/microsoft/onnxruntime/stack/33967). No CPU-format expansion, weight repacking, or GenAI source change. ## Summary of Changes ### Operator Contract and Documentation | File | Change | |------|--------| | `onnxruntime/core/graph/contrib_ops/contrib_defs.cc` | Add the optional NVFP4 multiplier; define rounded operands by default without a precision attribute. | | `docs/ContribOperators.md, docs/PackedWeightFormats.md` | Document the scale input, default rounding, session opt-out, and FP16 overflow semantics. | ### CUDA Implementation and Regression Tests The session key is declared in `include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h` and resolved once per kernel, without an environment alias or model attribute. | File | Change | |------|--------| | `onnxruntime/contrib_ops/cuda/quantization/matmul_packed.{cc,h,cu}` | Validate the scale, apply it before the output cast, retain bounded prefill, and select rounded BF16 TC/SIMT paths using compiled kernel capability. | | `onnxruntime/contrib_ops/cuda/quantization/gguf_quant_cuda.cuh` | Add the NVFP4 eight-element sub-block decode used by the projection path. | | `onnxruntime/test/contrib_ops/matmul_packed_precision_test.cc` | Cover default/explicit 0/1 policies, invalid values, FP16/BF16 complete operands, prefill boundaries, scale-before-cast, nonzero fallbacks, and cancellation. | ## Testing **Session-policy update:** owning head `2936957a4d9bfccaa070429938446c0c1482228b`; optimized stack tip `a3f2076b65e0d1a5c7e9b82165ffab014e233876`. - Owning layer: **10 native CUDA + 10 compute75-only PTX tests**, plus **3 Python tests** covering all packed formats, session-policy dispatch boundaries, and FP16 operand overflow. - Optimized stack tip: **15 native CUDA + 15 compute75-only PTX tests**, **5 Python tests** including byte-offset IOBinding fallbacks, and **1 actual internal CUDA cancellation test**. - Zero failures/skips. Production host/CUDA/schema/test sources compile; generated MatMulPacked documentation matches the production schema. CLANGFORMAT, Ruff/format and whitespace checks pass. Runtime checks use fresh policy objects and the exact MatMulPacked schema registration over ABI-matched preserved support. **Not a clean full-source build, full-CI approval, independent HF parity, performance remeasurement, or new end-to-end model qualification.** NVFP4 global-scale placement and unrelated MoE/router ownership remain unchanged. <details> <summary>Historical measurements and qualification evidence (not current-head acceptance)</summary> ### Earlier review qualification (historical) **Review-fix snapshot:** `1929a7099606c61f00a40f2e199007ee090eda3e`. Documented NVFP4 ID/layout, bit7-clear scale domain, scale edge cases, K geometry, CUDA-only availability and FP32 global-scale placement. Added default/opt-in scale tests, large-N default dispatch coverage, and an explicit failing switch default. Revised the cancellation fixture so both the native TC and compute75 PTX SIMT paths assert 2. **Owning-layer validation:** 8 native + 8 compute75-only PTX projection tests; zero failures/skips. **Integrated tip regression:** 51 C++ provider/schema tests, 5 actual internal CUDA tests and 2 Python IOBinding tests passed, zero failures/skips. All owning-layer provider cases are retained. The final overlay recompiles the changed CUDA/host/schema/test sources over ABI-matched preserved ORT support; **not a clean full-source build, full-CI approval, independent HF parity or new end-to-end qualification**. Targeted configured clang-format/Ruff and whitespace checks passed. These previously reported results are retained for provenance. They have not been rerun on the rebased head above; earlier CI/build status and benchmark results do not establish current-head CI, accuracy, or merge readiness. **Historical policy labels:** the table predates this session-policy change. 'Default' below denotes the former unrounded-GEMV policy (now permitted by the session opt-out); 'Precision opt-in' denotes rounded operands (now the default). The old attribute is no longer available. These timings have not been remeasured. ### Measured CUDA kernel latency - 2026-11-07 BF16 inputs/output and FP32 accumulation, Q8_0/NVFP4 packed weights; NVFP4 global scale 0.75. Default dispatch is compared with `dequantize_to_activation_dtype=true`. For rows >8 both paths use full dequantization plus cuBLAS (and the NVFP4 output-scale pass). **This is a precision option, not a universal speedup:** single-row latency regresses in all four shapes/formats; Q8_0 eight-row dispatch improves, NVFP4 eight-row results depend on shape, and 32-row results are approximately unchanged. Current operand rounding is now the default. All 12 synthetic cases have bitwise-equal complete outputs in both runs; these representable synthetic scales do not replace the separate adversarial precision tests. | Format | N x K | Rows | Default us | Precision opt-in us | Default / opt-in | |---|---|---|---|---|---| | Q8_0 | 18560 x 4096 | 1 | 53.82 | 95.33 | 0.56x | | Q8_0 | 18560 x 4096 | 8 | 108.98 | 95.49 | 1.14x | | Q8_0 | 18560 x 4096 | 32 | 162.65 | 162.57 | 1.00x | | Q8_0 | 4096 x 8192 | 1 | 34.77 | 39.17 | 0.89x | | Q8_0 | 4096 x 8192 | 8 | 71.73 | 40.88 | 1.75x | | Q8_0 | 4096 x 8192 | 32 | 80.23 | 80.23 | 1.00x | | NVFP4 | 18560 x 4096 | 1 | 51.80 | 132.81 | 0.39x | | NVFP4 | 18560 x 4096 | 8 | 119.29 | 134.85 | 0.88x | | NVFP4 | 18560 x 4096 | 32 | 154.32 | 154.29 | 1.00x | | NVFP4 | 4096 x 8192 | 1 | 29.83 | 54.09 | 0.55x | | NVFP4 | 4096 x 8192 | 8 | 66.63 | 56.90 | 1.17x | | NVFP4 | 4096 x 8192 | 32 | 71.00 | 70.98 | 1.00x | H100 80GB HBM3, CUDA 12.8.93, driver 580.159.04, GCC 11.4.0. CUDA-event median per dispatch; 64 dispatches per captured CUDA graph, 50 warmups, three graph warmups, and 15 paired timed batches alternating AB/BA. Four rotating allocation banks contain deterministic synthetic weights (seed 617); this is not a cold-cache guarantee or a checkpoint-weight benchmark. Raw p95 values describe batch-average latency, not individual-invocation tails. No profiler runs in the timing window. The assigned GPU had empty admission, one stable compute client during execution, and clean release afterward; clocks were not locked. Two independent 39-case runs passed, including the published replay runner. **Scope:** same-build production CUDA dispatch alternatives, not historical parent-commit binaries. The measured runtime is an isolated CUDA provider relink with preserved core/support, **not a clean full-source ORT build or end-to-end model qualification**. Each measured operator's CUDA source hash matches its owning PR head. A clean source build is a separate replication variant and must be measured again. Kernel-only timings do not establish model TTFT/tok/s, MMLU/LCB, speculative integration, or full-model readiness. [Complete primary/repeat results, numerical metrics, source hashes and benchmark code](#33962 (comment)). All 39 cases passed in both supervised runs; full-model work remains paused. No source push, stack change, merge, auto-merge or ready-for-review promotion is included. </details> ## Checklist - [x] Review feedback addressed with focused regressions - [x] Documentation and supported contracts updated - [x] Native stack order and immediate-parent dependencies preserved - [ ] Clean full-source/full-CI qualification (not claimed by focused overlays) --------- Signed-off-by: rui-ren <ruiren1225@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f4d0e1a3-a389-4cc8-9c85-0fd0e3ffce5b
… offload optimizations (#33973) ## Summary This PR consolidates and optimizes **CPU/GPU hybrid expert offload for `com.microsoft::MoEPacked` (GGUF sub-byte block-packed experts)** and **`com.microsoft::QMoE` (RC5 mixed-precision INT4/INT3/INT2 experts)** across 16 GB (RTX 5060 Ti), 24 GB (RTX 4090), 32 GB (RTX 5090), and H200 GPUs. ### Stacked On - #33935 (`[CUDA] Improve QMoE offload decode throughput via AVX2 spill elimination and working-set retention`) - #33944 (`[CUDA] Tail expert substitution for QMoE offload decode (stacked on #33935)`) - #33877 (`Support direct external initializer buffers in AddExternalInitializers`) - #33953 (`[CUDA] Add GatherPacked, MatMulPacked, and MoEPacked contrib ops for block-packed weights`) ### Key Changes 1. **End-to-End CPU/GPU Hybrid Offload for `com.microsoft::MoEPacked`** (`session_state.cc`, `moe_packed.h`, `moe_packed.cu`, `moe_packed.cc`): - Places `MoEPacked` expert weight initializers (`gate_weights`, `up_weights`, `down_weights`) on CPU (zero-copy file mapping) and implements `IMoeOffloadNode` admission with `QMoESessionController`. - Implements CUDA-graph-capturable hybrid doorbell decode (`MoEPackedOffloadClassifyAndBuildTilesKernel`, `MoEPackedDoorbellWaitKernel`, `MoEPackedOffloadFinalizeVec8Kernel`, and `LaunchQMoETailSubstitution` integration) and 8,192-row double-buffered 32-expert wave-streaming prefill with D2D adaptive hot-expert promotion. 2. **Lock-Free `qmoe::SpinPool` & Register-Accumulator AVX2+FMA+F16C GGUF Cold-Expert Kernels** (`moe_packed_cpu_avx2.cc`, `moe_packed.cc`, `cmake/onnxruntime_providers_cuda*.cmake`): - Backs `MoEPackedParallelPool` with `qmoe::SpinPoolRegistry` (`qmoe_spin_pool.h`) and pins `MoEPackedDoorbellService` to `CpuForWorker(0)`. - The AVX2+FMA+F16C kernels live in `moe_packed_cpu_avx2.cc` (ISA enabled per function; `/arch:AVX2` for that file on MSVC x64) and are dispatched after `qmoe_shared::CpuHasAvx2FmaF16c()`, with a scalar fallback. - Implements pure register-accumulator 2-channel (`GgufDualDot2ChAvx2Tpl<RT>`) and 4-column (`IQ4_NL`/`Q2_0`) AVX2+FMA+F16C kernels covering `IQ2_S`, `IQ2_XXS`, `IQ2_XS`, `IQ3_XXS`, `IQ4_XS`, `IQ4_NL`, `Q2_0`, `Q5_0`, and mixed `gate_type != up_type` layers, cutting `iq3_xxs` CPU cold-expert latency **4.8x** (`245.5 us/exp -> 49.2 us/exp`) and boosting `iq3_xxs` decode throughput **4.1x** (`16.2–20.8 tok/s -> 67.2–81.7 tok/s` lossless, `179.96 tok/s` with tail substitution) and `iq1_s` decode throughput up to **`142.91 tok/s` lossless (`261.65 tok/s` with tail substitution)** on RTX 5090. 3. **`QMoE` INT2 Prefill & AVX-512 Cold-Expert Optimizations + 16 GB / 24 GB / 32 GB WDDM Reserve Calibration** (`qmoe_offload.cc`, `moe_gemv_tc.cuh`, `qmoe_shared_layout_int2_avx512.cc`, `qmoe_session_controller.h`): - Dispatches `MoeGemvTcInt2Kernel` on sorted `expert_map` prefill waves (`+24%` to `+30%` faster `8K`/`32K` prefill on `2b375`, reaching `2,560 tok/s`). - Extends `Int2Group8Avx512` to `RT = 1..4` with factored scale FMA. - Calibrates WDDM post-session reserves across 16 GB, 24 GB, and 32 GB GPUs for both `QMoE` and `MoEPacked` and auto-detects 8-byte vs. 4-byte `STRP` v1 popularity profiles. 4. **Numerical Parity and Run-Control Lifetime for `MoEPacked` Hybrid Decode** (`moe_packed.cc`, `moe_packed.cu`, `moe_packed.h`, `test_gguf_packed_ops.py`): - Keeps the CPU cold-route partial sum in FP32 (`MoEPackedDecodePinned::host_cold_output`), so the hybrid combine rounds to BF16/FP16 once, as the GPU-only finalize does. Rounding the partial sum to the activation type first rounded the output twice. - Mirrors the CUDA FP16 rounding points on the CPU path (gate/up dot products, SwiGLU output, and per-route FC2 output), as the BF16 path already did. - Registers a per-node `QMoEInvocationRecord` with the kernel stream, and with the replay stream through the graph-replay hook, so the controller synchronizes it before `EndRun()` clears the warm-up flag. Previously, with device-resident outputs, 296 of 300 warm-up decode runs in an all-cold session computed the cold experts on the CPU; now none do. - Resolves the CPU pool size once per node instead of calling `std::thread::hardware_concurrency()` (a sysfs read, about 2.6 us on Linux) on every decode `ParallelFor`. --- ### Accuracy & Performance Impact of Tail Expert Substitution (threshold = 0.02, min_rank = 2) on 2b375 (RTX 5090 32 GB) Evaluated on qwen_flash_next_int4_int8_rc5_contrib_dflash2_qmoe_2b375_x02_y14_z32_dp23_b64_unified (xhigh reasoning, greedy decoding): - **MMLU-Pro (400 samples, max_new_tokens = 32,768)**: - **Without TailSub (thr = 0.0)**: 82.75% (331/400, strict 81.75%), median 162.09 tok/s, token-weighted 230.99 tok/s - **With TailSub (thr = 0.02, r = 2)**: **83.25% (333/400, strict 82.25%)** (+0.50 pp, 12W / 10L, McNemar p = 0.8318), median **255.64 tok/s (1.58x faster)**, token-weighted **328.52 tok/s (1.42x faster)** - **LiveCodeBench v6 (175 problems, 256K = 262,144 limit)**: - **Paired 161 / 175 problems on RTX 5090**: **83.85% (135/161)** With TailSub vs. **83.23% (134/161)** Without TailSub (+0.62 pp, 13W / 12L, McNemar p = 1.0000), median **217.27 tok/s (1.54x faster)**, token-weighted **248.82 tok/s (1.65x faster)** - **Full 175 / 175 problems (at 256K)**: **77.14% (135/175, 43/43 = 100% Easy, 42/52 = 80.8% Medium, 50/80 = 62.5% Hard, conditional 88.24% when code is emitted)** vs. 82.86% (145/175) lossless H200 reference. --- ### CPU vs. CUDA Numerical Parity of `MoEPacked` Hybrid Decode (H200) Fraction of output elements that differ from the GPU-only `MoEPacked` output (`session.moe.offload.mode=disabled`), over eight GGUF format mixes that cover every CPU cold-expert kernel family and decode batches of 1, 3, and 16 rows: | Placement | Activation | Before item 4 | After item 4 | |---|---|---|---| | All experts on CPU | FP16 | 54–65% | 0–6% (summation order only) | | Half of the experts resident | FP16 | 50–63% | 0–1.5% | | All experts on CPU | BF16 | 38–77% | Unchanged (see below) | With BF16, the CPU path matches a NumPy emulation that keeps dequantized weights in FP32 bit-for-bit, and the CUDA path matches one that rounds them to BF16 bit-for-bit. The remaining difference comes from the CUDA BF16 MMA kernels rounding GGUF-dequantized weights to BF16. The CPU kernels keep the more precise FP32 weights: emulating the rounding would slow the AVX2 loops, and results would still depend on expert placement because the summation order differs. ### Testing - `python -m pytest onnxruntime/test/python/transformers/test_gguf_packed_ops.py`: 39 passed (857 subtests) on H200 (sm90). The offload tests also pass with `ORT_QMOE_SHARED_CPU_THREADS=1` and `7`. - `test_moe_packed_cuda_offload_cpu_kernels_match_reference` runs every CPU cold-expert kernel family with both activation types against a reference with FP32 dequantized weights. `test_moe_packed_cuda_offload_mixed_placement_matches_gpu` compares FP16 hybrid decode with the GPU-only output, using aligned and offset buffers. Both fail before item 4 and pass now. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>



Description
Adds three
com.microsoftcontrib operators—GatherPacked(CPU and CUDA),MatMulPacked(CUDA), andMoEPacked(CUDA)—that consume 2D and 3D block-packed quantized weight blobs (such as GGUFIQ2_XXS,IQ2_XS,IQ2_S,IQ3_XXS,IQ4_NL,IQ4_XS,Q2_0,Q4_0,Q5_0,Q5_K,Q6_K,Q8_0,F16,BF16,F32) directly in their native block layout without offline weight repacking or separate scale tensors. Direct external initializer buffers (#33877) avoid redundant host-side copies while loading.ggufshards. CUDA execution still copies CPU-backed weights to device memory and requires device storage for the packed weights; it does not execute zero-copy from host-backed shards.Summary of Changes
Contrib Operator Schemas & Registration
onnxruntime/core/graph/contrib_ops/ms_opset.hGatherPacked,MatMulPacked, andMoEPackedincom.microsoftopsetonnxruntime/core/graph/contrib_ops/contrib_defs.ccGatherPacked,MatMulPacked(A, B -> YwithK, N, packed_type), andMoEPackedonnxruntime/contrib_ops/cpu/cpu_contrib_kernels.ccGatherPackedkernelonnxruntime/contrib_ops/cuda/cuda_contrib_kernels.ccGatherPacked,MatMulPacked, andMoEPackedkernelsBlock-Packed Quantization & Kernel Implementations
onnxruntime/contrib_ops/cpu/quantization/gguf_quant_tables.hiq2xxs_grid,iq2xs_grid,iq2s_grid,iq3xxs_grid,iq3s_grid), block geometry helper (GgmlRowBytes), and CPU row dequantizeronnxruntime/contrib_ops/cpu/quantization/gather_packed.ccGatherPackedimplementationonnxruntime/contrib_ops/cuda/quantization/gguf_quant_cuda.cuhDecodeGgufSubBlock8Impl,DecodeGgufSubBlock8SmemLutTpl,DecodeGgufSubBlock16Impl), register-onlyIq2xsSignsDev/Iq4NlValueDevhelpers, and Tensor CoreMmaBf16wrapperonnxruntime/contrib_ops/cuda/quantization/gather_packed.{h,cc,cu}GatherPackedkernelonnxruntime/contrib_ops/cuda/quantization/matmul_packed.{h,cc,cu}MatMulPackedkernel with warp-K-split Tensor Core (mma.sync.aligned.m16n8k16) and warp GEMV paths for decode (M <= 8), bounded tiled dequantization + cuBLAS GEMM for prefill (M > 8), and FP32 decoded weights for FP16 prefill when the packed format is not F16onnxruntime/contrib_ops/cuda/moe/moe_packed.{h,cc,cu}MoEPackedkernel with fused top-k softmax routing, parallel warp-scan tile bucketing (8routes/tile in decode,32routes/tile in prefill), warp-K-split Tensor Core FC1+SwiGLU in decode, 4-subtile Tensor Core FC1/FC2 in prefill, and 128-bit vectorized finalizeonnxruntime/test/python/transformers/test_gguf_packed_ops.pyGatherPacked(CPU vs CUDA bit-exactness across 15 formats),MatMulPacked(M = 1, 7, 8, 32), andMoEPacked(M = 4, 48)Testing
lintrunnerchecks pass.Qwen3.8-Flash-Next-GGUF(UD-IQ1_S,UD-IQ2_XS,UD-IQ3_XXS) on NVIDIA H200:engine_behaviours.py: 27 / 27 PASS across all three quantization variants.DFlash2 S=8): 20.0–20.9 ms/cycle (183–269 tok/s median, up to 359 tok/s peak).max_new=8192): 87.50% (UD-IQ1_S), 85.50% (UD-IQ2_XS), 86.00% (UD-IQ3_XXS).Checklist