Skip to content

Qualcomm AI Engine Direct - HF LLM Performance and Accuracy Improvement - #21487

Draft
winskuo-quic wants to merge 7 commits into
pytorch:mainfrom
CodeLinaro:dev1/winskuo/hf_llm_output_optimization
Draft

Qualcomm AI Engine Direct - HF LLM Performance and Accuracy Improvement#21487
winskuo-quic wants to merge 7 commits into
pytorch:mainfrom
CodeLinaro:dev1/winskuo/hf_llm_output_optimization

Conversation

@winskuo-quic

Copy link
Copy Markdown
Collaborator

Summary

python examples/qualcomm/oss_scripts/hf_causal_lm.py --prompt "Simply put, the theory of relativity states that" --soc_model SM8750 --device $DEVICE_ID --build_folder build-android/ --decoder_model llama3_2-1b --max_seq_len 128 --ptq 16a8w

Test plan

[PLEASE REMOVE] How did you test this PR? Please write down any manual commands you used and note down tests that you have written if applicable.

winskuo-quic and others added 7 commits July 23, 2026 16:33
Align the HF decoder wrapper's token input dtype with static_llama (int32
instead of int64) for both the exported graph signature and the calibration
loop. The shared qnn_llama_runner auto-detects the token dtype and narrows
accordingly, so no runner change is needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
annotate_kv_8bit_hf tags the KV-cache concat and its graph IO 8-bit for the HF
decoder flow, matching static_llama's annotate_kv_8bit. The HF wrapper keeps K
stored non-transposed with boundary transposes in forward(), so the walk also
traverses the past-KV branch backward (to the K/V placeholder) and the new-KV
branch forward (to the K/V graph output) through the pass-through transposes, so
both the input and output boundaries are tagged 8-bit. Wire it into pt2e_quantize
and set kv_type=uint8 for the 16a*w configs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
HF computes RoPE inside the traced graph, so the inv_freq math becomes a
quantization target. For rope_type=llama3 (llama3.2) inv_freq spans about seven
orders of magnitude, and a single per-tensor scale cannot represent it: the
low-frequency components that carry long-range position information collapse and
the model degenerates into repetitive output under 16a8w. qwen2.5 escapes this
only because its default RoPE range is roughly sixteen times tighter.

Constant folding cannot help here because the cos/sin computation depends on
position_ids, a runtime input. Instead, precompute the tables over the whole
position domain [0, max_seq_len) on the host, the way static_llama does, and
leave the graph with a gather. The tables are built by calling the original
rotary embedding module so any rope_type, scaling and attention_scaling are
honored exactly; cos/sin match the original bit-exactly. Only values bounded in
[-1, 1] then enter the quantized graph.

Removing the per-token inv_freq matmul, cos, sin and their quant/dequant nodes
also cuts real work: llama3_2-1b at 16a8w, CL=128 goes from 35.1/31.4 to
49.6/45.9 tokens per second for prefill/decode, and the output is coherent again.
fp16 stays coherent.

Also align the attention mask fill value with static_llama's PADDING_MASK_VALUE.
MHA-to-SHA is left disabled; it still produces a graph HTP rejects.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pytorch-bot

pytorch-bot Bot commented Jul 30, 2026

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/21487

Note: Links to docs will display an error until the docs builds have been completed.

❌ 2 New Failures

As of commit 6b07734 with merge base 39f4355 (image):

NEW FAILURES - The following jobs have failed:

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 30, 2026
@github-actions

Copy link
Copy Markdown

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

logging.warning("No rotary_emb found; skipping RoPE precompute.")
return
# HF API does not have a way to replace, so manually replace it.
decoder.rotary_emb = QnnPrecomputedRotaryEmbedding(

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rope manual override.

return self.max_cache_len, 0


class QnnCustomStaticCache(Cache):

@winskuo-quic winskuo-quic Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QNN Custom Cache

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

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant