blob: dd702c748ab9726bac491557f264adcb63047a44 [file] [log] [blame]
alexanderf4e2c472021-05-14 13:14:21 +01001#!/usr/bin/env python3
Kshitij Sisodia26bc9232023-03-10 16:33:23 +00002# SPDX-FileCopyrightText: Copyright 2021-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
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
Kshitij Sisodia36b5b132023-06-09 11:58:26 +010026import venv
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000027from argparse import ArgumentParser
28from argparse import ArgumentTypeError
Kshitij Sisodia3be26232021-10-29 12:29:06 +010029from collections import namedtuple
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000030from urllib.error import URLError
Richard Burton17069622022-03-17 10:54:26 +000031from pathlib import Path
Isabella Gottardi6c2ea452022-03-11 13:25:08 +000032
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +000033from scripts.py.check_update_resources_downloaded import get_md5sum_for_file
Kshitij Sisodia3be26232021-10-29 12:29:06 +010034
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010035
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000036json_uc_res = [
37 {
38 "use_case_name": "ad",
39 "url_prefix": [
40 "https://github.com/ARM-software/ML-zoo/raw/7c32b097f7d94aae2cd0b98a8ed5a3ba81e66b18/models/anomaly_detection/micronet_medium/tflite_int8/"
41 ],
42 "resources": [
43 {
44 "name": "ad_medium_int8.tflite",
45 "url": "{url_prefix:0}ad_medium_int8.tflite",
46 },
47 {"name": "ifm0.npy", "url": "{url_prefix:0}testing_input/input/0.npy"},
48 {"name": "ofm0.npy", "url": "{url_prefix:0}testing_output/Identity/0.npy"},
49 ],
50 },
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010051 {
52 "use_case_name": "asr",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000053 "url_prefix": [
54 "https://github.com/ARM-software/ML-zoo/raw/1a92aa08c0de49a7304e0a7f3f59df6f4fd33ac8/models/speech_recognition/wav2letter/tflite_pruned_int8/"
55 ],
56 "resources": [
57 {
58 "name": "wav2letter_pruned_int8.tflite",
59 "url": "{url_prefix:0}wav2letter_pruned_int8.tflite",
60 },
61 {
62 "name": "ifm0.npy",
63 "url": "{url_prefix:0}testing_input/input_2_int8/0.npy",
64 },
65 {
66 "name": "ofm0.npy",
67 "url": "{url_prefix:0}testing_output/Identity_int8/0.npy",
68 },
69 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010070 },
71 {
72 "use_case_name": "img_class",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000073 "url_prefix": [
74 "https://github.com/ARM-software/ML-zoo/raw/e0aa361b03c738047b9147d1a50e3f2dcb13dbcb/models/image_classification/mobilenet_v2_1.0_224/tflite_int8/"
75 ],
76 "resources": [
77 {
78 "name": "mobilenet_v2_1.0_224_INT8.tflite",
79 "url": "{url_prefix:0}mobilenet_v2_1.0_224_INT8.tflite",
80 },
81 {
82 "name": "ifm0.npy",
83 "url": "{url_prefix:0}testing_input/tfl.quantize/0.npy",
84 },
85 {
86 "name": "ofm0.npy",
87 "url": "{url_prefix:0}testing_output/MobilenetV2/Predictions/Reshape_11/0.npy",
88 },
89 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +010090 },
91 {
Michael Levit06fcf752022-01-12 11:53:46 +020092 "use_case_name": "object_detection",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +000093 "url_prefix": [
94 "https://github.com/emza-vs/ModelZoo/blob/v1.0/object_detection/"
95 ],
96 "resources": [
97 {
98 "name": "yolo-fastest_192_face_v4.tflite",
99 "url": "{url_prefix:0}yolo-fastest_192_face_v4.tflite?raw=true",
100 }
101 ],
Michael Levit06fcf752022-01-12 11:53:46 +0200102 },
103 {
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100104 "use_case_name": "kws",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000105 "url_prefix": [
106 "https://github.com/ARM-software/ML-zoo/raw/9f506fe52b39df545f0e6c5ff9223f671bc5ae00/models/keyword_spotting/micronet_medium/tflite_int8/"
107 ],
108 "resources": [
109 {"name": "ifm0.npy", "url": "{url_prefix:0}testing_input/input/0.npy"},
110 {"name": "ofm0.npy", "url": "{url_prefix:0}testing_output/Identity/0.npy"},
111 {
112 "name": "kws_micronet_m.tflite",
113 "url": "{url_prefix:0}kws_micronet_m.tflite",
114 },
115 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100116 },
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000117 {
Éanna Ó Catháin8f958872021-09-15 09:32:30 +0100118 "use_case_name": "vww",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000119 "url_prefix": [
120 "https://github.com/ARM-software/ML-zoo/raw/7dd3b16bb84007daf88be8648983c07f3eb21140/models/visual_wake_words/micronet_vww4/tflite_int8/"
121 ],
122 "resources": [
123 {
124 "name": "vww4_128_128_INT8.tflite",
125 "url": "{url_prefix:0}vww4_128_128_INT8.tflite",
126 },
127 {"name": "ifm0.npy", "url": "{url_prefix:0}testing_input/input/0.npy"},
128 {"name": "ofm0.npy", "url": "{url_prefix:0}testing_output/Identity/0.npy"},
129 ],
Éanna Ó Catháin8f958872021-09-15 09:32:30 +0100130 },
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100131 {
132 "use_case_name": "kws_asr",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000133 "url_prefix": [
134 "https://github.com/ARM-software/ML-zoo/raw/1a92aa08c0de49a7304e0a7f3f59df6f4fd33ac8/models/speech_recognition/wav2letter/tflite_pruned_int8/",
135 "https://github.com/ARM-software/ML-zoo/raw/9f506fe52b39df545f0e6c5ff9223f671bc5ae00/models/keyword_spotting/micronet_medium/tflite_int8/",
136 ],
137 "resources": [
138 {
139 "name": "wav2letter_pruned_int8.tflite",
140 "url": "{url_prefix:0}wav2letter_pruned_int8.tflite",
141 },
142 {
143 "sub_folder": "asr",
144 "name": "ifm0.npy",
145 "url": "{url_prefix:0}testing_input/input_2_int8/0.npy",
146 },
147 {
148 "sub_folder": "asr",
149 "name": "ofm0.npy",
150 "url": "{url_prefix:0}testing_output/Identity_int8/0.npy",
151 },
152 {
153 "sub_folder": "kws",
154 "name": "ifm0.npy",
155 "url": "{url_prefix:1}testing_input/input/0.npy",
156 },
157 {
158 "sub_folder": "kws",
159 "name": "ofm0.npy",
160 "url": "{url_prefix:1}testing_output/Identity/0.npy",
161 },
162 {
163 "name": "kws_micronet_m.tflite",
164 "url": "{url_prefix:1}kws_micronet_m.tflite",
165 },
166 ],
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100167 },
168 {
Richard Burton00553462021-11-10 16:27:14 +0000169 "use_case_name": "noise_reduction",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000170 "url_prefix": [
171 "https://github.com/ARM-software/ML-zoo/raw/a061600058097a2785d6f1f7785e5a2d2a142955/models/noise_suppression/RNNoise/tflite_int8/"
172 ],
173 "resources": [
174 {"name": "rnnoise_INT8.tflite", "url": "{url_prefix:0}rnnoise_INT8.tflite"},
175 {
176 "name": "ifm0.npy",
177 "url": "{url_prefix:0}testing_input/main_input_int8/0.npy",
178 },
179 {
180 "name": "ifm1.npy",
181 "url": "{url_prefix:0}testing_input/vad_gru_prev_state_int8/0.npy",
182 },
183 {
184 "name": "ifm2.npy",
185 "url": "{url_prefix:0}testing_input/noise_gru_prev_state_int8/0.npy",
186 },
187 {
188 "name": "ifm3.npy",
189 "url": "{url_prefix:0}testing_input/denoise_gru_prev_state_int8/0.npy",
190 },
191 {
192 "name": "ofm0.npy",
193 "url": "{url_prefix:0}testing_output/Identity_int8/0.npy",
194 },
195 {
196 "name": "ofm1.npy",
197 "url": "{url_prefix:0}testing_output/Identity_1_int8/0.npy",
198 },
199 {
200 "name": "ofm2.npy",
201 "url": "{url_prefix:0}testing_output/Identity_2_int8/0.npy",
202 },
203 {
204 "name": "ofm3.npy",
205 "url": "{url_prefix:0}testing_output/Identity_3_int8/0.npy",
206 },
207 {
208 "name": "ofm4.npy",
209 "url": "{url_prefix:0}testing_output/Identity_4_int8/0.npy",
210 },
211 ],
Richard Burton00553462021-11-10 16:27:14 +0000212 },
213 {
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100214 "use_case_name": "inference_runner",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000215 "url_prefix": [
216 "https://github.com/ARM-software/ML-zoo/raw/68b5fbc77ed28e67b2efc915997ea4477c1d9d5b/models/keyword_spotting/dnn_small/tflite_int8/"
217 ],
218 "resources": [
219 {
220 "name": "dnn_s_quantized.tflite",
221 "url": "{url_prefix:0}dnn_s_quantized.tflite",
222 }
223 ],
224 },
225]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100226
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100227# Valid NPU configurations:
228valid_npu_config_names = [
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000229 "ethos-u55-32",
230 "ethos-u55-64",
231 "ethos-u55-128",
232 "ethos-u55-256",
233 "ethos-u65-256",
234 "ethos-u65-512",
235]
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100236
237# Default NPU configurations (these are always run when the models are optimised)
238default_npu_config_names = [valid_npu_config_names[2], valid_npu_config_names[4]]
239
240# NPU config named tuple
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000241NPUConfig = namedtuple(
242 "NPUConfig",
243 [
244 "config_name",
245 "memory_mode",
246 "system_config",
247 "ethos_u_npu_id",
248 "ethos_u_config_id",
249 "arena_cache_size",
250 ],
251)
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100252
Kshitij Sisodia661959c2021-11-24 10:39:52 +0000253# The internal SRAM size for Corstone-300 implementation on MPS3 specified by AN552
Kshitij Sisodia8c61c0a2022-05-17 11:16:22 +0100254# The internal SRAM size for Corstone-310 implementation on MPS3 specified by AN555
255# is 4MB, but we are content with the 2MB specified below.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000256mps3_max_sram_sz = 2 * 1024 * 1024 # 2 MiB (2 banks of 1 MiB each)
Liam Barryb52b5852021-11-15 11:41:40 +0000257
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100258
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000259def call_command(command: str, verbose: bool = True) -> str:
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100260 """
261 Helpers function that call subprocess and return the output.
262
263 Parameters:
264 ----------
265 command (string): Specifies the command to run.
266 """
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000267 if verbose:
268 logging.info(command)
269 proc = subprocess.run(
270 command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True
271 )
alexander50a06502021-05-12 19:06:02 +0100272 log = proc.stdout.decode("utf-8")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000273 if proc.returncode == 0 and verbose:
alexander50a06502021-05-12 19:06:02 +0100274 logging.info(log)
275 else:
276 logging.error(log)
277 proc.check_returncode()
278 return log
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100279
280
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000281def get_default_npu_config_from_name(
282 config_name: str, arena_cache_size: int = 0
283) -> NPUConfig:
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100284 """
Richard Burton17069622022-03-17 10:54:26 +0000285 Gets the file suffix for the TFLite file from the
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100286 `accelerator_config` string.
287
288 Parameters:
289 ----------
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000290 config_name (str): Ethos-U NPU configuration from valid_npu_config_names
291
292 arena_cache_size (int): Specifies arena cache size in bytes. If a value
293 greater than 0 is provided, this will be taken
294 as the cache size. If 0, the default values, as per
295 the NPU config requirements, are used.
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100296
297 Returns:
298 -------
299 NPUConfig: An NPU config named tuple populated with defaults for the given
300 config name
301 """
302 if config_name not in valid_npu_config_names:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000303 raise ValueError(
304 f"""
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100305 Invalid Ethos-U NPU configuration.
306 Select one from {valid_npu_config_names}.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000307 """
308 )
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100309
310 strings_ids = ["ethos-u55-", "ethos-u65-"]
311 processor_ids = ["U55", "U65"]
312 prefix_ids = ["H", "Y"]
313 memory_modes = ["Shared_Sram", "Dedicated_Sram"]
314 system_configs = ["Ethos_U55_High_End_Embedded", "Ethos_U65_High_End"]
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000315 memory_modes_arena = {
Richard Burton17069622022-03-17 10:54:26 +0000316 # For shared SRAM memory mode, we use the MPS3 SRAM size by default.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000317 "Shared_Sram": mps3_max_sram_sz if arena_cache_size <= 0 else arena_cache_size,
Richard Burton17069622022-03-17 10:54:26 +0000318 # For dedicated SRAM memory mode, we do not override the arena size. This is expected to
319 # be defined in the Vela configuration file instead.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000320 "Dedicated_Sram": None if arena_cache_size <= 0 else arena_cache_size,
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000321 }
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100322
323 for i in range(len(strings_ids)):
324 if config_name.startswith(strings_ids[i]):
325 npu_config_id = config_name.replace(strings_ids[i], prefix_ids[i])
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000326 return NPUConfig(
327 config_name=config_name,
328 memory_mode=memory_modes[i],
329 system_config=system_configs[i],
330 ethos_u_npu_id=processor_ids[i],
331 ethos_u_config_id=npu_config_id,
332 arena_cache_size=memory_modes_arena[memory_modes[i]],
333 )
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100334
335 return None
336
337
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000338def remove_tree_dir(dir_path):
339 try:
Richard Burton17069622022-03-17 10:54:26 +0000340 # Remove the full directory.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000341 shutil.rmtree(dir_path)
Richard Burton17069622022-03-17 10:54:26 +0000342 # Re-create an empty one.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000343 os.mkdir(dir_path)
344 except Exception as e:
345 logging.error(f"Failed to delete {dir_path}.")
346
347
348def set_up_resources(
349 run_vela_on_models: bool = False,
Richard Burton17069622022-03-17 10:54:26 +0000350 additional_npu_config_names: tuple = (),
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000351 arena_cache_size: int = 0,
352 check_clean_folder: bool = False,
Kshitij Sisodia9c6f9f82022-05-20 14:30:02 +0100353 additional_requirements_file: str = "") -> (Path, Path):
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100354 """
355 Helpers function that retrieve the output from a command.
356
357 Parameters:
358 ----------
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000359 run_vela_on_models (bool): Specifies if run vela on downloaded models.
360 additional_npu_config_names(list): list of strings of Ethos-U NPU configs.
361 arena_cache_size (int): Specifies arena cache size in bytes. If a value
362 greater than 0 is provided, this will be taken
363 as the cache size. If 0, the default values, as per
364 the NPU config requirements, are used.
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000365 check_clean_folder (bool): Indicates whether the resources folder needs to
366 be checked for updates and cleaned.
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000367 additional_requirements_file (str): Path to a requirements.txt file if
368 additional packages need to be
369 installed.
Kshitij Sisodia9c6f9f82022-05-20 14:30:02 +0100370
371 Returns
372 -------
373
374 Tuple of pair of Paths: (download_directory_path, virtual_env_path)
375
376 download_directory_path: Root of the directory where the resources have been downloaded to.
377 virtual_env_path: Path to the root of virtual environment.
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100378 """
Richard Burton17069622022-03-17 10:54:26 +0000379 # Paths.
380 current_file_dir = Path(__file__).parent.resolve()
381 download_dir = current_file_dir / "resources_downloaded"
382 metadata_file_path = download_dir / "resources_downloaded_metadata.json"
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000383
384 metadata_dict = dict()
Richard Burtondf88c5d2023-05-30 17:40:39 +0100385 vela_version = "3.8.0"
Kshitij Sisodia36b5b132023-06-09 11:58:26 +0100386 py3_version_minimum = (3, 9)
Isabella Gottardi6c2ea452022-03-11 13:25:08 +0000387
388 # Is Python minimum requirement matched?
389 py3_version = sys.version_info
Kshitij Sisodia36b5b132023-06-09 11:58:26 +0100390 if py3_version < py3_version_minimum:
Isabella Gottardi6c2ea452022-03-11 13:25:08 +0000391 raise Exception(
Richard Burtondf88c5d2023-05-30 17:40:39 +0100392 "ERROR: Python3.9+ is required, please see the documentation on how to update it."
Isabella Gottardi6c2ea452022-03-11 13:25:08 +0000393 )
Kshitij Sisodia36b5b132023-06-09 11:58:26 +0100394 else:
395 logging.info(f"Using Python version: {py3_version}")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000396
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000397 setup_script_hash_verified = False
Richard Burton17069622022-03-17 10:54:26 +0000398 setup_script_hash = get_md5sum_for_file(Path(__file__).resolve())
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100399
400 try:
401 # 1.1 Does the download dir exist?
Richard Burton17069622022-03-17 10:54:26 +0000402 download_dir.mkdir()
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100403 except OSError as e:
404 if e.errno == errno.EEXIST:
405 logging.info("'resources_downloaded' directory exists.")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000406 # Check and clean?
Richard Burton17069622022-03-17 10:54:26 +0000407 if check_clean_folder and metadata_file_path.is_file():
408 with open(metadata_file_path) as metadata_file:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000409 metadata_dict = json.load(metadata_file)
410 vela_in_metadata = metadata_dict["ethosu_vela_version"]
411 if vela_in_metadata != vela_version:
412 # Check if all the resources needs to be removed and regenerated.
413 # This can happen when the Vela version has changed.
414 logging.info(
415 f"Vela version in metadata is {vela_in_metadata}, current {vela_version}. Removing the resources and re-download them."
416 )
417 remove_tree_dir(download_dir)
418 metadata_dict = dict()
419 else:
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000420 # Check if the set_up_default_resorces.py has changed from last setup
421 setup_script_hash_verified = (
Isabella Gottardi6c2ea452022-03-11 13:25:08 +0000422 metadata_dict.get("set_up_script_md5sum")
423 == setup_script_hash
424 )
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100425 else:
426 raise
427
428 # 1.2 Does the virtual environment exist?
Kshitij Sisodia9c6f9f82022-05-20 14:30:02 +0100429 env_dirname = "env"
430 env_path = download_dir / env_dirname
431 env_python = str(env_path / "bin" / "python3")
432 env_activate = str(env_path / "bin" / "activate")
Richard Burton17069622022-03-17 10:54:26 +0000433
Kshitij Sisodia9c6f9f82022-05-20 14:30:02 +0100434 if not env_path.is_dir():
Kshitij Sisodia36b5b132023-06-09 11:58:26 +0100435 # Create the virtual environment using current interpreter's venv
436 # (not necessarily the system's Python3)
437 venv.create(env_dir=env_path, with_pip=True, upgrade_deps=True)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000438
Richard Burton71f282e2022-12-01 12:31:23 +0000439 # 1.3 Install additional requirements first, if a valid file has been provided
440 if additional_requirements_file and os.path.isfile(additional_requirements_file):
441 command = f"{env_python} -m pip install -r {additional_requirements_file}"
442 call_command(command)
443
444 # 1.4 Make sure to have all the main requirements
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000445 requirements = [f"ethos-u-vela=={vela_version}"]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100446 command = f"{env_python} -m pip freeze"
447 packages = call_command(command)
448 for req in requirements:
449 if req not in packages:
450 command = f"{env_python} -m pip install {req}"
451 call_command(command)
452
453 # 2. Download models
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000454 logging.info("Downloading resources.")
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100455 for uc in json_uc_res:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000456 use_case_name = uc["use_case_name"]
457 res_url_prefix = uc["url_prefix"]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100458 try:
459 # Does the usecase_name download dir exist?
Richard Burton17069622022-03-17 10:54:26 +0000460 (download_dir / use_case_name).mkdir()
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100461 except OSError as e:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000462 if e.errno == errno.EEXIST:
Richard Burton17069622022-03-17 10:54:26 +0000463 # The usecase_name download dir exist.
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000464 if check_clean_folder and not setup_script_hash_verified:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000465 for idx, metadata_uc_url_prefix in enumerate(
466 [
467 f
468 for f in metadata_dict["resources_info"]
469 if f["use_case_name"] == use_case_name
470 ][0]["url_prefix"]
471 ):
472 if metadata_uc_url_prefix != res_url_prefix[idx]:
473 logging.info(f"Removing {use_case_name} resources.")
Richard Burton17069622022-03-17 10:54:26 +0000474 remove_tree_dir(download_dir / use_case_name)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000475 break
476 elif e.errno != errno.EEXIST:
477 logging.error(f"Error creating {use_case_name} directory.")
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100478 raise
479
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000480 reg_expr_str = r"{url_prefix:(.*\d)}"
481 reg_expr_pattern = re.compile(reg_expr_str)
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100482 for res in uc["resources"]:
483 res_name = res["name"]
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000484 url_prefix_idx = int(reg_expr_pattern.search(res["url"]).group(1))
485 res_url = res_url_prefix[url_prefix_idx] + re.sub(
486 reg_expr_str, "", res["url"]
487 )
488
489 sub_folder = ""
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100490 if "sub_folder" in res:
491 try:
492 # Does the usecase_name/sub_folder download dir exist?
Richard Burton17069622022-03-17 10:54:26 +0000493 (download_dir / use_case_name / res["sub_folder"]).mkdir()
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100494 except OSError as e:
495 if e.errno != errno.EEXIST:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000496 logging.error(
497 f"Error creating {use_case_name} / {res['sub_folder']} directory."
498 )
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100499 raise
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000500 sub_folder = res["sub_folder"]
501
Richard Burton17069622022-03-17 10:54:26 +0000502 res_dst = download_dir / use_case_name / sub_folder / res_name
alexander3ef1fd42021-05-24 18:56:32 +0100503
Richard Burton17069622022-03-17 10:54:26 +0000504 if res_dst.is_file():
alexander3ef1fd42021-05-24 18:56:32 +0100505 logging.info(f"File {res_dst} exists, skipping download.")
506 else:
507 try:
508 g = urllib.request.urlopen(res_url)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000509 with open(res_dst, "b+w") as f:
alexander3ef1fd42021-05-24 18:56:32 +0100510 f.write(g.read())
511 logging.info(f"- Downloaded {res_url} to {res_dst}.")
512 except URLError:
513 logging.error(f"URLError while downloading {res_url}.")
514 raise
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100515
516 # 3. Run vela on models in resources_downloaded
517 # New models will have same name with '_vela' appended.
518 # For example:
Kshitij Sisodia76a15802021-12-24 11:05:11 +0000519 # original model: kws_micronet_m.tflite
520 # after vela model: kws_micronet_m_vela_H128.tflite
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100521 #
522 # Note: To avoid to run vela twice on the same model, it's supposed that
523 # downloaded model names don't contain the 'vela' word.
524 if run_vela_on_models is True:
Richard Burton17069622022-03-17 10:54:26 +0000525 config_file = current_file_dir / "scripts" / "vela" / "default_vela.ini"
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000526 models = [
Richard Burton17069622022-03-17 10:54:26 +0000527 Path(dirpath) / f
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000528 for dirpath, dirnames, files in os.walk(download_dir)
529 for f in fnmatch.filter(files, "*.tflite")
530 if "vela" not in f
531 ]
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100532
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100533 # Consolidate all config names while discarding duplicates:
534 config_names = list(set(default_npu_config_names + additional_npu_config_names))
535
536 # Get npu config tuple for each config name in a list:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000537 npu_configs = [
538 get_default_npu_config_from_name(name, arena_cache_size)
539 for name in config_names
540 ]
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100541
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000542 logging.info(f"All models will be optimised for these configs:")
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100543 for config in npu_configs:
544 logging.info(config)
545
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000546 optimisation_skipped = False
547
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100548 for model in models:
Richard Burton17069622022-03-17 10:54:26 +0000549 output_dir = model.parent
alexander3ef1fd42021-05-24 18:56:32 +0100550 # model name after compiling with vela is an initial model name + _vela suffix
Richard Burton17069622022-03-17 10:54:26 +0000551 vela_optimised_model_path = model.parent / (model.stem + "_vela.tflite")
alexander3ef1fd42021-05-24 18:56:32 +0100552
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100553 for config in npu_configs:
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000554 vela_command_arena_cache_size = ""
555
556 if config.arena_cache_size:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000557 vela_command_arena_cache_size = (
558 f"--arena-cache-size={config.arena_cache_size}"
559 )
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000560
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000561 vela_command = (
562 f". {env_activate} && vela {model} "
563 + f"--accelerator-config={config.config_name} "
564 + "--optimise Performance "
565 + f"--config {config_file} "
566 + f"--memory-mode={config.memory_mode} "
567 + f"--system-config={config.system_config} "
568 + f"--output-dir={output_dir} "
569 + f"{vela_command_arena_cache_size}"
570 )
alexander3ef1fd42021-05-24 18:56:32 +0100571
Richard Burton17069622022-03-17 10:54:26 +0000572 # We want the name to include the configuration suffix. For example: vela_H128,
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100573 # vela_Y512 etc.
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000574 new_suffix = "_vela_" + config.ethos_u_config_id + ".tflite"
Richard Burton17069622022-03-17 10:54:26 +0000575 new_vela_optimised_model_path = model.parent / (model.stem + new_suffix)
Isabella Gottardi118f73e2021-09-16 17:54:35 +0100576
Richard Burton17069622022-03-17 10:54:26 +0000577 if new_vela_optimised_model_path.is_file():
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000578 logging.info(
579 f"File {new_vela_optimised_model_path} exists, skipping optimisation."
580 )
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000581 optimisation_skipped = True
Isabella Gottardi118f73e2021-09-16 17:54:35 +0100582 continue
583
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100584 call_command(vela_command)
Isabella Gottardi118f73e2021-09-16 17:54:35 +0100585
Richard Burton17069622022-03-17 10:54:26 +0000586 # Rename default vela model.
587 vela_optimised_model_path.rename(new_vela_optimised_model_path)
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000588 logging.info(
589 f"Renaming {vela_optimised_model_path} to {new_vela_optimised_model_path}."
590 )
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100591
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000592 # If any optimisation was skipped, show how to regenerate:
593 if optimisation_skipped:
594 logging.warning("One or more optimisations were skipped.")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000595 logging.warning(
596 f"To optimise all the models, please remove the directory {download_dir}."
597 )
598
599 # 4. Collect and write metadata
600 logging.info("Collecting and write metadata.")
601 metadata_dict["ethosu_vela_version"] = vela_version
Kshitij Sisodia6a2ac462022-03-01 17:36:06 +0000602 metadata_dict["set_up_script_md5sum"] = setup_script_hash.strip("\n")
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000603 metadata_dict["resources_info"] = json_uc_res
604
605 with open(metadata_file_path, "w") as metadata_file:
606 json.dump(metadata_dict, metadata_file, indent=4)
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000607
Kshitij Sisodia9c6f9f82022-05-20 14:30:02 +0100608 return download_dir, env_path
609
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000610
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000611if __name__ == "__main__":
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100612 parser = ArgumentParser()
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000613 parser.add_argument(
614 "--skip-vela",
615 help="Do not run Vela optimizer on downloaded models.",
616 action="store_true",
617 )
618 parser.add_argument(
619 "--additional-ethos-u-config-name",
620 help=f"""Additional (non-default) configurations for Vela:
Kshitij Sisodia3be26232021-10-29 12:29:06 +0100621 {valid_npu_config_names}""",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000622 default=[],
623 action="append",
624 )
625 parser.add_argument(
626 "--arena-cache-size",
627 help="Arena cache size in bytes (if overriding the defaults)",
628 type=int,
629 default=0,
630 )
631 parser.add_argument(
632 "--clean",
Richard Burton17069622022-03-17 10:54:26 +0000633 help="Clean the directory and optimize the downloaded resources",
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000634 action="store_true",
635 )
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000636 parser.add_argument(
637 "--requirements-file",
638 help="Path to requirements.txt file to install additional packages",
639 type=str,
Richard Burton17069622022-03-17 10:54:26 +0000640 default=Path(__file__).parent.resolve() / 'scripts' / 'py' / 'requirements.txt'
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000641 )
642
Isabella Gottardi2181d0a2021-04-07 09:27:38 +0100643 args = parser.parse_args()
Kshitij Sisodiab9e9c892021-05-27 13:57:35 +0100644
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000645 if args.arena_cache_size < 0:
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000646 raise ArgumentTypeError("Arena cache size cannot not be less than 0")
Isabella Gottardi3acaaee2021-11-30 12:33:27 +0000647
Richard Burton17069622022-03-17 10:54:26 +0000648 if not Path(args.requirements_file).is_file():
Kshitij Sisodiac22e80e2022-03-14 09:26:48 +0000649 raise ArgumentTypeError(f"Invalid requirements file: {args.requirements_file}")
650
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000651 logging.basicConfig(filename="log_build_default.log", level=logging.DEBUG)
Kshitij Sisodiab9e9c892021-05-27 13:57:35 +0100652 logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
653
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000654 set_up_resources(
655 not args.skip_vela,
656 args.additional_ethos_u_config_name,
657 args.arena_cache_size,
658 args.clean,
Isabella Gottardi6c2ea452022-03-11 13:25:08 +0000659 args.requirements_file,
Isabella Gottardief2b9dd2022-02-16 14:24:03 +0000660 )