blob: 9e0bdf41528ef905f020bae4eb9acac8329282bf [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
Richard Burton17069622022-03-17 10:54:26 +000030from pathlib import Path
Isabella Gottardi6c2ea452022-03-11 13:25:08 +000031
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +000032from scripts.py.check_update_resources_downloaded import get_md5sum_for_file
Kshitij Sisodia3be26232021-10-29 12:29:06 +010033
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010034
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000035json_uc_res = [
36 {
37 "use_case_name": "ad",
38 "url_prefix": [
39 "https://github.com/ARM-software/ML-zoo/raw/7c32b097f7d94aae2cd0b98a8ed5a3ba81e66b18/models/anomaly_detection/micronet_medium/tflite_int8/"
40 ],
41 "resources": [
42 {
43 "name": "ad_medium_int8.tflite",
44 "url": "{url_prefix:0}ad_medium_int8.tflite",
45 },
46 {"name": "ifm0.npy", "url": "{url_prefix:0}testing_input/input/0.npy"},
47 {"name": "ofm0.npy", "url": "{url_prefix:0}testing_output/Identity/0.npy"},
48 ],
49 },
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010050 {
51 "use_case_name": "asr",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000052 "url_prefix": [
53 "https://github.com/ARM-software/ML-zoo/raw/1a92aa08c0de49a7304e0a7f3f59df6f4fd33ac8/models/speech_recognition/wav2letter/tflite_pruned_int8/"
54 ],
55 "resources": [
56 {
57 "name": "wav2letter_pruned_int8.tflite",
58 "url": "{url_prefix:0}wav2letter_pruned_int8.tflite",
59 },
60 {
61 "name": "ifm0.npy",
62 "url": "{url_prefix:0}testing_input/input_2_int8/0.npy",
63 },
64 {
65 "name": "ofm0.npy",
66 "url": "{url_prefix:0}testing_output/Identity_int8/0.npy",
67 },
68 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010069 },
70 {
71 "use_case_name": "img_class",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000072 "url_prefix": [
73 "https://github.com/ARM-software/ML-zoo/raw/e0aa361b03c738047b9147d1a50e3f2dcb13dbcb/models/image_classification/mobilenet_v2_1.0_224/tflite_int8/"
74 ],
75 "resources": [
76 {
77 "name": "mobilenet_v2_1.0_224_INT8.tflite",
78 "url": "{url_prefix:0}mobilenet_v2_1.0_224_INT8.tflite",
79 },
80 {
81 "name": "ifm0.npy",
82 "url": "{url_prefix:0}testing_input/tfl.quantize/0.npy",
83 },
84 {
85 "name": "ofm0.npy",
86 "url": "{url_prefix:0}testing_output/MobilenetV2/Predictions/Reshape_11/0.npy",
87 },
88 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010089 },
90 {
Michael Levit06fcf752022-01-12 11:53:46 +020091 "use_case_name": "object_detection",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000092 "url_prefix": [
93 "https://github.com/emza-vs/ModelZoo/blob/v1.0/object_detection/"
94 ],
95 "resources": [
96 {
97 "name": "yolo-fastest_192_face_v4.tflite",
98 "url": "{url_prefix:0}yolo-fastest_192_face_v4.tflite?raw=true",
99 }
100 ],
Michael Levit06fcf752022-01-12 11:53:46 +0200101 },
102 {
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100103 "use_case_name": "kws",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000104 "url_prefix": [
105 "https://github.com/ARM-software/ML-zoo/raw/9f506fe52b39df545f0e6c5ff9223f671bc5ae00/models/keyword_spotting/micronet_medium/tflite_int8/"
106 ],
107 "resources": [
108 {"name": "ifm0.npy", "url": "{url_prefix:0}testing_input/input/0.npy"},
109 {"name": "ofm0.npy", "url": "{url_prefix:0}testing_output/Identity/0.npy"},
110 {
111 "name": "kws_micronet_m.tflite",
112 "url": "{url_prefix:0}kws_micronet_m.tflite",
113 },
114 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100115 },
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000116 {
Éanna Ó Catháin8f958872021-09-15 09:32:30 +0100117 "use_case_name": "vww",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000118 "url_prefix": [
119 "https://github.com/ARM-software/ML-zoo/raw/7dd3b16bb84007daf88be8648983c07f3eb21140/models/visual_wake_words/micronet_vww4/tflite_int8/"
120 ],
121 "resources": [
122 {
123 "name": "vww4_128_128_INT8.tflite",
124 "url": "{url_prefix:0}vww4_128_128_INT8.tflite",
125 },
126 {"name": "ifm0.npy", "url": "{url_prefix:0}testing_input/input/0.npy"},
127 {"name": "ofm0.npy", "url": "{url_prefix:0}testing_output/Identity/0.npy"},
128 ],
Éanna Ó Catháin8f958872021-09-15 09:32:30 +0100129 },
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100130 {
131 "use_case_name": "kws_asr",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000132 "url_prefix": [
133 "https://github.com/ARM-software/ML-zoo/raw/1a92aa08c0de49a7304e0a7f3f59df6f4fd33ac8/models/speech_recognition/wav2letter/tflite_pruned_int8/",
134 "https://github.com/ARM-software/ML-zoo/raw/9f506fe52b39df545f0e6c5ff9223f671bc5ae00/models/keyword_spotting/micronet_medium/tflite_int8/",
135 ],
136 "resources": [
137 {
138 "name": "wav2letter_pruned_int8.tflite",
139 "url": "{url_prefix:0}wav2letter_pruned_int8.tflite",
140 },
141 {
142 "sub_folder": "asr",
143 "name": "ifm0.npy",
144 "url": "{url_prefix:0}testing_input/input_2_int8/0.npy",
145 },
146 {
147 "sub_folder": "asr",
148 "name": "ofm0.npy",
149 "url": "{url_prefix:0}testing_output/Identity_int8/0.npy",
150 },
151 {
152 "sub_folder": "kws",
153 "name": "ifm0.npy",
154 "url": "{url_prefix:1}testing_input/input/0.npy",
155 },
156 {
157 "sub_folder": "kws",
158 "name": "ofm0.npy",
159 "url": "{url_prefix:1}testing_output/Identity/0.npy",
160 },
161 {
162 "name": "kws_micronet_m.tflite",
163 "url": "{url_prefix:1}kws_micronet_m.tflite",
164 },
165 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100166 },
167 {
Richard Burton00553462021-11-10 16:27:14 +0000168 "use_case_name": "noise_reduction",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000169 "url_prefix": [
170 "https://github.com/ARM-software/ML-zoo/raw/a061600058097a2785d6f1f7785e5a2d2a142955/models/noise_suppression/RNNoise/tflite_int8/"
171 ],
172 "resources": [
173 {"name": "rnnoise_INT8.tflite", "url": "{url_prefix:0}rnnoise_INT8.tflite"},
174 {
175 "name": "ifm0.npy",
176 "url": "{url_prefix:0}testing_input/main_input_int8/0.npy",
177 },
178 {
179 "name": "ifm1.npy",
180 "url": "{url_prefix:0}testing_input/vad_gru_prev_state_int8/0.npy",
181 },
182 {
183 "name": "ifm2.npy",
184 "url": "{url_prefix:0}testing_input/noise_gru_prev_state_int8/0.npy",
185 },
186 {
187 "name": "ifm3.npy",
188 "url": "{url_prefix:0}testing_input/denoise_gru_prev_state_int8/0.npy",
189 },
190 {
191 "name": "ofm0.npy",
192 "url": "{url_prefix:0}testing_output/Identity_int8/0.npy",
193 },
194 {
195 "name": "ofm1.npy",
196 "url": "{url_prefix:0}testing_output/Identity_1_int8/0.npy",
197 },
198 {
199 "name": "ofm2.npy",
200 "url": "{url_prefix:0}testing_output/Identity_2_int8/0.npy",
201 },
202 {
203 "name": "ofm3.npy",
204 "url": "{url_prefix:0}testing_output/Identity_3_int8/0.npy",
205 },
206 {
207 "name": "ofm4.npy",
208 "url": "{url_prefix:0}testing_output/Identity_4_int8/0.npy",
209 },
210 ],
Richard Burton00553462021-11-10 16:27:14 +0000211 },
212 {
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100213 "use_case_name": "inference_runner",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000214 "url_prefix": [
215 "https://github.com/ARM-software/ML-zoo/raw/68b5fbc77ed28e67b2efc915997ea4477c1d9d5b/models/keyword_spotting/dnn_small/tflite_int8/"
216 ],
217 "resources": [
218 {
219 "name": "dnn_s_quantized.tflite",
220 "url": "{url_prefix:0}dnn_s_quantized.tflite",
221 }
222 ],
223 },
224]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100225
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100226# Valid NPU configurations:
227valid_npu_config_names = [
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000228 "ethos-u55-32",
229 "ethos-u55-64",
230 "ethos-u55-128",
231 "ethos-u55-256",
232 "ethos-u65-256",
233 "ethos-u65-512",
234]
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100235
236# Default NPU configurations (these are always run when the models are optimised)
237default_npu_config_names = [valid_npu_config_names[2], valid_npu_config_names[4]]
238
239# NPU config named tuple
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000240NPUConfig = namedtuple(
241 "NPUConfig",
242 [
243 "config_name",
244 "memory_mode",
245 "system_config",
246 "ethos_u_npu_id",
247 "ethos_u_config_id",
248 "arena_cache_size",
249 ],
250)
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100251
Kshitij Sisodia661959c2021-11-24 10:39:52 +0000252# The internal SRAM size for Corstone-300 implementation on MPS3 specified by AN552
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000253mps3_max_sram_sz = 2 * 1024 * 1024 # 2 MiB (2 banks of 1 MiB each)
Liam Barryb52b5852021-11-15 11:41:40 +0000254
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100255
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000256def call_command(command: str, verbose: bool = True) -> str:
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100257 """
258 Helpers function that call subprocess and return the output.
259
260 Parameters:
261 ----------
262 command (string): Specifies the command to run.
263 """
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000264 if verbose:
265 logging.info(command)
266 proc = subprocess.run(
267 command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True
268 )
alexander50a06502021-05-12 19:06:02 +0100269 log = proc.stdout.decode("utf-8")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000270 if proc.returncode == 0 and verbose:
alexander50a06502021-05-12 19:06:02 +0100271 logging.info(log)
272 else:
273 logging.error(log)
274 proc.check_returncode()
275 return log
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100276
277
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000278def get_default_npu_config_from_name(
279 config_name: str, arena_cache_size: int = 0
280) -> NPUConfig:
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100281 """
Richard Burton17069622022-03-17 10:54:26 +0000282 Gets the file suffix for the TFLite file from the
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100283 `accelerator_config` string.
284
285 Parameters:
286 ----------
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000287 config_name (str): Ethos-U NPU configuration from valid_npu_config_names
288
289 arena_cache_size (int): Specifies arena cache size in bytes. If a value
290 greater than 0 is provided, this will be taken
291 as the cache size. If 0, the default values, as per
292 the NPU config requirements, are used.
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100293
294 Returns:
295 -------
296 NPUConfig: An NPU config named tuple populated with defaults for the given
297 config name
298 """
299 if config_name not in valid_npu_config_names:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000300 raise ValueError(
301 f"""
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100302 Invalid Ethos-U NPU configuration.
303 Select one from {valid_npu_config_names}.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000304 """
305 )
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100306
307 strings_ids = ["ethos-u55-", "ethos-u65-"]
308 processor_ids = ["U55", "U65"]
309 prefix_ids = ["H", "Y"]
310 memory_modes = ["Shared_Sram", "Dedicated_Sram"]
311 system_configs = ["Ethos_U55_High_End_Embedded", "Ethos_U65_High_End"]
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000312 memory_modes_arena = {
Richard Burton17069622022-03-17 10:54:26 +0000313 # For shared SRAM memory mode, we use the MPS3 SRAM size by default.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000314 "Shared_Sram": mps3_max_sram_sz if arena_cache_size <= 0 else arena_cache_size,
Richard Burton17069622022-03-17 10:54:26 +0000315 # For dedicated SRAM memory mode, we do not override the arena size. This is expected to
316 # be defined in the Vela configuration file instead.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000317 "Dedicated_Sram": None if arena_cache_size <= 0 else arena_cache_size,
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000318 }
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100319
320 for i in range(len(strings_ids)):
321 if config_name.startswith(strings_ids[i]):
322 npu_config_id = config_name.replace(strings_ids[i], prefix_ids[i])
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000323 return NPUConfig(
324 config_name=config_name,
325 memory_mode=memory_modes[i],
326 system_config=system_configs[i],
327 ethos_u_npu_id=processor_ids[i],
328 ethos_u_config_id=npu_config_id,
329 arena_cache_size=memory_modes_arena[memory_modes[i]],
330 )
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100331
332 return None
333
334
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000335def remove_tree_dir(dir_path):
336 try:
Richard Burton17069622022-03-17 10:54:26 +0000337 # Remove the full directory.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000338 shutil.rmtree(dir_path)
Richard Burton17069622022-03-17 10:54:26 +0000339 # Re-create an empty one.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000340 os.mkdir(dir_path)
341 except Exception as e:
342 logging.error(f"Failed to delete {dir_path}.")
343
344
345def set_up_resources(
346 run_vela_on_models: bool = False,
Richard Burton17069622022-03-17 10:54:26 +0000347 additional_npu_config_names: tuple = (),
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000348 arena_cache_size: int = 0,
349 check_clean_folder: bool = False,
Isabella Gottardi6c2ea452022-03-11 13:25:08 +0000350 additional_requirements_file: str = "",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000351):
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100352 """
353 Helpers function that retrieve the output from a command.
354
355 Parameters:
356 ----------
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000357 run_vela_on_models (bool): Specifies if run vela on downloaded models.
358 additional_npu_config_names(list): list of strings of Ethos-U NPU configs.
359 arena_cache_size (int): Specifies arena cache size in bytes. If a value
360 greater than 0 is provided, this will be taken
361 as the cache size. If 0, the default values, as per
362 the NPU config requirements, are used.
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000363 check_clean_folder (bool): Indicates whether the resources folder needs to
364 be checked for updates and cleaned.
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000365 additional_requirements_file (str): Path to a requirements.txt file if
366 additional packages need to be
367 installed.
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100368 """
Richard Burton17069622022-03-17 10:54:26 +0000369 # Paths.
370 current_file_dir = Path(__file__).parent.resolve()
371 download_dir = current_file_dir / "resources_downloaded"
372 metadata_file_path = download_dir / "resources_downloaded_metadata.json"
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000373
374 metadata_dict = dict()
Richard Burtonb4123fd2022-03-04 09:19:09 +0000375 vela_version = "3.3.0"
Isabella Gottardi6c2ea452022-03-11 13:25:08 +0000376 py3_major_version_minimum = 3 # Python > 3.8 is required
377 py3_minor_version_minimum = 8
378
379 # Is Python minimum requirement matched?
380 py3_version = sys.version_info
381 if (
382 py3_version.major < py3_major_version_minimum
383 or py3_version.minor < py3_minor_version_minimum
384 ):
385 raise Exception(
386 "ERROR: Python3.8+ is required, please see the documentation on how to update it."
387 )
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000388
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000389 setup_script_hash_verified = False
Richard Burton17069622022-03-17 10:54:26 +0000390 setup_script_hash = get_md5sum_for_file(Path(__file__).resolve())
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100391
392 try:
393 # 1.1 Does the download dir exist?
Richard Burton17069622022-03-17 10:54:26 +0000394 download_dir.mkdir()
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100395 except OSError as e:
396 if e.errno == errno.EEXIST:
397 logging.info("'resources_downloaded' directory exists.")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000398 # Check and clean?
Richard Burton17069622022-03-17 10:54:26 +0000399 if check_clean_folder and metadata_file_path.is_file():
400 with open(metadata_file_path) as metadata_file:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000401 metadata_dict = json.load(metadata_file)
402 vela_in_metadata = metadata_dict["ethosu_vela_version"]
403 if vela_in_metadata != vela_version:
404 # Check if all the resources needs to be removed and regenerated.
405 # This can happen when the Vela version has changed.
406 logging.info(
407 f"Vela version in metadata is {vela_in_metadata}, current {vela_version}. Removing the resources and re-download them."
408 )
409 remove_tree_dir(download_dir)
410 metadata_dict = dict()
411 else:
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000412 # Check if the set_up_default_resorces.py has changed from last setup
413 setup_script_hash_verified = (
Isabella Gottardi6c2ea452022-03-11 13:25:08 +0000414 metadata_dict.get("set_up_script_md5sum")
415 == setup_script_hash
416 )
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100417 else:
418 raise
419
420 # 1.2 Does the virtual environment exist?
Richard Burton17069622022-03-17 10:54:26 +0000421 env_python = str(download_dir / "env" / "bin" / "python3")
422 env_activate = str(download_dir / "env" / "bin" / "activate")
423
424 if not (download_dir / "env").is_dir():
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100425 os.chdir(download_dir)
Richard Burton17069622022-03-17 10:54:26 +0000426 # Create the virtual environment.
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100427 command = "python3 -m venv env"
428 call_command(command)
429 commands = ["pip install --upgrade pip", "pip install --upgrade setuptools"]
430 for c in commands:
431 command = f"{env_python} -m {c}"
432 call_command(command)
433 os.chdir(current_file_dir)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000434
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000435 # 1.3 Make sure to have all the requirements
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000436 requirements = [f"ethos-u-vela=={vela_version}"]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100437 command = f"{env_python} -m pip freeze"
438 packages = call_command(command)
439 for req in requirements:
440 if req not in packages:
441 command = f"{env_python} -m pip install {req}"
442 call_command(command)
443
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000444 # 1.4 Install additional requirements, if a valid file has been provided
445 if additional_requirements_file and os.path.isfile(additional_requirements_file):
446 command = f"{env_python} -m pip install -r {additional_requirements_file}"
447 call_command(command)
448
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100449 # 2. Download models
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000450 logging.info("Downloading resources.")
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100451 for uc in json_uc_res:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000452 use_case_name = uc["use_case_name"]
453 res_url_prefix = uc["url_prefix"]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100454 try:
455 # Does the usecase_name download dir exist?
Richard Burton17069622022-03-17 10:54:26 +0000456 (download_dir / use_case_name).mkdir()
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100457 except OSError as e:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000458 if e.errno == errno.EEXIST:
Richard Burton17069622022-03-17 10:54:26 +0000459 # The usecase_name download dir exist.
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000460 if check_clean_folder and not setup_script_hash_verified:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000461 for idx, metadata_uc_url_prefix in enumerate(
462 [
463 f
464 for f in metadata_dict["resources_info"]
465 if f["use_case_name"] == use_case_name
466 ][0]["url_prefix"]
467 ):
468 if metadata_uc_url_prefix != res_url_prefix[idx]:
469 logging.info(f"Removing {use_case_name} resources.")
Richard Burton17069622022-03-17 10:54:26 +0000470 remove_tree_dir(download_dir / use_case_name)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000471 break
472 elif e.errno != errno.EEXIST:
473 logging.error(f"Error creating {use_case_name} directory.")
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100474 raise
475
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000476 reg_expr_str = r"{url_prefix:(.*\d)}"
477 reg_expr_pattern = re.compile(reg_expr_str)
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100478 for res in uc["resources"]:
479 res_name = res["name"]
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000480 url_prefix_idx = int(reg_expr_pattern.search(res["url"]).group(1))
481 res_url = res_url_prefix[url_prefix_idx] + re.sub(
482 reg_expr_str, "", res["url"]
483 )
484
485 sub_folder = ""
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100486 if "sub_folder" in res:
487 try:
488 # Does the usecase_name/sub_folder download dir exist?
Richard Burton17069622022-03-17 10:54:26 +0000489 (download_dir / use_case_name / res["sub_folder"]).mkdir()
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100490 except OSError as e:
491 if e.errno != errno.EEXIST:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000492 logging.error(
493 f"Error creating {use_case_name} / {res['sub_folder']} directory."
494 )
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100495 raise
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000496 sub_folder = res["sub_folder"]
497
Richard Burton17069622022-03-17 10:54:26 +0000498 res_dst = download_dir / use_case_name / sub_folder / res_name
alexander3ef1fd42021-05-24 18:56:32 +0100499
Richard Burton17069622022-03-17 10:54:26 +0000500 if res_dst.is_file():
alexander3ef1fd42021-05-24 18:56:32 +0100501 logging.info(f"File {res_dst} exists, skipping download.")
502 else:
503 try:
504 g = urllib.request.urlopen(res_url)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000505 with open(res_dst, "b+w") as f:
alexander3ef1fd42021-05-24 18:56:32 +0100506 f.write(g.read())
507 logging.info(f"- Downloaded {res_url} to {res_dst}.")
508 except URLError:
509 logging.error(f"URLError while downloading {res_url}.")
510 raise
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100511
512 # 3. Run vela on models in resources_downloaded
513 # New models will have same name with '_vela' appended.
514 # For example:
Kshitij Sisodia76a15802021-12-24 11:05:11 +0000515 # original model: kws_micronet_m.tflite
516 # after vela model: kws_micronet_m_vela_H128.tflite
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100517 #
518 # Note: To avoid to run vela twice on the same model, it's supposed that
519 # downloaded model names don't contain the 'vela' word.
520 if run_vela_on_models is True:
Richard Burton17069622022-03-17 10:54:26 +0000521 config_file = current_file_dir / "scripts" / "vela" / "default_vela.ini"
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000522 models = [
Richard Burton17069622022-03-17 10:54:26 +0000523 Path(dirpath) / f
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000524 for dirpath, dirnames, files in os.walk(download_dir)
525 for f in fnmatch.filter(files, "*.tflite")
526 if "vela" not in f
527 ]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100528
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100529 # Consolidate all config names while discarding duplicates:
530 config_names = list(set(default_npu_config_names + additional_npu_config_names))
531
532 # Get npu config tuple for each config name in a list:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000533 npu_configs = [
534 get_default_npu_config_from_name(name, arena_cache_size)
535 for name in config_names
536 ]
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100537
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000538 logging.info(f"All models will be optimised for these configs:")
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100539 for config in npu_configs:
540 logging.info(config)
541
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000542 optimisation_skipped = False
543
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100544 for model in models:
Richard Burton17069622022-03-17 10:54:26 +0000545 output_dir = model.parent
alexander3ef1fd42021-05-24 18:56:32 +0100546 # model name after compiling with vela is an initial model name + _vela suffix
Richard Burton17069622022-03-17 10:54:26 +0000547 vela_optimised_model_path = model.parent / (model.stem + "_vela.tflite")
alexander3ef1fd42021-05-24 18:56:32 +0100548
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100549 for config in npu_configs:
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000550 vela_command_arena_cache_size = ""
551
552 if config.arena_cache_size:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000553 vela_command_arena_cache_size = (
554 f"--arena-cache-size={config.arena_cache_size}"
555 )
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000556
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000557 vela_command = (
558 f". {env_activate} && vela {model} "
559 + f"--accelerator-config={config.config_name} "
560 + "--optimise Performance "
561 + f"--config {config_file} "
562 + f"--memory-mode={config.memory_mode} "
563 + f"--system-config={config.system_config} "
564 + f"--output-dir={output_dir} "
565 + f"{vela_command_arena_cache_size}"
566 )
alexander3ef1fd42021-05-24 18:56:32 +0100567
Richard Burton17069622022-03-17 10:54:26 +0000568 # We want the name to include the configuration suffix. For example: vela_H128,
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100569 # vela_Y512 etc.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000570 new_suffix = "_vela_" + config.ethos_u_config_id + ".tflite"
Richard Burton17069622022-03-17 10:54:26 +0000571 new_vela_optimised_model_path = model.parent / (model.stem + new_suffix)
Isabella Gottardi118f73e2021-09-16 17:54:35 +0100572
Richard Burton17069622022-03-17 10:54:26 +0000573 if new_vela_optimised_model_path.is_file():
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000574 logging.info(
575 f"File {new_vela_optimised_model_path} exists, skipping optimisation."
576 )
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000577 optimisation_skipped = True
Isabella Gottardi118f73e2021-09-16 17:54:35 +0100578 continue
579
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100580 call_command(vela_command)
Isabella Gottardi118f73e2021-09-16 17:54:35 +0100581
Richard Burton17069622022-03-17 10:54:26 +0000582 # Rename default vela model.
583 vela_optimised_model_path.rename(new_vela_optimised_model_path)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000584 logging.info(
585 f"Renaming {vela_optimised_model_path} to {new_vela_optimised_model_path}."
586 )
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100587
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000588 # If any optimisation was skipped, show how to regenerate:
589 if optimisation_skipped:
590 logging.warning("One or more optimisations were skipped.")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000591 logging.warning(
592 f"To optimise all the models, please remove the directory {download_dir}."
593 )
594
595 # 4. Collect and write metadata
596 logging.info("Collecting and write metadata.")
597 metadata_dict["ethosu_vela_version"] = vela_version
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000598 metadata_dict["set_up_script_md5sum"] = setup_script_hash.strip("\n")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000599 metadata_dict["resources_info"] = json_uc_res
600
601 with open(metadata_file_path, "w") as metadata_file:
602 json.dump(metadata_dict, metadata_file, indent=4)
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000603
604
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000605if __name__ == "__main__":
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100606 parser = ArgumentParser()
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000607 parser.add_argument(
608 "--skip-vela",
609 help="Do not run Vela optimizer on downloaded models.",
610 action="store_true",
611 )
612 parser.add_argument(
613 "--additional-ethos-u-config-name",
614 help=f"""Additional (non-default) configurations for Vela:
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100615 {valid_npu_config_names}""",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000616 default=[],
617 action="append",
618 )
619 parser.add_argument(
620 "--arena-cache-size",
621 help="Arena cache size in bytes (if overriding the defaults)",
622 type=int,
623 default=0,
624 )
625 parser.add_argument(
626 "--clean",
Richard Burton17069622022-03-17 10:54:26 +0000627 help="Clean the directory and optimize the downloaded resources",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000628 action="store_true",
629 )
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000630 parser.add_argument(
631 "--requirements-file",
632 help="Path to requirements.txt file to install additional packages",
633 type=str,
Richard Burton17069622022-03-17 10:54:26 +0000634 default=Path(__file__).parent.resolve() / 'scripts' / 'py' / 'requirements.txt'
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000635 )
636
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100637 args = parser.parse_args()
Kshitij Sisodiab9e9c892021-05-27 13:57:35 +0100638
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000639 if args.arena_cache_size < 0:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000640 raise ArgumentTypeError("Arena cache size cannot not be less than 0")
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000641
Richard Burton17069622022-03-17 10:54:26 +0000642 if not Path(args.requirements_file).is_file():
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000643 raise ArgumentTypeError(f"Invalid requirements file: {args.requirements_file}")
644
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000645 logging.basicConfig(filename="log_build_default.log", level=logging.DEBUG)
Kshitij Sisodiab9e9c892021-05-27 13:57:35 +0100646 logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
647
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000648 set_up_resources(
649 not args.skip_vela,
650 args.additional_ethos_u_config_name,
651 args.arena_cache_size,
652 args.clean,
Isabella Gottardi6c2ea452022-03-11 13:25:08 +0000653 args.requirements_file,
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000654 )