Repository navigation
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/24071
Note: Links to docs will display an error until the docs builds have been completed. ❌ 1 New Failure, 2 Unrelated FailuresAs of commit 1dda032 with merge base 9bf80eb ( NEW FAILURE - The following job has failed:
FLAKY - The following job failed but was likely due to flakiness present on trunk:
BROKEN TRUNK - The following job failed but was present on the merge base:👉 Rebase onto the `viable/strict` branch to avoid these failures
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
Contributor
|
@pssrawat has exported this pull request. If you are a Meta employee, you can view the originating Diff in D126708891. |
Summary:
`ValidateCortexMExplicitLayoutPass` requires every NHWC layout copy to move
an int8 tensor, and reads `node.meta["val"].dtype` to decide. In
`explicit_layout_pass_list` that validator runs before `AtenToCortexMPass`,
so at validation time only the activations that `ActivationFusionPass` has
already folded into the convolution clamp -- relu, clamp, hardtanh -- carry
an int8 fake tensor. The LUT activations (tanh, sigmoid, which become
`cortex_m::quantized_activation`) and softmax (which becomes
`cortex_m::softmax`) are still `aten.*` with an fp32 fake tensor, even
though `FoldAndAnnotateQParamsPass` has already attached their int8 qparams.
That fp32 propagates into any convolution fed by one, and the layout copy on
its output trips the assertion.
The explicit-layout path validates rather than falling back, so this is a
hard abort, not a coverage loss -- and explicit layout is the only mode that
supports Conv1d. A two-node graph reproduces it: `Conv1d(relu(x))` lowers,
`Conv1d(tanh(x))` raises
RuntimeError: Cortex-M layout copy channels_last_permute_copy_default
must move an int8 tensor.
out of `_CortexMLoweringPass`. `LutActivationThenConv1d` in
`test_explicit_layout_pipeline.py` is that graph.
Judge the condition the kernels will actually see. `_produces_int8` accepts
an int8 fake tensor as before, and otherwise asks `has_qparams`, which is
what `AtenToCortexMPass` reads before it will rewrite a node at all, plus an
int8 `output_qparams[0]`. Both annotations are in place by the time this
pass runs. Anything looser accepts a node the dialect goes on to decline,
which really does leave a portable fp32 kernel feeding an int8 transpose.
Graphs that were rejected lower unchanged: on a 31-convolution ECAPA-TDNN
speaker model, 0 of 31 convolutions reached a CMSIS-NN kernel before and 31
of 31 do after, with 0.000e+00 max absolute difference against the
quantized eager module.
`has_qparams` moves to `cortex_m/utils.py` to make that sharing possible.
It was private to `aten_to_cortex_m_pass`, and a pass that has to predict a
later one should not be reaching into it for the rule; utils is already
where this backend keeps its node predicates. Its ten existing call sites
change in name only.
The error message now also names the producing node. The layout copy is
synthesized by this pass and appears in no graph the caller holds, so its
own name gives nothing to go on.
Differential Revision: D126708891
pssrawat
force-pushed
the
export-D126708891
branch
from
October 21, 2026 21:04
ed2f8b5 to
1dda032
Compare
rascani
reviewed
Oct 21, 2026
| if not has_qparams(input_node): | ||
| return False | ||
| folded = input_node.meta["output_qparams"].get(0) | ||
| return folded is not None and folded.dtype == torch.int8 |
Contributor
There was a problem hiding this comment.
QuantizedClampActivationPass also checks fake-tensor dtype and skips rewriting clamps after LUT activations. The new validator then accepts those graphs:
sigmoid → ReLU → Conv1dclamps at integer0instead of zero-point−128.tanh → clamp(-0.5, 0.5) → Conv2dserializes float inputs feeding int8-only Cortex-M kernels.
Update the clamp rewrite to handle folded qparams before admitting these graphs, and add activation-chain regression tests.
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.
Summary:
ValidateCortexMExplicitLayoutPassrequires every NHWC layout copy to movean int8 tensor, and reads
node.meta["val"].dtypeto decide. Inexplicit_layout_pass_listthat validator runs beforeAtenToCortexMPass,so at validation time only the activations that
ActivationFusionPasshasalready folded into the convolution clamp -- relu, clamp, hardtanh -- carry
an int8 fake tensor. The LUT activations (tanh, sigmoid, which become
cortex_m::quantized_activation) and softmax (which becomescortex_m::softmax) are stillaten.*with an fp32 fake tensor, eventhough
FoldAndAnnotateQParamsPasshas already attached their int8 qparams.That fp32 propagates into any convolution fed by one, and the layout copy on
its output trips the assertion.
The explicit-layout path validates rather than falling back, so this is a
hard abort, not a coverage loss -- and explicit layout is the only mode that
supports Conv1d. A two-node graph reproduces it:
Conv1d(relu(x))lowers,Conv1d(tanh(x))raisesout of
_CortexMLoweringPass.LutActivationThenConv1dintest_explicit_layout_pipeline.pyis that graph.Judge the condition the kernels will actually see.
_produces_int8acceptsan int8 fake tensor as before, and otherwise asks
has_qparams, which iswhat
AtenToCortexMPassreads before it will rewrite a node at all, plus anint8
output_qparams[0]. Both annotations are in place by the time thispass runs. Anything looser accepts a node the dialect goes on to decline,
which really does leave a portable fp32 kernel feeding an int8 transpose.
Graphs that were rejected lower unchanged: on a 31-convolution ECAPA-TDNN
speaker model, 0 of 31 convolutions reached a CMSIS-NN kernel before and 31
of 31 do after, with 0.000e+00 max absolute difference against the
quantized eager module.
has_qparamsmoves tocortex_m/utils.pyto make that sharing possible.It was private to
aten_to_cortex_m_pass, and a pass that has to predict alater one should not be reaching into it for the rule; utils is already
where this backend keeps its node predicates. Its ten existing call sites
change in name only.
The error message now also names the producing node. The layout copy is
synthesized by this pass and appears in no graph the caller holds, so its
own name gives nothing to go on.
Differential Revision: D126708891