Model Attributes
operators:
# Matches all operators
- type: "*"
attributes:
code_placement: ITCM
scratch_placement: DTCM
# Matches all operators of type CONV_2D
- type: "CONV_2D"
attributes:
code_placement: MRAM
scratch_placement: SRAM
# Match operators with IDs: 1, 2
- id:
- "1"
- "2"
attributes:
code_placement: MRAM
scratch_placement: MRAM
Attribute Precedence
For each operator in the model, the convert routine will select all attributes that match the operator type and ID. The attributes with higher specificity (i.e., more specific operator IDs) will take precedence over more general ones. The attributes will be consolidated into a single set of attributes for each operator. To verify the attributes applied to each operator, you can set the verbose level to 2 during conversion. This will provide detailed information about the attributes assigned to each operator in the generated module.
RSQRT LUT mode via operator attributes
INT16 RSQRT uses the standard operators attribute ruleset instead of a dedicated top-level flag.
Supported values are:
per_op: default; eachRSQRToperator gets its own LUTuniversal: matchingRSQRToperators share one universal LUT
Example:
model:
path: ./model.tflite
module:
path: ./out
name: helia_aot_nn
operators:
- type: RSQRT
attributes:
lut_mode: universal
You can also override specific operator IDs after setting a broader default:
operators:
- type: RSQRT
attributes:
lut_mode: universal
- type: RSQRT
id: ["23", "56"]
attributes:
lut_mode: per_op
Example: Customizing Memory Placement
Let's say we have a model (simple.tflite) with the following architecture:
%%{ init: {
"flowchart": {
"nodeSpacing": 20,
"rankSpacing": 30
}
}
}%%
flowchart TB;
A[Input] ==> B["CONV_2D (ID:1)"]
B ==> C["CONV_2D (ID:2)"]
C ==> D["MAX_POOL_2D (ID:3)"]
D ==> E["FULLY_CONNECTED (ID:4)"]
E ==> F["SOFTMAX (ID:5)"]
Let's define an initial YAML configuration file (simple.yaml) for the conversion:
model:
path: simple.tflite
module:
prefix: simple
type: zephyr
path: simple.zip
memory:
planner: greedy
verbose: 1
By default, all operator wrappers are typically placed in ITCM. However, ITCM is extremely limited in size. In addition, CONV_2D, MAX_POOL_2D, and SOFTMAX are least sensitive to code placement. Only FULLY_CONNECTED is sensitive. Therefore, we can set the default behavior for these operators. We will by default map all operator wrappers to MRAM with scratch in SRAM, and then route FULLY_CONNECTED to ITCM/DTCM. The new YAML configuration file (simple.yaml) will look like this:
model:
path: simple.tflite
module:
prefix: simple
type: zephyr
path: simple.zip
memory:
planner: greedy
verbose: 1
operators:
# Default placement for all operators
- type: "*"
attributes:
code_placement: MRAM
scratch_placement: SRAM
# All Fully Connected operators get the fast TCM path
- type: FULLY_CONNECTED
attributes:
code_placement: ITCM
scratch_placement: DTCM
After experimenting, let's say we find the CONV_2D operator w/ ID:1 is too slow when placed in MRAM. We can override the placement for this operator. The final YAML configuration file (simple.yaml) will be the following:
model:
path: simple.tflite
module:
prefix: simple
type: zephyr
path: simple.zip
memory:
planner: greedy
verbose: 1
operators:
# Default placement for all operators
- type: "*"
attributes:
code_placement: MRAM
scratch_placement: SRAM
# Place CONV_2D operator w/ ID:1 wrapper in ITCM
- id:
- "1"
attributes:
code_placement: ITCM
scratch_placement: SRAM
# All Fully Connected operators get the fast TCM path
- type: FULLY_CONNECTED
attributes:
code_placement: ITCM
scratch_placement: DTCM