blob: 56363a14c99fc2b7a91f90c8ca999afc0583e250 [file] [log] [blame]
alexanderf4e2c472021-05-14 13:14:21 +01001#!/usr/bin/env python3
Isabella Gottardief2b9dd2022-02-16 14:24:03 +00002# Copyright (c) 2021-2022 Arm Limited. All rights reserved.
Isabella Gottardi2181d0a2021-04-07 09:27:38 +01003# SPDX-License-Identifier: Apache-2.0
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://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,
13# WITHOUT 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.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000016import errno
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010017import fnmatch
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000018import json
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010019import logging
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000020import os
21import re
22import shutil
23import subprocess
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010024import sys
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000025import urllib.request
26from argparse import ArgumentParser
27from argparse import ArgumentTypeError
Kshitij Sisodia3be26232021-10-29 12:29:06 +010028from collections import namedtuple
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000029from urllib.error import URLError
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +000030from scripts.py.check_update_resources_downloaded import get_md5sum_for_file
Kshitij Sisodia3be26232021-10-29 12:29:06 +010031
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010032
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000033json_uc_res = [
34 {
35 "use_case_name": "ad",
36 "url_prefix": [
37 "https://github.com/ARM-software/ML-zoo/raw/7c32b097f7d94aae2cd0b98a8ed5a3ba81e66b18/models/anomaly_detection/micronet_medium/tflite_int8/"
38 ],
39 "resources": [
40 {
41 "name": "ad_medium_int8.tflite",
42 "url": "{url_prefix:0}ad_medium_int8.tflite",
43 },
44 {"name": "ifm0.npy", "url": "{url_prefix:0}testing_input/input/0.npy"},
45 {"name": "ofm0.npy", "url": "{url_prefix:0}testing_output/Identity/0.npy"},
46 ],
47 },
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010048 {
49 "use_case_name": "asr",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000050 "url_prefix": [
51 "https://github.com/ARM-software/ML-zoo/raw/1a92aa08c0de49a7304e0a7f3f59df6f4fd33ac8/models/speech_recognition/wav2letter/tflite_pruned_int8/"
52 ],
53 "resources": [
54 {
55 "name": "wav2letter_pruned_int8.tflite",
56 "url": "{url_prefix:0}wav2letter_pruned_int8.tflite",
57 },
58 {
59 "name": "ifm0.npy",
60 "url": "{url_prefix:0}testing_input/input_2_int8/0.npy",
61 },
62 {
63 "name": "ofm0.npy",
64 "url": "{url_prefix:0}testing_output/Identity_int8/0.npy",
65 },
66 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010067 },
68 {
69 "use_case_name": "img_class",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000070 "url_prefix": [
71 "https://github.com/ARM-software/ML-zoo/raw/e0aa361b03c738047b9147d1a50e3f2dcb13dbcb/models/image_classification/mobilenet_v2_1.0_224/tflite_int8/"
72 ],
73 "resources": [
74 {
75 "name": "mobilenet_v2_1.0_224_INT8.tflite",
76 "url": "{url_prefix:0}mobilenet_v2_1.0_224_INT8.tflite",
77 },
78 {
79 "name": "ifm0.npy",
80 "url": "{url_prefix:0}testing_input/tfl.quantize/0.npy",
81 },
82 {
83 "name": "ofm0.npy",
84 "url": "{url_prefix:0}testing_output/MobilenetV2/Predictions/Reshape_11/0.npy",
85 },
86 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010087 },
88 {
Michael Levit06fcf752022-01-12 11:53:46 +020089 "use_case_name": "object_detection",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000090 "url_prefix": [
91 "https://github.com/emza-vs/ModelZoo/blob/v1.0/object_detection/"
92 ],
93 "resources": [
94 {
95 "name": "yolo-fastest_192_face_v4.tflite",
96 "url": "{url_prefix:0}yolo-fastest_192_face_v4.tflite?raw=true",
97 }
98 ],
Michael Levit06fcf752022-01-12 11:53:46 +020099 },
100 {
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100101 "use_case_name": "kws",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000102 "url_prefix": [
103 "https://github.com/ARM-software/ML-zoo/raw/9f506fe52b39df545f0e6c5ff9223f671bc5ae00/models/keyword_spotting/micronet_medium/tflite_int8/"
104 ],
105 "resources": [
106 {"name": "ifm0.npy", "url": "{url_prefix:0}testing_input/input/0.npy"},
107 {"name": "ofm0.npy", "url": "{url_prefix:0}testing_output/Identity/0.npy"},
108 {
109 "name": "kws_micronet_m.tflite",
110 "url": "{url_prefix:0}kws_micronet_m.tflite",
111 },
112 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100113 },
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000114 {
Éanna Ó Catháin8f958872021-09-15 09:32:30 +0100115 "use_case_name": "vww",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000116 "url_prefix": [
117 "https://github.com/ARM-software/ML-zoo/raw/7dd3b16bb84007daf88be8648983c07f3eb21140/models/visual_wake_words/micronet_vww4/tflite_int8/"
118 ],
119 "resources": [
120 {
121 "name": "vww4_128_128_INT8.tflite",
122 "url": "{url_prefix:0}vww4_128_128_INT8.tflite",
123 },
124 {"name": "ifm0.npy", "url": "{url_prefix:0}testing_input/input/0.npy"},
125 {"name": "ofm0.npy", "url": "{url_prefix:0}testing_output/Identity/0.npy"},
126 ],
Éanna Ó Catháin8f958872021-09-15 09:32:30 +0100127 },
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100128 {
129 "use_case_name": "kws_asr",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000130 "url_prefix": [
131 "https://github.com/ARM-software/ML-zoo/raw/1a92aa08c0de49a7304e0a7f3f59df6f4fd33ac8/models/speech_recognition/wav2letter/tflite_pruned_int8/",
132 "https://github.com/ARM-software/ML-zoo/raw/9f506fe52b39df545f0e6c5ff9223f671bc5ae00/models/keyword_spotting/micronet_medium/tflite_int8/",
133 ],
134 "resources": [
135 {
136 "name": "wav2letter_pruned_int8.tflite",
137 "url": "{url_prefix:0}wav2letter_pruned_int8.tflite",
138 },
139 {
140 "sub_folder": "asr",
141 "name": "ifm0.npy",
142 "url": "{url_prefix:0}testing_input/input_2_int8/0.npy",
143 },
144 {
145 "sub_folder": "asr",
146 "name": "ofm0.npy",
147 "url": "{url_prefix:0}testing_output/Identity_int8/0.npy",
148 },
149 {
150 "sub_folder": "kws",
151 "name": "ifm0.npy",
152 "url": "{url_prefix:1}testing_input/input/0.npy",
153 },
154 {
155 "sub_folder": "kws",
156 "name": "ofm0.npy",
157 "url": "{url_prefix:1}testing_output/Identity/0.npy",
158 },
159 {
160 "name": "kws_micronet_m.tflite",
161 "url": "{url_prefix:1}kws_micronet_m.tflite",
162 },
163 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100164 },
165 {
Richard Burton00553462021-11-10 16:27:14 +0000166 "use_case_name": "noise_reduction",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000167 "url_prefix": [
168 "https://github.com/ARM-software/ML-zoo/raw/a061600058097a2785d6f1f7785e5a2d2a142955/models/noise_suppression/RNNoise/tflite_int8/"
169 ],
170 "resources": [
171 {"name": "rnnoise_INT8.tflite", "url": "{url_prefix:0}rnnoise_INT8.tflite"},
172 {
173 "name": "ifm0.npy",
174 "url": "{url_prefix:0}testing_input/main_input_int8/0.npy",
175 },
176 {
177 "name": "ifm1.npy",
178 "url": "{url_prefix:0}testing_input/vad_gru_prev_state_int8/0.npy",
179 },
180 {
181 "name": "ifm2.npy",
182 "url": "{url_prefix:0}testing_input/noise_gru_prev_state_int8/0.npy",
183 },
184 {
185 "name": "ifm3.npy",
186 "url": "{url_prefix:0}testing_input/denoise_gru_prev_state_int8/0.npy",
187 },
188 {
189 "name": "ofm0.npy",
190 "url": "{url_prefix:0}testing_output/Identity_int8/0.npy",
191 },
192 {
193 "name": "ofm1.npy",
194 "url": "{url_prefix:0}testing_output/Identity_1_int8/0.npy",
195 },
196 {
197 "name": "ofm2.npy",
198 "url": "{url_prefix:0}testing_output/Identity_2_int8/0.npy",
199 },
200 {
201 "name": "ofm3.npy",
202 "url": "{url_prefix:0}testing_output/Identity_3_int8/0.npy",
203 },
204 {
205 "name": "ofm4.npy",
206 "url": "{url_prefix:0}testing_output/Identity_4_int8/0.npy",
207 },
208 ],
Richard Burton00553462021-11-10 16:27:14 +0000209 },
210 {
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100211 "use_case_name": "inference_runner",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000212 "url_prefix": [
213 "https://github.com/ARM-software/ML-zoo/raw/68b5fbc77ed28e67b2efc915997ea4477c1d9d5b/models/keyword_spotting/dnn_small/tflite_int8/"
214 ],
215 "resources": [
216 {
217 "name": "dnn_s_quantized.tflite",
218 "url": "{url_prefix:0}dnn_s_quantized.tflite",
219 }
220 ],
221 },
222]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100223
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100224# Valid NPU configurations:
225valid_npu_config_names = [
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000226 "ethos-u55-32",
227 "ethos-u55-64",
228 "ethos-u55-128",
229 "ethos-u55-256",
230 "ethos-u65-256",
231 "ethos-u65-512",
232]
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100233
234# Default NPU configurations (these are always run when the models are optimised)
235default_npu_config_names = [valid_npu_config_names[2], valid_npu_config_names[4]]
236
237# NPU config named tuple
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000238NPUConfig = namedtuple(
239 "NPUConfig",
240 [
241 "config_name",
242 "memory_mode",
243 "system_config",
244 "ethos_u_npu_id",
245 "ethos_u_config_id",
246 "arena_cache_size",
247 ],
248)
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100249
Kshitij Sisodia661959c2021-11-24 10:39:52 +0000250# The internal SRAM size for Corstone-300 implementation on MPS3 specified by AN552
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000251mps3_max_sram_sz = 2 * 1024 * 1024 # 2 MiB (2 banks of 1 MiB each)
Liam Barryb52b5852021-11-15 11:41:40 +0000252
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100253
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000254def call_command(command: str, verbose: bool = True) -> str:
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100255 """
256 Helpers function that call subprocess and return the output.
257
258 Parameters:
259 ----------
260 command (string): Specifies the command to run.
261 """
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000262 if verbose:
263 logging.info(command)
264 proc = subprocess.run(
265 command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True
266 )
alexander50a06502021-05-12 19:06:02 +0100267 log = proc.stdout.decode("utf-8")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000268 if proc.returncode == 0 and verbose:
alexander50a06502021-05-12 19:06:02 +0100269 logging.info(log)
270 else:
271 logging.error(log)
272 proc.check_returncode()
273 return log
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100274
275
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000276def get_default_npu_config_from_name(
277 config_name: str, arena_cache_size: int = 0
278) -> NPUConfig:
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100279 """
280 Gets the file suffix for the tflite file from the
281 `accelerator_config` string.
282
283 Parameters:
284 ----------
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000285 config_name (str): Ethos-U NPU configuration from valid_npu_config_names
286
287 arena_cache_size (int): Specifies arena cache size in bytes. If a value
288 greater than 0 is provided, this will be taken
289 as the cache size. If 0, the default values, as per
290 the NPU config requirements, are used.
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100291
292 Returns:
293 -------
294 NPUConfig: An NPU config named tuple populated with defaults for the given
295 config name
296 """
297 if config_name not in valid_npu_config_names:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000298 raise ValueError(
299 f"""
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100300 Invalid Ethos-U NPU configuration.
301 Select one from {valid_npu_config_names}.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000302 """
303 )
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100304
305 strings_ids = ["ethos-u55-", "ethos-u65-"]
306 processor_ids = ["U55", "U65"]
307 prefix_ids = ["H", "Y"]
308 memory_modes = ["Shared_Sram", "Dedicated_Sram"]
309 system_configs = ["Ethos_U55_High_End_Embedded", "Ethos_U65_High_End"]
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000310 memory_modes_arena = {
311 # For shared SRAM memory mode, we use the MPS3 SRAM size by default
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000312 "Shared_Sram": mps3_max_sram_sz if arena_cache_size <= 0 else arena_cache_size,
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000313 # For dedicated SRAM memory mode, we do no override the arena size. This is expected to
314 # be defined in the vela configuration file instead.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000315 "Dedicated_Sram": None if arena_cache_size <= 0 else arena_cache_size,
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000316 }
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100317
318 for i in range(len(strings_ids)):
319 if config_name.startswith(strings_ids[i]):
320 npu_config_id = config_name.replace(strings_ids[i], prefix_ids[i])
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000321 return NPUConfig(
322 config_name=config_name,
323 memory_mode=memory_modes[i],
324 system_config=system_configs[i],
325 ethos_u_npu_id=processor_ids[i],
326 ethos_u_config_id=npu_config_id,
327 arena_cache_size=memory_modes_arena[memory_modes[i]],
328 )
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100329
330 return None
331
332
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000333def remove_tree_dir(dir_path):
334 try:
335 # Remove the full directory
336 shutil.rmtree(dir_path)
337 # Re-create an empty one
338 os.mkdir(dir_path)
339 except Exception as e:
340 logging.error(f"Failed to delete {dir_path}.")
341
342
343def set_up_resources(
344 run_vela_on_models: bool = False,
345 additional_npu_config_names: list = (),
346 arena_cache_size: int = 0,
347 check_clean_folder: bool = False,
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000348 additional_requirements_file: str = ''
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000349):
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100350 """
351 Helpers function that retrieve the output from a command.
352
353 Parameters:
354 ----------
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000355 run_vela_on_models (bool): Specifies if run vela on downloaded models.
356 additional_npu_config_names(list): list of strings of Ethos-U NPU configs.
357 arena_cache_size (int): Specifies arena cache size in bytes. If a value
358 greater than 0 is provided, this will be taken
359 as the cache size. If 0, the default values, as per
360 the NPU config requirements, are used.
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000361 check_clean_folder (bool): Indicates whether the resources folder needs to
362 be checked for updates and cleaned.
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000363 additional_requirements_file (str): Path to a requirements.txt file if
364 additional packages need to be
365 installed.
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100366 """
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000367 # Paths
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100368 current_file_dir = os.path.dirname(os.path.abspath(__file__))
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000369 download_dir = os.path.abspath(
370 os.path.join(current_file_dir, "resources_downloaded")
371 )
372 metadata_file_path = os.path.join(
373 download_dir, "resources_downloaded_metadata.json"
374 )
375
376 metadata_dict = dict()
Richard Burtonb4123fd2022-03-04 09:19:09 +0000377 vela_version = "3.3.0"
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000378
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000379 setup_script_hash_verified = False
380 setup_script_hash = get_md5sum_for_file(os.path.abspath(__file__))
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100381
382 try:
383 # 1.1 Does the download dir exist?
384 os.mkdir(download_dir)
385 except OSError as e:
386 if e.errno == errno.EEXIST:
387 logging.info("'resources_downloaded' directory exists.")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000388 # Check and clean?
389 if check_clean_folder and os.path.isfile(metadata_file_path):
390 with open(metadata_file_path) as (metadata_file):
391 metadata_dict = json.load(metadata_file)
392 vela_in_metadata = metadata_dict["ethosu_vela_version"]
393 if vela_in_metadata != vela_version:
394 # Check if all the resources needs to be removed and regenerated.
395 # This can happen when the Vela version has changed.
396 logging.info(
397 f"Vela version in metadata is {vela_in_metadata}, current {vela_version}. Removing the resources and re-download them."
398 )
399 remove_tree_dir(download_dir)
400 metadata_dict = dict()
401 else:
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000402 # Check if the set_up_default_resorces.py has changed from last setup
403 setup_script_hash_verified = (
404 metadata_dict.get('set_up_script_md5sum') == setup_script_hash)
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100405 else:
406 raise
407
408 # 1.2 Does the virtual environment exist?
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000409 env_python = str(
410 os.path.abspath(os.path.join(download_dir, "env", "bin", "python3"))
411 )
412 env_activate = str(
413 os.path.abspath(os.path.join(download_dir, "env", "bin", "activate"))
414 )
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100415 if not os.path.isdir(os.path.join(download_dir, "env")):
416 os.chdir(download_dir)
417 # Create the virtual environment
418 command = "python3 -m venv env"
419 call_command(command)
420 commands = ["pip install --upgrade pip", "pip install --upgrade setuptools"]
421 for c in commands:
422 command = f"{env_python} -m {c}"
423 call_command(command)
424 os.chdir(current_file_dir)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000425
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000426 # 1.3 Make sure to have all the requirements
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000427 requirements = [f"ethos-u-vela=={vela_version}"]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100428 command = f"{env_python} -m pip freeze"
429 packages = call_command(command)
430 for req in requirements:
431 if req not in packages:
432 command = f"{env_python} -m pip install {req}"
433 call_command(command)
434
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000435 # 1.4 Install additional requirements, if a valid file has been provided
436 if additional_requirements_file and os.path.isfile(additional_requirements_file):
437 command = f"{env_python} -m pip install -r {additional_requirements_file}"
438 call_command(command)
439
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100440 # 2. Download models
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000441 logging.info("Downloading resources.")
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100442 for uc in json_uc_res:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000443 use_case_name = uc["use_case_name"]
444 res_url_prefix = uc["url_prefix"]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100445 try:
446 # Does the usecase_name download dir exist?
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000447 os.mkdir(os.path.join(download_dir, use_case_name))
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100448 except OSError as e:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000449 if e.errno == errno.EEXIST:
450 # The usecase_name download dir exist
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000451 if check_clean_folder and not setup_script_hash_verified:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000452 for idx, metadata_uc_url_prefix in enumerate(
453 [
454 f
455 for f in metadata_dict["resources_info"]
456 if f["use_case_name"] == use_case_name
457 ][0]["url_prefix"]
458 ):
459 if metadata_uc_url_prefix != res_url_prefix[idx]:
460 logging.info(f"Removing {use_case_name} resources.")
461 remove_tree_dir(os.path.join(download_dir, use_case_name))
462 break
463 elif e.errno != errno.EEXIST:
464 logging.error(f"Error creating {use_case_name} directory.")
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100465 raise
466
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000467 reg_expr_str = r"{url_prefix:(.*\d)}"
468 reg_expr_pattern = re.compile(reg_expr_str)
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100469 for res in uc["resources"]:
470 res_name = res["name"]
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000471 url_prefix_idx = int(reg_expr_pattern.search(res["url"]).group(1))
472 res_url = res_url_prefix[url_prefix_idx] + re.sub(
473 reg_expr_str, "", res["url"]
474 )
475
476 sub_folder = ""
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100477 if "sub_folder" in res:
478 try:
479 # Does the usecase_name/sub_folder download dir exist?
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000480 os.mkdir(
481 os.path.join(download_dir, use_case_name, res["sub_folder"])
482 )
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100483 except OSError as e:
484 if e.errno != errno.EEXIST:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000485 logging.error(
486 f"Error creating {use_case_name} / {res['sub_folder']} directory."
487 )
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100488 raise
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000489 sub_folder = res["sub_folder"]
490
491 res_dst = os.path.join(download_dir, use_case_name, sub_folder, res_name)
alexander3ef1fd42021-05-24 18:56:32 +0100492
493 if os.path.isfile(res_dst):
494 logging.info(f"File {res_dst} exists, skipping download.")
495 else:
496 try:
497 g = urllib.request.urlopen(res_url)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000498 with open(res_dst, "b+w") as f:
alexander3ef1fd42021-05-24 18:56:32 +0100499 f.write(g.read())
500 logging.info(f"- Downloaded {res_url} to {res_dst}.")
501 except URLError:
502 logging.error(f"URLError while downloading {res_url}.")
503 raise
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100504
505 # 3. Run vela on models in resources_downloaded
506 # New models will have same name with '_vela' appended.
507 # For example:
Kshitij Sisodia76a15802021-12-24 11:05:11 +0000508 # original model: kws_micronet_m.tflite
509 # after vela model: kws_micronet_m_vela_H128.tflite
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100510 #
511 # Note: To avoid to run vela twice on the same model, it's supposed that
512 # downloaded model names don't contain the 'vela' word.
513 if run_vela_on_models is True:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000514 config_file = os.path.join(
515 current_file_dir, "scripts", "vela", "default_vela.ini"
516 )
517 models = [
518 os.path.join(dirpath, f)
519 for dirpath, dirnames, files in os.walk(download_dir)
520 for f in fnmatch.filter(files, "*.tflite")
521 if "vela" not in f
522 ]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100523
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100524 # Consolidate all config names while discarding duplicates:
525 config_names = list(set(default_npu_config_names + additional_npu_config_names))
526
527 # Get npu config tuple for each config name in a list:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000528 npu_configs = [
529 get_default_npu_config_from_name(name, arena_cache_size)
530 for name in config_names
531 ]
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100532
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000533 logging.info(f"All models will be optimised for these configs:")
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100534 for config in npu_configs:
535 logging.info(config)
536
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000537 optimisation_skipped = False
538
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100539 for model in models:
540 output_dir = os.path.dirname(model)
alexander3ef1fd42021-05-24 18:56:32 +0100541 # model name after compiling with vela is an initial model name + _vela suffix
542 vela_optimised_model_path = str(model).replace(".tflite", "_vela.tflite")
alexander3ef1fd42021-05-24 18:56:32 +0100543
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100544 for config in npu_configs:
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000545 vela_command_arena_cache_size = ""
546
547 if config.arena_cache_size:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000548 vela_command_arena_cache_size = (
549 f"--arena-cache-size={config.arena_cache_size}"
550 )
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000551
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000552 vela_command = (
553 f". {env_activate} && vela {model} "
554 + f"--accelerator-config={config.config_name} "
555 + "--optimise Performance "
556 + f"--config {config_file} "
557 + f"--memory-mode={config.memory_mode} "
558 + f"--system-config={config.system_config} "
559 + f"--output-dir={output_dir} "
560 + f"{vela_command_arena_cache_size}"
561 )
alexander3ef1fd42021-05-24 18:56:32 +0100562
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100563 # we want the name to include the configuration suffix. For example: vela_H128,
564 # vela_Y512 etc.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000565 new_suffix = "_vela_" + config.ethos_u_config_id + ".tflite"
566 new_vela_optimised_model_path = vela_optimised_model_path.replace(
567 "_vela.tflite", new_suffix
568 )
Isabella Gottardi118f73e2021-09-16 17:54:35 +0100569
570 if os.path.isfile(new_vela_optimised_model_path):
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000571 logging.info(
572 f"File {new_vela_optimised_model_path} exists, skipping optimisation."
573 )
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000574 optimisation_skipped = True
Isabella Gottardi118f73e2021-09-16 17:54:35 +0100575 continue
576
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100577 call_command(vela_command)
Isabella Gottardi118f73e2021-09-16 17:54:35 +0100578
579 # rename default vela model
580 os.rename(vela_optimised_model_path, new_vela_optimised_model_path)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000581 logging.info(
582 f"Renaming {vela_optimised_model_path} to {new_vela_optimised_model_path}."
583 )
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100584
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000585 # If any optimisation was skipped, show how to regenerate:
586 if optimisation_skipped:
587 logging.warning("One or more optimisations were skipped.")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000588 logging.warning(
589 f"To optimise all the models, please remove the directory {download_dir}."
590 )
591
592 # 4. Collect and write metadata
593 logging.info("Collecting and write metadata.")
594 metadata_dict["ethosu_vela_version"] = vela_version
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000595 metadata_dict["set_up_script_md5sum"] = setup_script_hash.strip("\n")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000596 metadata_dict["resources_info"] = json_uc_res
597
598 with open(metadata_file_path, "w") as metadata_file:
599 json.dump(metadata_dict, metadata_file, indent=4)
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000600
601
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000602if __name__ == "__main__":
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100603 parser = ArgumentParser()
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000604 parser.add_argument(
605 "--skip-vela",
606 help="Do not run Vela optimizer on downloaded models.",
607 action="store_true",
608 )
609 parser.add_argument(
610 "--additional-ethos-u-config-name",
611 help=f"""Additional (non-default) configurations for Vela:
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100612 {valid_npu_config_names}""",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000613 default=[],
614 action="append",
615 )
616 parser.add_argument(
617 "--arena-cache-size",
618 help="Arena cache size in bytes (if overriding the defaults)",
619 type=int,
620 default=0,
621 )
622 parser.add_argument(
623 "--clean",
624 help="Clean the disctory and optimize the downloaded resources",
625 action="store_true",
626 )
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000627 parser.add_argument(
628 "--requirements-file",
629 help="Path to requirements.txt file to install additional packages",
630 type=str,
631 default=os.path.join(os.path.dirname(os.path.abspath(__file__)),
632 'scripts', 'py', 'requirements.txt')
633 )
634
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100635 args = parser.parse_args()
Kshitij Sisodiab9e9c892021-05-27 13:57:35 +0100636
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000637 if args.arena_cache_size < 0:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000638 raise ArgumentTypeError("Arena cache size cannot not be less than 0")
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000639
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000640 if not os.path.isfile(args.requirements_file):
641 raise ArgumentTypeError(f"Invalid requirements file: {args.requirements_file}")
642
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000643 logging.basicConfig(filename="log_build_default.log", level=logging.DEBUG)
Kshitij Sisodiab9e9c892021-05-27 13:57:35 +0100644 logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
645
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000646 set_up_resources(
647 not args.skip_vela,
648 args.additional_ethos_u_config_name,
649 args.arena_cache_size,
650 args.clean,
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000651 args.requirements_file
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000652 )