99import os .path
1010import shutil
1111import subprocess
12+ from enum import Enum
1213from os import mkdir
1314
1415import numpy as np
1516import torch
1617from executorch .backends .nxp .backend .edge_helper import is_channels_last_dim_order
1718from executorch .backends .nxp .backend .ir .converter .conversion import translator
1819from executorch .backends .nxp .neutron_partitioner import NeutronPartitioner
19-
2020from executorch .backends .nxp .tests_models .config_importer import test_config
21-
2221from executorch .backends .nxp .tests_models .dataset_creator import RandomDatasetCreator
2322from executorch .backends .nxp .tests_models .graph_verifier import GraphVerifier
2423from executorch .backends .nxp .tests_models .model_input_spec import ModelInputSpec
2827from executorch .backends .nxp .tests_models .outputs_dir_importer import outputs_dir
2928from executorch .backends .nxp .tests_models .utils import (
3029 save_pte_program ,
30+ to_quantized_edge_program ,
3131 to_quantized_executorch_program ,
3232)
3333from executorch .devtools .visualization .visualization_utils import (
3434 visualize_with_clusters ,
3535)
3636from pytest_mock import MockerFixture
3737from torch .export import ExportedProgram
38+ from torch .fx import GraphModule
3839
3940logger = logging .getLogger (__name__ )
4041
4546NEUTRON_TEST_PATH = test_config .NEUTRON_TEST_PATH
4647
4748
49+ class ReferenceModel (Enum ):
50+ QUANTIZED_EXECUTORCH_CPP = 0
51+ QUANTIZED_EDGE_PYTHON = 1
52+ # QUANTIZED_ATEN_PYTHON = 2 # Not implemented.
53+ # FLOAT_ATEN_PYTHON = 3 # Not implemented.
54+ FLOAT_PYTORCH_PYTHON = 4
55+
56+
4857def _run_delegated_executorch_program (
4958 model ,
5059 test_dir ,
@@ -266,14 +275,27 @@ def store_results(
266275 output_array .tofile (bin_file_path )
267276
268277
269- def _run_pytorch_program (
270- model ,
278+ def _run_python_program (
279+ model : torch . nn . Module | GraphModule ,
271280 testing_dataset_dir ,
272281 input_spec : list [ModelInputSpec ],
273282 output_spec : list [torch .Tensor ],
274283 cpu_results_dir ,
275284 npu_results_dir ,
276285):
286+ """Run a model in Python with channels first (contiguous) inputs.
287+
288+ :param model: Any PyTorch/ExecuTorch model runnable directly in python with channels first (contiguous) inputs.
289+ :param testing_dataset_dir: Directory containing testing data. The samples can be channels last (NHWC) or channels
290+ first (NCHW). The format must match the input_spec.dim_order. The data will be
291+ converted to channels first if needed.
292+ :param input_spec: List of ModelInputSpec defining the shape, type, and dimension order of each input.
293+ :param output_spec: List of output tensor specifications.
294+ :param cpu_results_dir: Directory where CPU results will be stored. The structure will match the existing structure
295+ of `npu_results_dir`.
296+ :param npu_results_dir: Directory where NPU results are already stored, to serve as reference directory structure
297+ for `cpu_results_dir`.
298+ """
277299 all_outputs = []
278300
279301 for input_samples in read_prepared_samples (testing_dataset_dir , input_spec ):
@@ -333,7 +355,7 @@ def convert_run_compare(
333355 dataset_creator = None ,
334356 output_comparator = None ,
335357 mocker : MockerFixture = None ,
336- run_cpu_version_in_pytorch : bool = False ,
358+ reference_model : ReferenceModel = ReferenceModel . QUANTIZED_EXECUTORCH_CPP ,
337359 use_qat : bool = False ,
338360):
339361 """
@@ -347,7 +369,7 @@ def convert_run_compare(
347369 :param dataset_creator: Creator that should fill provided `dataset_dir` with model input samples.
348370 :param output_comparator: Comparator of results produced by NPU and CPU runs of the program.
349371 :param dlg_model_verifier: Graph verifier instance.
350- :param run_cpu_version_in_pytorch: If True, runs CPU version in float32 PyTorch instead of quantized ExecuTorch .
372+ :param reference_model: Version of the model which will be run to obtain reference output data .
351373 :param mocker: Mocker instance used by visualizer.
352374 :param use_qat: If True, applies quantization-aware training before conversion (without the QAT training).
353375 """
@@ -393,25 +415,55 @@ def convert_run_compare(
393415
394416 output_spec = _get_program_output_spec (delegated_program )
395417
396- if run_cpu_version_in_pytorch :
397- _run_pytorch_program (
398- model ,
399- testing_dataset_dir ,
400- input_spec ,
401- output_spec ,
402- cpu_results_dir ,
403- npu_results_dir ,
404- )
405- else :
406- _run_non_delegated_executorch_program (
407- model ,
408- test_dir ,
409- test_name ,
410- calibration_dataset_dir ,
411- testing_dataset_dir ,
412- input_spec ,
413- cpu_results_dir ,
414- )
418+ match reference_model :
419+ case ReferenceModel .QUANTIZED_EXECUTORCH_CPP :
420+ # Lower to quantized executorch program, export to `.pte` file and run in c++ using
421+ # examples/nxp/executor_runner/nxp_executor_runner.cpp
422+ _run_non_delegated_executorch_program (
423+ model ,
424+ test_dir ,
425+ test_name ,
426+ calibration_dataset_dir ,
427+ testing_dataset_dir ,
428+ input_spec ,
429+ cpu_results_dir ,
430+ )
431+
432+ case ReferenceModel .QUANTIZED_EDGE_PYTHON :
433+ # Lower to quantized edge program and run in Python.
434+ non_delegated_edge_program = (
435+ to_quantized_edge_program (
436+ model ,
437+ input_spec ,
438+ calibration_dataset_dir ,
439+ delegate_to_npu = False ,
440+ use_qat = use_qat ,
441+ )
442+ .exported_program ()
443+ .module ()
444+ )
445+ _run_python_program (
446+ non_delegated_edge_program ,
447+ testing_dataset_dir ,
448+ input_spec ,
449+ output_spec ,
450+ cpu_results_dir ,
451+ npu_results_dir ,
452+ )
453+
454+ case ReferenceModel .FLOAT_PYTORCH_PYTHON :
455+ # Run the PyTorch nn.Module directly in Python.
456+ _run_python_program (
457+ model ,
458+ testing_dataset_dir ,
459+ input_spec ,
460+ output_spec ,
461+ cpu_results_dir ,
462+ npu_results_dir ,
463+ )
464+
465+ case _:
466+ raise ValueError (f"Unsupported reference model: `{ reference_model } `." )
415467
416468 output_tensor_spec = _get_program_output_spec (delegated_program )
417469
0 commit comments