diff options
Diffstat (limited to 'src/aiet/resources')
-rw-r--r-- | src/aiet/resources/applications/.gitignore | 6 | ||||
-rw-r--r-- | src/aiet/resources/systems/.gitignore | 6 | ||||
-rw-r--r-- | src/aiet/resources/tools/vela/aiet-config.json | 73 | ||||
-rw-r--r-- | src/aiet/resources/tools/vela/aiet-config.json.license | 3 | ||||
-rw-r--r-- | src/aiet/resources/tools/vela/check_model.py | 75 | ||||
-rw-r--r-- | src/aiet/resources/tools/vela/run_vela.py | 65 | ||||
-rw-r--r-- | src/aiet/resources/tools/vela/vela.ini | 53 |
7 files changed, 281 insertions, 0 deletions
diff --git a/src/aiet/resources/applications/.gitignore b/src/aiet/resources/applications/.gitignore new file mode 100644 index 0000000..0226166 --- /dev/null +++ b/src/aiet/resources/applications/.gitignore @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. +# SPDX-License-Identifier: Apache-2.0 +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/src/aiet/resources/systems/.gitignore b/src/aiet/resources/systems/.gitignore new file mode 100644 index 0000000..0226166 --- /dev/null +++ b/src/aiet/resources/systems/.gitignore @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. +# SPDX-License-Identifier: Apache-2.0 +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/src/aiet/resources/tools/vela/aiet-config.json b/src/aiet/resources/tools/vela/aiet-config.json new file mode 100644 index 0000000..c12f291 --- /dev/null +++ b/src/aiet/resources/tools/vela/aiet-config.json @@ -0,0 +1,73 @@ +[ + { + "name": "vela", + "description": "Neural network model compiler for Arm Ethos-U NPUs", + "supported_systems": [ + { + "name": "Corstone-300: Cortex-M55+Ethos-U55" + }, + { + "name": "Corstone-310: Cortex-M85+Ethos-U55" + }, + { + "name": "Corstone-300: Cortex-M55+Ethos-U65", + "variables": { + "accelerator_config_prefix": "ethos-u65", + "system_config": "Ethos_U65_High_End", + "shared_sram": "U65_Shared_Sram" + }, + "user_params": { + "run": [ + { + "description": "MACs per cycle", + "values": [ + "256", + "512" + ], + "default_value": "512", + "alias": "mac" + } + ] + } + } + ], + "variables": { + "accelerator_config_prefix": "ethos-u55", + "system_config": "Ethos_U55_High_End_Embedded", + "shared_sram": "U55_Shared_Sram" + }, + "commands": { + "run": [ + "run_vela {user_params:input} {user_params:output} --config {tool.config_dir}/vela.ini --accelerator-config {variables:accelerator_config_prefix}-{user_params:mac} --system-config {variables:system_config} --memory-mode {variables:shared_sram} --optimise Performance" + ] + }, + "user_params": { + "run": [ + { + "description": "MACs per cycle", + "values": [ + "32", + "64", + "128", + "256" + ], + "default_value": "128", + "alias": "mac" + }, + { + "name": "--input-model", + "description": "Path to the TFLite model", + "values": [], + "alias": "input" + }, + { + "name": "--output-model", + "description": "Path to the output model file of the vela-optimisation step. The vela output is saved in the parent directory.", + "values": [], + "default_value": "output_model.tflite", + "alias": "output" + } + ] + } + } +] diff --git a/src/aiet/resources/tools/vela/aiet-config.json.license b/src/aiet/resources/tools/vela/aiet-config.json.license new file mode 100644 index 0000000..9b83bfc --- /dev/null +++ b/src/aiet/resources/tools/vela/aiet-config.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. + +SPDX-License-Identifier: Apache-2.0 diff --git a/src/aiet/resources/tools/vela/check_model.py b/src/aiet/resources/tools/vela/check_model.py new file mode 100644 index 0000000..7c700b1 --- /dev/null +++ b/src/aiet/resources/tools/vela/check_model.py @@ -0,0 +1,75 @@ +# SPDX-FileCopyrightText: Copyright 2020, 2022, Arm Limited and/or its affiliates. +# SPDX-License-Identifier: Apache-2.0 +"""Check if a TFLite model file is Vela-optimised.""" +import struct +from pathlib import Path + +from ethosu.vela.tflite.Model import Model + +from aiet.cli.common import InvalidTFLiteFileError +from aiet.cli.common import ModelOptimisedException +from aiet.utils.fs import read_file_as_bytearray + + +def get_model_from_file(input_model_file: Path) -> Model: + """Generate Model instance from TFLite file using flatc generated code.""" + buffer = read_file_as_bytearray(input_model_file) + try: + model = Model.GetRootAsModel(buffer, 0) + except (TypeError, RuntimeError, struct.error) as tflite_error: + raise InvalidTFLiteFileError( + f"Error reading in model from {input_model_file}." + ) from tflite_error + return model + + +def is_vela_optimised(tflite_model: Model) -> bool: + """Return True if 'ethos-u' custom operator found in the Model.""" + operators = get_operators_from_model(tflite_model) + + custom_codes = get_custom_codes_from_operators(operators) + + return check_custom_codes_for_ethosu(custom_codes) + + +def get_operators_from_model(tflite_model: Model) -> list: + """Return list of the unique operator codes used in the Model.""" + return [ + tflite_model.OperatorCodes(index) + for index in range(tflite_model.OperatorCodesLength()) + ] + + +def get_custom_codes_from_operators(operators: list) -> list: + """Return list of each operator's CustomCode() strings, if they exist.""" + return [ + operator.CustomCode() + for operator in operators + if operator.CustomCode() is not None + ] + + +def check_custom_codes_for_ethosu(custom_codes: list) -> bool: + """Check for existence of ethos-u string in the custom codes.""" + return any( + custom_code_name.decode("utf-8") == "ethos-u" + for custom_code_name in custom_codes + ) + + +def check_model(tflite_file_name: str) -> None: + """Raise an exception if model in given file is Vela optimised.""" + tflite_path = Path(tflite_file_name) + + tflite_model = get_model_from_file(tflite_path) + + if is_vela_optimised(tflite_model): + raise ModelOptimisedException( + f"TFLite model in {tflite_file_name} is already " + f"vela optimised ('ethos-u' custom op detected)." + ) + + print( + f"TFLite model in {tflite_file_name} is not vela optimised " + f"('ethos-u' custom op not detected)." + ) diff --git a/src/aiet/resources/tools/vela/run_vela.py b/src/aiet/resources/tools/vela/run_vela.py new file mode 100644 index 0000000..2c1b0be --- /dev/null +++ b/src/aiet/resources/tools/vela/run_vela.py @@ -0,0 +1,65 @@ +# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates. +# SPDX-License-Identifier: Apache-2.0 +"""Wrapper to only run Vela when the input is not already optimised.""" +import shutil +import subprocess +from pathlib import Path +from typing import Tuple + +import click + +from aiet.cli.common import ModelOptimisedException +from aiet.resources.tools.vela.check_model import check_model + + +def vela_output_model_path(input_model: str, output_dir: str) -> Path: + """Construct the path to the Vela output file.""" + in_path = Path(input_model) + tflite_vela = Path(output_dir) / f"{in_path.stem}_vela{in_path.suffix}" + return tflite_vela + + +def execute_vela(vela_args: Tuple, output_dir: Path, input_model: str) -> None: + """Execute vela as external call.""" + cmd = ["vela"] + list(vela_args) + cmd += ["--output-dir", str(output_dir)] # Re-add parsed out_dir to arguments + cmd += [input_model] + subprocess.run(cmd, check=True) + + +@click.command(context_settings=dict(ignore_unknown_options=True)) +@click.option( + "--input-model", + "-i", + type=click.Path(exists=True, file_okay=True, readable=True), + required=True, +) +@click.option("--output-model", "-o", type=click.Path(), required=True) +# Collect the remaining arguments to be directly forwarded to Vela +@click.argument("vela-args", nargs=-1, type=click.UNPROCESSED) +def run_vela(input_model: str, output_model: str, vela_args: Tuple) -> None: + """Check input, run Vela (if needed) and copy optimised file to destination.""" + output_dir = Path(output_model).parent + try: + check_model(input_model) # raises an exception if already Vela-optimised + execute_vela(vela_args, output_dir, input_model) + print("Vela optimisation complete.") + src_model = vela_output_model_path(input_model, str(output_dir)) + except ModelOptimisedException as ex: + # Input already optimized: copy input file to destination path and return + print(f"Input already vela-optimised.\n{ex}") + src_model = Path(input_model) + except subprocess.CalledProcessError as ex: + print(ex) + raise SystemExit(ex.returncode) from ex + + try: + shutil.copyfile(src_model, output_model) + except (shutil.SameFileError, OSError) as ex: + print(ex) + raise SystemExit(ex.errno) from ex + + +def main() -> None: + """Entry point of check_model application.""" + run_vela() # pylint: disable=no-value-for-parameter diff --git a/src/aiet/resources/tools/vela/vela.ini b/src/aiet/resources/tools/vela/vela.ini new file mode 100644 index 0000000..5996553 --- /dev/null +++ b/src/aiet/resources/tools/vela/vela.ini @@ -0,0 +1,53 @@ +; SPDX-FileCopyrightText: Copyright 2021-2022, Arm Limited and/or its affiliates. +; SPDX-License-Identifier: Apache-2.0 + +; ----------------------------------------------------------------------------- +; Vela configuration file + +; ----------------------------------------------------------------------------- +; System Configuration + +; Ethos-U55 High-End Embedded: SRAM (4 GB/s) and Flash (0.5 GB/s) +[System_Config.Ethos_U55_High_End_Embedded] +core_clock=500e6 +axi0_port=Sram +axi1_port=OffChipFlash +Sram_clock_scale=1.0 +Sram_burst_length=32 +Sram_read_latency=32 +Sram_write_latency=32 +OffChipFlash_clock_scale=0.125 +OffChipFlash_burst_length=128 +OffChipFlash_read_latency=64 +OffChipFlash_write_latency=64 + +; Ethos-U65 High-End: SRAM (16 GB/s) and DRAM (3.75 GB/s) +[System_Config.Ethos_U65_High_End] +core_clock=1e9 +axi0_port=Sram +axi1_port=Dram +Sram_clock_scale=1.0 +Sram_burst_length=32 +Sram_read_latency=32 +Sram_write_latency=32 +Dram_clock_scale=0.234375 +Dram_burst_length=128 +Dram_read_latency=500 +Dram_write_latency=250 + +; ----------------------------------------------------------------------------- +; Memory Mode + +; Shared SRAM: the SRAM is shared between the Ethos-U and the Cortex-M software +; The non-SRAM memory is assumed to be read-only +[Memory_Mode.U55_Shared_Sram] +const_mem_area=Axi1 +arena_mem_area=Axi0 +cache_mem_area=Axi0 +arena_cache_size=4194304 + +[Memory_Mode.U65_Shared_Sram] +const_mem_area=Axi1 +arena_mem_area=Axi0 +cache_mem_area=Axi0 +arena_cache_size=2097152 |