STM32N6 NPU Deployment — Politecnico di Milano  1.0
Documentation for Neural Network Deployment on STM32N6 NPU - Politecnico di Milano 2024-2025
deploy.py
Go to the documentation of this file.
1 
32 
33 import os
34 import sys
35 import warnings
36 import shutil
37 
38 from hydra.core.hydra_config import HydraConfig
39 from omegaconf import DictConfig
40 from typing import Optional
41 
42 warnings.filterwarnings("ignore")
43 os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
44 
45 from common.utils import get_model_name_and_its_input_shape, get_model_name
46 from common.deployment import stm32ai_deploy_stm32n6, stm32ai_deploy_mpu
47 from common.benchmarking import cloud_connect
48 from src.utils import gen_h_user_file_n6
49 
50 
51 def deploy(cfg: DictConfig = None, model_path_to_deploy: Optional[str] = None,
52  credentials: list = None) -> None:
53  """
54  @brief Deploy a quantized INT8 model onto an STM32N6 MCU board.
55 
56  @details
57  This function implements the full deployment pipeline for STM32N6-series boards:
58 
59  **Step 1 — Parameter extraction from YAML config:**
60  All deployment parameters are read from the Hydra configuration object:
61  - `board` : Target board name (e.g., "STM32N6570-DK").
62  - `stlink_serial_number`: ST-Link serial number for multi-board setups.
63  - `c_project_path` : Path to the STM32CubeIDE C project directory.
64  - `stm32ai_version` : Version of ST Edge AI Core to use.
65  - `optimization` : Optimization level for code generation (e.g., "balanced").
66  - `path_to_stm32ai` : Local path to the stedgeai executable.
67  - `path_to_cube_ide` : Local path to the STM32CubeIDE executable.
68  - `stm32ai_ide` : IDE/compiler to use (must be "gcc" for STM32N6).
69  - `stm32ai_serie` : MCU series (must be "STM32N6" for this path).
70 
71  **Step 2 — C header file generation:**
72  gen_h_user_file_n6() generates `ai_model_config.h`, a C header that embeds
73  model metadata (input/output shapes, number of keypoints, confidence thresholds)
74  into the firmware. This allows the C application to configure itself at compile time.
75 
76  **Step 3 — Board configuration file selection:**
77  A board-specific .conf file is selected:
78  - `stmaic_STM32N6570-DK.conf` for the STM32N6570-DK Discovery Kit.
79  - `stmaic_NUCLEO-N657X0-Q.conf` for the NUCLEO-N657X0-Q board.
80 
81  **Step 4 — Full deployment via stm32ai_deploy_stm32n6():**
82  This common function:
83  a. Invokes ST Edge AI Core to convert the .tflite model into optimized C arrays.
84  b. Integrates the C code into the STM32CubeIDE project.
85  c. Compiles the firmware using GCC.
86  d. Flashes the binary onto the board via ST-Link (USB debugger).
87 
88  @note After flashing, the user must manually toggle the boot switches on the
89  STM32N6570-DK to the left and power-cycle the board to boot from flash.
90 
91  @param cfg Hydra DictConfig loaded from user_config.yaml.
92  @param model_path_to_deploy Path to the quantized .tflite model to deploy.
93  If None, uses cfg.general.model_path.
94  @param credentials Optional cloud credentials from a prior cloud_connect() call.
95 
96  @return None
97  @throws ValueError If the hardware series is STM32H7 (not supported in this flow).
98  @throws TypeError If the board name or IDE/serie combination is not supported.
99  """
100 
101  # --- Extract all deployment parameters from the Hydra configuration ---
102  board = cfg.deployment.hardware_setup.board
103  stlink_serial_number = cfg.deployment.hardware_setup.stlink_serial_number
104  c_project_path = cfg.deployment.c_project_path
105  output_dir = HydraConfig.get().runtime.output_dir
106 
107 
108  stm32ai_output = output_dir + "/generated"
109 
110  stm32ai_version = cfg.tools.stm32ai.version
111  optimization = cfg.tools.stm32ai.optimization
112  path_to_stm32ai = cfg.tools.stm32ai.path_to_stm32ai
113  path_to_cube_ide = cfg.tools.path_to_cubeIDE
114  verbosity = cfg.deployment.verbosity
115  stm32ai_ide = cfg.deployment.IDE
116  stm32ai_serie = cfg.deployment.hardware_setup.serie
117  check_large_model = False
118 
119  # --- Determine the model path to deploy ---
120 
122  model_path = model_path_to_deploy if model_path_to_deploy else cfg.general.model_path
123  model_name, input_shape = get_model_name_and_its_input_shape(model_path=model_path)
124 
125  get_model_name_output = get_model_name(model_type=str(model_name),
126  input_shape=str(input_shape[0]),
127  project_name=cfg.general.project_name)
128 
129  # --- Generate the C header file for the firmware application ---
130 
134  print("[INFO] : Generating C header file for Getting Started...")
135  if stm32ai_serie.upper() == "STM32H7":
136  # STM32H7 deployment is handled by a different function, not supported here
137  raise ValueError("STM32H7 is not supported in this deployment flow.")
138  else:
139  gen_h_user_file_n6(config=cfg, quantized_model_path=model_path)
140 
141  # --- Select board-specific configuration and launch deployment ---
142  if stm32ai_serie.upper() == "STM32N6" and stm32ai_ide.lower() == "gcc":
143 
144 
147  if board == "STM32N6570-DK":
148  stmaic_conf_filename = "stmaic_STM32N6570-DK.conf"
149  elif board == "NUCLEO-N657X0-Q":
150  stmaic_conf_filename = "stmaic_NUCLEO-N657X0-Q.conf"
151  else:
152  raise TypeError(
153  "The hardware selected in cfg.deployment.hardware_setup.board is not supported yet!\n"
154  "Please choose one of the following boards: "
155  "`STM32N6570-DK` or `NUCLEO-N657X0-Q`.")
156 
157 
167  target=board,
168  stlink_serial_number=stlink_serial_number,
169  stm32ai_version=stm32ai_version,
170  c_project_path=c_project_path,
171  output_dir=output_dir,
172  stm32ai_output=stm32ai_output,
173  optimization=optimization,
174  path_to_stm32ai=path_to_stm32ai,
175  path_to_cube_ide=path_to_cube_ide,
176  stmaic_conf_filename=stmaic_conf_filename,
177  verbosity=verbosity,
178  debug=False,
179  model_path=model_path,
180  get_model_name_output=get_model_name_output,
181  stm32ai_ide=stm32ai_ide,
182  stm32ai_serie=stm32ai_serie,
183  on_cloud=cfg.tools.stm32ai.on_cloud,
184  build_conf=cfg.deployment.build_conf,
185  check_large_model=True,
186  cfg=cfg,
187  input_data_type='uint8',
188  output_data_type='',
189  inputs_ch_position='chlast',
190  outputs_ch_position=''
191  )
192  else:
193  raise TypeError(
194  "Options for cfg.deployment.hardware_setup.serie and cfg.deployment.IDE not supported yet!\n"
195  "The only supported combination is serie=`STM32N6` and IDE=`gcc`.")
196 
197 
198 def deploy_mpu(cfg: DictConfig = None, model_path_to_deploy: Optional[str] = None,
199  credentials: list = None) -> None:
200  """
201  @brief Deploy an AI model onto an STM32MP MPU target device.
202 
203  @details
204  This function handles deployment on STM32MP-series Microprocessor Units (MPUs),
205  which run Linux and have more memory and compute resources than MCUs.
206 
207  Unlike the MCU path, MPU deployment can optionally leverage the STM32Cube.AI
208  Developer Cloud to generate an optimized NBG (Neural Binary Graph) file,
209  which is a proprietary binary format optimized for ST's NPU on MP2 devices.
210 
211  Cloud optimization flow (STM32MP2 + .tflite or .onnx + on_cloud=True):
212  1. Upload the model to the Developer Cloud.
213  2. Request NBG generation (optimized binary format for the NPU).
214  3. Download the resulting .nb file.
215  4. Deploy the .nb file instead of the original model.
216 
217  If cloud optimization is not available or fails, the original model is used directly.
218 
219  Supported boards:
220  - STM32MP257F-EV1
221  - STM32MP157F-DK2
222  - STM32MP135F-DK
223 
224  @param cfg Hydra DictConfig loaded from user_config.yaml.
225  @param model_path_to_deploy Path to the model file to deploy (.tflite or .onnx).
226  If None, uses cfg.general.model_path.
227  @param credentials Optional cloud credentials from a prior cloud_connect() call.
228 
229  @return None
230  @throws TypeError If the board is not in the list of supported MPU boards,
231  or if the deployment process fails.
232  """
233 
234  # --- Extract MPU deployment parameters ---
235  board = cfg.deployment.hardware_setup.board
236  c_project_path = cfg.deployment.c_project_path
237  keypoints_file_path = cfg.dataset.keypoints_file_path
238  board_deploy_path = cfg.deployment.board_deploy_path
239  verbosity = cfg.deployment.verbosity
240  board_serie = cfg.deployment.hardware_setup.serie
241  board_ip = cfg.deployment.hardware_setup.ip_address
242 
243 
244  optimized_model_path = c_project_path + "Optimized_models/"
245 
246  model_path = model_path_to_deploy if model_path_to_deploy else cfg.general.model_path
247  model_extension = os.path.splitext(model_path)[1]
248  model_name, input_shape = get_model_name_and_its_input_shape(model_path=model_path)
249 
250  # --- Optional cloud-based NBG optimization for STM32MP2 ---
251 
253  if board_serie == "STM32MP2" and (model_extension == ".tflite" or model_extension == ".onnx") \
254  and cfg.tools.stm32ai.on_cloud:
255  login_success, ai, _ = cloud_connect(stm32ai_version=None, credentials=credentials)
256  if login_success:
257  try:
258  ai.upload_model(model_path)
259  model = model_name + model_extension
260  res = ai.generate_nbg(model)
261  ai.download_model(res, optimized_model_path + res)
262  model_path = os.path.join(optimized_model_path, res)
263  model_name = model_name + ".nb"
264  rename_model_path = os.path.join(optimized_model_path, model_name)
265  os.rename(model_path, rename_model_path)
266  model_path = rename_model_path
267  print("[INFO] : Optimized Model Name:", model_name)
268  print("[INFO] : Optimization done! Model available at:", optimized_model_path)
269  except Exception as e:
270  print(f"[FAIL] : Model optimization via Cloud failed: {e}.")
271  print("[INFO] : Use default model instead of optimized ...")
272 
273  # --- Deploy to the MPU board ---
274  if board in ["STM32MP257F-EV1", "STM32MP157F-DK2", "STM32MP135F-DK"]:
275  res = stm32ai_deploy_mpu(
276  target=board,
277  board_ip_address=board_ip,
278  class_names=keypoints_file_path,
279  board_deploy=board_deploy_path,
280  c_project_path=c_project_path,
281  verbosity=verbosity,
282  debug=False,
283  model_path=model_path,
284  cfg=cfg
285  )
286  if res == False:
287  raise TypeError("Deployment on the target failed\n")
288  else:
289  raise TypeError(
290  "Options for cfg.deployment.hardware_setup.board not supported!\n"
291  "Only valid options are STM32MP257F-EV1, STM32MP157F-DK2, STM32MP135F-DK\n")
None stm32ai_deploy_mpu(bool target=False, str board_ip_address=None, str board_deploy=None, List class_names=None, str c_project_path=None, int verbosity=None, bool debug=False, str model_path=None, cfg=None)
None stm32ai_deploy_stm32n6(bool target=False, str stlink_serial_number=None, str stm32ai_version=None, str c_project_path=None, str output_dir=None, str stm32ai_output=None, str optimization=None, str path_to_stm32ai=None, str path_to_cube_ide=None, list additional_files=None, str stmaic_conf_filename='stmaic_c_project.conf', int verbosity=None, bool debug=False, str model_path=None, str get_model_name_output=None, str stm32ai_ide=None, str stm32ai_serie=None, list credentials=None, bool on_cloud=False, bool check_large_model=False, str build_conf=None, cfg=None, Dict custom_objects=None, str input_data_type='', str output_data_type='', str inputs_ch_position='', str outputs_ch_position='')
None deploy(DictConfig cfg=None, Optional[str] model_path_to_deploy=None, list credentials=None)
Key parameters:
Definition: deploy.py:52
None deploy_mpu(DictConfig cfg=None, Optional[str] model_path_to_deploy=None, list credentials=None)
Definition: deploy.py:199
None gen_h_user_file_n6(DictConfig config=None, str quantized_model_path=None)
Definition: gen_h_file.py:23