Skip to content

Commit e2a4659

Browse files
authored
Merge branch 'main' into add-adaptive_avg_pool2d
2 parents d99ab40 + f858e0d commit e2a4659

Some content is hidden

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

44 files changed

+2156
-210
lines changed

backends/arm/_passes/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from .decompose_ne_pass import DecomposeNotEqualPass # noqa
4343
from .decompose_round_pass import DecomposeRoundPass # noqa
4444
from .decompose_select import DecomposeSelectPass # noqa
45+
from .decompose_sign_pass import DecomposeSignPass # noqa
4546
from .decompose_silu_pass import DecomposeSiluPass # noqa
4647
from .decompose_sinh_pass import DecomposeSinhPass # noqa
4748
from .decompose_softmax_pass import DecomposeSoftmaxPass # noqa

backends/arm/_passes/arm_pass_manager.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
# LICENSE file in the root directory of this source tree.
77

88
# pyre-unsafe
9+
10+
import executorch.backends.arm.tosa.dialect # noqa: unused
911
from executorch.backends.arm._passes import (
1012
AddBiasPass,
1113
AnnotateChannelsLastDimOrder,
@@ -45,6 +47,7 @@
4547
DecomposeNotEqualPass,
4648
DecomposeRoundPass,
4749
DecomposeSelectPass,
50+
DecomposeSignPass,
4851
DecomposeSiluPass,
4952
DecomposeSinhPass,
5053
DecomposeSoftmaxPass,
@@ -160,6 +163,7 @@ def _tosa_080_MI_pipeline(self, exported_program: ExportedProgram) -> GraphModul
160163
self.add_pass(ConvertIntPowToMuls())
161164
self.add_pass(CastBoolToInt8Pass())
162165
self.add_pass(DecomposeSinhPass())
166+
self.add_pass(DecomposeSignPass())
163167
self.add_pass(ReplaceScalarWithTensorArgPassTOSAMI())
164168
self.add_pass(DecomposeEmbeddingPass())
165169
self.add_pass(FuseQuantizedActivationPass())
@@ -245,6 +249,7 @@ def transform_for_annotation_pipeline(self, graph_module: GraphModule):
245249
self.add_pass(DecomposeScaledDotProductAttention())
246250
self.add_pass(DecomposeRoundPass())
247251
self.add_pass(CastBoolToInt8Pass())
252+
self.add_pass(DecomposeSignPass())
248253
self.add_pass(ReplaceScalarWithTensorArgPassTOSABI())
249254
self.add_pass(ScalarsToAttributePass())
250255
self.add_pass(DecomposeGroupNormPass())
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Copyright 2025 Arm Limited and/or its affiliates.
2+
#
3+
# This source code is licensed under the BSD-style license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
import torch
7+
8+
from executorch.backends.arm._passes import ArmPass
9+
from executorch.exir.dialects._ops import ops as exir_ops
10+
11+
12+
# For MI case
13+
edge_sign = exir_ops.edge.aten.sign.default
14+
# For BI case
15+
aten_sign = torch.ops.aten.sign.default
16+
17+
18+
def get_ops(op):
19+
"""Returns the appropriate operator functions based on the input operator."""
20+
if op == edge_sign:
21+
return (
22+
exir_ops.edge.aten.gt.Scalar,
23+
exir_ops.edge.aten.lt.Scalar,
24+
exir_ops.edge.aten.where.self,
25+
exir_ops.edge.aten.neg.default,
26+
exir_ops.edge.aten.mul.Scalar,
27+
exir_ops.edge.aten.add.Scalar,
28+
)
29+
elif op == aten_sign:
30+
return (
31+
torch.ops.aten.gt.Scalar,
32+
torch.ops.aten.lt.Scalar,
33+
torch.ops.aten.where.self,
34+
torch.ops.aten.neg.default,
35+
torch.ops.aten.mul.Scalar,
36+
torch.ops.aten.add.Scalar,
37+
)
38+
else:
39+
raise ValueError(f"Unsupported operator: {op}")
40+
41+
42+
class DecomposeSignPass(ArmPass):
43+
"""Decomposes the sign operator into a sequence of operations that are supported by the Arm backend."""
44+
45+
def call_operator(self, op, args, kwargs, meta):
46+
if op not in (edge_sign, aten_sign):
47+
return super().call_operator(op, args, kwargs, meta)
48+
49+
gt_op, lt_op, where_op, neg_op, mul_op, add_op = get_ops(op)
50+
51+
x = args[0]
52+
53+
gt_mask = super().call_operator(gt_op, (x, 0.0), {}, meta, updated=True)
54+
lt_mask = super().call_operator(lt_op, (x, 0.0), {}, meta, updated=True)
55+
56+
zeros = super().call_operator(mul_op, (x, 0.0), {}, meta, updated=True)
57+
ones = super().call_operator(add_op, (zeros, 1.0), {}, meta, updated=True)
58+
neg_ones = super().call_operator(neg_op, (ones,), {}, meta, updated=True)
59+
60+
negative_tensor = super().call_operator(
61+
where_op, (lt_mask, neg_ones, zeros), {}, meta, updated=True
62+
)
63+
positive_tensor = super().call_operator(
64+
where_op, (gt_mask, ones, zeros), {}, meta, updated=True
65+
)
66+
67+
return super().call_operator(
68+
where_op,
69+
(lt_mask, negative_tensor, positive_tensor),
70+
{},
71+
meta,
72+
updated=True,
73+
)

backends/arm/operator_support/tosa_supported_operators.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ def is_node_supported(
250250
exir_ops.edge.aten.atan.default,
251251
exir_ops.edge.aten.acosh.default,
252252
exir_ops.edge.aten._adaptive_avg_pool2d.default,
253+
exir_ops.edge.aten.sign.default,
253254
]
254255

255256
return supported

backends/arm/quantizer/quantization_annotator.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ def _match_pattern(
216216
torch.ops.aten.sinh.default,
217217
torch.ops.aten.atan.default,
218218
torch.ops.aten.acosh.default,
219+
torch.ops.aten.sign.default,
219220
]
220221

221222
_one_to_one_shared_input_qspec = [

backends/arm/scripts/build_executor_runner.sh

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ set -eu
99
script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd)
1010
et_root_dir=$(cd ${script_dir}/../../.. && pwd)
1111
et_root_dir=$(realpath ${et_root_dir})
12-
toolchain_cmake=${et_root_dir}/examples/arm/ethos-u-setup/arm-none-eabi-gcc.cmake
12+
toolchain=arm-none-eabi-gcc
1313
setup_path_script=${et_root_dir}/examples/arm/ethos-u-scratch/setup_path.sh
1414
_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools."
1515

@@ -46,6 +46,7 @@ help() {
4646
echo " --output=<FOLDER> Output folder Default: <MODEL>/<MODEL>_<TARGET INFO>.pte"
4747
echo " --et_build_root=<FOLDER> Build output root folder to use, defaults to ${et_build_root}"
4848
echo " --ethosu_tools_dir=<FOLDER> Path to your Ethos-U tools dir if you not using default: ${ethosu_tools_dir}"
49+
echo " --toolchain=<TOOLCHAIN> Toolchain can be specified (e.g. bare metal as arm-none-eabi-gcc or zephyr as arm-zephyr-eabi-gcc"
4950
exit 0
5051
}
5152

@@ -63,11 +64,23 @@ for arg in "$@"; do
6364
--output=*) output_folder="${arg#*=}" ; output_folder_set=true ;;
6465
--et_build_root=*) et_build_root="${arg#*=}";;
6566
--ethosu_tools_dir=*) ethosu_tools_dir="${arg#*=}";;
67+
--toolchain=*) toolchain="${arg#*=}";;
6668
*)
6769
;;
6870
esac
6971
done
7072

73+
if [[ ${toolchain} == "arm-none-eabi-gcc" ]]; then
74+
toolchain_cmake=${et_root_dir}/examples/arm/ethos-u-setup/${toolchain}.cmake
75+
elif [[ ${toolchain} == "arm-zephyr-eabi-gcc" ]]; then
76+
toolchain_cmake=${et_root_dir}/examples/zephyr/x86_64-linux-arm-zephyr-eabi-gcc.cmake
77+
else
78+
echo "Error: Invalid toolchain selection, provided: ${tolchain}"
79+
echo " Valid options are {arm-none-eabi-gcc, arm-zephyr-eabi-gcc}"
80+
exit 1;
81+
fi
82+
toolchain_cmake=$(realpath ${toolchain_cmake})
83+
7184
# Source the tools
7285
# This should be prepared by the setup.sh
7386
[[ -f ${setup_path_script} ]] \
@@ -116,7 +129,7 @@ else
116129
target_cpu=cortex-m85
117130
fi
118131
echo "--------------------------------------------------------------------------------"
119-
echo "Build Arm Baremetal executor_runner for ${target} with ${pte_file} using ${system_config} ${memory_mode} ${extra_build_flags} to '${output_folder}/cmake-out'"
132+
echo "Build Arm ${toolchain/-gcc/} executor_runner for ${target} with ${pte_file} using ${system_config} ${memory_mode} ${extra_build_flags} to '${output_folder}/cmake-out'"
120133
echo "--------------------------------------------------------------------------------"
121134

122135
cd ${et_root_dir}/examples/arm/executor_runner
@@ -130,7 +143,6 @@ if [ "$build_with_etdump" = true ] ; then
130143
fi
131144

132145
echo "Building with BundleIO/etdump/extra flags: ${build_bundleio_flags} ${build_with_etdump_flags} ${extra_build_flags}"
133-
134146
cmake \
135147
-DCMAKE_BUILD_TYPE=${build_type} \
136148
-DCMAKE_TOOLCHAIN_FILE=${toolchain_cmake} \
@@ -152,8 +164,8 @@ echo "[${BASH_SOURCE[0]}] Configured CMAKE"
152164

153165
cmake --build ${output_folder}/cmake-out -j$(nproc) -- arm_executor_runner
154166

155-
echo "[${BASH_SOURCE[0]}] Generated baremetal elf file:"
167+
echo "[${BASH_SOURCE[0]}] Generated ${toolchain} elf file:"
156168
find ${output_folder}/cmake-out -name "arm_executor_runner"
157-
echo "executable_text: $(find ${output_folder}/cmake-out -name arm_executor_runner -exec arm-none-eabi-size {} \; | grep -v filename | awk '{print $1}') bytes"
158-
echo "executable_data: $(find ${output_folder}/cmake-out -name arm_executor_runner -exec arm-none-eabi-size {} \; | grep -v filename | awk '{print $2}') bytes"
159-
echo "executable_bss: $(find ${output_folder}/cmake-out -name arm_executor_runner -exec arm-none-eabi-size {} \; | grep -v filename | awk '{print $3}') bytes"
169+
echo "executable_text: $(find ${output_folder}/cmake-out -name arm_executor_runner -exec ${toolchain/-gcc/-size} {} \; | grep -v filename | awk '{print $1}') bytes"
170+
echo "executable_data: $(find ${output_folder}/cmake-out -name arm_executor_runner -exec ${toolchain/-gcc/-size} {} \; | grep -v filename | awk '{print $2}') bytes"
171+
echo "executable_bss: $(find ${output_folder}/cmake-out -name arm_executor_runner -exec ${toolchain/-gcc/-size} {} \; | grep -v filename | awk '{print $3}') bytes"

backends/arm/scripts/build_executorch.sh

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ set -eu
1313
script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd)
1414
et_root_dir=$(cd ${script_dir}/../../.. && pwd)
1515
et_root_dir=$(realpath ${et_root_dir})
16-
toolchain_cmake=${script_dir}/../../../examples/arm/ethos-u-setup/arm-none-eabi-gcc.cmake
17-
toolchain_cmake=$(realpath ${toolchain_cmake})
16+
toolchain=arm-none-eabi-gcc
1817
setup_path_script=${et_root_dir}/examples/arm/ethos-u-scratch/setup_path.sh
1918
_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools."
2019

@@ -30,6 +29,7 @@ help() {
3029
echo " --build_type=<TYPE> Build with Release, Debug or RelWithDebInfo, default is ${build_type}"
3130
echo " --devtools Build Devtools libs"
3231
echo " --etdump Adds Devtools etdump support to track timing, etdump area will be base64 encoded in the log"
32+
echo " --toolchain=<TOOLCHAIN> Toolchain can be specified (e.g. bare metal as arm-none-eabi-gcc or zephyr as arm-zephyr-eabi-gcc"
3333
exit 0
3434
}
3535

@@ -40,11 +40,23 @@ for arg in "$@"; do
4040
--build_type=*) build_type="${arg#*=}";;
4141
--devtools) build_devtools=true ;;
4242
--etdump) build_with_etdump=true ;;
43+
--toolchain=*) toolchain="${arg#*=}";;
4344
*)
4445
;;
4546
esac
4647
done
4748

49+
if [[ ${toolchain} == "arm-none-eabi-gcc" ]]; then
50+
toolchain_cmake=${et_root_dir}/examples/arm/ethos-u-setup/${toolchain}.cmake
51+
elif [[ ${toolchain} == "arm-zephyr-eabi-gcc" ]]; then
52+
toolchain_cmake=${et_root_dir}/examples/zephyr/x86_64-linux-arm-zephyr-eabi-gcc.cmake
53+
else
54+
echo "Error: Invalid toolchain selection, provided: ${tolchain}"
55+
echo " Valid options are {arm-none-eabi-gcc, arm-zephyr-eabi-gcc}"
56+
exit 1;
57+
fi
58+
toolchain_cmake=$(realpath ${toolchain_cmake})
59+
4860
# Source the tools
4961
# This should be prepared by the setup.sh
5062
[[ -f ${setup_path_script} ]] \

backends/arm/scripts/build_portable_kernels.sh

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ set -eu
1313
script_dir=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd)
1414
et_root_dir=$(cd ${script_dir}/../../.. && pwd)
1515
et_root_dir=$(realpath ${et_root_dir})
16-
toolchain_cmake=${script_dir}/../../../examples/arm/ethos-u-setup/arm-none-eabi-gcc.cmake
17-
toolchain_cmake=$(realpath ${toolchain_cmake})
16+
toolchain=arm-none-eabi-gcc
1817
setup_path_script=${et_root_dir}/examples/arm/ethos-u-scratch/setup_path.sh
1918
_setup_msg="please refer to ${et_root_dir}/examples/arm/setup.sh to properly install necessary tools."
2019

@@ -29,6 +28,7 @@ help() {
2928
echo " --et_build_root=<FOLDER> Build output root folder to use, defaults to ${et_build_root}"
3029
echo " --build_type=<TYPE> Build with Release, Debug or RelWithDebInfo, default is ${build_type}"
3130
echo " --portable_kernels=<OPS> Comma separated list of portable (non delagated) kernels to include Default: ${portable_kernels}"
31+
echo " --toolchain=<TOOLCHAIN> Toolchain can be specified (e.g. bare metal as arm-none-eabi-gcc or zephyr as arm-zephyr-eabi-gcc"
3232
exit 0
3333
}
3434

@@ -38,11 +38,23 @@ for arg in "$@"; do
3838
--et_build_root=*) et_build_root="${arg#*=}";;
3939
--build_type=*) build_type="${arg#*=}";;
4040
--portable_kernels=*) portable_kernels="${arg#*=}";;
41+
--toolchain=*) toolchain="${arg#*=}";;
4142
*)
4243
;;
4344
esac
4445
done
4546

47+
if [[ ${toolchain} == "arm-none-eabi-gcc" ]]; then
48+
toolchain_cmake=${et_root_dir}/examples/arm/ethos-u-setup/${toolchain}.cmake
49+
elif [[ ${toolchain} == "arm-zephyr-eabi-gcc" ]]; then
50+
toolchain_cmake=${et_root_dir}/examples/zephyr/x86_64-linux-arm-zephyr-eabi-gcc.cmake
51+
else
52+
echo "Error: Invalid toolchain selection, provided: ${tolchain}"
53+
echo " Valid options are {arm-none-eabi-gcc, arm-zephyr-eabi-gcc}"
54+
exit 1;
55+
fi
56+
toolchain_cmake=$(realpath ${toolchain_cmake})
57+
4658
# Source the tools
4759
# This should be prepared by the setup.sh
4860
[[ -f ${setup_path_script} ]] \

backends/arm/test/models/test_mobilenet_v2_arm.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,28 @@
3232
input_t = Tuple[torch.Tensor]
3333

3434

35+
quant_test_data = {
36+
"per_channel_quantization=true": True,
37+
"per_channel_quantization=false": False,
38+
}
39+
40+
3541
def test_mv2_tosa_MI():
3642
pipeline = TosaPipelineMI[input_t](
3743
mv2, model_inputs, aten_op=[], exir_op=[], use_to_edge_transform_and_lower=True
3844
)
3945
pipeline.run()
4046

4147

42-
def test_mv2_tosa_BI():
48+
@common.parametrize("per_channel_quantization", quant_test_data)
49+
def test_mv2_tosa_BI(per_channel_quantization):
4350
pipeline = TosaPipelineBI[input_t](
4451
mv2,
4552
model_inputs,
4653
aten_op=[],
4754
exir_op=[],
4855
use_to_edge_transform_and_lower=True,
49-
per_channel_quantization=True,
56+
per_channel_quantization=per_channel_quantization,
5057
atol=0.25,
5158
qtol=1,
5259
)
@@ -55,15 +62,16 @@ def test_mv2_tosa_BI():
5562

5663
@pytest.mark.slow
5764
@common.XfailIfNoCorstone300
58-
def test_mv2_u55_BI():
65+
@common.parametrize("per_channel_quantization", quant_test_data)
66+
def test_mv2_u55_BI(per_channel_quantization):
5967
pipeline = EthosU55PipelineBI[input_t](
6068
mv2,
6169
model_inputs,
6270
aten_ops=[],
6371
exir_ops=[],
6472
run_on_fvp=True,
6573
use_to_edge_transform_and_lower=True,
66-
per_channel_quantization=True,
74+
per_channel_quantization=per_channel_quantization,
6775
atol=0.25,
6876
qtol=1,
6977
)
@@ -72,15 +80,16 @@ def test_mv2_u55_BI():
7280

7381
@pytest.mark.slow
7482
@common.XfailIfNoCorstone320
75-
def test_mv2_u85_BI():
83+
@common.parametrize("per_channel_quantization", quant_test_data)
84+
def test_mv2_u85_BI(per_channel_quantization):
7685
pipeline = EthosU85PipelineBI[input_t](
7786
mv2,
7887
model_inputs,
7988
aten_ops=[],
8089
exir_ops=[],
8190
run_on_fvp=True,
8291
use_to_edge_transform_and_lower=True,
83-
per_channel_quantization=True,
92+
per_channel_quantization=per_channel_quantization,
8493
atol=0.25,
8594
qtol=1,
8695
)

0 commit comments

Comments
 (0)