Skip to content

Commit 2755662

Browse files
committed
support log in XNNPACK backend
1 parent 339b75c commit 2755662

File tree

189 files changed

+21274
-970
lines changed

Some content is hidden

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

189 files changed

+21274
-970
lines changed

.buckconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
[buck2]
4141
restarter=true
42+
file_watcher=notify
4243

4344
[oss]
4445
folly_cxx_tests = False

.vscode/launch.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Debug CMake project",
9+
"type": "lldb", // https://github.com/vadimcn/vscode-lldb
10+
"request": "launch",
11+
"program": "${command:cmake.launchTargetPath}",
12+
"args": [
13+
"--model_path=./add.pte",
14+
]
15+
}
16+
]
17+
}

.vscode/settings.json

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"files.associations": {
3+
"cstdlib": "cpp",
4+
"__bit_reference": "cpp",
5+
"__hash_table": "cpp",
6+
"__locale": "cpp",
7+
"__node_handle": "cpp",
8+
"__split_buffer": "cpp",
9+
"__tree": "cpp",
10+
"__verbose_abort": "cpp",
11+
"array": "cpp",
12+
"bitset": "cpp",
13+
"cctype": "cpp",
14+
"charconv": "cpp",
15+
"clocale": "cpp",
16+
"cmath": "cpp",
17+
"complex": "cpp",
18+
"condition_variable": "cpp",
19+
"cstdarg": "cpp",
20+
"cstdint": "cpp",
21+
"cstdio": "cpp",
22+
"cstring": "cpp",
23+
"ctime": "cpp",
24+
"cwchar": "cpp",
25+
"cwctype": "cpp",
26+
"deque": "cpp",
27+
"execution": "cpp",
28+
"memory": "cpp",
29+
"forward_list": "cpp",
30+
"future": "cpp",
31+
"initializer_list": "cpp",
32+
"iomanip": "cpp",
33+
"ios": "cpp",
34+
"iosfwd": "cpp",
35+
"iostream": "cpp",
36+
"istream": "cpp",
37+
"limits": "cpp",
38+
"list": "cpp",
39+
"locale": "cpp",
40+
"map": "cpp",
41+
"mutex": "cpp",
42+
"new": "cpp",
43+
"optional": "cpp",
44+
"print": "cpp",
45+
"queue": "cpp",
46+
"ratio": "cpp",
47+
"regex": "cpp",
48+
"set": "cpp",
49+
"shared_mutex": "cpp",
50+
"sstream": "cpp",
51+
"stack": "cpp",
52+
"stdexcept": "cpp",
53+
"streambuf": "cpp",
54+
"string": "cpp",
55+
"string_view": "cpp",
56+
"typeindex": "cpp",
57+
"typeinfo": "cpp",
58+
"unordered_map": "cpp",
59+
"unordered_set": "cpp",
60+
"variant": "cpp",
61+
"vector": "cpp",
62+
"algorithm": "cpp",
63+
"iterator": "cpp",
64+
"tuple": "cpp",
65+
"span": "cpp"
66+
},
67+
"C_Cpp.default.compilerPath": "/library/developer/commandlinetools/usr/bin/c++",
68+
"python.analysis.typeCheckingMode": "off"
69+
}

CMakePresets.json

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,55 @@
11
{
2-
"version": 10,
3-
"cmakeMinimumRequired": {
4-
"major": 3,
5-
"minor": 31,
6-
"patch": 0
7-
},
8-
"$comment": "On-device AI across mobile, embedded and edge for PyTorch.",
9-
"configurePresets": [
10-
{
11-
"name": "common",
12-
"hidden": true,
13-
"binaryDir": "${sourceDir}/cmake-out",
14-
"generator": "Unix Makefiles"
2+
"version": 10,
3+
"cmakeMinimumRequired": {
4+
"major": 3,
5+
"minor": 31,
6+
"patch": 0
157
},
16-
{
17-
"name": "macos-arm64",
18-
"inherits": ["common"],
19-
"generator": "Xcode",
20-
"cacheVariables": {
21-
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/third-party/ios-cmake/ios.toolchain.cmake",
22-
"EXECUTORCH_BUILD_PRESET_FILE": "${sourceDir}/tools/cmake/preset/macos-arm64.cmake",
23-
"PLATFORM": "MAC_ARM64",
24-
"DEPLOYMENT_TARGET": "10.15"
25-
},
26-
"condition": {
27-
"lhs": "${hostSystemName}",
28-
"type": "equals",
29-
"rhs": "Darwin"
30-
}
31-
}
32-
]
8+
"configurePresets": [
9+
{
10+
"name": "common",
11+
"hidden": true,
12+
"binaryDir": "${sourceDir}/cmake-out",
13+
"generator": "Unix Makefiles"
14+
},
15+
{
16+
"name": "macos-arm64",
17+
"inherits": [
18+
"common"
19+
],
20+
"generator": "Xcode",
21+
"cacheVariables": {
22+
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/third-party/ios-cmake/ios.toolchain.cmake",
23+
"EXECUTORCH_BUILD_PRESET_FILE": "${sourceDir}/tools/cmake/preset/macos-arm64.cmake",
24+
"PLATFORM": "MAC_ARM64",
25+
"DEPLOYMENT_TARGET": "10.15"
26+
},
27+
"condition": {
28+
"lhs": "${hostSystemName}",
29+
"type": "equals",
30+
"rhs": "Darwin"
31+
}
32+
},
33+
{
34+
"name": "Executorch",
35+
"displayName": "Executorch",
36+
"description": "Sets Ninja generator, build and install directory",
37+
"generator": "Ninja",
38+
"binaryDir": "${sourceDir}/out/build/${presetName}",
39+
"cacheVariables": {
40+
"CMAKE_BUILD_TYPE": "Debug",
41+
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
42+
"EXECUTORCH_LOG_LEVEL": "Debug",
43+
"EXECUTORCH_BUILD_PORTABLE_OPS": "ON"
44+
}
45+
}
46+
],
47+
"buildPresets": [
48+
{
49+
"name": "Executorch",
50+
"description": "",
51+
"displayName": "",
52+
"configurePreset": "Executorch"
53+
}
54+
]
3355
}
236 KB
Binary file not shown.

backends/arm/_passes/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from .decompose_gelu_pass import DecomposeGeluPass # noqa
2525
from .decompose_layernorm_pass import DecomposeLayerNormPass # noqa
2626
from .decompose_leaky_relu_pass import DecomposeLeakyReLUPass # noqa
27+
from .decompose_linalg_vector_norm_pass import DecomposeLinearVectorNormPass # noqa
2728
from .decompose_linear_pass import DecomposeLinearPass # noqa
2829
from .decompose_meandim_pass import DecomposeMeanDimPass # noqa
2930
from .decompose_ne_pass import DecomposeNotEqualPass # noqa

backends/arm/_passes/arm_pass_manager.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
DecomposeLayerNormPass,
3030
DecomposeLeakyReLUPass,
3131
DecomposeLinearPass,
32+
DecomposeLinearVectorNormPass,
3233
DecomposeMeanDimPass,
3334
DecomposeNotEqualPass,
3435
DecomposeSelectPass,
@@ -86,6 +87,7 @@ def _tosa_080_BI_pipeline(self, exported_program: ExportedProgram) -> GraphModul
8687
self.add_pass(ConvertSplitToSlicePass())
8788
self.add_pass(ConvertMmToBmmPass())
8889
self.add_pass(DecomposeLinearPass())
90+
self.add_pass(DecomposeLinearVectorNormPass())
8991
self.add_pass(DecomposeMeanDimPass())
9092
self.add_pass(ConvertFullLikeToFullPass())
9193
self.add_pass(ConvertToClampPass())
@@ -133,6 +135,7 @@ def _tosa_080_MI_pipeline(self, exported_program: ExportedProgram) -> GraphModul
133135
self.add_pass(FuseBatchnorm2DPass(exported_program))
134136
self.add_pass(ConvertMmToBmmPass())
135137
self.add_pass(DecomposeLinearPass())
138+
self.add_pass(DecomposeLinearVectorNormPass())
136139
self.add_pass(DecomposeLeakyReLUPass())
137140
self.add_pass(DecomposeBatchNormPass())
138141
self.add_pass(DecomposeLayerNormPass())
@@ -207,6 +210,7 @@ def transform_for_annotation_pipeline(self, graph_module: GraphModule):
207210
self.add_pass(DecomposeCosineSimilarityPass())
208211
self.add_pass(DecomposeDivPass())
209212
self.add_pass(DecomposeLeakyReLUPass())
213+
self.add_pass(DecomposeLinearVectorNormPass())
210214
self.add_pass(DecomposeSqrtPass())
211215
self.add_pass(DecomposeSiluPass())
212216

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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+
from executorch.exir.pass_base import ExportPass
8+
9+
10+
class DecomposeLinearVectorNormPass(ExportPass):
11+
"""
12+
This pass decomposes aten.linalg_vector_norm.default into more primitive ops.
13+
We need to add this pass before quantization for graph annotation.
14+
By default, aten.linalg_vector_norm op is decomposed during legalization to Edge IR.
15+
16+
The decomposition is as follows:
17+
18+
For p == 1:
19+
out = REDUCE_SUM(ABS(x), dims, keepdim)
20+
21+
For p == 2:
22+
out = SQRT(REDUCE_SUM(MUL(x, x), dims, keepdim))
23+
24+
For arbitrary p:
25+
We dont support arbitrary p, because our decomposition looks like
26+
out = POW(REDUCE_SUM(POW(ABS(x), p), dims, keepdim), 1/p)
27+
In this case we need to wrap p into Tensor and we need to know
28+
dtype prior, but we dont know this from FX graph.
29+
"""
30+
31+
torch_linalg_vector_norm = (torch.ops.aten.linalg_vector_norm.default,)
32+
33+
def call_operator(self, op, args, kwargs, meta):
34+
if op not in self.torch_linalg_vector_norm:
35+
return super().call_operator(op, args, kwargs, meta)
36+
37+
# Extract inputs and optional arguments.
38+
# Expected args:
39+
# args[0]: input tensor
40+
# args[1]: norm order 'p' (optional, default: 2.0)
41+
# args[2]: dimensions to reduce (should be provided)
42+
# args[3]: keepdim flag (optional, default: False)
43+
input_tensor = args[0]
44+
norm_order = args[1] if len(args) > 1 else 2.0
45+
norm_dim = args[2] if len(args) > 2 else None
46+
keepdim = args[3] if len(args) > 3 else False
47+
48+
if norm_order not in (1, 2):
49+
raise ValueError(
50+
f"The order of {norm_order}\n"
51+
f"is not supported for linalg_vector_norm operator"
52+
)
53+
54+
if norm_dim is None:
55+
raise ValueError("The norm_dim for linalg_vector_norm is None.")
56+
57+
dims = [norm_dim] if isinstance(norm_dim, int) else list(norm_dim)
58+
59+
# Decomposition based on norm order.
60+
if norm_order == 1:
61+
op1 = super().call_operator(
62+
torch.ops.aten.abs.default, (input_tensor,), {}, meta
63+
)
64+
op2 = super().call_operator(
65+
torch.ops.aten.sum.dim_IntList, (op1, dims, keepdim), {}, meta
66+
)
67+
return op2
68+
69+
elif norm_order == 2:
70+
# For p == 2, decomposition is sqrt(sum(x * x, dims, keepdim))
71+
op1 = super().call_operator(
72+
torch.ops.aten.mul.Tensor, (input_tensor, input_tensor), {}, meta
73+
)
74+
op2 = super().call_operator(
75+
torch.ops.aten.sum.dim_IntList, (op1, dims, keepdim), {}, meta
76+
)
77+
op3 = super().call_operator(torch.ops.aten.sqrt.default, (op2,), {}, meta)
78+
return op3

backends/arm/operators/op_abs.py

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
)
1616
from executorch.backends.arm.operators.operator_validation_utils import (
1717
validate_num_inputs,
18+
validate_same_dtype,
1819
)
1920
from executorch.backends.arm.tosa_mapping import TosaArg
2021
from executorch.backends.arm.tosa_specification import TosaSpecification
@@ -43,13 +44,8 @@ def define_node(
4344
import tosa_tools.v0_80.serializer.tosa_serializer as ts # type: ignore
4445

4546
validate_num_inputs(self.target, inputs, 1)
46-
# Specification (0.80) states that input and output types
47-
# should all be the same
48-
if not (inputs[0].dtype == output.dtype):
49-
raise ValueError(
50-
"All inputs and outputs need same dtype."
51-
f"Got {inputs[0].dtype=}, {output.dtype=}"
52-
)
47+
validate_same_dtype(self.target, [*inputs, output])
48+
5349
# Handle int8 (quantized) and int32
5450
if not (inputs[0].dtype in [ts.DType.INT8, ts.DType.INT32]):
5551
raise ValueError(
@@ -110,13 +106,7 @@ def define_node(
110106
import tosa_tools.v0_80.serializer.tosa_serializer as ts # type: ignore
111107

112108
validate_num_inputs(self.target, inputs, 1)
113-
# Specification (0.80) states that input and output types
114-
# should all be the same
115-
if not (inputs[0].dtype == output.dtype):
116-
raise ValueError(
117-
"All inputs and output need same dtype."
118-
f"Got {inputs[0].dtype=}, {output.dtype=}"
119-
)
109+
validate_same_dtype(self.target, [*inputs, output])
120110

121111
if inputs[0].dtype in [ts.DType.INT8, ts.DType.INT32]:
122112
# Call the inherited define_node for handling integers
@@ -163,14 +153,8 @@ def define_node(
163153
import serializer.tosa_serializer as ts # type: ignore
164154

165155
validate_num_inputs(self.target, inputs, 1)
156+
validate_same_dtype(self.target, [*inputs, output])
166157

167-
# Specification (1.0) states that input and output types
168-
# should all be the same
169-
if not (inputs[0].dtype == output.dtype):
170-
raise ValueError(
171-
"All inputs and outputs need same dtype."
172-
f"Got {inputs[0].dtype=}, {output.dtype=}"
173-
)
174158
# Handle int8 (quantized) and int32
175159
if not (inputs[0].dtype in [ts.DType.INT8, ts.DType.INT32]):
176160
raise ValueError(
@@ -232,14 +216,7 @@ def define_node(
232216
import serializer.tosa_serializer as ts # type: ignore
233217

234218
validate_num_inputs(self.target, inputs, 1)
235-
236-
# Specification (1.0) states that input and output types
237-
# should all be the same
238-
if not (inputs[0].dtype == output.dtype):
239-
raise ValueError(
240-
"All inputs and output need same dtype."
241-
f"Got {inputs[0].dtype=}, {output.dtype=}"
242-
)
219+
validate_same_dtype(self.target, [*inputs, output])
243220

244221
if inputs[0].dtype in [ts.DType.INT8, ts.DType.INT32]:
245222
# Call the inherited define_node for handling integers

0 commit comments

Comments
 (0)