diff --git a/python/tvm/autotvm/__init__.py b/python/tvm/autotvm/__init__.py index a3c59252b01a..5a7d00960ecd 100644 --- a/python/tvm/autotvm/__init__.py +++ b/python/tvm/autotvm/__init__.py @@ -60,5 +60,6 @@ FallbackContext, ApplyHistoryBest as apply_history_best, ApplyGraphBest as apply_graph_best, + ApplyFixedConfig as apply_fixed_config, ) from .env import GLOBAL_SCOPE diff --git a/python/tvm/autotvm/task/__init__.py b/python/tvm/autotvm/task/__init__.py index 6eea62264d7d..3949d324c4df 100644 --- a/python/tvm/autotvm/task/__init__.py +++ b/python/tvm/autotvm/task/__init__.py @@ -36,6 +36,7 @@ from .dispatcher import ( DispatchContext, ApplyConfig, + ApplyFixedConfig, ApplyHistoryBest, FallbackContext, clear_fallback_cache, diff --git a/python/tvm/autotvm/task/dispatcher.py b/python/tvm/autotvm/task/dispatcher.py index 6c072dc1fa17..11a608d4cbbf 100644 --- a/python/tvm/autotvm/task/dispatcher.py +++ b/python/tvm/autotvm/task/dispatcher.py @@ -31,6 +31,8 @@ from __future__ import absolute_import as _abs import logging +import typing +from typing import Union from collections.abc import Iterable import numpy as np @@ -179,6 +181,57 @@ def update(self, target, workload, cfg): self._config = cfg +class ApplyFixedConfig(DispatchContext): + """Apply a config of a deterministic schedule. + This is used for building a single Relay operator with deterministic schedule + for testing schedules at Relay level. + + Parameters + ---------- + tasks : list[tvm.autotvm.task.task.Task] + List of autoTVM tasks. + schedule_names : str, List[str] + Name of schedules to use. + """ + + def __init__(self, tasks, schedule_names: Union[str, typing.List[str]]): + super(ApplyFixedConfig, self).__init__() + if isinstance(schedule_names, str): + self._schedule_names = list(schedule_names) + elif isinstance(schedule_names, list): + self._schedule_names = schedule_names + else: + raise RuntimeError("Incorrect type: " + schedule_names) + self._tasks = tasks + self.workload = None + + def _query_inside(self, target, workload): + """Override query""" + self.workload = workload + + # Create a config from correct task + for task in self._tasks: + if task.name == workload[0]: + config = task.config_space.get(0) + break + + if not config: + raise RuntimeError( + "workload: %s does not exist in %s" % (str(workload), str(self._tasks)) + ) + # Add low cost to the target schedule and high cost to others. + if workload[0] in self._schedule_names: + config.cost = 1e-6 + else: + config.cost = 100000 + return config + + def update(self, target, workload, cfg): + """Override update""" + self.workload = workload + self._config = cfg + + class ApplyHistoryBest(DispatchContext): """ Apply the history best config diff --git a/python/tvm/micro/testing/aot_test_utils.py b/python/tvm/micro/testing/aot_test_utils.py new file mode 100644 index 000000000000..82ac1ac68e9d --- /dev/null +++ b/python/tvm/micro/testing/aot_test_utils.py @@ -0,0 +1,105 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +import logging +import itertools +import shutil + +import pytest + +pytest.importorskip("tvm.micro") + +import tvm +from tvm.testing.aot import AOTTestRunner + +_LOG = logging.getLogger(__name__) + + +AOT_DEFAULT_RUNNER = AOTTestRunner() + +# AOT Test Runner using the Arm® Corstone™-300 Reference Systems +# see: https://developer.arm.com/ip-products/subsystem/corstone/corstone-300 +AOT_CORSTONE300_RUNNER = AOTTestRunner( + makefile="corstone300", + prologue=""" + uart_init(); + """, + includes=["uart.h"], + pass_config={ + "relay.ext.cmsisnn.options": { + "mcpu": "cortex-m55", + } + }, +) + +AOT_USMP_CORSTONE300_RUNNER = AOTTestRunner( + makefile="corstone300", + prologue=""" + uart_init(); + """, + includes=["uart.h"], + pass_config={ + "relay.ext.cmsisnn.options": { + "mcpu": "cortex-m55", + }, + "tir.usmp.enable": True, + }, +) + + +def parametrize_aot_options(test): + """Parametrize over valid option combinations""" + + requires_arm_eabi = pytest.mark.skipif( + shutil.which("arm-none-eabi-gcc") is None, reason="ARM embedded toolchain unavailable" + ) + + interface_api = ["packed", "c"] + use_unpacked_api = [True, False] + test_runner = [AOT_DEFAULT_RUNNER, AOT_CORSTONE300_RUNNER] + + all_combinations = itertools.product(interface_api, use_unpacked_api, test_runner) + + # Filter out packed operators with c interface + valid_combinations = filter( + lambda parameters: not (parameters[0] == "c" and not parameters[1]), + all_combinations, + ) + + # Only use reference system for C interface and unpacked API calls + valid_combinations = filter( + lambda parameters: not ( + parameters[2] == AOT_CORSTONE300_RUNNER + and (parameters[0] == "packed" or not parameters[1]) + ), + valid_combinations, + ) + + # Skip reference system tests if running in i386 container + marked_combinations = map( + lambda parameters: pytest.param(*parameters, marks=[requires_arm_eabi]) + if parameters[2] == AOT_CORSTONE300_RUNNER + else parameters, + valid_combinations, + ) + + fn = pytest.mark.parametrize( + ["interface_api", "use_unpacked_api", "test_runner"], + marked_combinations, + )(test) + + return tvm.testing.skip_if_32bit(reason="Reference system unavailable in i386 container")(fn) diff --git a/python/tvm/micro/testing.py b/python/tvm/micro/testing/utils.py similarity index 100% rename from python/tvm/micro/testing.py rename to python/tvm/micro/testing/utils.py diff --git a/tests/python/relay/aot/aot_test_utils.py b/python/tvm/testing/aot.py similarity index 72% rename from tests/python/relay/aot/aot_test_utils.py rename to python/tvm/testing/aot.py index 2c4262a3d2be..f8f170366ac5 100644 --- a/tests/python/relay/aot/aot_test_utils.py +++ b/python/tvm/testing/aot.py @@ -14,39 +14,41 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - +"""Common functions for AOT test cases""" import sys import datetime -import itertools -import json -import logging import os import pathlib -import platform import re import shutil import subprocess import tarfile import tempfile +import logging from typing import Any, NamedTuple, Union, Optional, List, Dict - -import pytest import numpy as np -pytest.importorskip("tvm.micro") - import tvm from tvm import relay -from tvm import te +from tvm import autotvm from tvm.contrib import utils, graph_executor -from tvm.relay.backend import te_compiler, Executor, Runtime -from tvm.relay.backend.te_compiler import TECompiler +from tvm.relay.backend import Executor, Runtime from tvm.relay.backend.utils import mangle_module_name from tvm.micro import export_model_library_format -from tvm.micro.testing import mlf_extract_workspace_size_bytes +from tvm.micro.testing.utils import mlf_extract_workspace_size_bytes _LOG = logging.getLogger(__name__) +NP_TYPE_TO_C = { + "int8": "int8_t", + "uint8": "uint8_t", + "int16": "int16_t", + "uint16": "uint16_t", + "int32": "int32_t", + "uint32": "uint32_t", + "float32": "float", +} + AOT_SUCCESS_TOKEN = "AOT_TEST_SUCCESS" AOT_FAILURE_TOKEN = "AOT_TEST_FAILURE" @@ -138,119 +140,7 @@ class AOTTestRunner(NamedTuple): pass_config: Dict[str, Any] = {} -AOT_DEFAULT_RUNNER = AOTTestRunner() - -# AOT Test Runner using the Arm® Corstone™-300 Reference Systems -# see: https://developer.arm.com/ip-products/subsystem/corstone/corstone-300 -AOT_CORSTONE300_RUNNER = AOTTestRunner( - makefile="corstone300", - prologue=""" - uart_init(); - """, - includes=["uart.h"], - pass_config={ - "relay.ext.cmsisnn.options": { - "mcpu": "cortex-m55", - } - }, -) - -AOT_USMP_CORSTONE300_RUNNER = AOTTestRunner( - makefile="corstone300", - prologue=""" - uart_init(); - """, - includes=["uart.h"], - pass_config={ - "relay.ext.cmsisnn.options": { - "mcpu": "cortex-m55", - }, - "tir.usmp.enable": True, - }, -) - -NP_TYPE_TO_C = { - "int8": "int8_t", - "uint8": "uint8_t", - "int16": "int16_t", - "uint16": "uint16_t", - "int32": "int32_t", - "uint32": "uint32_t", - "float32": "float", -} - - -def mangle_name(mod_name, name): - mod_name = mangle_module_name(mod_name) - return mod_name + "_" + name - - -def convert_to_relay( - tflite_model_buf, -): - """Convert a tflite model buffer in a Relay module""" - # TFLite.Model.Model has changed to TFLite.Model from 1.14 to 2.1 - try: - import tflite.Model - - tflite_model = tflite.Model.Model.GetRootAsModel(tflite_model_buf, 0) - except AttributeError: - import tflite - - tflite_model = tflite.Model.GetRootAsModel(tflite_model_buf, 0) - except ImportError: - raise ImportError("The tflite package must be installed") - - mod, params = relay.frontend.from_tflite(tflite_model) - mod["main"] = relay.build_module.bind_params_by_name(mod["main"], params) - return mod, params - - -def parametrize_aot_options(test): - """Parametrize over valid option combinations""" - - requires_arm_eabi = pytest.mark.skipif( - shutil.which("arm-none-eabi-gcc") is None, reason="ARM embedded toolchain unavailable" - ) - - interface_api = ["packed", "c"] - use_unpacked_api = [True, False] - test_runner = [AOT_DEFAULT_RUNNER, AOT_CORSTONE300_RUNNER] - - all_combinations = itertools.product(interface_api, use_unpacked_api, test_runner) - - # Filter out packed operators with c interface - valid_combinations = filter( - lambda parameters: not (parameters[0] == "c" and not parameters[1]), - all_combinations, - ) - - # Only use reference system for C interface and unpacked API calls - valid_combinations = filter( - lambda parameters: not ( - parameters[2] == AOT_CORSTONE300_RUNNER - and (parameters[0] == "packed" or not parameters[1]) - ), - valid_combinations, - ) - - # Skip reference system tests if running in i386 container - marked_combinations = map( - lambda parameters: pytest.param(*parameters, marks=[requires_arm_eabi]) - if parameters[2] == AOT_CORSTONE300_RUNNER - else parameters, - valid_combinations, - ) - - fn = pytest.mark.parametrize( - ["interface_api", "use_unpacked_api", "test_runner"], - marked_combinations, - )(test) - - return tvm.testing.skip_if_32bit(reason="Reference system unavailable in i386 container")(fn) - - -def subprocess_check_log_output(cmd, cwd, logfile): +def _subprocess_check_log_output(cmd, cwd, logfile): """ This method runs a process and logs the output to both a log file and stdout """ @@ -290,15 +180,21 @@ def subprocess_check_log_output(cmd, cwd, logfile): raise RuntimeError(f"Subprocess failed: {cmd}\nstdout:\n{stdout}") +def _mangle_name(mod_name, name): + mod_name = mangle_module_name(mod_name) + return mod_name + "_" + name + + # TODO: Move to linker script with list of symbols rather than coding into source -def emit_data_linkage(output_file, data_linkage): +def _emit_data_linkage(output_file, data_linkage): if data_linkage is not None: output_file.write( - f'__attribute__((section("{data_linkage.section}"), aligned({data_linkage.alignment}))) ' + f'__attribute__((section("{data_linkage.section}"), ' + f"aligned({data_linkage.alignment}))) " ) -def emit_main_prologue( +def _emit_main_prologue( main_file, custom_prologue, workspace_bytes, @@ -316,16 +212,14 @@ def emit_main_prologue( # Add TVM_RUNTIME_ALLOC_ALIGNMENT_BYTES because of memory alignment. workspace_define += " + TVM_RUNTIME_ALLOC_ALIGNMENT_BYTES)\n" main_file.write(workspace_define) - emit_data_linkage(main_file, data_linkage) + _emit_data_linkage(main_file, data_linkage) main_file.write("static uint8_t g_aot_memory[WORKSPACE_SIZE];\n") main_file.write("tvm_workspace_t app_workspace;\n") main_file.write( - """ - + """\n tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev, void** out_ptr) { return StackMemoryManager_Allocate(&app_workspace, num_bytes, out_ptr); } - tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) { return StackMemoryManager_Free(&app_workspace,ptr); } @@ -334,30 +228,24 @@ def emit_main_prologue( else: # An implementation is not needed for these if the stack allocator is not used main_file.write( - """ - + """\n tvm_crt_error_t TVMPlatformMemoryAllocate(size_t num_bytes, DLDevice dev, void** out_ptr) { return kTvmErrorFunctionCallNotImplemented; } - tvm_crt_error_t TVMPlatformMemoryFree(void* ptr, DLDevice dev) { return kTvmErrorFunctionCallNotImplemented; } - """ ) main_file.write( - """ - + """\n void TVMPlatformAbort(tvm_crt_error_t code) { exit(-1); } - void TVMLogf(const char* msg, ...) { va_list args; va_start(args, msg); vfprintf(stdout, msg, args); va_end(args); -} - +}\n TVM_DLL int TVMFuncRegisterGlobal(const char* name, TVMFunctionHandle f, int override) {} int main(){\n """ @@ -365,105 +253,105 @@ def emit_main_prologue( main_file.write(custom_prologue) -def emit_main_data(main_file, input_map, output_map, mod_name): +def _emit_main_data(main_file, input_map, output_map, mod_name): for key in input_map: sanitized_tensor_name = re.sub(r"\W", "_", key) main_file.write( - f'#include "{mangle_name(mod_name,"input_data")}_{sanitized_tensor_name}.h"\n' + f'#include "{_mangle_name(mod_name,"input_data")}_{sanitized_tensor_name}.h"\n' ) for key in output_map: sanitized_tensor_name = re.sub(r"\W", "_", key) main_file.write( - f'#include "{mangle_name(mod_name,"expected_output_data")}_{sanitized_tensor_name}.h"\n' - f'#include "{mangle_name(mod_name,"output_data")}_{sanitized_tensor_name}.h"\n' + f'#include "{_mangle_name(mod_name,"expected_output_data")}_' + f'{sanitized_tensor_name}.h"\n' + f'#include "{_mangle_name(mod_name,"output_data")}_' + f'{sanitized_tensor_name}.h"\n' ) -def emit_main_device_structs(main_file, devices, mod_name): +def _emit_main_device_structs(main_file, devices, mod_name): if devices: main_file.write( - f"struct {mangle_name(mod_name, 'devices')} {mangle_name(mod_name, 'devices')} = {{" + f"struct {_mangle_name(mod_name, 'devices')} {_mangle_name(mod_name, 'devices')} = {{" ) for device in devices: main_file.write(f"\t.{device} = {device},\n") main_file.write("};\n") -def emit_main_workspace_pool_structs(main_file, workspace_pool_names, mod_name): +def _emit_main_workspace_pool_structs(main_file, workspace_pool_names, mod_name): if workspace_pool_names and len(workspace_pool_names) > 0: main_file.write( - f"struct {mangle_name(mod_name, 'workspace_pools')} {mangle_name(mod_name, 'workspace_pools')} = {{" + f"struct {_mangle_name(mod_name, 'workspace_pools')} " + f"{_mangle_name(mod_name, 'workspace_pools')} = {{" ) for workspace_pool_name in workspace_pool_names: main_file.write(f"\t.{workspace_pool_name} = {workspace_pool_name},\n") main_file.write("};\n") -def emit_main_data_structs(main_file, input_map, output_map, mod_name): +def _emit_main_data_structs(main_file, input_map, output_map, mod_name): main_file.write( - f"struct {mangle_name(mod_name, 'inputs')} {mangle_name(mod_name, 'inputs')} = {{" + f"struct {_mangle_name(mod_name, 'inputs')} {_mangle_name(mod_name, 'inputs')} = {{" ) for key in input_map: sanitized_tensor_name = re.sub(r"\W", "_", key) main_file.write( - f"\t.{sanitized_tensor_name} = {mangle_name(mod_name, 'input_data')}_{sanitized_tensor_name},\n" + f"\t.{sanitized_tensor_name} = " + f"{_mangle_name(mod_name, 'input_data')}_{sanitized_tensor_name},\n" ) main_file.write("};\n") main_file.write( - f"struct {mangle_name(mod_name, 'outputs')} {mangle_name(mod_name, 'outputs')} = {{" + f"struct {_mangle_name(mod_name, 'outputs')} {_mangle_name(mod_name, 'outputs')} = {{" ) for key in output_map: sanitized_tensor_name = re.sub(r"\W", "_", key) main_file.write( - f"\t.{sanitized_tensor_name} = {mangle_name(mod_name, 'output_data')}_{sanitized_tensor_name},\n" + f"\t.{sanitized_tensor_name} = {_mangle_name(mod_name, 'output_data')}_" + f"{sanitized_tensor_name},\n" ) main_file.write("};\n") -def emit_main_data_setup(main_file, input_map, output_map, mod_name): +def _emit_main_data_setup(main_file, input_map, output_map, mod_name): num_outputs = len(output_map) num_inputs = len(input_map) - - main_file.write(f'void* {mangle_name(mod_name,"inputs")}[{num_inputs}] = {{ ') + main_file.write(f'void* {_mangle_name(mod_name,"inputs")}[{num_inputs}] = {{ ') for key in input_map: sanitized_tensor_name = re.sub(r"\W", "_", key) - main_file.write(f'{mangle_name(mod_name,"input_data")}_{sanitized_tensor_name}, ') + main_file.write(f'{_mangle_name(mod_name,"input_data")}_{sanitized_tensor_name}, ') main_file.write("};\n") - - main_file.write(f'void* {mangle_name(mod_name,"outputs")}[{num_outputs}] = {{ ') + main_file.write(f'void* {_mangle_name(mod_name,"outputs")}[{num_outputs}] = {{ ') for key in output_map: sanitized_tensor_name = re.sub(r"\W", "_", key) - main_file.write(f'{mangle_name(mod_name, "output_data")}_{sanitized_tensor_name}, ') + main_file.write(f'{_mangle_name(mod_name, "output_data")}_{sanitized_tensor_name}, ') main_file.write("};\n") -def emit_main_c_interface_call( +def _emit_main_c_interface_call( main_file, devices, workspace_pool_names, mod_name, use_workspace_io ): sub_strings = list() - sub_strings.append(f'{mangle_name(mod_name,"run")}(') + sub_strings.append(f'{_mangle_name(mod_name,"run")}(') if not use_workspace_io: - sub_strings.append(f'&{mangle_name(mod_name,"inputs")}, ') - sub_strings.append(f'&{mangle_name(mod_name,"outputs")}, ') + sub_strings.append(f'&{_mangle_name(mod_name,"inputs")}, ') + sub_strings.append(f'&{_mangle_name(mod_name,"outputs")}, ') if workspace_pool_names: - sub_strings.append(f'&{mangle_name(mod_name,"workspace_pools")}, ') + sub_strings.append(f'&{_mangle_name(mod_name,"workspace_pools")}, ') if devices: - sub_strings.append(f'&{mangle_name(mod_name,"devices")}, ') + sub_strings.append(f'&{_mangle_name(mod_name,"devices")}, ') # Removing the last two characters that is a comma and a space sub_strings[-1] = sub_strings[-1][:-2] # Adding brackets and newline instead sub_strings[-1] = sub_strings[-1] + ");\n" - main_file_string = "" - for sub_string in sub_strings: - main_file_string += sub_string - + main_file_string = "".join(sub_strings) main_file.write(main_file_string) -def emit_main_fake_packed_values(main_file): +def _emit_main_fake_packed_values(main_file): main_file.write( """ static DLDevice fake_device = {kDLCPU, 0}; @@ -473,10 +361,10 @@ def emit_main_fake_packed_values(main_file): ) -def emit_main_packed_call(main_file, input_map, output_list, mod_name): - tensors_name = mangle_name(mod_name, "tensors") - values_name = mangle_name(mod_name, "values") - typeids_name = mangle_name(mod_name, "typeids") +def _emit_main_packed_call(main_file, input_map, output_list, mod_name): + tensors_name = _mangle_name(mod_name, "tensors") + values_name = _mangle_name(mod_name, "values") + typeids_name = _mangle_name(mod_name, "typeids") def fake_tensor(source, source_index, packed_index): main_file.write( @@ -503,20 +391,20 @@ def fake_tensor(source, source_index, packed_index): ) for i in range(0, num_inputs): - fake_tensor(mangle_name(mod_name, "inputs"), i, i) + fake_tensor(_mangle_name(mod_name, "inputs"), i, i) for i in range(0, num_outputs): - fake_tensor(mangle_name(mod_name, "outputs"), i, i + num_inputs) + fake_tensor(_mangle_name(mod_name, "outputs"), i, i + num_inputs) main_file.write( - f'{mangle_name(mod_name, "run")}({values_name}, {typeids_name}, 0, NULL, 0, NULL);\n' + f'{_mangle_name(mod_name, "run")}({values_name}, {typeids_name}, 0, NULL, 0, NULL);\n' ) main_file.write("\n") -def emit_main_compare(main_file, outputs, output_tolerance, mod_name, use_interface_c=False): +def _emit_main_compare(main_file, outputs, output_tolerance, mod_name, use_interface_c=False): for key in outputs: sanitized_tensor_name = re.sub(r"\W", "_", key) - expected_data_name = mangle_name(mod_name, f"expected_output_data_{sanitized_tensor_name}") + expected_data_name = _mangle_name(mod_name, f"expected_output_data_{sanitized_tensor_name}") is_float_dtype = outputs[key].dtype == "float32" comparison_function = "abs" @@ -526,40 +414,39 @@ def emit_main_compare(main_file, outputs, output_tolerance, mod_name, use_interf tolerance = output_tolerance or 0.001 data_length_var_name = ( - mangle_name(mod_name, f"output_data_{sanitized_tensor_name}") + "_len" + _mangle_name(mod_name, f"output_data_{sanitized_tensor_name}") + "_len" ) if use_interface_c: c_type = NP_TYPE_TO_C[str(outputs[key].dtype)] - actual_data_name = f"(({c_type}*)" + mangle_name( + actual_data_name = f"(({c_type}*)" + _mangle_name( mod_name, f"outputs.{sanitized_tensor_name})" ) else: - actual_data_name = mangle_name(mod_name, f"output_data_{sanitized_tensor_name}") + actual_data_name = _mangle_name(mod_name, f"output_data_{sanitized_tensor_name}") main_file.write( - f""" - for (int i = 0; i<{data_length_var_name}; i++) {{ - if ({comparison_function}({actual_data_name}[i]-{expected_data_name}[i]) > {tolerance}) {{ - printf("{AOT_FAILURE_TOKEN}\\n"); - return -1; - }} - }} - """ + f"for (int i = 0; i<{data_length_var_name}; i++) {{\n" + f"\tif ({comparison_function}({actual_data_name}[i]-" + f"{expected_data_name}[i]) > {tolerance}) {{\n" + f'\t\tprintf("{AOT_FAILURE_TOKEN}\\n");\n' + f"\t\treturn -1;\n" + f"\t}}\n" + f"}}" ) -def emit_main_init_memory_manager(main_file): +def _emit_main_init_memory_manager(main_file): main_file.write("StackMemoryManager_Init(&app_workspace, g_aot_memory, WORKSPACE_SIZE);") main_file.write("\n") -def emit_main_epilogue(main_file, custom_epilogue): +def _emit_main_epilogue(main_file, custom_epilogue): main_file.write(custom_epilogue) main_file.write(f'printf("{AOT_SUCCESS_TOKEN}\\n");') main_file.write("return 0;") main_file.write("}\n") -def emit_main_common_includes(main_file, custom_includes): +def _emit_main_common_includes(main_file, custom_includes): main_file.write("#include \n") main_file.write("#include \n") main_file.write("#include \n") @@ -570,11 +457,11 @@ def emit_main_common_includes(main_file, custom_includes): main_file.write(f'#include "{include}"\n') -def emit_main_micro_include(main_file, mod_name): +def _emit_main_micro_include(main_file, mod_name): main_file.write(f"#include <{mangle_module_name(mod_name)}.h>\n") -def create_main( +def _create_main( test_name, compiled_models, output_path, @@ -591,17 +478,17 @@ def create_main( # create header file raw_path = file_path.with_suffix(".c").resolve() with open(raw_path, "w") as main_file: - emit_main_common_includes(main_file, custom_includes) + _emit_main_common_includes(main_file, custom_includes) if interface_api == "c": for compiled_model in compiled_models: model = compiled_model.model - emit_main_micro_include(main_file, model.name) + _emit_main_micro_include(main_file, model.name) for compiled_model in compiled_models: model = compiled_model.model - emit_main_data(main_file, model.inputs, model.outputs, model.name) + _emit_main_data(main_file, model.inputs, model.outputs, model.name) - emit_main_prologue( + _emit_main_prologue( main_file, custom_prologue, workspace_bytes, @@ -611,7 +498,7 @@ def create_main( use_stack_allocator, ) if use_stack_allocator: - emit_main_init_memory_manager(main_file) + _emit_main_init_memory_manager(main_file) if interface_api == "c": for compiled_model in compiled_models: @@ -627,32 +514,33 @@ def create_main( for allocated_pool in dict(executor_codegen_metadata.pool_inputs).values() if not allocated_pool.pool_info.is_internal ] - emit_main_device_structs(main_file, devices, model.name) + _emit_main_device_structs(main_file, devices, model.name) if not use_workspace_io: - emit_main_workspace_pool_structs(main_file, workspace_pool_names, model.name) - emit_main_data_structs(main_file, model.inputs, model.outputs, model.name) - emit_main_c_interface_call( + _emit_main_workspace_pool_structs(main_file, workspace_pool_names, model.name) + _emit_main_data_structs(main_file, model.inputs, model.outputs, model.name) + _emit_main_c_interface_call( main_file, devices, workspace_pool_names, model.name, use_workspace_io ) else: - emit_main_fake_packed_values(main_file) + _emit_main_fake_packed_values(main_file) for compiled_model in compiled_models: model = compiled_model.model - emit_main_data_setup(main_file, model.inputs, model.outputs, model.name) - emit_main_packed_call(main_file, model.inputs, model.outputs, model.name) + _emit_main_data_setup(main_file, model.inputs, model.outputs, model.name) + _emit_main_packed_call(main_file, model.inputs, model.outputs, model.name) for compiled_model in compiled_models: model = compiled_model.model - emit_main_compare( + _emit_main_compare( main_file, model.outputs, model.output_tolerance, model.name, interface_api == "c" ) - emit_main_epilogue(main_file, custom_epilogue) + _emit_main_epilogue(main_file, custom_epilogue) -def create_header_file(tensor_name, npy_data, output_path, data_linkage): +def _create_header_file(tensor_name, npy_data, output_path, data_linkage): """ This method generates a header file containing the data contained in the numpy array provided. - It is used to capture the tensor data (for both inputs and expected outputs) to be bundled into the standalone application. + It is used to capture the tensor data (for both inputs and expected outputs) + to be bundled into the standalone application. """ file_path = pathlib.Path(f"{output_path}/" + tensor_name).resolve() # create header file @@ -663,7 +551,7 @@ def create_header_file(tensor_name, npy_data, output_path, data_linkage): header_file.write("#include \n") header_file.write(f"const size_t {tensor_name}_len = {npy_data.size};\n") - emit_data_linkage(header_file, data_linkage) + _emit_data_linkage(header_file, data_linkage) header_file.write(f"{NP_TYPE_TO_C[str(npy_data.dtype)]} {tensor_name}[] =") @@ -673,6 +561,27 @@ def create_header_file(tensor_name, npy_data, output_path, data_linkage): header_file.write("};\n\n") +def convert_to_relay( + tflite_model_buf, +): + """Convert a tflite model buffer in a Relay module""" + # TFLite.Model.Model has changed to TFLite.Model from 1.14 to 2.1 + try: + import tflite.Model # pylint: disable=import-outside-toplevel + + tflite_model = tflite.Model.Model.GetRootAsModel(tflite_model_buf, 0) + except AttributeError: + import tflite # pylint: disable=import-outside-toplevel + + tflite_model = tflite.Model.GetRootAsModel(tflite_model_buf, 0) + except ImportError: + raise ImportError("The tflite package must be installed") + + mod, params = relay.frontend.from_tflite(tflite_model) + mod["main"] = relay.build_module.bind_params_by_name(mod["main"], params) + return mod, params + + def compile_models( models: Union[List[AOTTestModel], AOTTestModel], interface_api: str, @@ -683,6 +592,7 @@ def compile_models( use_runtime_executor: bool = True, target: tvm.target.Target = tvm.target.Target("c"), workspace_memory_pools=None, + schedule_name: str = None, ) -> List[AOTCompiledTestModel]: """ This method generates runtime.Modules for the tests @@ -708,31 +618,62 @@ def compile_models( compiled_mods = list() for model in models: - with tvm.transform.PassContext(opt_level=3, config=config): - # TODO(Mousius) - Remove once executor/runtime are fully removed from Target - if use_runtime_executor: - executor_factory = tvm.relay.build( - model.module, - target, - executor=executor, - runtime=runtime, - workspace_memory_pools=workspace_memory_pools, - params=model.params, - mod_name=model.name, - ) - compiled_mods.append( - AOTCompiledTestModel(model=model, executor_factory=executor_factory) - ) - else: - executor_factory = tvm.relay.build( - model.module, - tvm.target.Target(target, host=target), - params=model.params, - mod_name=model.name, - ) - compiled_mods.append( - AOTCompiledTestModel(model=model, executor_factory=executor_factory) - ) + if schedule_name: + # Testing with deterministic schedule + task_list = autotvm.task.extract_from_program( + model.module, target=target, params=model.params + ) + with tvm.autotvm.apply_fixed_config(task_list, schedule_name): + with tvm.transform.PassContext(opt_level=3, config=config): + if use_runtime_executor: + executor_factory = tvm.relay.build( + model.module, + target, + executor=executor, + runtime=runtime, + workspace_memory_pools=workspace_memory_pools, + params=model.params, + mod_name=model.name, + ) + compiled_mods.append( + AOTCompiledTestModel(model=model, executor_factory=executor_factory) + ) + else: + executor_factory = tvm.relay.build( + model.module, + tvm.target.Target(target, host=target), + params=model.params, + mod_name=model.name, + ) + compiled_mods.append( + AOTCompiledTestModel(model=model, executor_factory=executor_factory) + ) + else: + with tvm.transform.PassContext(opt_level=3, config=config): + # TODO(Mousius) - Remove once executor/runtime are fully removed from Target + if use_runtime_executor: + executor_factory = tvm.relay.build( + model.module, + target, + executor=executor, + runtime=runtime, + workspace_memory_pools=workspace_memory_pools, + params=model.params, + mod_name=model.name, + ) + compiled_mods.append( + AOTCompiledTestModel(model=model, executor_factory=executor_factory) + ) + else: + executor_factory = tvm.relay.build( + model.module, + tvm.target.Target(target, host=target), + params=model.params, + mod_name=model.name, + ) + compiled_mods.append( + AOTCompiledTestModel(model=model, executor_factory=executor_factory) + ) return compiled_mods @@ -788,8 +729,8 @@ def run_and_check_body(base_path): workspace_bytes += model.extra_memory_in_bytes for key in model.inputs: sanitized_tensor_name = re.sub(r"\W", "_", key) - create_header_file( - f'{mangle_name(model.name, "input_data")}_{sanitized_tensor_name}', + _create_header_file( + f'{_mangle_name(model.name, "input_data")}_{sanitized_tensor_name}', model.inputs[key], include_path, data_linkage, @@ -797,14 +738,14 @@ def run_and_check_body(base_path): for key in model.outputs: sanitized_tensor_name = re.sub(r"\W", "_", key) - create_header_file( - f'{mangle_name(model.name, "output_data")}_{sanitized_tensor_name}', + _create_header_file( + f'{_mangle_name(model.name, "output_data")}_{sanitized_tensor_name}', np.zeros(model.outputs[key].shape, model.outputs[key].dtype), include_path, data_linkage, ) - create_header_file( - f'{mangle_name(model.name, "expected_output_data")}_{sanitized_tensor_name}', + _create_header_file( + f'{_mangle_name(model.name, "expected_output_data")}_{sanitized_tensor_name}', model.outputs[key], include_path, data_linkage, @@ -814,7 +755,7 @@ def run_and_check_body(base_path): # We only need the stack allocator if USMP is not used use_stack_allocator = not use_usmp - create_main( + _create_main( "test.c", models, build_path, @@ -830,8 +771,9 @@ def run_and_check_body(base_path): # Verify that compiles fine file_dir = os.path.dirname(os.path.abspath(__file__)) + makefile_dir = os.path.join(file_dir, "../../../tests/python/relay/aot") codegen_path = os.path.join(base_path, "codegen") - makefile = os.path.join(file_dir, f"{runner.makefile}.mk") + makefile = os.path.join(makefile_dir, f"{runner.makefile}.mk") fvp_dir = "/opt/arm/FVP_Corstone_SSE-300/models/Linux64_GCC-6.4/" # TODO(@grant-arm): Remove once ci_cpu docker image has been updated to FVP_Corstone_SSE if not os.path.isdir(fvp_dir): @@ -842,8 +784,8 @@ def run_and_check_body(base_path): make_command = ( f"make -f {makefile} build_dir={build_path}" + f" CFLAGS='{cflags}'" - + f" TVM_ROOT={file_dir}/../../../.." - + f" AOT_TEST_ROOT={file_dir}" + + f" TVM_ROOT={file_dir}/../../.." + + f" AOT_TEST_ROOT={makefile_dir}" + f" CODEGEN_ROOT={codegen_path}" + f" STANDALONE_CRT_DIR={tvm.micro.get_standalone_crt_dir()}" + f" FVP_DIR={fvp_dir}" @@ -854,7 +796,7 @@ def run_and_check_body(base_path): compile_command = f"{make_command} aot_test_runner" if verbose: print("Compile command:\n", compile_command) - subprocess_check_log_output(compile_command, ".", compile_log_path) + _subprocess_check_log_output(compile_command, ".", compile_log_path) # Verify that runs fine run_log_path = os.path.join(build_path, "test_run.log") @@ -865,11 +807,11 @@ def run_and_check_body(base_path): # TODO(lhutton1) This is a quick and dirty work around to help temporarily reduce # the flakyness of the tests. Will remove once #10300 and #10314 are resolved. try: - subprocess_check_log_output(run_command, build_path, run_log_path) + _subprocess_check_log_output(run_command, build_path, run_log_path) except RuntimeError as err: print("Failed to run the module, having a second attempt...", file=sys.stderr) print(err, file=sys.stderr) - subprocess_check_log_output(run_command, build_path, run_log_path) + _subprocess_check_log_output(run_command, build_path, run_log_path) with open(run_log_path) as run_log: assert AOT_SUCCESS_TOKEN in run_log.read() @@ -895,6 +837,7 @@ def compile_and_run( target_opts: Dict = None, test_dir: str = None, verbose: bool = False, + schedule_name: str = None, ): """This is a wrapper API to compile and run models as test for AoT @@ -919,6 +862,7 @@ def compile_and_run( pass_config=runner.pass_config, use_runtime_executor=use_runtime_executor, target=tvm.target.Target(target), + schedule_name=schedule_name, ) run_and_check( diff --git a/tests/micro/zephyr/test_utils.py b/tests/micro/zephyr/test_utils.py index e0aad7c3c6d5..4fd3e39fd1c0 100644 --- a/tests/micro/zephyr/test_utils.py +++ b/tests/micro/zephyr/test_utils.py @@ -32,7 +32,7 @@ import tvm.micro from tvm.micro import export_model_library_format from tvm.micro.model_library_format import generate_c_interface_header -from tvm.micro.testing import ( +from tvm.micro.testing.utils import ( mlf_extract_workspace_size_bytes, aot_transport_init_wait, aot_transport_find_message, diff --git a/tests/micro/zephyr/test_zephyr.py b/tests/micro/zephyr/test_zephyr.py index 1582d7e4a5fe..49e5e2757b20 100644 --- a/tests/micro/zephyr/test_zephyr.py +++ b/tests/micro/zephyr/test_zephyr.py @@ -30,7 +30,7 @@ from tvm.relay.backend import Executor, Runtime from tvm.relay.testing import byoc from tvm.contrib import utils -from tvm.micro.testing import check_tune_log +from tvm.micro.testing.utils import check_tune_log import test_utils diff --git a/tests/micro/zephyr/test_zephyr_aot.py b/tests/micro/zephyr/test_zephyr_aot.py index 87c7dc92fbda..6b355f28de4b 100644 --- a/tests/micro/zephyr/test_zephyr_aot.py +++ b/tests/micro/zephyr/test_zephyr_aot.py @@ -33,7 +33,6 @@ from tvm.relay.backend import Executor, Runtime from tvm.contrib.download import download_testdata -from tvm.micro.testing import aot_transport_init_wait, aot_transport_find_message import test_utils diff --git a/tests/python/contrib/test_cmsisnn/test_binary_ops.py b/tests/python/contrib/test_cmsisnn/test_binary_ops.py index 028ab406243f..7846bba1e089 100644 --- a/tests/python/contrib/test_cmsisnn/test_binary_ops.py +++ b/tests/python/contrib/test_cmsisnn/test_binary_ops.py @@ -36,12 +36,10 @@ assert_partitioned_function, assert_no_external_function, ) -from tests.python.relay.aot.aot_test_utils import ( - AOTTestModel, +from tvm.testing.aot import generate_ref_data, AOTTestModel, compile_and_run +from tvm.micro.testing.aot_test_utils import ( AOT_CORSTONE300_RUNNER, AOT_USMP_CORSTONE300_RUNNER, - generate_ref_data, - compile_and_run, ) diff --git a/tests/python/contrib/test_cmsisnn/test_conv2d.py b/tests/python/contrib/test_cmsisnn/test_conv2d.py index 47245f60e15e..1cdf98510148 100644 --- a/tests/python/contrib/test_cmsisnn/test_conv2d.py +++ b/tests/python/contrib/test_cmsisnn/test_conv2d.py @@ -23,15 +23,9 @@ from tvm import relay from tvm.relay.op.contrib import cmsisnn +from tvm.testing.aot import generate_ref_data, AOTTestModel, compile_and_run -from tests.python.relay.aot.aot_test_utils import ( - AOTTestModel, - AOT_CORSTONE300_RUNNER, - AOT_USMP_CORSTONE300_RUNNER, - AOT_DEFAULT_RUNNER, - generate_ref_data, - compile_and_run, -) +from tvm.micro.testing.aot_test_utils import AOT_USMP_CORSTONE300_RUNNER from utils import ( skip_if_no_reference_system, make_module, diff --git a/tests/python/contrib/test_cmsisnn/test_fully_connected.py b/tests/python/contrib/test_cmsisnn/test_fully_connected.py index ec2e9bbdcca7..111d3b2edac1 100644 --- a/tests/python/contrib/test_cmsisnn/test_fully_connected.py +++ b/tests/python/contrib/test_cmsisnn/test_fully_connected.py @@ -23,14 +23,9 @@ from tvm import relay from tvm.relay.op.contrib import cmsisnn - -from tests.python.relay.aot.aot_test_utils import ( - AOTTestModel, - AOT_CORSTONE300_RUNNER, +from tvm.testing.aot import generate_ref_data, AOTTestModel, compile_and_run +from tvm.micro.testing.aot_test_utils import ( AOT_USMP_CORSTONE300_RUNNER, - AOT_DEFAULT_RUNNER, - generate_ref_data, - compile_and_run, ) from utils import ( skip_if_no_reference_system, diff --git a/tests/python/contrib/test_cmsisnn/test_invalid_graphs.py b/tests/python/contrib/test_cmsisnn/test_invalid_graphs.py index 7808fbf7752f..d0a8547d32ac 100644 --- a/tests/python/contrib/test_cmsisnn/test_invalid_graphs.py +++ b/tests/python/contrib/test_cmsisnn/test_invalid_graphs.py @@ -22,12 +22,9 @@ import tvm from tvm import relay - -from tests.python.relay.aot.aot_test_utils import ( - AOTTestModel, +from tvm.testing.aot import AOTTestModel, compile_and_run, generate_ref_data +from tvm.micro.testing.aot_test_utils import ( AOT_USMP_CORSTONE300_RUNNER, - generate_ref_data, - compile_and_run, ) from utils import ( skip_if_no_reference_system, diff --git a/tests/python/contrib/test_cmsisnn/test_networks.py b/tests/python/contrib/test_cmsisnn/test_networks.py index a6e77515859e..fefce9e86c2d 100644 --- a/tests/python/contrib/test_cmsisnn/test_networks.py +++ b/tests/python/contrib/test_cmsisnn/test_networks.py @@ -28,16 +28,14 @@ from tvm.relay.op.contrib import cmsisnn from utils import skip_if_no_reference_system, get_range_for_dtype_str -from tests.python.relay.aot.aot_test_utils import ( - AOTTestModel, +from tvm.testing.aot import AOTTestModel, compile_and_run, generate_ref_data +from tvm.micro.testing.aot_test_utils import ( AOT_CORSTONE300_RUNNER, AOT_USMP_CORSTONE300_RUNNER, - generate_ref_data, - compile_and_run, ) -def convert_to_relay( +def _convert_to_relay( tflite_model_buf, input_data, input_node, @@ -95,7 +93,7 @@ def test_cnn_small(test_runner): rng = np.random.default_rng(12345) input_data = rng.integers(in_min, high=in_max, size=input_shape, dtype=dtype) - orig_mod, params = convert_to_relay(tflite_model_buf, input_data, "input") + orig_mod, params = _convert_to_relay(tflite_model_buf, input_data, "input") cmsisnn_mod = cmsisnn.partition_for_cmsisnn(orig_mod, params) # validate CMSIS-NN output against CPU output diff --git a/tests/python/contrib/test_cmsisnn/test_pooling.py b/tests/python/contrib/test_cmsisnn/test_pooling.py index cca1288ac2a0..a2650bb8d028 100644 --- a/tests/python/contrib/test_cmsisnn/test_pooling.py +++ b/tests/python/contrib/test_cmsisnn/test_pooling.py @@ -23,15 +23,8 @@ from tvm import relay from tvm.relay.op.contrib import cmsisnn - -from tests.python.relay.aot.aot_test_utils import ( - AOTTestModel, - AOT_CORSTONE300_RUNNER, - AOT_USMP_CORSTONE300_RUNNER, - AOT_DEFAULT_RUNNER, - generate_ref_data, - compile_and_run, -) +from tvm.testing.aot import AOTTestModel, compile_and_run, generate_ref_data +from tvm.micro.testing.aot_test_utils import AOT_USMP_CORSTONE300_RUNNER from utils import ( skip_if_no_reference_system, make_module, diff --git a/tests/python/contrib/test_cmsisnn/test_softmax.py b/tests/python/contrib/test_cmsisnn/test_softmax.py index 6eac76d841b4..5a44a7865e66 100644 --- a/tests/python/contrib/test_cmsisnn/test_softmax.py +++ b/tests/python/contrib/test_cmsisnn/test_softmax.py @@ -34,13 +34,8 @@ assert_partitioned_function, assert_no_external_function, ) -from tests.python.relay.aot.aot_test_utils import ( - AOTTestModel, - AOT_CORSTONE300_RUNNER, - AOT_USMP_CORSTONE300_RUNNER, - generate_ref_data, - compile_and_run, -) +from tvm.testing.aot import AOTTestModel, compile_and_run, generate_ref_data +from tvm.micro.testing.aot_test_utils import AOT_USMP_CORSTONE300_RUNNER def make_model( diff --git a/tests/python/contrib/test_ethosu/infra.py b/tests/python/contrib/test_ethosu/infra.py index 0c42b024f274..20bd12945f8f 100644 --- a/tests/python/contrib/test_ethosu/infra.py +++ b/tests/python/contrib/test_ethosu/infra.py @@ -47,7 +47,7 @@ import tvm.relay.testing.tf as tf_testing from tvm.relay.op.contrib.ethosu import partition_for_ethosu -from tests.python.relay.aot.aot_test_utils import ( +from tvm.testing.aot import ( AOTCompiledTestModel, AOTDataLinkage, AOTTestModel, diff --git a/tests/python/contrib/test_ethosu/test_codegen.py b/tests/python/contrib/test_ethosu/test_codegen.py index 4268392f1b78..7ea813762796 100644 --- a/tests/python/contrib/test_ethosu/test_codegen.py +++ b/tests/python/contrib/test_ethosu/test_codegen.py @@ -29,7 +29,7 @@ from tvm.relay.backend.contrib.ethosu import util from tvm.relay.op.contrib.ethosu import partition_for_ethosu -from tests.python.relay.aot.aot_test_utils import generate_ref_data +from tvm.testing.aot import generate_ref_data from . import infra diff --git a/tests/python/contrib/test_ethosu/test_networks.py b/tests/python/contrib/test_ethosu/test_networks.py index f64263ca0623..b91168b7bbe6 100644 --- a/tests/python/contrib/test_ethosu/test_networks.py +++ b/tests/python/contrib/test_ethosu/test_networks.py @@ -24,7 +24,7 @@ from tvm.relay.op.contrib.ethosu import partition_for_ethosu from tvm.micro import model_library_format as mlf -from tests.python.relay.aot.aot_test_utils import convert_to_relay +from tvm.testing.aot import convert_to_relay from . import infra diff --git a/tests/python/integration/test_arm_mprofile_dsp.py b/tests/python/integration/test_arm_mprofile_dsp.py index 484c19fa222c..7628755af4ac 100644 --- a/tests/python/integration/test_arm_mprofile_dsp.py +++ b/tests/python/integration/test_arm_mprofile_dsp.py @@ -20,12 +20,8 @@ import tvm import tvm.testing from tvm import relay -from tests.python.relay.aot.aot_test_utils import ( - AOTTestModel, - AOT_CORSTONE300_RUNNER, - generate_ref_data, - compile_and_run, -) +from tvm.testing.aot import AOTTestModel, compile_and_run, generate_ref_data +from tvm.micro.testing.aot_test_utils import AOT_CORSTONE300_RUNNER @tvm.testing.requires_corstone300 diff --git a/tests/python/relay/aot/test_c_device_api.py b/tests/python/relay/aot/test_c_device_api.py index f9fa0c6eadbb..3c7db62890f5 100644 --- a/tests/python/relay/aot/test_c_device_api.py +++ b/tests/python/relay/aot/test_c_device_api.py @@ -24,12 +24,8 @@ from tvm import relay from tvm.ir.module import IRModule -from aot_test_utils import ( - AOT_DEFAULT_RUNNER, - AOTTestModel, - generate_ref_data, - compile_models, -) +from tvm.testing.aot import AOTTestModel, generate_ref_data, compile_models +from tvm.micro.testing.aot_test_utils import AOT_DEFAULT_RUNNER @pytest.fixture diff --git a/tests/python/relay/aot/test_cpp_aot.py b/tests/python/relay/aot/test_cpp_aot.py index cdcc61c33ac7..4a12678a79d9 100644 --- a/tests/python/relay/aot/test_cpp_aot.py +++ b/tests/python/relay/aot/test_cpp_aot.py @@ -27,7 +27,8 @@ from tvm import IRModule from tvm import relay from tvm.relay import backend, testing -from aot_test_utils import AOT_DEFAULT_RUNNER, AOTTestModel, generate_ref_data, compile_and_run +from tvm.testing.aot import generate_ref_data +from tvm.micro.testing.aot_test_utils import AOT_DEFAULT_RUNNER def test_error_c_interface(): diff --git a/tests/python/relay/aot/test_crt_aot.py b/tests/python/relay/aot/test_crt_aot.py index 2991cc01fc92..d1d80d434b6a 100644 --- a/tests/python/relay/aot/test_crt_aot.py +++ b/tests/python/relay/aot/test_crt_aot.py @@ -37,16 +37,14 @@ from tvm.micro import model_library_format as mlf from tvm.micro import export_model_library_format from tvm.ir.instrument import pass_instrument -from aot_test_utils import ( +from tvm.testing.aot import ( AOTTestModel, - AOT_DEFAULT_RUNNER, generate_ref_data, - convert_to_relay, compile_and_run, compile_models, - parametrize_aot_options, create_relay_module_and_inputs_from_tflite_file, ) +from tvm.micro.testing.aot_test_utils import AOT_DEFAULT_RUNNER, parametrize_aot_options def test_error_c_interface_with_packed_api(): diff --git a/tests/python/relay/aot/test_crt_aot_usmp.py b/tests/python/relay/aot/test_crt_aot_usmp.py index 650cb4526f09..60b46d96b555 100644 --- a/tests/python/relay/aot/test_crt_aot_usmp.py +++ b/tests/python/relay/aot/test_crt_aot_usmp.py @@ -32,14 +32,13 @@ from tvm.relay.backend import Executor, Runtime from tvm import WorkspaceMemoryPools, PoolInfo from tvm.micro import model_library_format as mlf -from aot_test_utils import ( +from tvm.micro.testing.aot_test_utils import parametrize_aot_options +from tvm.testing.aot import ( AOTTestModel, AOTTestRunner, generate_ref_data, - convert_to_relay, compile_and_run, compile_models, - parametrize_aot_options, run_and_check, create_relay_module_and_inputs_from_tflite_file, ) diff --git a/tests/python/relay/strategy/arm_cpu/test_conv2d_nchw.py b/tests/python/relay/strategy/arm_cpu/test_conv2d_nchw.py new file mode 100644 index 000000000000..e88210a59e77 --- /dev/null +++ b/tests/python/relay/strategy/arm_cpu/test_conv2d_nchw.py @@ -0,0 +1,110 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import sys +import numpy as np +import pytest +import tvm +import tvm.testing +from tvm import relay +from tvm.testing.aot import AOTTestModel, compile_and_run, generate_ref_data +from tvm.micro.testing.aot_test_utils import ( + AOT_CORSTONE300_RUNNER, +) + + +class BasicConv2dTests: + @tvm.testing.requires_corstone300 + def test_conv2d( + self, + data_shape, + kernel_size, + kernel_layout, + num_filter, + strides, + padding, + dilation, + dtype, + schedule_name, + ): + """Test a subgraph with a single conv2d_nchw operator.""" + ishape = data_shape + wshape = (num_filter, data_shape[1], *kernel_size) + weight_data = np.random.randint(low=-10, high=10, size=wshape, dtype=dtype) + + input0 = relay.var("input", relay.TensorType(ishape, dtype)) + weight0 = relay.const(weight_data) + out0 = relay.op.nn.conv2d( + input0, + weight0, + kernel_size=kernel_size, + strides=strides, + padding=padding, + dilation=(dilation, dilation), + data_layout="NCHW", + kernel_layout="OIHW", + out_dtype="int32", + out_layout="NCHW", + ) + ref_mod = tvm.IRModule.from_expr(relay.Function([input0], out0)) + + input1 = relay.var("input", relay.TensorType(ishape, dtype)) + weight1 = relay.const(weight_data) + + out1 = relay.op.nn.conv2d( + input1, + weight1, + kernel_size=kernel_size, + strides=strides, + padding=padding, + dilation=(dilation, dilation), + data_layout="NCHW", + kernel_layout=kernel_layout, + out_dtype="int32", + out_layout="NCHW", + ) + mod = tvm.IRModule.from_expr(relay.Function([input1], out1)) + + inputs = {"input": np.random.randint(low=-128, high=127, size=ishape, dtype=dtype)} + output_list = generate_ref_data(ref_mod, inputs) + + compile_and_run( + AOTTestModel(module=mod, inputs=inputs, outputs=output_list), + runner=AOT_CORSTONE300_RUNNER, + interface_api="c", + use_unpacked_api=True, + target_opts={ + "-keys": "arm_cpu", + "-mcpu": "cortex-m7", + }, + schedule_name=schedule_name, + ) + + +class TestConv2d_OIHW_small_kernel(BasicConv2dTests): + """This test is for conv2d_nchw_spatial_pack.arm_cpu schedule.""" + + data_shape, kernel_size, num_filter, strides, padding, dilation, dtype = tvm.testing.parameters( + ((1, 16, 32, 32), (3, 3), 12, 1, 0, 1, "int8"), + ((1, 16, 32, 32), (3, 3), 12, 1, 0, 1, "int16"), + ((1, 32, 16, 16), (3, 3), 12, 1, 0, 1, "int16"), + ) + kernel_layout = tvm.testing.parameter("OIHW") + schedule_name = tvm.testing.parameter("conv2d_nchw_spatial_pack.arm_cpu") + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/tests/python/relay/strategy/arm_cpu/test_conv2d_nhwc.py b/tests/python/relay/strategy/arm_cpu/test_conv2d_nhwc.py new file mode 100644 index 000000000000..f56645d43672 --- /dev/null +++ b/tests/python/relay/strategy/arm_cpu/test_conv2d_nhwc.py @@ -0,0 +1,154 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import sys +import numpy as np +import pytest +import tvm +import tvm.testing +from tvm import relay +from tvm.testing.aot import AOTTestModel, compile_and_run, generate_ref_data +from tvm.micro.testing.aot_test_utils import AOT_CORSTONE300_RUNNER + + +class BasicConv2dTests: + @tvm.testing.requires_corstone300 + def test_conv2d( + self, + data_shape, + kernel_size, + kernel_layout, + num_filter, + strides, + padding, + dilation, + dtype, + schedule_name, + ): + """Test a subgraph with a single conv2d operator.""" + ishape = data_shape + wshape = (*kernel_size, data_shape[-1], num_filter) + + weight_data = np.random.randint(low=-10, high=10, size=wshape, dtype=dtype) + + input0 = relay.var("input", relay.TensorType(ishape, dtype)) + weight0 = relay.const(weight_data) + out0 = relay.op.nn.conv2d( + input0, + weight0, + kernel_size=kernel_size, + strides=strides, + padding=padding, + dilation=(dilation, dilation), + data_layout="NHWC", + kernel_layout="HWIO", + out_dtype="int32", + out_layout="NHWC", + ) + ref_mod = tvm.IRModule.from_expr(relay.Function([input0], out0)) + + input1 = relay.var("input", relay.TensorType(ishape, dtype)) + + if kernel_layout == "HWOI": + weight1 = relay.const(np.moveaxis(weight_data, 2, -1)) + elif kernel_layout == "HWIO": + weight1 = relay.const(weight_data) + + out1 = relay.op.nn.conv2d( + input1, + weight1, + kernel_size=kernel_size, + strides=strides, + padding=padding, + dilation=(dilation, dilation), + data_layout="NHWC", + kernel_layout=kernel_layout, + out_dtype="int32", + out_layout="NHWC", + ) + mod = tvm.IRModule.from_expr(relay.Function([input1], out1)) + + inputs = {"input": np.random.randint(low=-128, high=127, size=ishape, dtype=dtype)} + output_list = generate_ref_data(ref_mod, inputs) + + compile_and_run( + AOTTestModel(module=mod, inputs=inputs, outputs=output_list), + runner=AOT_CORSTONE300_RUNNER, + interface_api="c", + use_unpacked_api=True, + target_opts={ + "-keys": "arm_cpu", + "-mcpu": "cortex-m7", + }, + schedule_name=schedule_name, + ) + + +class TestConv2d_DSP_HWOI(BasicConv2dTests): + """This test is for conv2d_nhwc_dsp.arm_cpu schedule.""" + + data_shape, kernel_size, num_filter, strides, padding, dilation = tvm.testing.parameters( + # TODO(mehrdadh): Fails due to https://github.com/apache/tvm/issues/11216 + # ((1, 32, 32, 1), (3, 3), 12, 1, 0, 1), + # ((1, 32, 10, 3), (3, 3), 16, 1, 0, 1), + # ((1, 49, 10, 1), (10, 4), 64, (2, 1), (4, 1, 5, 1), 1), + ((1, 32, 32, 16), (3, 3), 16, 1, (0, 2, 2, 0), 1), + ((1, 32, 32, 16), (3, 3), 16, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 16, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 16, 1, (0, 2, 2, 0), 2), + ((1, 32, 32, 16), (3, 3), 16, 1, (1, 1, 2, 2), 2), + # from Keyword Spotting model from MLPerfTiny models + # TODO(mehrdad): Fails due to https://github.com/apache/tvm/issues/11216 + # ((1, 49, 10, 1), (10, 4), 64, (2, 2), (4, 1, 5, 1), 1), + # from Visual Wake Word model from MLPerfTiny models + # TODO(mehrdadh): fails due to https://github.com/apache/tvm/issues/11216 + # ((1, 96, 96, 3), (3, 3), 8, (2, 2), (0, 0, 1, 1), 1), + # from Image Classification model from MLPerfTiny models + ((1, 16, 16, 32), (1, 1), 64, (2, 2), 0, 1), + ((4, 16, 16, 8), (5, 5), 8, 2, (0, 4, 4, 0), 1), + ((4, 16, 16, 8), (5, 5), 16, 2, (0, 4, 4, 0), 1), + ((4, 16, 16, 8), (5, 5), 8, 2, 0, 1), + ((4, 16, 16, 8), (5, 5), 16, 2, 0, 1), + ((1, 16, 16, 8), (3, 3), 16, 2, (0, 0, 1, 1), 1), + ((1, 16, 16, 8), (3, 3), 16, 2, (1, 1, 2, 2), 1), + ((1, 16, 16, 8), (5, 5), 16, 2, (3, 3, 2, 2), 1), + ((1, 16, 16, 8), (3, 3), 16, 2, (0, 1, 2, 3), 1), + ) + dtype = tvm.testing.parameter("int8", "int16") + kernel_layout = tvm.testing.parameter("HWOI") + schedule_name = tvm.testing.parameter("conv2d_nhwc_dsp.arm_cpu") + + +class TestConv2d_HWIO(BasicConv2dTests): + """This test is for conv2d_nhwc_spatial_pack.arm_cpu schedule.""" + + data_shape, kernel_size, num_filter, strides, padding, dilation = tvm.testing.parameters( + ((1, 32, 32, 1), (3, 3), 12, 1, 0, 1), + ((1, 32, 10, 3), (3, 3), 16, 1, 0, 1), + ((1, 49, 10, 1), (10, 4), 64, (2, 1), (4, 1, 5, 1), 1), + ((1, 32, 32, 16), (3, 3), 16, 1, (0, 2, 2, 0), 1), + ((1, 32, 32, 16), (3, 3), 16, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 16, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 16, 1, (0, 2, 2, 0), 2), + ((1, 32, 32, 16), (3, 3), 16, 1, (1, 1, 2, 2), 2), + ) + dtype = tvm.testing.parameter("int8", "int16") + kernel_layout = tvm.testing.parameter("HWIO") + schedule_name = tvm.testing.parameter("conv2d_nhwc_spatial_pack.arm_cpu") + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/tests/python/relay/strategy/arm_cpu/test_depthwise_conv2d.py b/tests/python/relay/strategy/arm_cpu/test_depthwise_conv2d.py new file mode 100644 index 000000000000..89f1fb1843b4 --- /dev/null +++ b/tests/python/relay/strategy/arm_cpu/test_depthwise_conv2d.py @@ -0,0 +1,153 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import sys +import numpy as np +import pytest +import tvm +import tvm.testing +from tvm import relay +from tvm.testing.aot import AOTTestModel, compile_and_run, generate_ref_data +from tvm.micro.testing.aot_test_utils import AOT_CORSTONE300_RUNNER + + +class BasicDepthwiseConv2dTests: + @tvm.testing.requires_corstone300 + def test_conv2d( + self, + data_shape, + data_layout, + kernel_size, + kernel_layout, + num_filter, + strides, + padding, + dilation, + dtype, + schedule_name, + ): + """Test a subgraph with a single conv2d operator.""" + ishape = data_shape + groups = num_filter + + assert groups > 1, f"groups should be more than 1 to create a depthwise conv2d." + + if data_layout == "NCHW" and kernel_layout == "OIHW": + assert ( + num_filter == data_shape[1] + ), f"Output channels({num_filter}) should be equal to input channels({data_shape[1]})." + wshape = (num_filter, data_shape[1] // groups, *kernel_size) + elif data_layout == "NHWC" and kernel_layout == "HWOI": + assert ( + num_filter == data_shape[3] + ), f"Output channels({num_filter}) should be equal to input channels({data_shape[3]})." + wshape = (*kernel_size, num_filter, data_shape[3] // groups) + else: + raise ValueError( + f"Incorrect data layout({data_layout}) and kernel layout({kernel_layout})." + ) + + weight_data = np.random.randint(low=-10, high=10, size=wshape, dtype=dtype) + + input0 = relay.var("input", relay.TensorType(ishape, dtype)) + weight0 = relay.const(weight_data) + out0 = relay.op.nn.conv2d( + input0, + weight0, + kernel_size=kernel_size, + strides=strides, + padding=padding, + groups=groups, + dilation=(dilation, dilation), + data_layout=data_layout, + kernel_layout=kernel_layout, + out_dtype="int32", + out_layout=data_layout, + ) + ref_mod = tvm.IRModule.from_expr(relay.Function([input0], out0)) + + input1 = relay.var("input", relay.TensorType(ishape, dtype)) + weight1 = relay.const(weight_data) + out1 = relay.op.nn.conv2d( + input1, + weight1, + kernel_size=kernel_size, + strides=strides, + padding=padding, + groups=groups, + dilation=(dilation, dilation), + data_layout=data_layout, + kernel_layout=kernel_layout, + out_dtype="int32", + out_layout=data_layout, + ) + mod = tvm.IRModule.from_expr(relay.Function([input1], out1)) + + inputs = {"input": np.random.randint(low=-128, high=127, size=ishape, dtype=dtype)} + output_list = generate_ref_data(ref_mod, inputs) + + compile_and_run( + AOTTestModel(module=mod, inputs=inputs, outputs=output_list), + runner=AOT_CORSTONE300_RUNNER, + interface_api="c", + use_unpacked_api=True, + target_opts={ + "-keys": "arm_cpu", + "-mcpu": "cortex-m7", + }, + schedule_name=schedule_name, + ) + + +class TestDepthwiseConv2d_NCHW_OIHW(BasicDepthwiseConv2dTests): + """This test is for depthwise_conv2d_nchw.arm_cpu schedule.""" + + data_shape, kernel_size, num_filter, strides, padding, dilation = tvm.testing.parameters( + ((1, 16, 32, 32), (3, 3), 16, 1, 0, 1), + ((1, 32, 10, 3), (3, 3), 32, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 32, 1, (0, 2, 2, 0), 1), + ((1, 32, 32, 16), (3, 3), 32, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 32, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 32, 1, (0, 2, 2, 0), 2), + ((1, 16, 32, 16), (3, 3), 16, 1, (1, 1, 2, 2), 2), + ) + data_layout = tvm.testing.parameter("NCHW") + dtype = tvm.testing.parameter("int8", "int16") + kernel_layout = tvm.testing.parameter("OIHW") + schedule_name = tvm.testing.parameter("depthwise_conv2d_nchw.arm_cpu") + + +class TestDepthwiseConv2d_NHWC_HWOI(BasicDepthwiseConv2dTests): + """This test is for depthwise_conv2d_nhwc.generic schedule.""" + + data_shape, kernel_size, num_filter, strides, padding, dilation = tvm.testing.parameters( + ((1, 32, 32, 16), (3, 3), 16, 1, 0, 1), + ((1, 32, 10, 16), (3, 3), 16, 1, 0, 1), + ((1, 49, 10, 64), (10, 4), 64, (2, 1), (4, 1, 5, 1), 1), + ((1, 32, 32, 16), (3, 3), 16, 1, (0, 2, 2, 0), 1), + ((1, 32, 32, 16), (3, 3), 16, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 16, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 16, 1, (0, 2, 2, 0), 2), + ((1, 32, 32, 16), (3, 3), 16, 1, (1, 1, 2, 2), 2), + ) + data_layout = tvm.testing.parameter("NHWC") + dtype = tvm.testing.parameter("int8", "int16") + kernel_layout = tvm.testing.parameter("HWOI") + schedule_name = tvm.testing.parameter("depthwise_conv2d_nhwc.generic") + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/tests/python/relay/strategy/arm_cpu/test_group_conv2d.py b/tests/python/relay/strategy/arm_cpu/test_group_conv2d.py new file mode 100644 index 000000000000..d3f504d04e35 --- /dev/null +++ b/tests/python/relay/strategy/arm_cpu/test_group_conv2d.py @@ -0,0 +1,151 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +import sys +import numpy as np +import pytest +import tvm +import tvm.testing +from tvm import relay +from tvm.testing.aot import AOTTestModel, compile_and_run, generate_ref_data +from tvm.micro.testing.aot_test_utils import AOT_CORSTONE300_RUNNER + + +class BasicGroupConv2dTests: + @tvm.testing.requires_corstone300 + def test_conv2d( + self, + data_shape, + data_layout, + kernel_size, + kernel_layout, + num_filter, + strides, + padding, + dilation, + groups, + dtype, + schedule_name, + ): + """Test a subgraph with a single conv2d operator.""" + ishape = data_shape + + assert groups > 1, f"groups should be more than 1 to create a group conv2d." + + if data_layout == "NCHW" and kernel_layout == "OIHW": + assert data_shape[1] % groups == 0 + wshape = (num_filter, data_shape[1] // groups, *kernel_size) + elif data_layout == "NHWC" and kernel_layout == "HWIO": + assert data_shape[3] % groups == 0 + wshape = (*kernel_size, data_shape[3] // groups, num_filter) + else: + raise ValueError( + f"Incorrect data layout({data_layout}) and kernel layout({kernel_layout})." + ) + + weight_data = np.random.randint(low=-10, high=10, size=wshape, dtype=dtype) + + input0 = relay.var("input", relay.TensorType(ishape, dtype)) + weight0 = relay.const(weight_data) + out0 = relay.op.nn.conv2d( + input0, + weight0, + kernel_size=kernel_size, + strides=strides, + padding=padding, + groups=groups, + dilation=(dilation, dilation), + data_layout=data_layout, + kernel_layout=kernel_layout, + out_dtype="int32", + out_layout=data_layout, + ) + ref_mod = tvm.IRModule.from_expr(relay.Function([input0], out0)) + + input1 = relay.var("input", relay.TensorType(ishape, dtype)) + weight1 = relay.const(weight_data) + out1 = relay.op.nn.conv2d( + input1, + weight1, + kernel_size=kernel_size, + strides=strides, + padding=padding, + groups=groups, + dilation=(dilation, dilation), + data_layout=data_layout, + kernel_layout=kernel_layout, + out_dtype="int32", + out_layout=data_layout, + ) + mod = tvm.IRModule.from_expr(relay.Function([input1], out1)) + + inputs = {"input": np.random.randint(low=-128, high=127, size=ishape, dtype=dtype)} + output_list = generate_ref_data(ref_mod, inputs) + + compile_and_run( + AOTTestModel(module=mod, inputs=inputs, outputs=output_list), + runner=AOT_CORSTONE300_RUNNER, + interface_api="c", + use_unpacked_api=True, + target_opts={ + "-keys": "arm_cpu", + "-mcpu": "cortex-m7", + }, + schedule_name=schedule_name, + ) + + +class TestGroupConv2d_NCHW_OIHW(BasicGroupConv2dTests): + """This test is for group_conv2d_nchw.arm_cpu schedule.""" + + data_shape, kernel_size, num_filter, strides, padding, dilation = tvm.testing.parameters( + ((1, 16, 32, 32), (3, 3), 12, 1, 0, 1), + ((1, 16, 32, 10), (3, 3), 16, 1, 0, 1), + ((1, 16, 32, 32), (3, 3), 16, 1, (0, 2, 2, 0), 1), + ((1, 16, 32, 32), (3, 3), 16, 1, 0, 1), + ((1, 16, 32, 32), (3, 3), 16, 1, 0, 1), + ((1, 16, 32, 32), (3, 3), 16, 1, (0, 2, 2, 0), 2), + ((1, 16, 32, 32), (3, 3), 32, 1, (1, 1, 2, 2), 2), + ) + groups = tvm.testing.parameter(2, 4) + data_layout = tvm.testing.parameter("NCHW") + dtype = tvm.testing.parameter("int8", "int16") + kernel_layout = tvm.testing.parameter("OIHW") + schedule_name = tvm.testing.parameter("group_conv2d_nchw.arm_cpu") + + +class TestGroupConv2d_NHWC_HWIO(BasicGroupConv2dTests): + """This test is for group_conv2d_nhwc.generic schedule.""" + + data_shape, kernel_size, num_filter, strides, padding, dilation = tvm.testing.parameters( + ((1, 32, 32, 16), (3, 3), 12, 1, 0, 1), + ((1, 32, 10, 16), (3, 3), 16, 1, 0, 1), + ((1, 49, 10, 16), (10, 4), 64, (2, 1), (4, 1, 5, 1), 1), + ((1, 32, 32, 16), (3, 3), 16, 1, (0, 2, 2, 0), 1), + ((1, 32, 32, 16), (3, 3), 16, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 16, 1, 0, 1), + ((1, 32, 32, 16), (3, 3), 16, 1, (0, 2, 2, 0), 2), + ((1, 32, 32, 16), (3, 3), 16, 1, (1, 1, 2, 2), 2), + ) + groups = tvm.testing.parameter(2, 4) + data_layout = tvm.testing.parameter("NHWC") + dtype = tvm.testing.parameter("int8", "int16") + kernel_layout = tvm.testing.parameter("HWIO") + schedule_name = tvm.testing.parameter("group_conv2d_nhwc.generic") + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__] + sys.argv[1:])) diff --git a/tests/python/relay/utils/external_codegen.py b/tests/python/relay/utils/external_codegen.py index 4dbc8f274264..6d3d917ff5a2 100644 --- a/tests/python/relay/utils/external_codegen.py +++ b/tests/python/relay/utils/external_codegen.py @@ -104,7 +104,8 @@ def check_aot_executor_result( mod, map_inputs, out_shape, result, tol=1e-5, target="llvm", device=tvm.cpu() ): # Late import to avoid breaking test with USE_MICRO=OFF. - from aot.aot_test_utils import AOTTestModel, AOT_DEFAULT_RUNNER, compile_and_run + from tvm.testing.aot import AOTTestModel, compile_and_run + from tvm.micro.testing.aot_test_utils import AOT_DEFAULT_RUNNER interface_api = "packed" use_unpacked_api = False diff --git a/tests/python/unittest/test_crt.py b/tests/python/unittest/test_crt.py index 3a93dbc89b1f..d5611906fc5d 100644 --- a/tests/python/unittest/test_crt.py +++ b/tests/python/unittest/test_crt.py @@ -292,7 +292,7 @@ def test_platform_timer(): def test_autotune(): """Verify that autotune works with micro.""" import tvm.relay as relay - from tvm.micro.testing import check_tune_log + from tvm.micro.testing.utils import check_tune_log runtime = Runtime("crt", {"system-lib": True}) diff --git a/tests/scripts/task_python_microtvm.sh b/tests/scripts/task_python_microtvm.sh index d13ee91a0ba8..7301c6f833ab 100755 --- a/tests/scripts/task_python_microtvm.sh +++ b/tests/scripts/task_python_microtvm.sh @@ -51,3 +51,5 @@ export TVM_MICRO_USE_HW=1 export TVM_MICRO_BOARD=qemu_x86 python3 gallery/how_to/work_with_microtvm/micro_tflite.py python3 gallery/how_to/work_with_microtvm/micro_autotune.py + +run_pytest ctypes python-relay-strategy-arm_cpu tests/python/relay/strategy/arm_cpu --enable-corstone300-tests