Skip to content

Only rewrite addmm/mm to linear when the weight is a constant - #22402

Open
msluszniak wants to merge 1 commit into
pytorch:mainfrom
msluszniak:ms/addmm-to-linear-constant-weight
Open

Only rewrite addmm/mm to linear when the weight is a constant#22402
msluszniak wants to merge 1 commit into
pytorch:mainfrom
msluszniak:ms/addmm-to-linear-constant-weight

Conversation

@msluszniak

Copy link
Copy Markdown
Contributor

Summary

replace_addmm_mm_with_linear rewrites mm(x, transpose(w)) into linear(x, w) whenever the second operand is fed through a transpose. It never checks where w comes from, so a matmul against a tensor computed at runtime becomes a linear too.

That rewrite is not sound. mm/addmm place no constraint on their second operand, but backends prepack a linear's weight while building their delegate graph, which is only possible for a constant. The Vulkan runtime aborts when it gets anything else:

Exception raised from toTensorRef at
backends/vulkan/runtime/graph/containers/Value.h:266:
(isTensorRef()) is false! Expected value to have type TensorRef, got TENSOR instead.

reached through linear_packed_weight -> prepack_fp_linear_weight -> PrepackNode, at delegate build time. The model fails to load, and the message names neither the op nor the operand, so there is nothing to work back from.

This shows up in any model that multiplies an activation by a runtime-derived matrix. It was found in a TTS duration predictor whose mm second operand is permute_copy(squeeze_copy(...)), a 64x64 style-conditioned matrix produced during execution. Two other addmm nodes in the same graph have real parameter weights and rewrite correctly; only the computed one is affected.

Fix

Guard both rewrites on the operand actually being a parameter, buffer or lifted constant, and thread the owning program through so that check can be made. Callers that pass no program keep the previous behaviour for placeholders and only lose the rewrite for runtime-computed operands, which is the case that was broken anyway.

The pass is used by the Vulkan and Samsung ENN backends.

Test plan

New backends/transforms/test/test_addmm_mm_to_linear.py, four cases: a constant weight still rewrites to linear, a computed mm operand stays mm, a computed addmm operand stays addmm, and a user-input weight is left alone.

Verified against the reported model on a Galaxy S26 Ultra (Adreno 840). Before, the delegate aborts at build time. After, it loads and runs, and all four sub-models of that TTS pipeline match their CPU references:

sub-model cosine vs CPU
duration_predictor 1.000000 (was: abort)
text_encoder 0.999414
vector_estimator 0.999994
vocoder 0.999977

Confirmed the guard is what changes the outcome: on the unpatched pass the same graph yields linear=1, mm=0; patched it yields linear=0, mm=1.

`replace_addmm_mm_with_linear` turns `mm(x, transpose(w))` into
`linear(x, w)` whenever the second operand is fed through a transpose. It
never checks where `w` comes from, so a matmul against a tensor computed at
runtime is rewritten into a linear too.

That rewrite is not sound. `mm`/`addmm` place no constraint on their second
operand, but backends prepack a linear's weight while building their delegate
graph, which is only possible for a constant. The Vulkan runtime aborts when
it gets anything else:

  Exception raised from toTensorRef at
  backends/vulkan/runtime/graph/containers/Value.h:266:
  (isTensorRef()) is false! Expected value to have type TensorRef,
  got TENSOR instead.

reached through linear_packed_weight -> prepack_fp_linear_weight ->
PrepackNode, at delegate build time. A model that multiplies an activation by
a runtime-derived matrix fails to load with no indication of which op is
responsible.

Guard both rewrites on the operand actually being a parameter, buffer or
lifted constant, and thread the owning program through so that check can be
made. Callers that pass no program keep the previous behaviour for
placeholders and only lose the rewrite for runtime-computed operands, which is
the case that was broken anyway.

The pass is used by the Vulkan and Samsung ENN backends.
@pytorch-bot

pytorch-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

🔗 Helpful Links

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

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

⚠️ 14 Awaiting Approval

As of commit 835b2b3 with merge base 5428092 (image):

AWAITING APPROVAL - The following workflows need approval before CI can run:

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 Sep 1, 2026
msluszniak added a commit to software-mansion-labs/executorch that referenced this pull request Sep 1, 2026
Backport of pytorch/executorch#22402.

replace_addmm_mm_with_linear rewrote mm(x, transpose(w)) into linear(x, w)
without checking that w is a constant, so a matmul against a runtime-computed
matrix became a linear whose weight the Vulkan runtime then tried to prepack
at delegate build time:

  (isTensorRef()) is false! Expected value to have type TensorRef,
  got TENSOR instead.

Guard both rewrites on the operand being a parameter, buffer or lifted
constant.
@github-actions

github-actions Bot commented Sep 1, 2026

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.

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.

2 participants