Repository navigation
Add fuse_attention pass for torch.onnx SDPA graphs - #321
Open
take-cheeze wants to merge 4 commits into
Open
take-cheeze wants to merge 4 commits into
take-cheeze wants to merge 4 commits into
Conversation
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Incomplete shape and scale validation can produce invalid models or silently change outputs.
3 open issues
What changed in this PR
Adds an optimizer pass that replaces TorchScript-exported scaled dot-product attention subgraphs with ONNX Attention.
Changes:
- Recognizes explicit/default scales and optional masks, gated on opset 23+.
- Registers
fuse_attentionand adds synthetic-graph and optional PyTorch export tests.
| File | Description |
|---|---|
| onnxoptimizer/test/optimizer_test.py | Tests fusion patterns and unsupported cases. |
| onnxoptimizer/passes/fuse_attention.h | Implements attention pattern matching and replacement. |
| onnxoptimizer/pass_registry.h | Registers the new pass. |
Review effort: Balanced
take-cheeze
force-pushed
the
claude/fuse-attention-torch-onnx-viw15m
branch
2 times, most recently
from
October 18, 2026 20:43
defb8fc to
355b76b
Compare
Fuse the sub-graph that `torch.onnx.export` (the TorchScript exporter) emits for `scaled_dot_product_attention` into a single ONNX `Attention` operator (opset 23+). The exported pattern scales Q and the transposed K by `sqrt(scale)`, multiplies them, optionally adds an attention mask, applies Softmax over the last axis and multiplies by V. Anchored on the final `MatMul(Softmax(...), V)`, the pass recognizes this shape and rewrites it to `Attention(Q, K, V[, attn_mask])`: - explicit `scale=` (constant sqrt(scale) factors) -> `scale` attribute set to the product of the two factors - default scale (the `1/sqrt(head_size)` sub-graph torch derives from `Shape(Q)`) -> `scale` left implicit, matching Attention's default - additive / causal masks -> fed through as `attn_mask` Guarded on opset >= 23 (where `Attention` exists) so lower-opset models are left untouched. Tests cover hand-built graphs mirroring the exporter output plus graphs produced by the real torch.onnx exporter. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CHJoCKJ1p5YFm2ZMwdwaWV Signed-off-by: take-cheeze <takechi101010@gmail.com>
Only fuse graphs that the Attention op can represent: - Q, K and V must be rank 4 with static, matching batch and head dims. - The default scale must come from a Shape covering all of Q and a Slice that selects only the last dimension (start -1, end >= 4, axis 0/-1, step 1). Previously a Shape end or an unchecked Slice end/step could pick a different dimension and silently change the scale. - An explicit scale must be a scalar, so a higher-rank constant cannot promote Q or K^T and change the output rank. Add negative tests for the shape-selection, scale-rank and batch mismatch cases. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VPahbkPmWYWChRCBQX7osk Signed-off-by: take-cheeze <takechi101010@gmail.com>
Fixes the ruff RUF015 lint failure reported by CI. Signed-off-by: take-cheeze <takechi101010@gmail.com>
The explicit-scale Mul constants come from Constant nodes, which carry no sizes on their output value, so the scalar check rejected every explicit scale. Read the rank from the constant tensor instead. The test also trusted torch's ONNX_MAX_OPSET, but on CI the exporter falls back to opset 20 with a warning. Skip when the exported model is not opset 23, and drop the unused import. Signed-off-by: take-cheeze <takechi101010@gmail.com>
take-cheeze
force-pushed
the
claude/fuse-attention-torch-onnx-viw15m
branch
from
October 18, 2026 21:57
355b76b to
b3d82a3
Compare
justinchuby
approved these changes
Oct 20, 2026
Comment on lines
+95
to
+96
| float numerator; | ||
| if (!FetchSoleValueOfTensor(n->input(0), numerator) || numerator != 1.0f) { |
Comment on lines
+302
to
+303
| if (attn_mask != nullptr) { | ||
| attention->addInput(attn_mask); |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Fuse the sub-graph that
torch.onnx.export(the TorchScript exporter) emits forscaled_dot_product_attentioninto a single ONNXAttentionoperator (opset 23+).The exported pattern scales Q and the transposed K by
sqrt(scale), multiplies them, optionally adds an attention mask, applies Softmax over the last axis and multiplies by V. Anchored on the finalMatMul(Softmax(...), V), the pass recognizes this shape and rewrites it toAttention(Q, K, V[, attn_mask]):scale=(constant sqrt(scale) factors) ->scaleattribute set to the product of the two factors1/sqrt(head_size)sub-graph torch derives fromShape(Q)) ->scaleleft implicit, matching Attention's defaultattn_maskGuarded on opset >= 23 (where
Attentionexists) so lower-opset models are left untouched. Tests cover hand-built graphs mirroring the exporter output plus graphs produced by the real torch.onnx exporter.Claude-Session: https://claude.ai/code/session_01CHJoCKJ1p5YFm2ZMwdwaWV