Skip to content

Commit 557ad6b

Browse files
author
morelos
committed
Update base for Update on "[ET-VK] Creating get_symmetric_quantization_config"
# Context Eventually dynamic quantization will be enabled in the vulkan_quantizer (particularly 8bit dyn act with 8bit weights). In order to enable this functionality we need to utilize a similar method as XNNPack with how they define their quantization config. This diff aims to align with XNNPack quantizer logic and also migrate away from utilizing the old static quantization config logic. # Changes A few noticable changes is that we migrate away from `get_linear_weight_only_qcs_xnn_qconfig`, and we now define a symmetric config that has parameters to define whether it's dynamically quantized or not. Furthermore, we also incorporate bits_to_range so that we can automatically designate the min and max quant ranges without having to set them during initialization. We also change some wording from using just static as we are now enabling dynamic quantization as well. Furthermore, we change internally other codebases that are calling our existing legacy config, and move them into the more universal symmetric config. Since this follows the same naming scheme as XNNPack, I have decided to just add aliases in cases where its being imported directly along with XNNPack. Differential Revision: [D78291249](https://our.internmc.facebook.com/intern/diff/D78291249/) [ghstack-poisoned]
2 parents ef6bd56 + f57633b commit 557ad6b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1088
-105
lines changed

.github/workflows/trunk.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,37 @@ jobs:
302302
exit 1
303303
fi
304304
305+
test-arm-ootb-linux:
306+
name: test-arm-ootb-linux
307+
uses: pytorch/test-infra/.github/workflows/linux_job_v2.yml@main
308+
permissions:
309+
id-token: write
310+
contents: read
311+
with:
312+
runner: linux.2xlarge
313+
docker-image: executorch-ubuntu-22.04-arm-sdk
314+
submodules: 'recursive'
315+
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
316+
timeout: 90
317+
script: |
318+
# The generic Linux job chooses to use base env, not the one setup by the image
319+
CONDA_ENV=$(conda env list --json | jq -r ".envs | .[-1]")
320+
conda activate "${CONDA_ENV}"
321+
322+
# Follow the steps required before running the notebooks
323+
# Try to mirror these as closely as possible
324+
source .ci/scripts/utils.sh
325+
install_executorch "--use-pt-pinned-commit"
326+
327+
.ci/scripts/setup-arm-baremetal-tools.sh
328+
source examples/arm/ethos-u-scratch/setup_path.sh
329+
330+
# Install requirements for converting notebooks
331+
pip install notebook
332+
333+
# Run OOTB tests
334+
backends/arm/test/test_arm_ootb.sh
335+
305336
test-coreml-delegate:
306337
name: test-coreml-delegate
307338
uses: pytorch/test-infra/.github/workflows/macos_job.yml@main

CMakePresets.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/third-party/ios-cmake/ios.toolchain.cmake",
1616
"EXECUTORCH_BUILD_PRESET_FILE": "${sourceDir}/tools/cmake/preset/macos.cmake",
1717
"PLATFORM": "MAC_ARM64",
18-
"DEPLOYMENT_TARGET": "12.0"
18+
"DEPLOYMENT_TARGET": "12.0",
19+
"CMAKE_MACOSX_BUNDLE": "OFF"
1920
},
2021
"condition": {
2122
"lhs": "${hostSystemName}",

backends/arm/_passes/decompose_asin_pass.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,11 @@ def _build_polynomial(
8585
return result
8686

8787
def call_operator(self, op, args, kwargs, meta):
88+
if op not in edge_asin_op:
89+
return super().call_operator(op, args, kwargs, meta)
8890
logging.info(
8991
f"Approximating asin. This may introduce small numerical errors. For details, see {__file__}."
9092
)
91-
if op not in edge_asin_op:
92-
return super().call_operator(op, args, kwargs, meta)
93-
9493
x = args[0]
9594
half = 0.5
9695
one = 1.0

backends/arm/test/ops/test_add.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,5 @@ def test_add_tensor_vgf_int(test_data: input_t1):
205205
aten_op,
206206
exir_op,
207207
tosa_version="TOSA-1.0+INT",
208-
symmetric_io_quantization=True,
209208
)
210209
pipeline.run()

backends/arm/test/test_arm_ootb.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
3+
# Copyright 2025 Arm Limited and/or its affiliates.
4+
#
5+
# This source code is licensed under the BSD-style license found in the
6+
# LICENSE file in the root directory of this source tree.
7+
8+
set -e
9+
10+
run_ootb_tests_ethos_u() {
11+
echo "$FUNCNAME: Running out-of-the-box tests for Arm Ethos-U"
12+
jupyter nbconvert \
13+
--to notebook \
14+
--execute examples/arm/ethos_u_minimal_example.ipynb
15+
echo "${FUNCNAME}: PASS"
16+
}
17+
18+
run_ootb_tests_ethos_u

backends/arm/test/tester/arm_tester.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
EthosUQuantizer,
4444
get_symmetric_quantization_config,
4545
TOSAQuantizer,
46+
VgfQuantizer,
4647
)
4748
from executorch.backends.arm.test.runner_utils import (
4849
dbg_tosa_fb_to_json,
@@ -332,6 +333,8 @@ def quantize(
332333
quantizer = TOSAQuantizer(tosa_spec)
333334
elif is_ethosu(self.compile_spec):
334335
quantizer = EthosUQuantizer(self.compile_spec)
336+
elif is_vgf(self.compile_spec):
337+
quantizer = VgfQuantizer(self.compile_spec)
335338
quantize_stage = tester.Quantize(
336339
quantizer,
337340
get_symmetric_quantization_config(),

backends/arm/test/tester/test_pipeline.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -861,18 +861,15 @@ def __init__(
861861
rtol: float = 1e-03,
862862
qtol: int = 1,
863863
dynamic_shapes: Optional[Tuple[Any]] = None,
864+
transform_passes: Optional[
865+
Union[Sequence[PassType], Dict[str, Sequence[PassType]]]
866+
] = None,
864867
):
865868

866869
if (
867870
symmetric_io_quantization or per_channel_quantization
868871
) and tosa_version == "TOSA-1.0+FP":
869872
raise ValueError("Dont configure quantization with FP TOSA profile.")
870-
if (
871-
symmetric_io_quantization is False
872-
and per_channel_quantization is False
873-
and tosa_version == "TOSA-1.0+INT"
874-
):
875-
raise ValueError("Missing quantization options for INT TOSA profile.")
876873

877874
tosa_profile = TosaSpecification.create_from_string(tosa_version)
878875
compile_spec = common.get_vgf_compile_spec(
@@ -887,6 +884,7 @@ def __init__(
887884
exir_op,
888885
use_to_edge_transform_and_lower,
889886
dynamic_shapes,
887+
transform_passes=transform_passes,
890888
)
891889

892890
if symmetric_io_quantization or per_channel_quantization:
@@ -900,7 +898,7 @@ def __init__(
900898
else:
901899
quant_stage = None
902900

903-
if quant_stage:
901+
if "INT" in tosa_version:
904902
self.add_stage(self.tester.quantize, quant_stage, pos=0)
905903

906904
self.add_stage_after(

backends/cadence/aot/TARGETS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,8 +539,10 @@ python_unittest(
539539
],
540540
typing = True,
541541
deps = [
542+
":program_builder",
542543
"//executorch/backends/cadence/aot:graph_builder",
543544
"//executorch/backends/cadence/aot:ops_registrations",
545+
"//executorch/runtime:runtime",
544546
"//later:lib",
545547
],
546548
)

backends/cadence/aot/memory_planning.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
MemoryPlanningAlgo,
2020
MemoryPlanningState,
2121
)
22-
from executorch.backends.cadence.aot.utils import MemoryConfig
22+
from executorch.backends.cadence.aot.utils import (
23+
MemoryConfig,
24+
MemoryPlanningAlgoFailure,
25+
)
2326

2427
from executorch.exir import ExecutorchProgramManager
2528
from executorch.exir.memory_planning import collect_specs_from_nodes, Verifier
@@ -95,7 +98,9 @@ def plan(
9598
):
9699
self.plan_spec(spec, state, placement_constraints)
97100
if not state.is_placed(spec):
98-
raise MemoryError(f"Cannot fit {spec} in any memory hierarchy")
101+
raise MemoryPlanningAlgoFailure(
102+
f"Cannot fit {spec} {spec.allocated_memory=} in any memory hierarchy for {self.memory_config}"
103+
)
99104

100105

101106
class GreedyWithHeuristic(MemoryPlanningAlgo):
@@ -169,7 +174,9 @@ def plan(
169174
):
170175
self.plan_spec(spec, state, placement_constraints)
171176
if not state.is_placed(spec):
172-
raise MemoryError(f"Cannot fit {spec} in any memory hierarchy")
177+
raise MemoryPlanningAlgoFailure(
178+
f"Cannot fit {spec} in any memory hierarchy for {self.memory_config}"
179+
)
173180

174181
logging.debug(
175182
f"greedy by size for offset calculation with hierarchy returns bufsizes: {state.bufsizes}"

backends/cadence/aot/tests/test_fusion_ops_passes.py

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
import executorch.backends.cadence.aot.ops_registrations # noqa
1414
import torch
15-
from executorch.backends.cadence.aot import compiler
1615
from executorch.backends.cadence.aot.fuse_ops import (
1716
FuseCascadedTransposeOrPermuteOps,
1817
FuseCascadedViewOps,
@@ -30,7 +29,6 @@
3029
from executorch.exir.dialects._ops import ops as exir_ops
3130
from executorch.exir.dialects.edge._ops import EdgeOpOverload
3231
from executorch.exir.pass_base import PassResult, ProxyValue
33-
from torch import nn
3432

3533

3634
class TestFusionPassesBase(unittest.TestCase):
@@ -178,43 +176,6 @@ def test_keep_mm_add_with_multiple_users(self) -> None:
178176
self.assertEqual(count_node(converted_graph, exir_ops.edge.aten.mm.default), 1)
179177
self.assertEqual(count_node(converted_graph, exir_ops.edge.aten.add.Tensor), 3)
180178

181-
# TODO(matthiascremon) -> None: enable that pass with new flow
182-
@torch.no_grad()
183-
@unittest.expectedFailure
184-
def test_legacy_conv_bn_fusion(self) -> None:
185-
class ModelConvBN(torch.nn.Module):
186-
def __init__(
187-
self, in_features: int, out_features: int, kernel_size: int
188-
) -> None:
189-
super().__init__()
190-
self.conv1d = nn.Conv1d(in_features, out_features, kernel_size)
191-
self.bn = nn.BatchNorm1d(out_features)
192-
193-
def forward(self, x: torch.Tensor) -> torch.Tensor:
194-
y = self.conv1d(x)
195-
return self.bn(y)
196-
197-
model = ModelConvBN(64, 1, 2)
198-
x = torch.randn(1, 64, 4)
199-
200-
graph_module = (
201-
compiler.export_to_executorch_gen_etrecord(model.eval(), (x,))
202-
.exported_program()
203-
.graph_module
204-
)
205-
# Assert that after running the fusion passes, batchnorm was fused with conv1d
206-
self.assertEqual(
207-
count_node(graph_module, torch.ops.aten.linear.out)
208-
+ count_node(graph_module, torch.ops.cadence.convolution.out),
209-
1,
210-
)
211-
self.assertEqual(
212-
count_node(
213-
graph_module, torch.ops.aten._native_batch_norm_legit_no_training.out
214-
),
215-
0,
216-
)
217-
218179
def test_permute_transpose_fusion(self) -> None:
219180
builder = GraphBuilder()
220181
x = builder.placeholder("x", torch.randn(3, 1, 3, 1, 4, dtype=torch.float32))

0 commit comments

Comments
 (0)