heliaAOT Walkthrough
This guide walks through a full heliaAOT flow: install, verify, inspect convert help, convert a model, and repeat with a YAML config.
What heliaAOT Does Not Do
- Training, quantization, or dataset handling (do these upstream and feed in a ready model).
- Runtime scheduling on dynamic shapes; the emitted code assumes static shapes and buffer sizes.
Limitations to Keep in Mind
- Operator support is currently limited to the kernels registered in this repo; check the registries reference before relying on a layer.
- Mixed-precision flows are constrained by the available kernels.
- Generated sources are static; rebuild when the model, platform, or planner settings change.
1) Pick a small model to convert
Sample models live here:
2) Install heliaAOT (pipx)
The pipx interpreter must be Python >=3.11.
Expected output:
3) Verify the CLI works
Expected output:
Expected output:
Usage: helia-aot [OPTIONS] COMMAND [ARGS]...
heliaAOT command line interface.
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮
│ --help -h Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────────────────────────╮
│ version Display the version of the heliaAOT library. │
│ convert Convert a model to standalone C inference module. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
4) Inspect convert help
Expected output:
Usage: helia-aot convert [OPTIONS]
Convert a model to standalone C inference module.
╭─ Options ────────────────────────────────────────────────────────────────────────────────────────╮
│ --help -h Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ general ────────────────────────────────────────────────────────────────────────────────────────╮
│ --path PATH Path to yaml configuration │
│ --transforms [TEXT ...] Transforms configuration │
│ --operators [TEXT ...] Operator attributes │
│ --verbose INT Verbosity level (default: 1) │
│ --force --no-force Force conversion even if output exists (default: │
│ False) │
│ --log-file PATH Optional log file path │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ model ──────────────────────────────────────────────────────────────────────────────────────────╮
│ --model.path PATH Path to target model file (default: model.tflite) │
│ --model.subgraph INT Subgraph index (default: 0) │
│ --model.type TEXT Model type (e.g., tflite, litert) │
│ --model.name TEXT Model name (default: model) │
│ --model.description TEXT Description of the model │
│ --model.version TEXT Model version (default: v1.0.0) │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ module ─────────────────────────────────────────────────────────────────────────────────────────╮
│ --module.path PATH Output path for the generated │
│ module. Use a directory for an │
│ unpacked module, a '.zip' suffix │
│ for a generic zip archive, or a │
│ '.pack' suffix for an │
│ Open-CMSIS-Pack archive (requires │
│ module.type=cmsis_pack). (default: │
│ output.zip) │
│ --module.type <neuralspot|zephyr|cmake|nsx|cmsis Module type (default: neuralspot) │
│ _pack> │
│ --module.name TEXT Module name (default: helia_aot_nn) │
│ --module.prefix TEXT Prefix added to sources for unique │
│ namespace (default: aot) │
│ --module.schedule <table|static> Operator dispatch shape in the │
│ generated model: 'table' (default) │
│ keeps the runtime function-pointer │
│ table and per-node callback seam; │
│ 'static' emits straight-line direct │
│ calls (no table, no loop, no │
│ indirect dispatch). (default: │
│ table) │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ test ───────────────────────────────────────────────────────────────────────────────────────────╮
│ --test.enabled --no-test.enabled Include test case (default: │
│ False) │
│ --test.tolerance FLOAT Test tolerance (default: 1.0) │
│ --test.skip-verification --no-test.skip-verification Skip runtime output │
│ verification (default: False) │
│ --test.golden-data PATH Golden input/output npz file │
│ --test.num-iterations INT Number of times to run the │
│ same stimulus through the │
│ model (default: 1) │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ memory ─────────────────────────────────────────────────────────────────────────────────────────╮
│ --memory.planner <greedy> Memory planner strategy │
│ (default: greedy) │
│ --memory.constraints [TEXT ...] Memory constraints │
│ (ordered by preference) │
│ --memory.tensors [TEXT ...] Tensor attributes │
│ --memory.allocate-arenas --no-memory.allocate-ar… If true, the module will │
│ use internal, statically │
│ allocated arenas. If │
│ false, the caller must │
│ bind every region via │
│ <prefix>_bind_arena() / │
│ <prefix>_bind_arenas() │
│ before model_init. │
│ (default: True) │
│ --memory.auto-hydrate-con… --no-memory.auto-hydrat… Deprecated — retained for │
│ backwards compatibility │
│ but no longer changes │
│ generated runtime │
│ behavior. model_init │
│ always invokes │
│ hydrate_constants between │
│ context_init and the │
│ operator init loop. │
│ Override the weak │
│ hydrate_constants symbol │
│ for custom hydration │
│ mechanisms (DMA / async │
│ pre-stage / model swap). │
│ (default: True) │
│ --memory.dump-residency-j… --no-memory.dump-reside… If true, write a │
│ machine-readable residency │
│ report │
│ (``<prefix>_residency.jso… │
│ alongside the emitted │
│ module. Mirrors the │
│ verbose log summary as │
│ JSON for tooling that │
│ needs to introspect arena │
│ layout, staged-vs-cold │
│ residency, and per-tensor │
│ placement post-planning. │
│ (default: False) │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ platform ───────────────────────────────────────────────────────────────────────────────────────╮
│ --platform.name TEXT Target platform name (default: │
│ apollo510_evb) │
│ --platform.cpu TEXT CPU core type (e.g., cortex-m55) │
│ --platform.speeds [INT ...] List of supported clock speeds in MHz │
│ --platform.memories JSON Memory sizes in bytes │
│ --platform.capabilities [TEXT ...] List of SoC capabilities │
│ --platform.preferred-memory-order [TEXT ...] Preferred memory order for allocations │
│ --platform.min-alignment INT Minimum alignment requirement in bytes │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ documentation ──────────────────────────────────────────────────────────────────────────────────╮
│ --documentation.html --no-documentation.html Generate html documentation site │
│ (experimental). (default: False) │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
Quick start:
helia-aot convert --model.path model.tflite --module.path ./out
helia-aot convert --path my-model.yaml --verbose 2
helia-aot convert --model.path model.tflite --module.type zephyr --test.enabled
5) Convert the model (CLI or YAML)
helia-aot convert \
--model.path add_scalar_s8.tflite \
--module.path ./out \
--module.name add_scalar_s8 \
--module.type zephyr \
--test.enabled \
--verbose 3
Expected output (verbose 3):
heliaAOT v<X.Y.Z>
Analyze
DEBUG ========================================================================================================================
DEBUG AIR Operator ADD (id: 0)
DEBUG ========================================================================================================================
DEBUG Tensors:
DEBUG • Inputs: (['0', '1'])
DEBUG • Outputs: (['2'])
DEBUG • Local: ([])
DEBUG Options:
DEBUG • activation: none
DEBUG ========================================================================================================================
📥 Loading model add_scalar_s8.tflite ✓ 0.0s
DEBUG • Applying transform DEPTHWISE_TO_CONV
DEBUG • Applying transform PRUNE_IDENTITY_OPS
DEBUG • Applying transform TRANSPOSE_REVERSE_CONV
🔧 Applying graph-level transforms ✓ 0.0s
WARNING unresolved dynamic tensors remain (2): ['0', '2']. Conversion continues with placeholder dims.
DEBUG unresolved: tensor 0 (shape_signature=(-1, 3, 10)) remains unresolved with shape=(1, 3, 10)
DEBUG unresolved: tensor 2 (shape_signature=(-1, 3, 10)) remains unresolved with shape=(1, 3, 10)
📐 Propagating tensor shapes ✓ 0.0s
Plan
DEBUG Resolving operator ADD (0)
🧩 Resolving handlers ✓ 0.0s
⚡ Optimizing resolved model ✓ 0.0s
DEBUG Tensor lifetimes:
DEBUG • Tensor 0: Lifetime from operator 0 to 0
DEBUG • Tensor 1: Lifetime from operator 0 to 0
DEBUG • Tensor 2: Lifetime from operator 0 to 0
DEBUG Memory allocation:
DEBUG • Tensor 1: dtcm[0:1]
DEBUG • Tensor 0: dtcm[0:30]
DEBUG • Tensor 2: dtcm[32:62]
🧮 Memory planning via greedy ✓ 0.0s
Emit
DEBUG Tensor 0 - Allocated size: 30, Arena: dtcm
DEBUG Tensor 1 - Allocated size: 1, Arena: dtcm
DEBUG Tensor 2 - Allocated size: 30, Arena: dtcm
📝 Emitting code as zephyr module ✓ 0.1s
📦 Exporting module ✓ 0.0s
───────────────────────────────────────────────────────────────── Results ──────────────────────────────────────────────────────────────────
Model model · subgraph 0 · 1 operators
Module add_scalar_s8 · zephyr · prefix aot · schedule table
Platform apollo510_evb · cortex-m55 · MCU, USB, PSRAM, DSP, MVE, FP16
Arenas
Region Kind Size Capacity
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
dtcm scratch 62 B 512.0 KB ╌╌╌╌╌╌╌╌╌╌╌╌╌╌ 0%
dtcm constant (cold) · 1 tensors 1 B 512.0 KB ╌╌╌╌╌╌╌╌╌╌╌╌╌╌ 0%
╭─ Output → out ───────────────────────────╮
│ add_scalar_s8/ 7 sources · 10 headers │
╰───────────────────────────── 0.1s total ─╯
Or generate it locally:
cat <<'EOF' > convert.yaml
# Example config using add_scalar_s8.tflite; adjust paths and options for your model.
model:
path: add_scalar_s8.tflite
name: add_scalar_s8
module:
path: ./out
name: add_scalar_s8
type: zephyr
test:
enabled: true
EOF
Convert:
Expected output (verbose 1):
heliaAOT v<X.Y.Z>
Analyze
📥 Loading model add_scalar_s8.tflite ✓ 0.0s
🔧 Applying graph-level transforms ✓ 0.0s
WARNING unresolved dynamic tensors remain (2): ['0', '2']. Conversion continues with placeholder dims.
📐 Propagating tensor shapes ✓ 0.0s
Plan
🧩 Resolving handlers ✓ 0.0s
⚡ Optimizing resolved model ✓ 0.0s
🧮 Memory planning via greedy ✓ 0.0s
Emit
📝 Emitting code as zephyr module ✓ 0.1s
📦 Exporting module ✓ 0.0s
───────────────────────────────────────────────────────────────── Results ──────────────────────────────────────────────────────────────────
Model add_scalar_s8 · subgraph 0 · 1 operators
Module add_scalar_s8 · zephyr · prefix aot · schedule table
Platform apollo510_evb · cortex-m55 · MCU, USB, PSRAM, DSP, MVE, FP16
Arenas
Region Kind Size Capacity
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
dtcm scratch 62 B 512.0 KB ╌╌╌╌╌╌╌╌╌╌╌╌╌╌ 0%
dtcm constant (cold) · 1 tensors 1 B 512.0 KB ╌╌╌╌╌╌╌╌╌╌╌╌╌╌ 0%
╭─ Output → out ───────────────────────────╮
│ add_scalar_s8/ 7 sources · 10 headers │
╰───────────────────────────── 0.1s total ─╯
If the closing Results frame renders (with the Output panel pointing at your module) and the out/ directory is created, your conversion was successful.
6) Generated output highlight
After conversion, the output directory looks like this:
out/add_scalar_s8/
├── includes-api/
├── src/
├── zephyr/
│ ├── CMakeLists.txt
│ ├── Kconfig
│ └── module.yml
├── LICENSE
└── README.md
For more detail on module contents, see the Module Layout reference.
7) Integrate the generated output
Your output module is ready to drop into an application. Follow one of these guides to integrate and build: