Skip to content

Commit 11719ae

Browse files
Add QNN (Qualcomm Hexagon HTP) execution-provider profile
Registers an EpCapabilities entry for the "qnn" execution provider so the ORT-GenAI builder can target the Qualcomm Hexagon NPU (HTP backend, via the onnxruntime-qnn QAIRT plugin), and maps "qnn" -> "QNN" in the ORT-GenAI provider-name table. 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 profile forces decomposition to the standard ONNX primitives the QNN op builders can lower: no fused RoPE, no Skip[Simplified]LayerNorm, no PackedMHA, and no GroupQueryAttention (empty gqa_dtypes) -- the gemma4 multimodal decoder forgoes GQA anyway (bidirectional-vision overlay). past_present_share_buffer is disabled since standard-Attention KV concat cannot alias a shared buffer; fixed prefill-bucket / fixed-max-KV static shaping is applied as a separate downstream pass before context-binary generation. Validated by building gemma-4-12B (gemma4_unified) with execution_provider="qnn": the graph emits pure ai.onnx (zero com.microsoft contrib ops).
1 parent c4d460f commit 11719ae

2 files changed

Lines changed: 44 additions & 0 deletions

File tree

src/mobius/_execution_providers.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,47 @@ def _register_builtins() -> None:
267267
enable_graph_capture=True,
268268
supports_past_present_share_buffer=True,
269269
),
270+
# Qualcomm Hexagon NPU via the QNN execution provider (the
271+
# onnxruntime-qnn QAIRT plugin EP), targeting the HTP backend. The HTP
272+
# runs a STATICALLY-shaped, QDQ-quantized graph compiled into a QNN
273+
# context binary, and has no kernels for ORT contrib fused ops — so we
274+
# decompose everything down to standard ONNX primitives the QNN op
275+
# builders / HTP can lower:
276+
# supports_fused_rope=False -> SeparateRoPE + UnpackQKV
277+
# (no com.microsoft RotaryEmbedding
278+
# fused into attention).
279+
# supports_skip_layer_norm=False -> InlinePass expands Skip[Simplified]
280+
# LayerNormalization to standard ops.
281+
# supports_packed_multi_head_attention=False -> InlinePass expands
282+
# PackedMultiHeadAttention.
283+
# gqa_dtypes=frozenset() -> no GroupQueryAttention op: QNN has
284+
# no GQA builder, and the gemma4
285+
# multimodal decoder forgoes GQA
286+
# anyway (bidirectional-vision
287+
# overlay). Standard Attention is
288+
# emitted and static-shaped downstream.
289+
# KV cache therefore uses standard-Attention concat semantics (share-buffer
290+
# aliasing requires GQA), so supports_past_present_share_buffer=False; the
291+
# fixed prefill-bucket / fixed-max KV shaping is applied as a separate
292+
# static-shape pass before QNN context-binary generation.
293+
# provider_options are the onnxruntime-qnn HTP launch defaults; soc_model
294+
# and the EP-context binary path are device-specific and are set at
295+
# build/validation time on the Snapdragon target.
296+
EpCapabilities(
297+
name="qnn",
298+
gqa_dtypes=frozenset(),
299+
qkv_pack_dtypes=frozenset(),
300+
supports_fused_rope=False,
301+
supports_skip_layer_norm=False,
302+
supports_packed_multi_head_attention=False,
303+
provider_options={
304+
"backend_path": "QnnHtp.dll",
305+
"htp_performance_mode": "burst",
306+
"htp_graph_finalization_optimization_mode": "3",
307+
"enable_htp_shared_memory_allocator": "1",
308+
},
309+
supports_past_present_share_buffer=False,
310+
),
270311
# onnx-standard: ONNX-only runtime — emits zero custom-domain ops.
271312
# All com.microsoft ops (SkipLayerNorm, PackedMHA) are expanded via
272313
# InlinePass to their standard-ONNX function bodies. No GQA or QKV

src/mobius/integrations/ort_genai/ep_config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
"dml": "dml",
2727
"webgpu": "webgpu",
2828
"trt-rtx": "NvTensorRtRtx",
29+
# ORT-GenAI normalizes "qnn" -> "QNN" (config.cpp NormalizeProviderName) and
30+
# dispatches it to QNNExecutionProvider::AppendExecutionProvider.
31+
"qnn": "QNN",
2932
}
3033

3134

0 commit comments

Comments
 (0)