Deploy Structure and User Guide#
This guide provides a comprehensive overview of aidge_deploy, the dedicated Eclipse Aidge module responsible for target-specific compilation, artifact packaging, transport, flashing, target execution, log parsing, and Hardware-in-the-Loop (HIL) benchmarking and validation.
Introduction#
In the Aidge framework, model code generation (export) is cleanly decoupled from target-specific deployment orchestration (deploy). Once a model has been exported to standard C++ or device-optimized libraries, aidge_deploy automates the end-to-end pipeline required to compile, transfer, flash, execute, and evaluate the model on physical microcontrollers (bare-metal MCUs) or Single Board Computers (Linux SBCs).
Key Features:
Target Abstraction: Unified pipeline across diverse hardware targets (ARM Cortex-M, STMicroelectronics STM32, Alif Ensemble, Raspberry Pi, NVIDIA Jetson, custom SBCs).
Flexible Connection Backends: Run compilations and executions locally, over SSH, inside Docker containers, or remotely through a Board-Farm API.
Self-contained Export Input: Consumes buildable projects whose exporter already resolved the required BSP.
Hardware-in-the-Loop (HIL) Benchmarking & Validation: Cycle counting, latency measurements, RAM/Flash profiling, and target prediction accuracy checks.
System Architecture & Lifecycle Pipeline#
The deployment workflow processes a finalized Aidge export artifact through a multi-stage lifecycle pipeline.
┌───────────────────────────┐
│ Aidge Model Export │
│ (Generated Code Folder) │
└─────────────┬─────────────┘
│
▼
aidge_deploy.deploy()
│
▼
DeployTarget Registry
(target, backend) ──► Target Instance
│
┌─────────────────────────────┴─────────────────────────────┐
│ │
│ 1. prepare() Read manifest and runtime settings │
│ 2. build() Local, Docker, or Remote C++ compile │
│ 3. transfer() [Optional] SSH/SCP upload to SBC │
│ 4. flash() [Optional] Program MCU (pyOCD / J-Link)│
│ 5. execute() Run binary on target & capture log │
│ 6. parse_output() Extract timings, cycles & accuracy │
│ │
└─────────────────────────────┬─────────────────────────────┘
│
▼
DeployResult & Metrics Dict
Ownership Across the Three Layers#
aidge_deploy is the consumer of an export contract, not an extension of
code generation. Responsibilities are divided as follows:
Layer |
Owns |
Must not own |
|---|---|---|
|
Hardware targets, execution domains, memories, processing elements, architecture, build system, BSP coordinates, shared registries, export orchestration, and artifact schema |
Transport credentials, flashing sessions, or exporter templates |
Exporter package |
Kernels, graph-to-code mappings, target-specific export assets, project composition, BSP integration, generated entry points, and output protocol selection |
SSH/serial connections, flashing, or result collection |
|
Build location, transfer, flashing, execution, log capture, protocol parsing, and result aggregation |
Graph transformations, kernel generation, BSP selection, or duplicate hardware profiles |
The hardware model remains authoritative throughout the flow. Both
TargetExport and DeployTarget resolve an existing hardware target
class from aidge_core.hw_model. The manifest records the identity and
properties of the generated artifact, but it does not replace the hardware
model.
For the producer side of this contract, including ExportContext,
TargetExport, composers, preprocessors, and target strategies, see
Export Code Structure.
The Export/Deploy Boundary#
Export returns an ExportArtifact with two members:
pathDirectory containing the complete project produced by the exporter.
manifestAn immutable
ExportManifestalso serialized as.aidge-export.jsonin that directory.
The manifest contains the generated target, execution domain, environment,
build system, application kind, expected artifact path, output protocol,
input/output descriptions, profiling information, and serialized
ExportApplication settings. These are artifact facts: they describe what
was generated and how its output must be interpreted.
deploy() calls load_export_artifact() for either an artifact object or
a directory. Loading validates the manifest schema. Deployment then rejects a
configuration whose target differs from manifest.target. Runtime defaults
for benchmark, validation, TinyML Benchmark, and heterogeneous execution are
hydrated from manifest.application_config when the caller did not provide
explicit deploy sub-configurations.
This boundary provides two useful properties:
export and deploy can run independently, in different processes or on different machines;
deploy never needs the original Aidge graph, exporter configuration, or template-selection logic.
Target Capabilities & Mixins#
Every target implementation inherits from the abstract base class DeployTarget and can selectively implement mixin interfaces depending on its capabilities:
``DeployTarget``: Core interface defining
prepare(),build(),execute(), andparse_output().``TransferableTarget``: Adds
transfer()for targets requiring file transfers to a remote host (e.g., via SSH).``FlashableTarget``: Adds
flash()for bare-metal targets requiring firmware programming.``RemoteBuildTarget``: Replaces local
build()withbuild_remote()for builds executed on a remote server or API.
Heterogeneous graph partitioning and multi-program generation are exporter responsibilities. The resulting manifest tells deploy which build, flash, and runtime path to use; no deploy target generates model sources.
DeployTarget and the Hardware Model#
@register_deploy_target(target, backend) first resolves target through
get_target_class(). The decorator attaches that class as
hardware_target_class to the deploy implementation. Each instance exposes
hardware_target as a cached hardware-model object. Consequently, deploy
code reads target facts such as the target name, build system, HAL family, or
UART handle from self.hardware_target rather than declaring them again.
The deploy registry key has two dimensions because the same hardware may be reached in different ways:
("stm32h7a3", "local") -> local build, probe flash, UART capture
("stm32h7a3", "api") -> board-farm implementation
("raspberrypi", "ssh") -> remote transfer and execution
("raspberrypi", "ssh_docker") -> remote container implementation
The target dimension selects hardware identity; the backend dimension selects deployment mechanics. Neither dimension selects export templates.
Public Interfaces & API Reference#
The deploy() Function#
The primary entry point for deployment orchestration is aidge_deploy.deploy().
import aidge_deploy
result: aidge_deploy.DeployResult = aidge_deploy.deploy(export_dir, config)
Parameters:
``export_dir``: An
ExportArtifactreturned byexport(), or a path to its directory containing.aidge-export.json.``config`` (
DeployConfig): Configuration object specifying target hardware, connection backend, flashing parameters, serial settings, and optional benchmarking/validation parameters.
Returns:
A ``DeployResult`` object containing output dictionaries, performance metrics, peak memory usage, inference timing lists, and accuracy.
Configuration Data Structures#
DeployConfig#
The DeployConfig dataclass encapsulates all configuration flags required by aidge_deploy:
from pathlib import Path
from aidge_deploy import DeployConfig
config = DeployConfig(
target="stm32h7a3", # Name of target device
backend="local", # Backend: 'local', 'ssh', 'ssh_docker', 'api'
build_dir=Path("./build"), # Optional build workspace path
keep_build_dir=False, # Retain build directory after completion
# API Backend Options (for remote board farm)
api_url="http://127.0.0.1:8000",
api_username="admin",
api_password="password",
api_board_name="stm32h7_lab_01",
# SSH / SBC Options
ssh_host="192.168.1.100",
ssh_user="pi",
ssh_port=22,
ssh_key_path=Path("~/.ssh/id_ed25519"),
# Serial / UART Options
serial_port="/dev/ttyACM0",
serial_baudrate=115200,
uart_timeout=0.1,
uart_capture_duration=300.0,
end_keyword="END DEMO",
# Flashing & Docker Options
docker_image="aidge:latest",
flash_method="pyocd",
probe_unique_id="0001A",
pyocd_target="stm32h7a3zi",
# Optional Sub-configurations
validation=valid_config, # ValidationConfig
benchmark=bench_config # BenchmarkConfig
)
Alternatively, construct DeployConfig from a CLI connection namespace using the helper method:
deploy_config = DeployConfig.from_connection_config(
conn_cfg=conn_cfg,
target="stm32h7a3",
validation=valid_cfg,
benchmark=bench_cfg
)
Execution & Result Data Structures#
``DeployContext``: Passed across pipeline stages; holds
export_dir,target,backend,build_dir, and temporary attributes.``BuildResult``: Produced by
build(); containsartifact_path,mem_peaks, and compilation status.``ExecutionResult``: Produced by
execute(); captures rawstdoutor console logs from the target.``DeployResult``: Final result object with fields:
output(dict | None): Parsed log output containing layer timings or prediction arrays.metrics(dict): Collected hardware metrics (e.g. CPU cycles).memory_peak_bytes(int): Peak RAM usage during execution.timings(list[float] | None): Measured inference latencies in milliseconds.accuracy(float | None): Top-1 accuracy score when target validation is enabled.
Dynamic Selection Registry#
Targets and connection backends are registered dynamically using decorators. This eliminates hardcoded conditional logic and allows third-party target modules to register seamlessly.
Registering a Target#
Target classes decorate themselves with @register_deploy_target(target_name, backend_name):
from aidge_deploy.registry import register_deploy_target, DeployTarget
from aidge_deploy.boards.baremetal.stm32.base import BaseSTM32LocalDeployTarget
@register_deploy_target("stm32h7a3", "local")
class STM32H7A3LocalTarget(BaseSTM32LocalDeployTarget):
"""Only local deployment mechanics belong here."""
# Hardware metadata is available through self.hardware_target.
pass
Resolving a Target#
To retrieve an instantiated target:
from aidge_deploy.registry import get_deploy_target
target_instance = get_deploy_target("stm32h7a3", "local")
Board Support Package (BSP) Asset Management#
Static hardware support files (linker scripts .ld, vendor HAL headers,
assembly startup code, and Makefiles) are stored separately as Board Support
Packages (BSPs). BSP resolution happens during export, never during deploy.
Ownership and resolution#
The generic manager is aidge_core.export_utils.bsp_manager. The hardware
model declares the complete BSPPackage for each target: package name,
version, and archive name. The relevant exporter reads this package from its
resolved Device and incorporates it into the generated project. No package
coordinate is declared by a deploy target or duplicated in an exporter
profile.
ensure_bsp_package() first accepts a non-empty exporter-owned local BSP,
then checks the package/version/archive-specific cache, and finally downloads
the exact GitLab Generic Package asset. The exporter copies the result into the
generated project. aidge_deploy receives that complete project and does not
download or copy BSP content.
Authentication & Environment Variables#
When downloading or uploading BSP assets, authentication token lookup follows this priority:
export GITLAB_TOKEN="<your_personal_access_token>"
# or
export GITLAB_PRIVATE_TOKEN="<your_private_access_token>"
# or (automatically set in GitLab CI pipelines)
export CI_JOB_TOKEN="<job_token>"
Environment Overrides:
AIDGE_BSP_REGISTRY_URL: Custom GitLab package registry base URL (default: Eclipse GitLab repository).AIDGE_BSP_CACHE_DIR: Custom directory for storing downloaded BSP archives.
Publishing BSP Packages to GitLab#
When introducing a new target board, publish its BSP assets using either the Python API or curl.
Using Python:
from pathlib import Path
from aidge_core.export_utils import BSPPackage, publish_bsp_package
upload_url = publish_bsp_package(
Path("./stm32f413_bsp_staging"),
BSPPackage(
name="aidge_deploy_bsp_stm32f413",
version="v1.2.5",
archive_name="stm32f413.tar.gz",
),
token="your_gitlab_token"
)
print(f"BSP asset published to: {upload_url}")
Using Terminal curl:
# 1. Compress BSP staging directory
tar -czvf stm32f413.tar.gz -C ./stm32f413_bsp_staging .
# 2. Upload to GitLab Generic Package Registry
curl --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
--upload-file stm32f413.tar.gz \
"https://gitlab.eclipse.org/api/v4/projects/5138/packages/generic/aidge_deploy_bsp_stm32f413/v1.2.5/stm32f413.tar.gz"
Usage Examples#
Example 1: Local STM32 Bare-metal Deployment#
This example demonstrates exporting a model, flashing an STM32 board locally using pyOCD, and capturing inference timings over UART.
import aidge_core
from aidge_core.export_utils import ExportApplication, export
from aidge_core.export_utils.config import ExportConfig
import aidge_deploy
# 1. Generate a complete, buildable project
export_cfg = ExportConfig(
target="stm32h7a3",
export_folder="export_stm32h7",
dtype="int8",
cmsis=True,
application=ExportApplication(
kind="benchmark", nb_warmup=10, nb_iterations=100, profiling=True
),
)
artifact = export(model, export_cfg, input_tensors=[sample_tensor])
# 2. Configure Local Deployment
deploy_cfg = aidge_deploy.DeployConfig(
target="stm32h7a3",
backend="local",
serial_port="/dev/ttyACM0",
serial_baudrate=115200,
)
# 3. Execute Deployment
result = aidge_deploy.deploy(artifact, deploy_cfg)
print(f"Peak Memory: {result.memory_peak_bytes} bytes")
print(f"Mean Inference Latency: {sum(result.timings)/len(result.timings):.2f} ms")
Example 2: Remote SBC Deployment via SSH & Docker#
Deploy and benchmark an exported model on a remote Raspberry Pi board running inside a Docker container.
from pathlib import Path
import aidge_deploy
deploy_cfg = aidge_deploy.DeployConfig(
target="raspberrypi",
backend="ssh_docker",
ssh_host="192.168.1.50",
ssh_user="pi",
ssh_key_path=Path("~/.ssh/id_ed25519"),
docker_image="aidge:latest",
benchmark=BenchmarkConfig(nb_iterations=50)
)
result = aidge_deploy.deploy("export_raspberrypi", deploy_cfg)
print("Execution output:", result.output)
Example 3: Remote Board-Farm API Deployment#
Submit a model build to a remote Board-Farm server queue.
import aidge_deploy
deploy_cfg = aidge_deploy.DeployConfig(
target="stm32h7a3",
backend="api",
api_url="http://board-farm.example.com/api",
api_board_name="stm32h7_node_01",
api_username="ci_user",
api_password="ci_password"
)
result = aidge_deploy.deploy("export_stm32h7", deploy_cfg)
print(f"Board Farm Result Accuracy: {result.accuracy}")
Adding a New Target End to End#
Adding hardware support normally crosses all three layers, but each piece of information must have only one owner.
Register the hardware model in core. Define the
Device, processing elements, memories, execution domain, architecture, compatible export libraries, and build system. Put hardware-owned information such asBSPPackage, HAL family, UART handle, and electrical reference values on this model.Add exporter integration. Under the exporter, create
targets/<target>/__init__.pyand register aTargetExport. Store only exporter-owned assets there, such as a target-specific main or Makefile template. Put reusable composition intargets/common.py.Select an export hook only if necessary. Use a project composer for environment-wide project assembly, a target preprocessor for target graph transformation, or a target export strategy when the target must replace generic generation entirely.
Make export independently buildable. If the target needs a BSP, publish it and reference its coordinates from the hardware model. The exporter must resolve and copy it into the project. Verify export without invoking deploy.
Add deployment mechanics. Create the appropriate module under
aidge_deploy/boards/<environment>/<family>/<target>/. Subclass a common deploy implementation and register each supported connection backend with@register_deploy_target(target, backend).Implement only required capabilities. Add
TransferableTarget,FlashableTarget, orRemoteBuildTargetonly when the backend needs that stage. Reuseself.hardware_targetfor hardware metadata.Test the boundary. Test export generation and its manifest separately, then test deploy with an existing manifested directory. Also test rejection of mismatched targets and parsing for the declared protocol.
Before adding a value to an exporter or deploy class, ask whether it describes
the physical/logical hardware, the generated project, or the deployment
session. Hardware facts belong to the hardware model; generated-project facts
belong to exporter metadata or the manifest; connection and execution facts
belong to DeployConfig and DeployTarget.
For detailed developer instructions, see the internal guide in aidge_deploy/aidge_deploy/README.md.