Skip to content

Add dense Qwen PagedAttention export for ORT GenAI - #753

Open
titaiwangms wants to merge 3 commits into
mainfrom
feat/qwen-dense-paged-attention
Open

titaiwangms wants to merge 3 commits into
mainfrom
feat/qwen-dense-paged-attention

Conversation

@titaiwangms

@titaiwangms titaiwangms commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Opt in the existing --features paged-attention flow for text-only dense Qwen2, Qwen2.5, and Qwen3 models.
  • Export separate K/V-packed-token PagedAttention for ORT GenAI CUDA Engine dynamic batching.
  • Preserve the dense MLA path and reject unsupported graph, configuration, and execution-provider combinations. Native onnx-genai rejects packed page graphs before saving model artifacts; model-specific eligibility lives in the task rather than the reusable component.

Validation

183 related non-integration tests passed. All 18 synthetic CUDA tests passed on A100, comparing full logits and K/V caches against dynamic GQA for Qwen2 and Qwen3 at head dimensions 16, 64, and 128, including decode and a 256-token page crossing. Ruff check/format and git diff --check passed.

The broader non-integration suite had 10,596 passed, 69 skipped, and 2 failures: one test requires missing onnxruntime-genai distribution metadata, while a GGUF shard-identity test did not raise its expected error (also reproduced in isolation). Neither GGUF test implementation nor its source was changed here; this run is not claimed green.

Targeted real-checkpoint standard non-paged Qwen2.5/Qwen3 validation passed: L4 run 36941440582 (2 passed) and L5 run 36941440653 (2 passed, 2 non-applicable skips), both at earlier head f7b8088.

Limits/waivers

Dense paged BF16 is deliberately disabled due to independent BF16 parity evidence. No real-checkpoint paged or ORT GenAI Engine full-generation validation has been completed. Qwen3.8 hybrid is out of scope.

The required aggregate L4/L5 checks in PR run 36932993026 were cancelled after approximately 60 minutes with broad run_all=true because of shared infrastructure edits. Identical Bamba/Bloom/Arcee failures and cancellation were present on the exact base main commit c2fde938 in scheduled L4 run 36813810487 and L5 run 36817813688. The aggregate checks are not claimed green, and required checks were not changed or removed.

Add an opt-in dense PagedAttention export for Qwen2, Qwen2.5, and Qwen3 using the separate K/V packed ABI. Integrate CUDA Engine scheduling while preserving the existing MLA path and its validations.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: titaiwang <titaiwang@microsoft.com>
@titaiwangms
titaiwangms requested review from a team and a balanced review from Copilot October 1, 2026 21:18
@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Performance Comparison

Comparing c2fde938 → c61a06b3

Model Metric Baseline Current Delta
bert (feature-extraction) model_size_bytes 359 KB 359 KB +0.0% ⚪
bert (feature-extraction) num_nodes 68 68 +0.0% ⚪
falcon model_size_bytes 364 KB 364 KB +0.0% ⚪
falcon num_nodes 66 66 +0.0% ⚪
gemma2 model_size_bytes 428 KB 428 KB +0.0% ⚪
gemma2 num_nodes 105 105 +0.0% ⚪
gpt2 model_size_bytes 324 KB 324 KB +0.0% ⚪
gpt2 num_nodes 54 54 +0.0% ⚪
llama model_size_bytes 425 KB 425 KB +0.0% ⚪
llama num_nodes 60 60 +0.0% ⚪
llama (static-cache) model_size_bytes 425 KB 425 KB +0.0% ⚪
llama (static-cache) num_nodes 56 56 +0.0% ⚪
mamba (ssm-text-generation) model_size_bytes 296 KB 296 KB +0.0% ⚪
mamba (ssm-text-generation) num_nodes 94 94 +0.0% ⚪
phi3 model_size_bytes 421 KB 421 KB +0.0% ⚪
phi3 num_nodes 58 58 +0.0% ⚪
phi3 (static-cache) model_size_bytes 421 KB 421 KB +0.0% ⚪
phi3 (static-cache) num_nodes 54 54 +0.0% ⚪
qwen2 model_size_bytes 425 KB 425 KB +0.0% ⚪
qwen2 num_nodes 60 60 +0.0% ⚪
qwen2 (static-cache) model_size_bytes 425 KB 425 KB +0.0% ⚪
qwen2 (static-cache) num_nodes 56 56 +0.0% ⚪
qwen3_5_moe (hybrid-text-generation) model_size_bytes 506 KB 506 KB +0.0% ⚪
qwen3_5_moe (hybrid-text-generation) num_nodes 265 265 +0.0% ⚪
qwen3_5_text (hybrid-text-generation) model_size_bytes 458 KB 458 KB +0.0% ⚪
qwen3_5_text (hybrid-text-generation) num_nodes 127 127 +0.0% ⚪
qwen3_5_vl (hybrid-qwen-vl) model_size_bytes 977 KB 977 KB +0.0% ⚪
qwen3_5_vl (hybrid-qwen-vl) num_nodes 450 450 +0.0% ⚪
t5 (seq2seq) model_size_bytes 836 KB 836 KB +0.0% ⚪
t5 (seq2seq) num_nodes 176 176 +0.0% ⚪
whisper (speech-to-text) model_size_bytes 1008 KB 1008 KB +0.0% ⚪
whisper (speech-to-text) num_nodes 128 128 +0.0% ⚪

No performance regressions.

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

BF16 remains enabled despite an acknowledged numerical mismatch and lacks runtime parity coverage.

Review effort: Balanced
Findings: 1 High severity

Open (1)
What changed in this PR

Adds packed, separate-K/V PagedAttention export for dense text-only Qwen models targeting ORT GenAI dynamic batching.

Changes:

  • Adds packed-token PagedAttention graph construction and validation.
  • Generates ORT GenAI Engine metadata and rejects incompatible workflows.
  • Adds graph, configuration, CUDA parity, and boundary-crossing tests.
File Description
src/​mobius/​tasks/​_causal_lm.py Builds the dense paged decoder ABI.
src/​mobius/​models/​paged_qwen_export_test.py Tests graph contracts, validation, and CUDA parity.
src/​mobius/​models/​base.py Routes dense paged state through the text model.
src/​mobius/​integrations/​transformers/​_builder.py Selects the paged-cache task for eligible Qwen models.
src/​mobius/​integrations/​transformers/​_builder_test.py Tests automatic task selection.
src/​mobius/​integrations/​ort_genai/​genai_config.py Emits dynamic-batching Engine configuration.
src/​mobius/​integrations/​ort_genai/​auto_export.py Validates graph/config compatibility before export.
src/​mobius/​integrations/​onnx_genai/​auto_export.py Rejects the packed ABI for native onnx-genai.
src/​mobius/​components/​_paged_attention.py Implements dense PagedAttention state and operator wiring.
src/​mobius/​components/​_attention.py Dispatches attention through the paged implementation.
src/​mobius/​_configs/​_base.py Documents expanded paged-attention semantics.
src/​mobius/​_builder.py Rejects incompatible cache and pruning options.
src/​mobius/​__main__.py Adds CLI preflight validation.
docs/​cli_reference.md Documents usage, ABI, and limitations.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/mobius/components/_paged_attention.py Outdated
@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

🏗️ Architecture Diff

Comparing c2fde938 → c61a06b3

Model Sub-model Changes Status
bert (feature-extraction) model 0 ⚪
falcon model 0 ⚪
gemma2 model 0 ⚪
gemma4 (gemma4) decoder 0 ⚪
gemma4 (gemma4) embedding 0 ⚪
gemma4 (gemma4) vision_encoder 0 ⚪
gemma4_text model 0 ⚪
gpt2 model 0 ⚪
llama model 0 ⚪
llama (static-cache) model 0 ⚪
mamba (ssm-text-generation) model 0 ⚪
phi3 model 0 ⚪
phi3 (static-cache) model 0 ⚪
qwen model 0 ⚪
qwen (static-cache) model 0 ⚪
qwen2 model 0 ⚪
qwen2 (static-cache) model 0 ⚪
qwen2_moe model 0 ⚪
qwen2_moe (static-cache) model 0 ⚪
qwen3 model 0 ⚪
qwen3 (static-cache) model 0 ⚪
qwen3_5_moe (hybrid-text-generation) model 0 ⚪
qwen3_5_text (hybrid-text-generation) model 0 ⚪
qwen3_5_vl (hybrid-qwen-vl) decoder 0 ⚪
qwen3_5_vl (hybrid-qwen-vl) embedding 0 ⚪
qwen3_5_vl (hybrid-qwen-vl) vision_encoder 0 ⚪
qwen3_moe model 0 ⚪
qwen3_moe (static-cache) model 0 ⚪
qwen3_next (hybrid-text-generation) model 0 ⚪
t5 (seq2seq) decoder 0 ⚪
t5 (seq2seq) encoder 0 ⚪
whisper (speech-to-text) decoder 0 ⚪
whisper (speech-to-text) encoder 0 ⚪

No architecture changes detected. ✅


Legend: ⚪ No change · 🔵 Minor (attrs/inits) · 🟡 Moderate (nodes added/removed) · 🔴 Major (interface changed)

Dense Qwen paged exports showed A100 h64/h128 full-logit discrepancies versus dynamic GQA and an independent CPU FP32 reference. Gate BF16 through the builder/task/direct GenAI config while preserving MLA BF16 support.

Signed-off-by: titaiwang <titaiwang@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI 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.

Copilot review overview

🔵 Needs a closer look

Native export can leave partial artifacts, component policy violates layering conventions, and CUDA parity lacks representative Qwen head dimensions.

Review effort: Balanced
Findings: None

Resolved since last review (1)
Previously missed (3)

In code that hasn't changed since last review

Medium severity Preflight native runtime compatibility before saving outputs

src/​mobius/​__main__.py:556

Only the ORT GenAI runtime is preflighted before pkg.save(). With --runtime onnx-genai --features paged-attention, the new native-writer check raises later at write_onnx_genai_config, after the ONNX model and weights have already been written, leaving a partial output directory without runtime metadata. Run the packed-page incompatibility preflight here for the native runtime as well, before saving.

Medium severity Add FP16 head_dim 64/128 CUDA parity coverage

src/​mobius/​models/​paged_qwen_export_test.py:459

Both CUDA parity suites instantiate the default head_dim=16, but the feature accepts every multiple of 16 and the targeted Qwen checkpoints use representative 64/128-wide heads. PagedAttention dispatch and page-tile behavior change at those widths, so these tests can pass on a non-production kernel path while the advertised Qwen export fails or diverges. Add at least FP16 head_dim 64 and 128 prefill-plus-decode parity coverage (including the page-boundary case) before enabling the full range.

Low severity Move Qwen dispatch policy out of the reusable component

src/​mobius/​components/​_paged_attention.py:17

This puts model-family dispatch policy inside the reusable component layer: the new component is now the only component that branches on config.model_type, whereas the analogous MLA component determines eligibility from operator geometry (_paged_mla.py:152-170). Move the Qwen allowlist and Qwen-specific eligibility checks to the model/task or integration policy layer, leaving this component responsible only for the generic SEPARATE PagedAttention contract.

Reject unsupported native runtime exports before saving models, keep Qwen eligibility in the task layer, and exercise representative FP16 head widths across CUDA prefill, decode, and page boundaries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: titaiwang <titaiwang@microsoft.com>

Copilot AI 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.

Copilot review overview

🔵 Needs a closer look

Real-checkpoint paged Engine generation remains unvalidated, and the aggregate required checks were cancelled.

Review effort: Balanced
Findings: None

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants