Skip to content

Commit 9b6fc85

Browse files
NXP backend: Improve test result gathering
1 parent ef5c8a7 commit 9b6fc85

32 files changed

Lines changed: 688 additions & 312 deletions

backends/nxp/neutron_partitioner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ def partition(self, exported_program: ExportedProgram) -> PartitionResult:
436436

437437
graph_module.recompile()
438438

439-
operators_not_to_delegate = self.delegation_spec[1][3].value.decode().split(",")
439+
operators_not_to_delegate = self.delegation_spec[1][4].value.decode().split(",")
440440
logging.info(f"Operators not to delegate: {operators_not_to_delegate}")
441441

442442
parameters_mapping = EdgeProgramToIRConverter.map_inputs_to_parameters(

backends/nxp/nxp_backend.py

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
#
1010

1111
import logging
12+
import os
1213
import struct
13-
from typing import final, List, Optional
14+
from typing import final
1415

1516
import numpy as np
1617
import torch
@@ -45,10 +46,11 @@ class NeutronCompileSpecBuilder:
4546
config: NeutronTargetSpec
4647

4748
def __init__(self):
48-
self.compile_spec: List[CompileSpec] = []
49+
self.compile_spec: list[CompileSpec] = []
4950
self.compiler_flags = []
5051
self.output_format = None
51-
self.operators_not_to_delegate: List[str] = []
52+
self.intermediates_dir = None
53+
self.operators_not_to_delegate: list[str] = []
5254
self.use_neutron_for_format_conversion = True
5355
self.fetch_constants_to_sram = False
5456
self.dump_kernel_selection_code = False
@@ -62,15 +64,17 @@ def _replace_colons(self, operator: str) -> str:
6264
def neutron_compile_spec(
6365
self,
6466
config: str,
65-
extra_flags: Optional[str] = None,
66-
operators_not_to_delegate: Optional[List[str]] = None,
67+
intermediates_dir: str | None = None,
68+
extra_flags: str | None = None,
69+
operators_not_to_delegate: list[str] | None = None,
6770
use_neutron_for_format_conversion: bool = True,
6871
fetch_constants_to_sram: bool = False,
6972
dump_kernel_selection_code: bool = False,
7073
) -> "NeutronCompileSpecBuilder":
7174
"""Generate compile spec for Neutron NPU
7275
7376
:param config: Neutron accelerator configuration, e.g. "imxrt700"
77+
:param intermediates_dir: Directory to store intermediate artifact files.
7478
:param extra_flags: Extra flags for the Neutron compiler
7579
:param operators_not_to_delegate: List of operators that should not be delegated
7680
:param use_neutron_for_format_conversion: If True, the EdgeProgramToIRConverter will insert `Transpose` ops to
@@ -83,6 +87,7 @@ def neutron_compile_spec(
8387
"""
8488

8589
self.config = NeutronTargetSpec(config)
90+
self.intermediates_dir = intermediates_dir
8691

8792
assert (
8893
self.output_format is None
@@ -113,6 +118,7 @@ def build(self):
113118
CompileSpec("output_format", "tflite".encode()),
114119
CompileSpec("compile_flags", " ".join(self.compiler_flags).encode()),
115120
CompileSpec("target", self.config.get_name().encode()),
121+
CompileSpec("intermediates_dir", f"{self.intermediates_dir}".encode()),
116122
CompileSpec(
117123
"operators_not_to_delegate",
118124
",".join(self.operators_not_to_delegate).encode(),
@@ -136,17 +142,19 @@ def build(self):
136142

137143
def generate_neutron_compile_spec(
138144
config: str, # The target platform. For example "imxrt700".
139-
system_config: Optional[str] = None,
140-
extra_flags: Optional[str] = None,
141-
operators_not_to_delegate: Optional[List[str]] = None,
145+
system_config: str | None = None,
146+
extra_flags: str | None = None,
147+
intermediates_dir: str | None = None,
148+
operators_not_to_delegate: list[str] | None = None,
142149
use_neutron_for_format_conversion: bool = True,
143150
fetch_constants_to_sram: bool = False,
144151
dump_kernel_selection_code: bool = False,
145-
) -> List[CompileSpec]:
152+
) -> list[CompileSpec]:
146153
return (
147154
NeutronCompileSpecBuilder()
148155
.neutron_compile_spec(
149156
config,
157+
intermediates_dir=intermediates_dir,
150158
extra_flags=extra_flags,
151159
operators_not_to_delegate=operators_not_to_delegate,
152160
use_neutron_for_format_conversion=use_neutron_for_format_conversion,
@@ -163,7 +171,7 @@ class NeutronBackend(BackendDetails):
163171
@staticmethod
164172
def preprocess( # noqa C901
165173
edge_program: ExportedProgram,
166-
compile_spec: List[CompileSpec],
174+
compile_spec: list[CompileSpec],
167175
) -> PreprocessResult:
168176
logging.info("NeutronBackend::preprocess")
169177

@@ -173,6 +181,7 @@ def preprocess( # noqa C901
173181
compile_flags = []
174182
binary = bytes()
175183
target = ""
184+
intermediates_dir = "None"
176185
use_neutron_for_format_conversion = None
177186
fetch_constants_to_sram = False
178187
dump_kernel_selection_code = None
@@ -181,6 +190,8 @@ def preprocess( # noqa C901
181190
output_format = spec.value.decode()
182191
if spec.key == "target":
183192
target = spec.value.decode()
193+
if spec.key == "intermediates_dir":
194+
intermediates_dir = spec.value.decode()
184195
if spec.key == "compile_flags":
185196
compile_flags.append(spec.value.decode())
186197
if spec.key == "use_neutron_for_format_conversion":
@@ -194,6 +205,10 @@ def preprocess( # noqa C901
194205
if not output_format:
195206
raise RuntimeError("output format is required")
196207

208+
# Check if provided intermediates_dir is a correct path (None is decoded to str)
209+
if intermediates_dir != "None" and not os.path.isdir(intermediates_dir):
210+
raise ValueError("intermediates_dir is not a directory path.")
211+
197212
for node in edge_program.graph.nodes:
198213
if node.op == "call_function":
199214
logging.debug(f"Operator to be processed: {node.target}")
@@ -228,16 +243,22 @@ def preprocess( # noqa C901
228243
fetch_constants_to_sram,
229244
)
230245

231-
# Dump the tflite file if logging level is enabled
232-
if logging.root.isEnabledFor(logging.DEBUG):
233-
import os
234-
246+
# Dump the tflite file if intermediates_dir is set
247+
if intermediates_dir != "None":
235248
logging.debug(
236-
f"Serializing converted graph with tag {delegation_tag} to {os.getcwd()}"
249+
f"Serializing converted graph with tag {delegation_tag} to {intermediates_dir}"
237250
)
238-
with open(f"{delegation_tag}_pure.et.tflite", "wb") as f:
251+
with open(
252+
os.path.join(intermediates_dir, f"{delegation_tag}_pure.et.tflite"),
253+
"wb",
254+
) as f:
239255
f.write(bytes(tflite_model))
240-
with open(f"{delegation_tag}_neutron.et.tflite", "wb") as f:
256+
with open(
257+
os.path.join(
258+
intermediates_dir, f"{delegation_tag}_neutron.et.tflite"
259+
),
260+
"wb",
261+
) as f:
241262
f.write(bytes(neutron_model))
242263

243264
binary = PayloadComposer().get_binary_payload(io_formats, neutron_model)

backends/nxp/run_unittests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ EXECUTORCH_DIR=$(dirname $(dirname $SCRIPT_DIR))
1111
cd $EXECUTORCH_DIR
1212

1313
# '-c /dev/null' is used to ignore root level pytest.ini.
14-
pytest -c /dev/null backends/nxp/tests/
14+
pytest -c /dev/null -n "logical" backends/nxp/tests/
1515

1616
python -m unittest discover -s backends/nxp/tests/ -v

backends/nxp/tests/executorch_pipeline.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ def to_quantized_edge_program(
180180
operators_not_to_delegate: list[str] = None,
181181
get_calibration_inputs_fn: GetCalibrationInputsFn = get_random_calibration_inputs,
182182
target: str = "imxrt700",
183+
intermediates_dir: str | None = None,
183184
use_qat: bool = False,
184185
train_fn: Callable[[torch.fx.GraphModule], None] | None = None,
185186
remove_quant_io_ops: bool = False,
@@ -217,6 +218,7 @@ def to_quantized_edge_program(
217218
preserve_ops = [torch.ops.aten.prelu.default]
218219
compile_spec = generate_neutron_compile_spec(
219220
target,
221+
intermediates_dir=intermediates_dir,
220222
operators_not_to_delegate=operators_not_to_delegate,
221223
use_neutron_for_format_conversion=use_neutron_for_format_conversion,
222224
fetch_constants_to_sram=fetch_constants_to_sram,
@@ -266,6 +268,7 @@ def to_quantized_edge_program(
266268
def to_quantized_executorch_program(
267269
model: torch.nn.Module,
268270
input_spec: Iterable[ModelInputSpec] | tuple[int, ...] | list[tuple[int, ...]],
271+
intermediates_dir: str | None = None,
269272
use_qat: bool = False,
270273
train_fn: Callable[[torch.fx.GraphModule], None] | None = None,
271274
use_neutron_for_format_conversion: bool = True,
@@ -287,6 +290,7 @@ def to_quantized_executorch_program(
287290
edge_program_manager = to_quantized_edge_program(
288291
model,
289292
input_spec,
293+
intermediates_dir=intermediates_dir,
290294
use_qat=use_qat,
291295
train_fn=train_fn,
292296
use_neutron_for_format_conversion=use_neutron_for_format_conversion,

backends/nxp/tests/generic_tests/test_cifarnet.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def cifar_test_files(tmp_path_factory):
3434

3535

3636
@pytest.mark.parametrize("channels_last", [False, True])
37-
def test_cifarnet(mocker, cifar_test_files, channels_last):
37+
def test_cifarnet(mocker, request, cifar_test_files, channels_last):
3838
model = (
3939
CifarNet(
4040
pth_file=os.path.join(
@@ -64,9 +64,10 @@ def test_cifarnet(mocker, cifar_test_files, channels_last):
6464
lower_run_compare(
6565
model,
6666
[input_spec],
67+
BaseGraphVerifier(1, non_dlg_nodes),
68+
request,
6769
dataset_creator=CopyDatasetCreator(cifar_test_files),
6870
output_comparator=comparator,
69-
dlg_model_verifier=BaseGraphVerifier(1, non_dlg_nodes),
7071
mocker=mocker,
7172
# Run the channels last reference in PyTorch as the ExecuTorch CPU model contains incorrectly
7273
# lowered channels last convolution weights, which cause incorrect inference results. The issue
@@ -79,7 +80,7 @@ def test_cifarnet(mocker, cifar_test_files, channels_last):
7980
)
8081

8182

82-
def test_cifarnet_qat(mocker, cifar_test_files):
83+
def test_cifarnet_qat(mocker, request, cifar_test_files):
8384
model = CifarNet().get_eager_model().eval()
8485

8586
input_shape = (1, 3, 32, 32)
@@ -94,9 +95,10 @@ def test_cifarnet_qat(mocker, cifar_test_files):
9495
lower_run_compare(
9596
model,
9697
input_shape,
98+
BaseGraphVerifier(1, non_dlg_nodes),
99+
request,
97100
dataset_creator=CopyDatasetCreator(cifar_test_files),
98101
output_comparator=comparator,
99-
dlg_model_verifier=BaseGraphVerifier(1, non_dlg_nodes),
100102
mocker=mocker,
101103
use_qat=True,
102104
)

backends/nxp/tests/generic_tests/test_convert_div_to_mul.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ class TestConvertDivToMul:
208208
ids=lambda is_scalar: "scalar" if is_scalar else "tensor",
209209
)
210210
def test__static__full_pipeline(
211-
self, mocker, input_shape: tuple[int, ...], is_scalar: bool
211+
self, mocker, request, input_shape: tuple[int, ...], is_scalar: bool
212212
):
213213
if is_scalar:
214214
divisor = np.random.uniform(0.01, 15)
@@ -231,5 +231,6 @@ def test__static__full_pipeline(
231231
model,
232232
input_shape,
233233
graph_verifier,
234+
request,
234235
dataset_creator,
235236
)

0 commit comments

Comments
 (0)