Skip to content

lstm

Classes

UnidirectionalSequenceLstmOperator

UnidirectionalSequenceLstmOperator(op: AirOperator, model: AirModel, platform: SocPlatform, prefix: str = 'aot', attributes: dict[str, str] | None = None)

AOT operator for UNIDIRECTIONAL_SEQUENCE_LSTM.

Lowers to the CMSIS-NN arm_lstm_unidirectional_* kernels for the standard Keras LSTM subset (TANH cell activation, no projection clipping, no diagonal/peephole tensors).

Statefulness (int8 and float paths): the recurrent state persists across invocations. output_state/cell_state arrive as LiteRT variable tensors, which parse as :attr:AirTensorKind.PERSISTENT, and codegen points cmsis_nn_lstm_context::hidden_state at the persistent output_state slot. A non-NULL hidden_state selects the kernel's state-carry path: the stored state seeds timestep 0, the cell state is treated as in/out rather than re-zeroed, and the final hidden state is written back on return. State therefore survives across model_run calls exactly as it does in the LiteRT reference interpreter.

output_state/cell_state must not be model inputs. Statefulness is delivered entirely through the persistent slots above, so externally supplied recurrent state is a separate capability that codegen does not implement: the generated test harness re-copies every graph input before each iteration (templates/test_case.c.j2) whereas the reference interpreter sets inputs once and carries the mutated state, so the two would silently disagree. :meth:~helia_aot.aot.operators.operator.AotOperator._reject_runtime_recurrent_state_input rejects that configuration rather than emitting code that cannot be verified.

A second restriction is :meth:~helia_aot.aot.operators.operator.AotOperator._require_zero_initialized_state: baked-in initial state values are rejected because context_init() resets every persistent slot (see templates/context.c.j2), so such a value could not be honored. This is a persistent-arena contract, not an LSTM limitation. :meth:~helia_aot.aot.operators.operator.AotOperator._require_persistent_state enforces the other half of that contract: both state tensors must actually be persistent, since a scratch slot may be aliased with unrelated activations and is never initialized.

Minimum kernel version: hidden_state landed in the int8 context in ns-cmsis-nn v7.28.0 and in the float contexts in v7.29.0. Both are satisfied by :data:helia_aot.aot.defines.CMSIS_NN_VERSION, which sits higher for reasons unrelated to this operator, so no per-operator floor is declared here.

UNIDIRECTIONAL_SEQUENCE_LSTM operator for CMSIS-NN int8/float paths.

Functions

Functions