Skip to content

Commit cce28b8

Browse files
authored
Merge branch 'main' into theme-migration
2 parents 4a4957a + bdf658b commit cce28b8

Some content is hidden

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

47 files changed

+4138
-786
lines changed

.github/workflows/build-presets.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
strategy:
2121
fail-fast: false
2222
matrix:
23-
preset: [macos, ios, ios-simulator, pybind, llm]
23+
preset: [macos, ios, ios-simulator, pybind, profiling, llm]
2424
with:
2525
job-name: build
2626
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}

CMakePresets.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,26 @@
100100
"list": ["Darwin", "Linux", "Windows"]
101101
}
102102
},
103+
{
104+
"name": "profiling",
105+
"displayName": "Build ExecuTorch with Profiling Enabled",
106+
"inherits": [
107+
"common"
108+
],
109+
"cacheVariables": {
110+
"EXECUTORCH_BUILD_PRESET_FILE": "${sourceDir}/tools/cmake/preset/profiling.cmake",
111+
"CMAKE_OSX_DEPLOYMENT_TARGET": "12.0"
112+
},
113+
"condition": {
114+
"type": "inList",
115+
"string": "${hostSystemName}",
116+
"list": [
117+
"Darwin",
118+
"Linux",
119+
"Windows"
120+
]
121+
}
122+
},
103123
{
104124
"name": "zephyr",
105125
"displayName": "Build ExecuTorch for Zephyr RTOS",

backends/apple/coreml/TARGETS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ runtime.python_library(
1717
name = "backend",
1818
srcs = glob([
1919
"compiler/*.py",
20+
"logging.py",
2021
]),
2122
visibility = [
2223
"@EXECUTORCH_CLIENTS",
@@ -33,6 +34,7 @@ runtime.python_library(
3334
name = "partitioner",
3435
srcs = glob([
3536
"partition/*.py",
37+
"logging.py",
3638
]),
3739
visibility = [
3840
"@EXECUTORCH_CLIENTS",

backends/apple/coreml/compiler/coreml_preprocess.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@
1616

1717
import coremltools as ct
1818
import coremltools.optimize as cto
19-
2019
from executorch.backends.apple.coreml import executorchcoreml
20+
from executorch.backends.apple.coreml.logging import get_coreml_log_level
2121
from executorch.exir.backend.backend_details import (
2222
BackendDetails,
2323
ExportedProgram,
2424
PreprocessResult,
2525
)
2626
from executorch.exir.backend.compile_spec_schema import CompileSpec
2727

28-
logger = logging.getLogger(__name__)
29-
logger.setLevel(logging.WARNING)
30-
3128
from executorch.backends.apple.coreml.compiler.torch_ops import * # noqa: F401, F403
3229

30+
logger = logging.getLogger(__name__)
31+
logger.setLevel(get_coreml_log_level(default_level=logging.WARNING))
32+
3333

3434
class COMPILE_SPEC_KEYS(Enum):
3535
COMPUTE_UNITS = "compute_units"
@@ -409,6 +409,7 @@ def preprocess(
409409
edge_program: ExportedProgram,
410410
compile_specs: List[CompileSpec],
411411
) -> PreprocessResult:
412+
logger.info(f"Edge program: {edge_program}")
412413
model_type: CoreMLBackend.MODEL_TYPE = (
413414
CoreMLBackend.model_type_from_compile_specs(
414415
compile_specs,

backends/apple/coreml/compiler/torch_ops.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
# the op to the coremltools library.
1010

1111
import torch as _torch
12-
from coremltools import _logger as logger
12+
from coremltools import _logger
1313
from coremltools.converters.mil.frontend import _utils
1414
from coremltools.converters.mil.frontend.torch.ops import (
1515
_get_inputs,
16+
_get_kwinputs,
1617
NUM_TO_NUMPY_DTYPE,
1718
NUM_TO_TORCH_DTYPE,
1819
split,
20+
to,
1921
transpose,
2022
unbind,
2123
)
@@ -24,6 +26,7 @@
2426
register_torch_op,
2527
)
2628
from coremltools.converters.mil.mil import types
29+
from executorch.exir.dim_order_utils import get_memory_format
2730

2831

2932
# https://github.com/apple/coremltools/pull/2556
@@ -44,6 +47,26 @@ def split_copy(context, node):
4447
split(context, node)
4548

4649

50+
@register_torch_op(
51+
torch_alias=[
52+
"dim_order_ops::_to_dim_order_copy",
53+
"dim_order_ops._to_dim_order_copy",
54+
],
55+
override=False,
56+
)
57+
def _to_dim_order_copy(context, node):
58+
dim_order = _get_kwinputs(context, node, "dim_order", default=[None])[0]
59+
node.kwinputs.pop("dim_order")
60+
61+
# In CoreML, dim_order.val will be an ndarray, so we convert it to a list
62+
dim_order = [int(d) for d in dim_order.val]
63+
memory_format = get_memory_format(dim_order)
64+
assert (
65+
memory_format == _torch.contiguous_format
66+
), "Only contiguous memory format is supported in CoreML"
67+
to(context, node)
68+
69+
4770
# https://github.com/apple/coremltools/pull/2558
4871
@register_torch_op(
4972
torch_alias=["torchao::dequantize_affine", "torchao.dequantize_affine"],
@@ -88,7 +111,7 @@ def dequantize_affine(context, node):
88111
out_np_dtype = None
89112
if len(inputs) > 7:
90113
out_np_dtype = NUM_TO_NUMPY_DTYPE[inputs[7].val]
91-
logger.warning(
114+
_logger.warning(
92115
f"Core ML ignores output_dtype {out_np_dtype} on torchao.dequantize_affine and instead uses the native precision."
93116
)
94117

backends/apple/coreml/logging.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright © 2023 Apple Inc. All rights reserved.
2+
#
3+
# Please refer to the license found in the LICENSE file in the root directory of the source tree.
4+
5+
import logging
6+
import os
7+
from typing import Optional
8+
9+
10+
def get_coreml_log_level(default_level: int) -> Optional[str]:
11+
level_str = os.environ.get("ET_COREML_LOG_LEVEL", "").upper()
12+
if level_str == "":
13+
return default_level
14+
15+
level_map = {
16+
"DEBUG": logging.DEBUG,
17+
"INFO": logging.INFO,
18+
"WARNING": logging.WARNING,
19+
"ERROR": logging.ERROR,
20+
"CRITICAL": logging.CRITICAL,
21+
}
22+
if level_str not in level_map:
23+
raise ValueError(f"Invalid ET_COREML_LOG_LEVEL: {level_str}")
24+
return level_map[level_str]

backends/apple/coreml/partition/coreml_partitioner.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import torch
1111

1212
from executorch.backends.apple.coreml.compiler import CoreMLBackend
13+
14+
from executorch.backends.apple.coreml.logging import get_coreml_log_level
1315
from executorch.exir.backend.compile_spec_schema import CompileSpec
1416

1517
from executorch.exir.backend.partitioner import (
@@ -23,7 +25,7 @@
2325
from torch.fx.passes.operator_support import OperatorSupportBase
2426

2527
logger = logging.getLogger(__name__)
26-
logger.setLevel(logging.INFO)
28+
logger.setLevel(get_coreml_log_level(default_level=logging.INFO))
2729

2830

2931
def _is_view_op(op: torch._ops.OpOverload) -> bool:

backends/arm/_passes/unsqueeze_scalar_placeholders_pass.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import torch
99
from executorch.exir.pass_base import ExportPass, PassResult
10+
from torch._export.utils import is_buffer, is_param
1011

1112

1213
class UnsqueezeScalarPlaceholdersPass(ExportPass):
@@ -19,23 +20,27 @@ def __init__(self, exported_program):
1920
self.exported_program = exported_program
2021
super().__init__()
2122

22-
def _is_inputs_to_buffers_or_parameters(self, node):
23-
return (
24-
node.name in self.exported_program.graph_signature.inputs_to_buffers
25-
or node.name in self.exported_program.graph_signature.inputs_to_parameters
26-
)
27-
2823
def call(self, graph_module: torch.fx.GraphModule):
2924
for node in graph_module.graph.nodes:
3025
if node.op != "placeholder":
3126
continue
3227
rank = node.meta["val"].dim()
3328
if rank == 0:
34-
if not self._is_inputs_to_buffers_or_parameters(node):
29+
if is_buffer(self.exported_program, node):
30+
name = self.exported_program.graph_signature.inputs_to_buffers[
31+
node.name
32+
]
33+
elif is_param(self.exported_program, node):
34+
name = self.exported_program.graph_signature.inputs_to_parameters[
35+
node.name
36+
]
37+
else:
3538
continue
36-
tensor = self.exported_program.state_dict[node.name]
39+
40+
tensor = self.exported_program.state_dict[name]
41+
3742
if tensor.dim() == 0:
38-
self.exported_program.state_dict[node.name] = tensor.unsqueeze(0)
43+
self.exported_program.state_dict[name] = tensor.unsqueeze(0)
3944
node.meta["val"] = node.meta["val"].fake_mode.from_tensor(
4045
tensor.unsqueeze(0), static_shapes=True
4146
)
@@ -53,6 +58,9 @@ def ensures(self, graph_module: torch.fx.GraphModule):
5358
if node.op == "placeholder":
5459
rank = node.meta["val"].dim()
5560
if rank == 0:
56-
if not self._is_inputs_to_buffers_or_parameters(node):
61+
if not (
62+
is_buffer(self.exported_program, node)
63+
or is_param(self.exported_program, node)
64+
):
5765
continue
5866
raise ValueError("Placeholders of rank 0 are not supported!")

backends/cadence/aot/compiler.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
# if the quantizer here is different from the quantizer used to convert. It is
5555
# however useful for unit tests to separate the converted model from the fused
5656
# model, to be able to get reference numerics.
57-
# If this does not apply, please use quantize_and_fuse_pt2 instead.
57+
# If this does not apply, please use quantize_pt2 instead.
5858
def trace(
5959
model: torch.nn.Module,
6060
inputs: tuple[object, ...],
@@ -85,6 +85,29 @@ def trace(
8585

8686

8787
def prepare_pt2(
88+
model: torch.nn.Module,
89+
inputs: tuple[object, ...],
90+
quantizer: CadenceQuantizer,
91+
dump_graphs: bool = False,
92+
) -> torch.fx.GraphModule:
93+
"""
94+
Trace and Prepare a model using the given quantizer.
95+
The quantizer must be supplied and be the same as the one used to
96+
fuse the model later, if applicable. If you do not expect that behavior,
97+
please use quantize_pt2 instead, which will instantiate a
98+
default quantizer for you if needed.
99+
Returns a GraphModule with the prepared model.
100+
"""
101+
102+
traced_program = trace(model, inputs, dump_graphs=dump_graphs)
103+
prepared_program = prepare_traced_pt2(
104+
traced_program, quantizer, dump_graphs=dump_graphs
105+
)
106+
107+
return prepared_program
108+
109+
110+
def prepare_traced_pt2(
88111
program: ExportedProgram,
89112
quantizer: CadenceQuantizer,
90113
dump_graphs: bool = False,
@@ -93,7 +116,7 @@ def prepare_pt2(
93116
Prepare a model using the given quantizer.
94117
The quantizer must be supplied and be the same as the one used to
95118
fuse the model later, if applicable. If you do not expect that behavior,
96-
please use quantize_and_fuse_pt2 instead, which will instantiate a
119+
please use quantize_pt2 instead, which will instantiate a
97120
default quantizer for you if needed.
98121
Returns a GraphModule with the prepared model.
99122
"""
@@ -137,7 +160,7 @@ def fuse_pt2(
137160
"""
138161
Fuse a converted graph module using the given quantizer.
139162
The quantizer must be the same as the one used to convert the model.
140-
If you do not expect that behavior, please use quantize_and_fuse_pt2 instead,
163+
If you do not expect that behavior, please use quantize_pt2 instead,
141164
which will instantiate a default quantizer for you if needed.
142165
Returns a GraphModule with the fused model.
143166
"""
@@ -179,7 +202,7 @@ def quantize_pt2(
179202
logging.info(program.graph.print_tabular())
180203

181204
# Get prepared graph module
182-
prepared_gm = prepare_pt2(program, quantizer, dump_graphs=dump_graphs)
205+
prepared_gm = prepare_pt2(model, inputs, quantizer, dump_graphs=dump_graphs)
183206

184207
# Calibrate
185208
# If no calibration data is provided, use the inputs

backends/cadence/aot/export_example.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
export_to_executorch_gen_etrecord,
2020
fuse_pt2,
2121
prepare_pt2,
22-
trace,
2322
)
2423

2524
from executorch.backends.cadence.aot.quantizer.quantizer import CadenceDefaultQuantizer
@@ -50,11 +49,8 @@ def export_model(
5049
# Instantiate the quantizer
5150
quantizer = CadenceDefaultQuantizer()
5251

53-
# Trace the model
54-
ep = trace(model, example_inputs)
55-
5652
# Prepare the model
57-
prepared_gm = prepare_pt2(ep, quantizer)
53+
prepared_gm = prepare_pt2(model, example_inputs, quantizer)
5854

5955
# Calibrate the model
6056
for samples in [example_inputs]:

0 commit comments

Comments
 (0)