Only rewrite addmm/mm to linear when the weight is a constant - #22402
Open
msluszniak wants to merge 1 commit into
Open
Only rewrite addmm/mm to linear when the weight is a constant#22402msluszniak wants to merge 1 commit into
msluszniak wants to merge 1 commit into
Conversation
`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.
🔗 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.
|
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.
This PR needs a
|
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.
Summary
replace_addmm_mm_with_linearrewritesmm(x, transpose(w))intolinear(x, w)whenever the second operand is fed through a transpose. It never checks wherewcomes from, so a matmul against a tensor computed at runtime becomes a linear too.That rewrite is not sound.
mm/addmmplace 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: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
mmsecond operand ispermute_copy(squeeze_copy(...)), a 64x64 style-conditioned matrix produced during execution. Two otheraddmmnodes 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 tolinear, a computedmmoperand staysmm, a computedaddmmoperand staysaddmm, 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:
Confirmed the guard is what changes the outcome: on the unpatched pass the same graph yields
linear=1, mm=0; patched it yieldslinear=0, mm=1.