Skip to content
heliaAOT
API Reference
HELIA HUB

Changes before 1.0

Each item names the 0.x release that made the change. A configuration or a program written for an earlier release may need the change the item describes.

  • Next release. A looping --log-file symbolic link is rejected with exit 2 instead of a traceback and exit 1.

  • Next release. Archive output links whose target directory is missing are rejected before conversion with exit 2.

  • Next release. int16 CONCATENATION, EXPAND_DIMS and FILL with nonzero zero points are rejected, as in LiteRT.

  • 0.28.0. The legacy neuralspot module type was removed; use cmake (the new default), zephyr or nsx. With it, <prefix>_platform.h no longer maps <PREFIX>_PRINTF to ns_lp_printf or the <PREFIX>_PUT_IN_* hooks to neuralSPOT’s sections, and <PREFIX>_PUT_CODE_IN_ITCM is empty, so operators with code_placement: ITCM stay in the default code section. Define the hooks your application needs; without them the arenas and code follow the linker’s default placement and logging is silent.

  • 0.28.0. memory.planner defaults to hill_climb instead of greedy. Its scratch arenas are the same size or smaller than greedy’s in every memory when greedy’s plan fits, but tensor offsets and the memory of an individual tensor can change. Set memory.planner: greedy to keep the previous layout.

  • 0.28.0. An unknown key in a nested block, a list entry or memory.tensors[].attributes is an error that names the nearest valid key (the command line exits 2). Earlier releases dropped such keys, with a warning in the later ones; unknown top-level keys were already rejected. See When a key is wrong.

  • 0.28.0. A TRANSPOSE_CONV with SAME padding whose input height or width is not divisible by its stride, such as a Keras Conv2DTranspose decoder, produced output shifted by one pixel in earlier releases. It now follows LiteRT, and a declared output shape the operators do not produce is a typed error.

  • 0.28.0. Conversion applies LiteRT’s dtype, scale and quantization rules, so a model that breaks one is a typed error with a hint where earlier releases gave a traceback, wrong output or code that did not compile. Platform and configuration-value errors that do not depend on the model exit 2 (see When a key is wrong), and the public I/O tables report scale 1 and zero point 0 for every tensor but an int8, uint8 or int16 one with a scale.

  • 0.28.0. Golden data must match each tensor’s element count and dtype; a mismatch or an archive that cannot be loaded raises GoldenDataError and exits 2. Attribute values are checked before conversion starts, and a .zip export appears at the output path only when it is complete.

  • 0.31.0. The plan’s platform.core and the core of each report measurement are named cpu, as in the configuration’s platform.cpu, because CORE means heliaCORE everywhere else; measurements_for takes cpu. A plan or report that names it core still reads. OptimizationPlan and OptimizationReport read a file from a newer release with the same schema_version instead of rejecting a field, knob, value or member they do not know. To check that a file holds only what one release writes, validate it against the json_schema object in that release’s plan-schema.json or report-schema.json. The rename keeps schema_version 1, an exception made once before 1.0: a script that reads the raw JSON reads cpu and falls back to core, and heliaAOT 0.30 and earlier cannot read a plan or report that 0.31.0 or later writes. PlanOptimization.goal is the string written, which still compares equal to its OptimizationGoal member.

  • 0.31.0. A built-in operator’s operators[].attributes keys are checked: a key the operators a rule reaches do not take is an error that names the nearest valid key, where earlier releases passed it through. A custom operator class keeps free-form attributes only when its ATTRIBUTES model allows extra keys. A custom transform takes no options unless it declares OPTIONS; a built-in transform that takes none has rejected options since 0.28.0.

  • 0.31.0. Removed settings, each an error that names its replacement: memory.auto_hydrate_constants, which had no effect (<prefix>_model_init always hydrates staged constants); operators[].attributes.scratch_placement, which was never implemented (use a memory.tensors rule); and the ble, usb and psram values of platform.capabilities, which nothing read (declare PSRAM under platform.memories). The --memory.auto-hydrate-constants and --no-memory.auto-hydrate-constants flags are gone, so the command line rejects them as unknown options.

  • 0.31.0. model.type accepts only tflite and litert, and an unknown value is a command-line or configuration error. model.version defaults to none, so the generated documentation shows the LiteRT schema version the model file records (3) instead of v1.0.0. A custom platform no longer needs platform.speeds.

  • 0.31.0. list-targets and target-info are deprecated; use platforms list and platforms show NAME.

  • 0.31.0. AotConverter.convert() returns a ConversionResult with the output path, the prefix, the parsed plan and report, and the kept work directory, instead of the internal code generation context. Read those fields, or the residency report, instead of the context’s.

  • 0.31.0. ConvertArgs.from_yaml raises InvalidConfigError, a ConfigValueError with exit_code 2, for a file it cannot load or a key or value that does not validate, where earlier releases raised FileNotFoundError, ValueError or pydantic’s ValidationError.

  • 0.31.0. ModelLoadError is an OSError rather than a FileNotFoundError, and UnsupportedModelError is a ConfigValueError. Catch ModelLoadError or OSError for a model that cannot be loaded, and put an except UnsupportedModelError before an except ConfigValueError.

  • 0.31.0. Each typed error carries the exit code the command line ends with, as exit_code on its class. ConfigValueError no longer takes an exit_code argument: a configuration rejected on its own or against the target raises its subclass InvalidConfigError, which declares 2.

  • 0.31.0. helia_aot exports AotConverter, ConversionResult and ConvertArgs and no module objects, and each manifest name is promised at one import path: AotConverter and ConvertArgs from helia_aot, the registry names from helia_aot.registry, the operator names from helia_aot.aot.operators, the memory names from helia_aot.memory, and ValidCVarNameType and ValidModuleNameType from helia_aot.defines.

  • 0.31.0. A generated module needs ns-cmsis-nn 7.46.0 or later; a project on 7.45.x or earlier updates ns-cmsis-nn before rebuilding a regenerated module. See the heliaCORE floor.

  • 0.32.0. Public enum members are spelled in UPPER_CASE (ModuleType.CMAKE, ScheduleMode.TABLE, MemoryPlannerType.HILL_CLIMB, ModelType.TFLITE, ArenaRole.SCRATCH). The earlier lowercase names remain aliases of the same members, and configuration values are unchanged. member.name now returns the uppercase name (ModuleType.cmake.name is "CMAKE"), so code that compares .name with a lowercase string compares .value instead.

  • 0.32.0. Registry.unfreeze and RegistryContext.unfreeze are removed.

  • 0.32.0. MemoryType.readable and MemoryType.executable are removed, and MemoryType.writeable and the other compiler helpers on MemoryType, ConvertArgs, ModuleArgs and AirTensor are private. An AirTensor constructor keyword or assignment that uses a former field name is an error naming the new spelling.

  • 0.32.0. ConversionResult compares and hashes by identity.

  • 0.32.0. The command line logs at the level verbose names: 0 errors only, 1 stage milestones, 2 debug details, 3 debug details with each AIR operator’s tensors and options. Level 0 shows no warnings, configuration warnings included; from level 1 each reaches standard error and --log-file once. AotConverter.convert() leaves the helia_aot logger as the caller configured it.

  • 0.32.0. platform.speeds is deprecated; no conversion reads it, and a non-empty value is accepted with a warning until 2.0 removes it.

  • 0.32.0. On the experimental Python custom-operator path, a type: "*" operator rule is checked against the built-in operators’ attributes even when a custom operator with free-form (extra="allow") attributes is registered. A key no operator declares, or a removed key such as scratch_placement in a rule for a free-form custom operator, is a configuration error. Put free-form keys on a rule for the custom operator’s type.

  • 0.32.0. A former key of a renamed setting is accepted, with one warning per conversion, in transform options, planner options, operator attributes and tensor attributes as well as the configuration blocks.

  • 0.32.0. Generated modules require ns-cmsis-nn 7.47.0 or newer (was 7.46.0).

  • 0.32.0. Generated modules no longer contain the empty <prefix>_compiler.h; include <prefix>_model.h.

  • 0.32.0. The file-name promise covers only the names module-layout.json marks public (see What a release promises); operator, helper and CMSIS-Pack file names can change.

  • 0.32.0. <prefix>_context_init is advanced instead of public: <prefix>_model_init already calls it, so an application that only runs a model does not call it.

  • 0.32.0. The generated C API is version 1.1.0. The operator callback’s op argument is the operator’s layer index, its 0-based position in execution order, not its AIR node id. The two differ when a transform removed or reordered operators or the parser skipped one; ConversionResult.operators[op].source_indices gives the model-file operator index. <prefix>_status_t reserves 1000 to 1999 for custom operators (<prefix>_status_custom_first, <prefix>_status_custom_last). Hold statuses in int32_t.

  • 0.32.0. Exit code 2 means rejected input wherever the check runs. These used to exit 1 and now exit 2: a missing, unreadable or corrupt model file; an existing output without --force; a missing golden archive; test.state_feedback and test.tolerance values the model rejects; an out-of-range model.subgraph; an unsupported model extension; an invalid SOURCE_DATE_EPOCH; memory.tensors rules that give one constant memory two source memories; a float16 model on a target without FP16 support; an Ethos-U model on a target without an NPU. A script that treated 1 as bad input checks for 2.

  • 0.32.0. A rule that names an id outranks a rule that names only a type, for operators[] and memory.tensors. Where a type rule used to override an id rule, the id rule now wins; a rule that others override on everything it matches logs a warning.

  • 0.32.0. memory.tensors[].attributes.memory is unset by default. A rule that sets only constant_destination_memory stages its constants from a source the planner chooses, read-only memory first (MRAM on Apollo510), instead of taking DTCM as the source. Set memory: DTCM in the rule to keep the previous placement.

  • 0.32.0. Operator ids must be strings holding a decimal integer from 0 to 2147483647, unique in the model; OperatorIdError names any other. Only a custom parser or transform can produce another.

  • 0.32.0. Resource variables start at the constant their CALL_ONCE initialization assigns, as they do in LiteRT. They used to start at zero or at their zero point, which gave wrong output for stateful models whose variables have nonzero initial values, such as NNSE and NNVAD. Models whose variables start at zero are unchanged. Two handles that name one variable now share it.

  • 0.32.0. Conversion rejects, with UnsupportedModelError, models that earlier releases converted silently. These models are invalid: LiteRT refuses them, or for an element-count mismatch gives an undefined result:

    • a plain CALL node, which LiteRT has no kernel for;
    • a CALL_ONCE node that names no other subgraph of the model;
    • a CALL_ONCE initial value whose type differs from the variable’s read (LiteRT refuses the read), or whose element count differs from it (LiteRT copies the read’s byte count, past the variable’s end or short of it);
    • a fused activation on CONCATENATION, which LiteRT’s builtin kernel rejects;
    • int8 CONCATENATION, or int8 and int16 PACK, UNPACK, SPACE_TO_BATCH_ND, BATCH_TO_SPACE_ND, REDUCE_MAX, REDUCE_MIN, EXPAND_DIMS or FILL, whose inputs and outputs differ in scale or zero point.

    LiteRT runs these, but heliaAOT does not support them:

    • a CALL_ONCE node after a READ_VARIABLE or ASSIGN_VARIABLE;
    • a CALL_ONCE initialization subgraph that runs anything but VAR_HANDLE and the assignment of a constant, such as a nested CALL_ONCE or an initializer that computes its value.
  • 0.32.0. A module converted for a target without MVE stops a build with ARM_MATH_MVEI (#error in <prefix>_common.h) when one of its layers would be planned differently with MVE: another kernel entry, other scratch or weight sums. Examples are int8 convolution, fully connected, batch matmul and average pooling, and int8 3x3 depthwise. Layers planned the same either way, such as int8 max pooling or int16 fully connected, still build for both. HELIA_AOT_SKIP_TARGET_CHECK lifts the check.

  • 0.32.0. The optimization report counts MACs for TRANSPOSE_CONV and BATCH_MATMUL too. A TRANSPOSE_CONV rewritten to CONV_2D is counted at its input positions, no longer on its upscaled input, which counted four times too many at stride 2.