blob: 0e5e6ebaf57f758ba86b45e530bc0e6249f1c072 [file] [log] [blame]
wilisa0146c94772023-02-08 09:56:14 +00001# SPDX-FileCopyrightText: Copyright 2020-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
Tim Hall79d07d22020-04-27 18:20:16 +01002#
3# SPDX-License-Identifier: Apache-2.0
4#
5# Licensed under the Apache License, Version 2.0 (the License); you may
6# not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an AS IS BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
Rickard Bolinbc6ee582022-11-04 08:24:29 +000016#
Tim Hall79d07d22020-04-27 18:20:16 +010017# Description:
18# Main entry point for the Vela compiler.
19#
20# Provides command line interface, options parsing, and network loading. Before calling the compiler driver.
Diego Russoe8a10452020-04-21 17:39:10 +010021import argparse
Alexander Hansson2466d812023-05-17 12:38:46 +000022import datetime
Rickard Bolin1538dce2022-04-25 11:07:56 +000023import glob
Tim Hall1bd531d2020-11-01 20:59:36 +000024import os
Diego Russoea6111a2020-04-14 18:41:58 +010025import sys
Tim Hall79d07d22020-04-27 18:20:16 +010026import time
Tim Hall79d07d22020-04-27 18:20:16 +010027
erik.andersson@arm.comad45f792021-02-03 10:20:16 +010028import flatbuffers
29
Tim Hall79d07d22020-04-27 18:20:16 +010030from . import architecture_features
Diego Russoe8a10452020-04-21 17:39:10 +010031from . import compiler_driver
32from . import model_reader
Diqing Zhong5e5a7842021-08-16 17:24:09 +020033from . import rawdata_writer
Diego Russoe8a10452020-04-21 17:39:10 +010034from . import scheduler
Tim Hall79d07d22020-04-27 18:20:16 +010035from . import stats_writer
36from . import tflite_writer
Tim Hall79d07d22020-04-27 18:20:16 +010037from ._version import __version__
Louis Verhaard11831ce2020-11-18 18:53:24 +010038from .api import API_VERSION
Tim Halle6ccd872020-11-09 16:46:37 +000039from .debug_database import DebugDatabase
Louis Verhaard7db78962020-05-25 15:05:26 +020040from .errors import InputFileError
Henrik G Olssonea9b23c2021-03-23 17:34:49 +010041from .errors import VelaError
Tim Hallcda4fcb2022-05-19 12:36:58 +010042from .hillclimb_allocation import HillClimbAllocator
Jonas Ohlsson45e653d2021-07-26 16:13:12 +020043from .nn_graph import NetworkType
Diego Russoe8a10452020-04-21 17:39:10 +010044from .nn_graph import TensorAllocator
Diego Russoea6111a2020-04-14 18:41:58 +010045from .tensor import MemArea
Jacob Bohlin0628a8c2020-08-28 13:25:14 +020046from .tensor import Tensor
erik.andersson@arm.comad45f792021-02-03 10:20:16 +010047from .tflite.Model import Model
Michael McGeagh837dc1b2020-11-10 12:38:25 +000048from .tflite_mapping import builtin_operator_map
Tim Halla3fe6652022-03-03 17:43:16 +000049from .tflite_mapping import builtin_operator_name_map
Fredrik Svedberg88d5b122022-09-16 16:24:55 +020050from .tflite_mapping import optype_to_builtintype
Jonas Ohlsson45e653d2021-07-26 16:13:12 +020051from .tflite_model_semantic import TFLiteSemantic
52from .tflite_supported_operators import TFLiteSupportedOperators
53from .tosa_model_semantic import TosaSemantic
54from .tosa_supported_operators import TosaSupportedOperators
Louis Verhaard52078302020-11-18 13:35:06 +010055from ethosu.vela.architecture_features import ArchitectureFeatures
Tim Hall79d07d22020-04-27 18:20:16 +010056
Rickard Bolin7ce6b322022-06-02 09:30:33 +000057CONFIG_FILES_PATH = os.path.normpath(os.path.join(__file__, "..", "..", "config_files"))
Rickard Bolin1538dce2022-04-25 11:07:56 +000058
Tim Hall79d07d22020-04-27 18:20:16 +010059
Tim Halle6ccd872020-11-09 16:46:37 +000060def process(input_name, enable_debug_db, arch, model_reader_options, compiler_options, scheduler_options):
Tim Hall79d07d22020-04-27 18:20:16 +010061 if compiler_options.timing:
62 start = time.time()
63
Tim Halle6ccd872020-11-09 16:46:37 +000064 os.makedirs(compiler_options.output_dir, exist_ok=True)
65 output_basename = os.path.join(compiler_options.output_dir, os.path.splitext(os.path.basename(input_name))[0])
66 DebugDatabase.show_warnings = enable_debug_db
67
Patrik Gustavsson8f1f9aa2021-06-28 07:41:58 +020068 nng, network_type = model_reader.read_model(input_name, model_reader_options)
Tim Hall79d07d22020-04-27 18:20:16 +010069
70 if not nng:
Michael McGeagh7a6f8432020-12-02 15:29:22 +000071 raise InputFileError(input_name, "Input file could not be read")
Tim Hall79d07d22020-04-27 18:20:16 +010072
73 if compiler_options.verbose_operators:
74 nng.print_operators()
75
76 if compiler_options.timing:
77 stop = time.time()
78 print("Model reading took %f s" % (stop - start))
79 start = time.time()
80
wilisa0189a8cdd2022-08-22 16:13:06 +000081 compiler_driver.compiler_driver(nng, arch, compiler_options, scheduler_options, network_type, output_basename)
Tim Hall79d07d22020-04-27 18:20:16 +010082
Tim Halle6ccd872020-11-09 16:46:37 +000083 summary_csv_file = "{0}_summary_{1}.csv".format(output_basename, arch.system_config)
Tim Hall79d07d22020-04-27 18:20:16 +010084 stats_writer.write_summary_metrics_csv(nng, summary_csv_file, arch)
85
Fredrik Svedbergf5c07c42021-04-23 14:36:42 +020086 stats_writer.print_performance_metrics(
87 nng,
88 show_cpu_operations=compiler_options.show_cpu_operations,
89 verbose_weights=compiler_options.verbose_weights,
90 arch=arch,
91 )
Tim Hall79d07d22020-04-27 18:20:16 +010092
Diqing Zhong5e5a7842021-08-16 17:24:09 +020093 output_tfl_filename = output_basename + "_vela.tflite"
Patrik Gustavssonb081d672021-08-25 13:49:25 +020094 if input_name.endswith(".tflite"):
Diqing Zhong5e5a7842021-08-16 17:24:09 +020095 tflite_writer.write_tflite(nng, output_tfl_filename)
Patrik Gustavssonc74682c2021-08-17 14:26:38 +020096 if input_name.endswith(".tosa"):
Diqing Zhong5e5a7842021-08-16 17:24:09 +020097 rawdata_writer.write_rawdata_output(nng, arch, output_basename)
Tim Halle6ccd872020-11-09 16:46:37 +000098
99 if enable_debug_db:
Diqing Zhong5e5a7842021-08-16 17:24:09 +0200100 file_offsets = calculate_operator_file_offsets(output_tfl_filename)
erik.andersson@arm.comad45f792021-02-03 10:20:16 +0100101 for idx, offset in enumerate(sorted(file_offsets)):
102 sg = find_subgraph_with_command_stream_order(nng, idx)
103 if sg is not None:
104 DebugDatabase.set_stream_offset(sg, offset)
Tim Halle6ccd872020-11-09 16:46:37 +0000105 debug_filename = output_basename + "_debug.xml"
Diqing Zhong5e5a7842021-08-16 17:24:09 +0200106 DebugDatabase.write(debug_filename, input_name, output_tfl_filename)
Tim Hall79d07d22020-04-27 18:20:16 +0100107
108 if compiler_options.timing:
109 stop = time.time()
110 print("Compiler driver took %f s" % (stop - start))
111
112 return nng
113
114
erik.andersson@arm.comad45f792021-02-03 10:20:16 +0100115def find_subgraph_with_command_stream_order(nng, idx):
116 for sg in nng.subgraphs:
117 if sg.generated_stream_id == idx:
118 return sg
119 return None
120
121
122def calculate_operator_file_offsets(name: str):
123 # Read the vela optimized tflite file
124 with open(name, "rb") as f:
125 buf = bytearray(f.read())
126 # Calculate the file offsets for each custom operator
127 file_offsets = []
128 model = Model.GetRootAsModel(buf, 0)
129 for idx in range(model.SubgraphsLength()): # However only one subgraph is supported as of now
130 sg = model.Subgraphs(idx)
131 for idx in range(sg.OperatorsLength()):
132 operator = sg.Operators(idx)
133 if model.OperatorCodes(operator.OpcodeIndex()).CustomCode() is not None:
134 tensor_idx = operator.Inputs(0)
135 tensor = sg.Tensors(tensor_idx)
136 buffer = model.Buffers(tensor.Buffer())
137 offset = flatbuffers.number_types.UOffsetTFlags.py_type(buffer._tab.Offset(4))
138 file_offsets.append(buffer._tab.Vector(offset))
139 return file_offsets
140
141
Tim Hall79d07d22020-04-27 18:20:16 +0100142def print_subgraph_io_summary(nng):
143 """Print a summary of all the input and output tensor sizes for all subgraphs.
144 Also displays the total tensor size and the memory used area for sram.
145 """
146
147 print("Subgraph IO Summary")
148 print("-------------------")
James Ward93389782021-10-14 12:58:02 +0100149 print(f"NNG: {nng.name}")
Tim Hall79d07d22020-04-27 18:20:16 +0100150 max_sg_size = 0
151 for sg in reversed(nng.subgraphs):
James Ward93389782021-10-14 12:58:02 +0100152 print(f" NNG Subgraph: {sg.name} = {sg.placement}")
Tim Hall79d07d22020-04-27 18:20:16 +0100153 sg_size = 0
154
James Ward93389782021-10-14 12:58:02 +0100155 if hasattr(sg, "scratch_tensor") and sg.scratch_tensor is not None:
156 sg_tensors = sg.input_tensors + [sg.scratch_tensor] + sg.output_tensors
157 else:
158 sg_tensors = sg.input_tensors + sg.output_tensors
Tim Hall79d07d22020-04-27 18:20:16 +0100159
James Ward93389782021-10-14 12:58:02 +0100160 for tens in sg_tensors:
161 if tens in sg.input_tensors:
162 tens_dir = "In"
163 elif tens in sg.output_tensors:
164 tens_dir = "Out"
165 else:
166 tens_dir = "In/Out"
Tim Hall79d07d22020-04-27 18:20:16 +0100167
James Ward93389782021-10-14 12:58:02 +0100168 size = tens.elements() * tens.element_size() / 1024.0
169 sg_size = sg_size + size
170 print(f" Tensor [{tens_dir}]: {tens.name} = {size} KiB")
171
172 print(f" Total Size = {sg_size} KiB")
173 print(f" SRAM Memory Used = {sg.memory_used.get(MemArea.Sram, 0) / 1024.0} KiB")
Tim Hall79d07d22020-04-27 18:20:16 +0100174 max_sg_size = max(sg_size, max_sg_size)
175
James Ward93389782021-10-14 12:58:02 +0100176 print(f" Maximum NNG Subgraph Size = {max_sg_size} KiB")
Tim Hall79d07d22020-04-27 18:20:16 +0100177
178
Alexander Hansson2466d812023-05-17 12:38:46 +0000179def generate_license():
180 lines = [
181 "<!--",
182 f"SPDX-FileCopyrightText: Copyright 2020-{datetime.date.today().year} "
183 "Arm Limited and/or its affiliates <open-source-office@arm.com>",
184 "",
185 "SPDX-License-Identifier: Apache-2.0",
186 "",
187 "Licensed under the Apache License, Version 2.0 (the License); you may",
188 "not use this file except in compliance with the License.",
189 "You may obtain a copy of the License at",
190 "",
191 "www.apache.org/licenses/LICENSE-2.0",
192 "",
193 "Unless required by applicable law or agreed to in writing, software",
194 "distributed under the License is distributed on an AS IS BASIS, WITHOUT",
195 "WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.",
196 "See the License for the specific language governing permissions and",
197 "limitations under the License.",
198 "-->",
199 ]
200 return lines
201
202
Michael McGeagh837dc1b2020-11-10 12:38:25 +0000203def generate_supported_ops():
Jonas Ohlsson0957e3e2021-09-01 15:57:21 +0200204 # Exclude network type from generation by adding value to exclude list.
205 # To easily exclude NetworkType from generated documentation.
206 exclude_generation_network_type_value = [NetworkType.TOSA.value]
207
Fredrik Svedberg88d5b122022-09-16 16:24:55 +0200208 def _exclude_list_names(constraint, exclude_list):
209 constraints_excluded_names = [
210 optype_to_builtintype(op) for op, exclude_constraint in exclude_list if constraint in exclude_constraint
211 ]
212 return f" - [{', '.join(sorted(constraints_excluded_names))}]" if constraints_excluded_names else ""
213
Alexander Hansson2466d812023-05-17 12:38:46 +0000214 lines = generate_license()
215 lines += [
Michael McGeagh837dc1b2020-11-10 12:38:25 +0000216 "# Supported Ops",
217 "",
218 "This file was automatically generated by Vela using the `--supported-ops-report` parameter. ",
219 f"Vela version: `{__version__}`",
220 "",
Michael McGeagh54a61112020-11-24 14:58:51 +0000221 "This file complies with",
222 "[**Gitiles Markdown syntax**](https://github.com/google/gitiles/blob/master/Documentation/markdown.md)",
Michael McGeagh837dc1b2020-11-10 12:38:25 +0000223 "",
Jonas Ohlsson45e653d2021-07-26 16:13:12 +0200224 "Summary table of constraints for:",
Michael McGeagh837dc1b2020-11-10 12:38:25 +0000225 ]
Jonas Ohlsson45e653d2021-07-26 16:13:12 +0200226
227 for network_type in NetworkType:
Jonas Ohlsson0957e3e2021-09-01 15:57:21 +0200228 if network_type.value in exclude_generation_network_type_value:
229 continue
230
Jonas Ohlsson45e653d2021-07-26 16:13:12 +0200231 lines += [
232 f"- [{network_type.name}](#{network_type.name.lower()}-summary-table)",
233 ]
234
235 for network_type in NetworkType:
Jonas Ohlsson0957e3e2021-09-01 15:57:21 +0200236 if network_type.value in exclude_generation_network_type_value:
237 continue
238
Michael McGeagh837dc1b2020-11-10 12:38:25 +0000239 lines += [
240 "",
Jonas Ohlsson45e653d2021-07-26 16:13:12 +0200241 f"## {network_type.name} Summary Table",
Michael McGeagh837dc1b2020-11-10 12:38:25 +0000242 "",
243 ]
Jonas Ohlsson45e653d2021-07-26 16:13:12 +0200244 if network_type == NetworkType.TFLite:
245 lines += [
246 "The table below contains TFLite operators that can be placed on the Ethos-U NPU. ",
247 "If the constraints are not met, then that operator will be scheduled on the CPU instead. ",
248 "For any other TFLite operator not listed, will be left untouched and scheduled on the CPU. ",
249 "Please check the supported operator list for your chosen runtime for further information.",
250 "",
251 "| Operator | TFLite Constraints |",
252 "| --- | --- |",
253 ]
254 semantic_checker = TFLiteSemantic()
255 supported = TFLiteSupportedOperators()
256 elif network_type == NetworkType.TOSA:
257 lines += [
258 "The table below contains TOSA operators that can be placed on the Ethos-U NPU. ",
259 "Note: There is limited support for compiling a TOSA neural network (EXPERIMENTAL). ",
260 "The related constraints have not yet been populated in the list.",
261 "",
262 "| Operator | TOSA Constraints |",
263 "| --- | --- |",
264 ]
265 semantic_checker = TosaSemantic()
266 supported = TosaSupportedOperators()
267 else:
268 raise ValueError
269
270 op_constraint_links = []
Tim Halla3fe6652022-03-03 17:43:16 +0000271 op_list = sorted(((op, builtin_operator_name_map[op]) for op in builtin_operator_map), key=lambda x: x[1])
Jonas Ohlsson45e653d2021-07-26 16:13:12 +0200272 for op, name in op_list:
273 internal_op = builtin_operator_map[op][0]
274 if internal_op in TFLiteSupportedOperators.supported_operators:
275 links = f"[Generic](#{network_type.name.lower()}-generic-constraints)"
276 if (
277 internal_op in supported.specific_constraints
278 or internal_op in semantic_checker.specific_constraints
279 ):
280 links += f", [Specific](#{network_type.name.lower()}-{name.lower()}-constraints)"
281 op_constraint_links.append((internal_op, name))
282 lines.append(f"| {name} | {links} |")
283 lines += [
284 "",
285 f"### {network_type.name} Generic Constraints",
286 "",
Ayaan Masood4965fae2022-06-29 11:30:57 +0100287 "This is a list of constraints most NPU operators must satisfy in order to be scheduled on the NPU.",
288 "(Operators excluded from certain constraints are shown in brackets [ ] )\n" "",
Jonas Ohlsson45e653d2021-07-26 16:13:12 +0200289 ]
290 for constraint in semantic_checker.generic_constraints:
Michael McGeagh837dc1b2020-11-10 12:38:25 +0000291 # Markdown needs two spaces at the end of a line to render it as a separate line
292 reason = constraint.__doc__.replace("\n", " \n")
Ayaan Masood4965fae2022-06-29 11:30:57 +0100293 exclude_list = TFLiteSemantic.get_generic_constraint_exclude_list().items()
Fredrik Svedberg88d5b122022-09-16 16:24:55 +0200294 lines.append(f"- {reason}{_exclude_list_names(constraint, exclude_list)}")
Jonas Ohlsson45e653d2021-07-26 16:13:12 +0200295 for constraint in supported.generic_constraints:
296 # Markdown needs two spaces at the end of a line to render it as a separate line
297 reason = constraint.__doc__.replace("\n", " \n")
Fredrik Svedberg88d5b122022-09-16 16:24:55 +0200298 exclude_list = supported.generic_constraints_exceptions.items()
299 lines.append(f"- {reason}{_exclude_list_names(constraint, exclude_list)}")
Jonas Ohlsson45e653d2021-07-26 16:13:12 +0200300 for op, name in op_constraint_links:
301 lines += [
302 "",
303 f"### {network_type.name} {name} Constraints",
304 "",
305 f"This is a list of constraints that the {name} operator must satisfy in order to be scheduled on the"
306 " NPU.",
307 "",
308 ]
309 for constraint in semantic_checker.specific_constraints[op]:
310 # Markdown needs two spaces at the end of a line to render it as a separate line
311 reason = constraint.__doc__.replace("\n", " \n")
312 lines.append(f"- {reason}")
313 for constraint in supported.specific_constraints[op]:
314 # Markdown needs two spaces at the end of a line to render it as a separate line
315 reason = constraint.__doc__.replace("\n", " \n")
316 lines.append(f"- {reason}")
Michael McGeagh837dc1b2020-11-10 12:38:25 +0000317
318 # Note. this will generate the file in the CWD
319 filepath = os.path.join(os.getcwd(), "SUPPORTED_OPS.md")
320 with open(filepath, "wt") as md:
321 md.writelines(line + "\n" for line in lines)
322 print(f"Report file: {filepath}")
323
324
Rickard Bolin1538dce2022-04-25 11:07:56 +0000325def list_config_files():
Rickard Bolin9b8b4482022-05-24 07:43:03 +0000326 print("Available config files:")
327 path_length = len(CONFIG_FILES_PATH + os.path.sep)
Rickard Bolin1538dce2022-04-25 11:07:56 +0000328 for config in glob.glob(os.path.join(CONFIG_FILES_PATH, "*", "*.ini")):
Rickard Bolin9b8b4482022-05-24 07:43:03 +0000329 print(config[path_length:])
Rickard Bolin1538dce2022-04-25 11:07:56 +0000330
331
Tim Hall79d07d22020-04-27 18:20:16 +0100332def main(args=None):
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100333 try:
334 if args is None:
335 args = sys.argv[1:]
Tim Hall79d07d22020-04-27 18:20:16 +0100336
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100337 parser = argparse.ArgumentParser(prog="vela", description="Neural network model compiler for Arm Ethos-U NPUs")
338 parser.add_argument("--version", action="version", version=__version__)
339 parser.add_argument(
340 "--api-version", action="version", version=API_VERSION, help="Displays the version of the external API."
341 )
342 parser.add_argument(
343 "--supported-ops-report",
344 action="store_true",
345 help="Generate the SUPPORTED_OPS.md file in the current working directory and exit",
Tim Hallb9b515c2020-11-01 21:27:19 +0000346 )
Jacob Bohlin0628a8c2020-08-28 13:25:14 +0200347
Rickard Bolin1538dce2022-04-25 11:07:56 +0000348 parser.add_argument(
349 "--list-config-files",
350 action="store_true",
351 help=(
352 "Display all available configurations in the `config_files` folder and exit. To select config file, "
353 "use the --config argument with one of the listed config files (For example: --config Arm/vela.ini )"
354 ),
355 )
356
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100357 # set network nargs to be optional to allow the support-ops-report CLI option to be used standalone
358 parser.add_argument(
359 "network",
360 metavar="NETWORK",
361 type=str,
362 default=None,
363 nargs="?",
364 help="Filename of the input TensorFlow Lite for Microcontrollers network",
365 )
366 parser.add_argument(
367 "--output-dir", type=str, default="output", help="Output directory to write files to (default: %(default)s)"
368 )
369 parser.add_argument(
370 "--enable-debug-db",
371 action="store_true",
372 default=None,
373 help="Enables the calculation and writing of a network debug database to output directory",
374 )
375 parser.add_argument(
376 "--config",
377 type=str,
378 action="append",
379 help="Vela configuration file(s) in Python ConfigParser .ini file format",
380 )
381 parser.add_argument("--verbose-all", action="store_true", help="Enable all verbose options")
382 parser.add_argument(
383 "--verbose-config", action="store_true", help="Verbose system configuration and memory mode"
384 )
385 parser.add_argument("--verbose-graph", action="store_true", help="Verbose graph rewriter")
386 parser.add_argument("--verbose-quantization", action="store_true", help="Verbose quantization")
387 parser.add_argument("--verbose-packing", action="store_true", help="Verbose pass packing")
388 parser.add_argument("--verbose-tensor-purpose", action="store_true", help="Verbose tensor purpose")
389 parser.add_argument("--verbose-tensor-format", action="store_true", help="Verbose tensor format")
390 parser.add_argument("--verbose-schedule", action="store_true", help="Verbose schedule")
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100391 parser.add_argument("--verbose-allocation", action="store_true", help="Verbose tensor allocation")
392 parser.add_argument(
393 "--verbose-high-level-command-stream", action="store_true", help="Verbose high level command stream"
394 )
395 parser.add_argument(
396 "--verbose-register-command-stream", action="store_true", help="Verbose register command stream"
397 )
398 parser.add_argument("--verbose-operators", action="store_true", help="Verbose operator list")
Fredrik Svedbergf5c07c42021-04-23 14:36:42 +0200399 parser.add_argument("--verbose-weights", action="store_true", help="Verbose weights information")
Tim Hallc1be0872022-03-03 17:50:52 +0000400 parser.add_argument("--verbose-performance", action="store_true", help="Verbose performance information")
Raul Farkas1c54ac12023-04-26 07:49:15 +0100401 parser.add_argument("--verbose-progress", action="store_true", help="Verbose progress information")
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100402 parser.add_argument(
403 "--show-cpu-operations", action="store_true", help="Show the operations that fall back to the CPU"
404 )
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100405 parser.add_argument("--timing", action="store_true", help="Time the compiler doing operations")
406 parser.add_argument(
wilisa0146c94772023-02-08 09:56:14 +0000407 "--force-symmetric-int-weights",
408 action="store_true",
409 help="Forces all zero points to 0 for signed integer weights",
410 )
411 parser.add_argument(
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100412 "--accelerator-config",
413 type=str,
414 default="ethos-u55-256",
415 choices=list(architecture_features.Accelerator.member_list()),
416 help="Accelerator configuration to use (default: %(default)s)",
417 )
418 parser.add_argument(
419 "--system-config",
420 type=str,
421 default=architecture_features.ArchitectureFeatures.DEFAULT_CONFIG,
422 help="System configuration to select from the Vela configuration file (default: %(default)s)",
423 )
424 parser.add_argument(
425 "--memory-mode",
426 type=str,
427 default=architecture_features.ArchitectureFeatures.DEFAULT_CONFIG,
428 help="Memory mode to select from the Vela configuration file (default: %(default)s)",
429 )
430 parser.add_argument(
431 "--tensor-allocator",
432 default=TensorAllocator.HillClimb,
433 type=lambda s: TensorAllocator[s],
434 choices=list(TensorAllocator),
435 help="Tensor Allocator algorithm (default: %(default)s)",
436 )
437 parser.add_argument(
438 "--show-subgraph-io-summary",
439 action="store_true",
440 help="Shows a summary of all the subgraphs and their inputs and outputs",
441 )
442 parser.add_argument(
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100443 "--max-block-dependency",
444 type=int,
445 default=architecture_features.ArchitectureFeatures.MAX_BLOCKDEP,
446 choices=range(0, architecture_features.ArchitectureFeatures.MAX_BLOCKDEP + 1),
447 help=(
448 "Set the maximum value that can be used for the block dependency between npu kernel operations"
449 " (default: %(default)s)"
450 ),
451 )
452 parser.add_argument(
Tim Halld8339a72021-05-27 18:49:40 +0100453 "--optimise",
454 type=lambda s: scheduler.OptimizationStrategy[s],
455 default=scheduler.OptimizationStrategy.Performance,
456 choices=list(scheduler.OptimizationStrategy),
457 help=(
458 "Set the optimisation strategy. The Size strategy results in minimal SRAM usage (does not use"
459 " arena-cache-size). The Performance strategy results in maximal performance (uses the arena-cache-size"
460 " if specified) (default: %(default)s)"
461 ),
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100462 )
463 parser.add_argument(
Tim Halld8339a72021-05-27 18:49:40 +0100464 "--arena-cache-size",
465 type=int,
466 help=(
467 "Set the size of the arena cache memory area, in bytes. If specified, this option overrides the memory"
468 " mode attribute with the same name in a Vela configuration file"
469 ),
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100470 )
471 parser.add_argument(
472 "--cpu-tensor-alignment",
473 type=int,
474 default=Tensor.AllocationQuantum,
475 help=(
476 "Controls the allocation byte alignment of cpu tensors including Ethos-U Custom"
477 " operator inputs and outputs (default: %(default)s)"
478 ),
479 )
Dwight Lidmanb9c95422021-08-18 19:24:14 +0200480 parser.add_argument(
481 "--recursion-limit",
482 type=int,
483 default=1000,
484 help="Set the recursion depth limit, may result in RecursionError if too low (default: %(default)s)",
485 )
Tim Hallcda4fcb2022-05-19 12:36:58 +0100486 parser.add_argument(
487 "--hillclimb-max-iterations",
488 type=int,
489 default=HillClimbAllocator.MAX_ITERATIONS,
490 help=(
491 "Set the maximum number of iterations the Hill Climb tensor allocator will run (default: %(default)s)"
492 ),
493 )
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100494 args = parser.parse_args(args=args)
Louis Verhaard52078302020-11-18 13:35:06 +0100495
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100496 # Generate the supported ops report and exit
497 if args.supported_ops_report:
498 generate_supported_ops()
499 return 0
Louis Verhaard52078302020-11-18 13:35:06 +0100500
Rickard Bolin1538dce2022-04-25 11:07:56 +0000501 if args.list_config_files:
502 list_config_files()
503 return 0
504
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100505 if args.network is None:
506 parser.error("the following argument is required: NETWORK")
Michael McGeagh2fa40ae2020-12-02 10:55:04 +0000507
Rickard Bolin1538dce2022-04-25 11:07:56 +0000508 def _parse_config(config):
Rickard Bolin7ce6b322022-06-02 09:30:33 +0000509 # Make sure the correct separator is used depending on OS
510 config = os.path.normpath(config)
511
Rickard Bolin1538dce2022-04-25 11:07:56 +0000512 if not config.endswith(".ini"):
513 raise InputFileError(config, "Configuration files must use the .ini extension")
514
Rickard Bolin6d7a4f02022-05-24 14:17:58 +0000515 if (
516 len(config.split(os.path.sep)) == 2
517 and not config.startswith(os.path.sep)
518 and not config.startswith(".")
519 and not config.startswith("~")
520 ):
Rickard Bolin1538dce2022-04-25 11:07:56 +0000521 config_path = os.path.join(CONFIG_FILES_PATH, config)
522 else:
Rickard Bolin6d7a4f02022-05-24 14:17:58 +0000523 # Check if the configuration file is correctly placed inside the config_files directory
524 if os.access(os.path.join(CONFIG_FILES_PATH, *config.split(os.path.sep)[-2:]), os.R_OK):
525 rel_path = os.path.join(*config.split(os.path.sep)[-2:])
526 print(
527 f"Warning: Consider accessing the configuration by --config {rel_path} since it is located "
528 "inside the config_files directory."
529 )
Rickard Bolin1538dce2022-04-25 11:07:56 +0000530 config_path = config
531
532 if not os.access(config_path, os.R_OK):
Rickard Bolin6d7a4f02022-05-24 14:17:58 +0000533 raise InputFileError(
534 config_path,
535 "File not found or is not readable. The configuration file is either not located in a folder "
536 "directly under the `config_files` directory or its path has not been provided correctly.",
537 )
Rickard Bolin1538dce2022-04-25 11:07:56 +0000538
539 return config_path
540
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100541 # check all config files exist because they will be read as a group
Rickard Bolin1538dce2022-04-25 11:07:56 +0000542 config_files = [_parse_config(cfg) for cfg in args.config] if args.config else None
Tim Hall79d07d22020-04-27 18:20:16 +0100543
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100544 if args.cpu_tensor_alignment < 16 or args.cpu_tensor_alignment & (args.cpu_tensor_alignment - 1) != 0:
545 parser.error(
546 "Invalid argument to --cpu-tensor-alignment = {} (must be greater than or equal to 16 and a power of 2)"
547 "".format(args.cpu_tensor_alignment)
548 )
Tim Hall79d07d22020-04-27 18:20:16 +0100549
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100550 if args.system_config == ArchitectureFeatures.DEFAULT_CONFIG:
551 print(f"Warning: Using {ArchitectureFeatures.DEFAULT_CONFIG} values for system configuration")
Tim Hall79d07d22020-04-27 18:20:16 +0100552
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100553 if args.memory_mode == ArchitectureFeatures.DEFAULT_CONFIG:
554 print(f"Warning: Using {ArchitectureFeatures.DEFAULT_CONFIG} values for memory mode")
Tim Hall79d07d22020-04-27 18:20:16 +0100555
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100556 if args.verbose_all:
557 for v in vars(args):
558 if v.startswith("verbose") and v != "verbose_all":
559 setattr(args, v, True)
560
Dwight Lidmanb9c95422021-08-18 19:24:14 +0200561 sys.setrecursionlimit(args.recursion_limit)
562
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100563 arch = architecture_features.ArchitectureFeatures(
Rickard Bolin1538dce2022-04-25 11:07:56 +0000564 vela_config_files=config_files,
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100565 system_config=args.system_config,
566 memory_mode=args.memory_mode,
567 accelerator_config=args.accelerator_config,
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100568 max_blockdep=args.max_block_dependency,
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100569 verbose_config=args.verbose_config,
Tim Halld8339a72021-05-27 18:49:40 +0100570 arena_cache_size=args.arena_cache_size,
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100571 )
572
573 compiler_options = compiler_driver.CompilerOptions(
574 verbose_graph=args.verbose_graph,
575 verbose_quantization=args.verbose_quantization,
576 verbose_packing=args.verbose_packing,
577 verbose_tensor_purpose=args.verbose_tensor_purpose,
578 verbose_tensor_format=args.verbose_tensor_format,
579 verbose_allocation=args.verbose_allocation,
580 verbose_high_level_command_stream=args.verbose_high_level_command_stream,
581 verbose_register_command_stream=args.verbose_register_command_stream,
582 verbose_operators=args.verbose_operators,
Fredrik Svedbergf5c07c42021-04-23 14:36:42 +0200583 verbose_weights=args.verbose_weights,
Tim Hallc1be0872022-03-03 17:50:52 +0000584 verbose_performance=args.verbose_performance,
Raul Farkas1c54ac12023-04-26 07:49:15 +0100585 verbose_progress=args.verbose_progress,
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100586 show_cpu_operations=args.show_cpu_operations,
587 tensor_allocator=args.tensor_allocator,
588 timing=args.timing,
wilisa0146c94772023-02-08 09:56:14 +0000589 force_symmetric_int_weights=args.force_symmetric_int_weights,
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100590 output_dir=args.output_dir,
591 cpu_tensor_alignment=args.cpu_tensor_alignment,
Tim Hallcda4fcb2022-05-19 12:36:58 +0100592 hillclimb_max_iterations=args.hillclimb_max_iterations,
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100593 )
594
595 scheduler_options = scheduler.SchedulerOptions(
Tim Halld8339a72021-05-27 18:49:40 +0100596 optimization_strategy=args.optimise,
597 sram_target=arch.arena_cache_size,
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100598 verbose_schedule=args.verbose_schedule,
Raul Farkas1c54ac12023-04-26 07:49:15 +0100599 verbose_progress=args.verbose_progress,
Henrik G Olssonea9b23c2021-03-23 17:34:49 +0100600 )
601
602 model_reader_options = model_reader.ModelReaderOptions()
603
604 nng = process(
605 args.network, args.enable_debug_db, arch, model_reader_options, compiler_options, scheduler_options
606 )
607
608 if args.show_subgraph_io_summary:
609 print_subgraph_io_summary(nng)
610
611 return 0
612 except VelaError as e:
613 print(e.data)
614 return 1