Skip to content

Commit bab4068

Browse files
Add QNN (Qualcomm Hexagon HTP) execution-provider profile (#370)
## What Registers a `qnn` execution-provider profile so the ORT-GenAI builder can target the Qualcomm Hexagon NPU (HTP backend, via the onnxruntime-qnn QAIRT plugin): - `_execution_providers.py`: new `EpCapabilities(name="qnn", ...)`. - `integrations/ort_genai/ep_config.py`: map `qnn` → `QNN` for ORT-GenAI provider dispatch. ## Why Bringing up gemma-4-12B (`gemma4_unified`) on Qualcomm Copilot+ devices (Snapdragon X Elite / X2 Elite). The HTP runs a statically-shaped, QDQ-quantized graph compiled to a QNN context binary and has no kernels for ORT contrib fused ops, so the build must emit standard ONNX primitives the QNN op builders can lower. ## How The profile **reuses the existing rewrite infrastructure** rather than adding new passes: - `supports_fused_rope=False` → `SeparateRoPE` / `UnpackQKV` - `supports_skip_layer_norm=False` → skip-norm inlined to standard ops - `supports_packed_multi_head_attention=False` → PackedMHA expanded - `gqa_dtypes=frozenset()` → no GroupQueryAttention (the gemma-4 multimodal decoder forgoes GQA anyway — bidirectional-vision overlay); standard Attention is emitted and static-shaped downstream - `supports_past_present_share_buffer=False` (standard-Attention KV concat can't alias a shared buffer) - `provider_options` = onnxruntime-qnn HTP launch defaults; `soc_model` + EP-context binary path are device-specific, set at build/validation time. ## Validation Building gemma-4-12B with `execution_provider="qnn"` emits pure ai.onnx (zero `com.microsoft` contrib ops). ## Not in this PR (for discussion) The HTP-specific lowering we currently do downstream — 4D q/k-norm RMSNorm reshape, RoPE→`com.microsoft::RotaryEmbedding` op-swap, fold-shapes / drop-identity / decoder-split / mask-hoist — is a candidate follow-up PR. Some of it is QNN context-binary **deployment** rather than model build; happy to bring the in-scope pieces in-tree as `rewrite_rules`/`_passes` + tests if the team wants them here. Heads-up: this sets GQA **off** for `qnn`; flagging against `justinchu/gemma4-12b-text-gqa` in case the attention path needs to reconcile. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent c4d460f commit bab4068

2 files changed

Lines changed: 23 additions & 0 deletions

File tree

src/mobius/_execution_providers.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,28 @@ def _register_builtins() -> None:
267267
enable_graph_capture=True,
268268
supports_past_present_share_buffer=True,
269269
),
270+
# Qualcomm Hexagon NPU via the QNN EP (onnxruntime-qnn QAIRT plugin),
271+
# HTP backend. The HTP runs a static-shaped, QDQ-quantized QNN context
272+
# binary with no kernels for ORT contrib fused ops, so everything is
273+
# decomposed to standard ONNX. The gemma4 multimodal decoder forgoes GQA
274+
# (bidirectional-vision overlay), so standard Attention is emitted and
275+
# static-shaped downstream. provider_options are the HTP launch defaults;
276+
# soc_model and the EP-context binary path are set per-device at build time.
277+
EpCapabilities(
278+
name="qnn",
279+
gqa_dtypes=frozenset(), # no GroupQueryAttention (no QNN GQA builder)
280+
qkv_pack_dtypes=frozenset(), # no PackQKV
281+
supports_fused_rope=False, # SeparateRoPE + UnpackQKV
282+
supports_skip_layer_norm=False, # inline Skip[Simplified]LayerNorm
283+
supports_packed_multi_head_attention=False, # inline PackedMHA
284+
provider_options={
285+
"backend_path": "QnnHtp.dll",
286+
"htp_performance_mode": "burst",
287+
"htp_graph_finalization_optimization_mode": "3",
288+
"enable_htp_shared_memory_allocator": "1",
289+
},
290+
supports_past_present_share_buffer=False, # standard-Attention KV concat
291+
),
270292
# onnx-standard: ONNX-only runtime — emits zero custom-domain ops.
271293
# All com.microsoft ops (SkipLayerNorm, PackedMHA) are expanded via
272294
# InlinePass to their standard-ONNX function bodies. No GQA or QKV

src/mobius/integrations/ort_genai/ep_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"dml": "dml",
2727
"webgpu": "webgpu",
2828
"trt-rtx": "NvTensorRtRtx",
29+
"qnn": "QNN",
2930
}
3031

3132

0 commit comments

Comments
 (0)