Uh oh!
There was an error while loading. Please reload this page.
Arm backend: Make composable_quantizer default - #19758
Conversation
A few fixes needed: - Add new ops added since initial upstream of composable_quantizer - Add while-op quantize fix from 3be4546 to TosaQuantizerV2 - Add fixed_qparams fix from fb90480 to TosaQuantizerV2 - Update some tests to mirror new behaviours - Update quanitzer_tutorial to not be WIP - Remove hardswish from FUSED_ACTIVATION_OPS - Explicitly check that weights and biases are input args to conv/ linear ops. The assumption that wights and biases are the only parameters of networks does not hold for real models. Signed-off-by: Adrian Lundell <adrian.lundell@arm.com> Change-Id: Ifa127a73d4db45cd2d3461101f97c0cf852bf7bf
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/19758
Note: Links to docs will display an error until the docs builds have been completed. ✅ No FailuresAs of commit 130f60b with merge base e182e8b ( This comment was automatically generated by Dr. CI and updates every 15 minutes. |
There was a problem hiding this comment.
Pull request overview
This PR switches the Arm backend’s TOSAQuantizer to use the composable quantizer implementation by default, and updates Arm quantization annotation/support logic plus tests/tutorial materials to match the new behaviors (including while-loop and fixed-qparams handling).
Changes:
- Make
TOSAQuantizerdefault touse_composable_quantizer=True. - Extend/update quantizer support + annotation behavior (e.g., while-loop shared-qspec handling, fixed-qparams input qspecs for trig ops, additional supported ops).
- Update Arm backend tests and the Arm quantizer tutorial notebook to reflect the new defaults/behaviors.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| examples/arm/quantizer_tutorial.ipynb | Removes WIP framing in the composable quantizer tutorial intro. |
| backends/arm/test/ops/test_while.py | Adds an INT while-loop test path forcing composable quantizer usage. |
| backends/arm/test/ops/test_transpose_conv2d.py | Updates tests to use TOSAQuantizationConfig for global config setup. |
| backends/arm/test/ops/test_to_copy.py | Simplifies redundant-cast xfail configuration shared between FP/INT. |
| backends/arm/test/misc/test_shared_qspecs.py | Updates golden expectations for shared-qspec annotation counts/qparams. |
| backends/arm/test/misc/test_quant_custom_meta.py | Adjusts test quantizer config (including set_io(None)) to match new behavior. |
| backends/arm/quantizer/quantizer_support.py | Updates supported/fused patterns (and adds more supported ops). |
| backends/arm/quantizer/quantization_config.py | Adds fixed-qparams input spec generation for specific trig ops under composable flow. |
| backends/arm/quantizer/arm_quantizer.py | Makes composable quantizer the default for TOSAQuantizer. |
| backends/arm/quantizer/arm_quantizer_utils.py | Tightens weight/bias identification and adds while-loop shared-qspec special-casing; extends shared-qspec op list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Signed-off-by: Adrian Lundell <adrian.lundell@arm.com> Change-Id: I75e207d010b2bdc9abc86023153c86d2c96af3fd
@rascani has imported this pull request. If you are a Meta employee, you can view this in D106381887. |
rascani
commented
May 26, 2026
Kicking off an internal test run. |
rascani
commented
May 26, 2026
It looks like the new quantizer breaks |
…tream/change-1253855 Change-Id: I86bc8025e41175a796fa0ff7aabc9847b1de923a
These configs does not exist in the new quantizer, so checking it does not make sense anymore. Signed-off-by: Adrian Lundell <adrian.lundell@arm.com> Change-Id: Ic6c0b303466010be59e9c9c37fb179938c412a16
Uh oh!
There was an error while loading. Please reload this page.
| elif node.target in _fixed_input_qspec_ops: | ||
| input_act_qspec = super().get_input_act_qspec(node, input_node) | ||
| num_bits = torch.iinfo(input_act_qspec.dtype).bits | ||
| qparams = _fixed_input_qspec_ops[node.target][num_bits] | ||
| return FixedQParamsQuantizationSpec( | ||
| dtype=input_act_qspec.dtype, | ||
| scale=qparams.scale, | ||
| zero_point=qparams.zero_point, | ||
| quant_min=input_act_qspec.quant_min, | ||
| quant_max=input_act_qspec.quant_max, | ||
| qscheme=input_act_qspec.qscheme, | ||
| is_dynamic=input_act_qspec.is_dynamic, | ||
| ) |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Signed-off-by: Adrian Lundell <adrian.lundell@arm.com> Change-Id: I7760780d4f06e300f17575e7c6cb34c6dfdae64c
rascani
commented
May 27, 2026
Kicking off another internal run. |
FYI @3l1 - not sure if you saw this. |
digantdesai
commented
May 27, 2026
From @rascani 's internal CI runs, These should be forward fixed. |
rascani
commented
May 27, 2026
I already have these fixed in D106539874. I'll land it ahead of time so the default switch can be a no-op. |
Signed-off-by: Adrian Lundell <adrian.lundell@arm.com> Change-Id: Ib6fefa3ba308d955b46e23095633f54df8ed3bf0
AdrianLundell
commented
Jun 16, 2026
I would recommend replacing accessing e.g. |
AdrianLundell
commented
Jun 16, 2026
I realize we could also make a setter which takes the dict and calls |
…tream/change-1253855 Change-Id: I2c920401d797530b7bab6189941636e1b2035de1
…tream/change-1253855 Change-Id: I931de7467e5697c3a15420913e4b68a8e088a8b4
Signed-off-by: Adrian Lundell <adrian.lundell@arm.com> Change-Id: I9c8dc4e9690d591a286ad22376c509babfb24c0e
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…tream/change-1253855 Change-Id: I719898b5ea2056d5ab8e9723fb41f612de8e04e1
Signed-off-by: Adrian Lundell <adrian.lundell@arm.com> Change-Id: I39fd172f326909a084c8dc87613ed02d2032963d
AdrianLundell
commented
Jun 29, 2026
I had to take a break from this one, but now you should be able to set quantization specs from dicts as you are used to @rascani. |
AdrianLundell
commented
Jun 30, 2026
Look like the quantizers have diverged again, I will fix in a separate commit. |
digantdesai
commented
Jul 8, 2026
Still blocked on us, sorry. |
digantdesai
left a comment
There was a problem hiding this comment.
Review automatically exported from Phabricator review in Meta.
…tream/quantizer Change-Id: Ieb92342ab40135764270031d19e80a752595d96d
- Annotate IO with none for non supported nonzero operator - Ensure while cast node is created with a unique meta dict to avoid corrupted quantization annotations Signed-off-by: Adrian Lundell <adrian.lundell@arm.com> Change-Id: I22e4759cef7cff79f6dce26f147012f01d0d4883
Uh oh!
There was an error while loading. Please reload this page.
zingo
commented
Jul 16, 2026
Yeah! |
digantdesai
commented
Jul 16, 2026
sorry error on my part. Let me revert. |
AdrianLundell
commented
Jul 17, 2026
I see, when would you say this will be unblocked and can I make any updates to make it easier? @digantdesai |
rascani
commented
Jul 17, 2026
We had a bit of a race condition with an internal change. Barring no surprises, I am hoping to reland this today. |
rascani
commented
Jul 17, 2026
🤞 I think we should be good now. |
### Summary SiLU's quantized output is forced to reuse its input's quantization scale, which wastes resolution for no benefit. This commit gives SiLU its own output quantization spec. ### Where this happens: | Quantizer | Mechanism | `silu.default` | `silu_.default` | | --- | --- | --- | --- | | Composable (`_TOSAQuantizerV2`, default since #19758) | `TOSAQuantizationConfig.<br>SHARED_OUTPUT_ACT_QSPEC_PATTERNS` | shared (bug) | shared (bug) | | Legacy (`_TOSAQuantizerV1`) | `quantization_annotator.py` op sets | own qspec | shared (bug) | ### Why quantization sharing is wrong for SiLU: <img width="512" height="492" alt="image" src="https://github.com/user-attachments/assets/ea71702f-bbe0-402a-b2b0-595b25e0d170" /> - **SiLU non-linearly compresses and warps its input range:** - Unlike ReLU, which maintains a 1:1 linear mapping ($y = x$) for non-negative inputs, SiLU is non-linear across its entire domain. - For negative inputs, its output never goes below -0.278, no matter how negative the input gets. So its output range is always narrower than its input's. Reusing the input scale misaligns the quantization bins with the actual output distribution, **wasting resolution.** - **Reusing the input's scale doesn't save any computation at runtime:** SiLU runs as a lookup table (`class TableOps`) whose entries are precomputed at compile time, not runtime. ### Changes | File | Change | Why | | --- | --- | --- | | `quantizer/quantization_config.py` | Remove `silu.default`/`silu_.default` from `SHARED_OUTPUT_ACT_QSPEC_PATTERNS` | The accuracy loss as described above. | | `quantizer/quantization_annotator.py` | Move `silu_.default` into `_one_to_one`, next to `silu.default` | The legacy annotator classified the two variants differently. #17202 put `silu.default` in `_one_to_one` (own qspec) but `silu_.default` in `_one_to_one_shared_input_or_input_act_qspec` (shared qspec). | | `test/ops/test_silu.py` | `Silu.forward` clones its input | Latent bug found while working on this change: SiLU(inplace=True) was mutating the test pipeline's shared input tensor which the pipeline reuses. It stayed invisible because the buggy (too large) output scale made the comparison helper(`compare_rel_frobenius_and_cosine_similarity()`) treat every value as noise and skip the check entirely, so the test kept passing without validating anything. | | `test/misc/test_shared_qspecs.py` | Add `NonSharedQspecSilu` + `test_silu_does_not_share_input_qspec` | Check the emitted q/dq parameters, the same way the rest of `test_shared_qspecs.py` checks sharing. | ### Testing ```bash pytest backends/arm/test/misc/test_shared_qspecs.py # 17 passed pytest backends/arm/test/ops/test_silu.py -k "not vgf" # 34 passed, 32 xfailed ``` cc @kimishpatel@jerryzh168@digantdesai@freddan80@per@zingo@oscarandersson8218@mansnils@Sebastian-Larsson@robell@rascani Signed-off-by: Youngsik Yang <vacu9708@gmail.com>
A few fixes needed:
cc @digantdesai@freddan80@per@zingo@oscarandersson8218@mansnils@Sebastian-Larsson@robell@rascani