8.12.3.6. On-Device Training Data
8.12.3.6.1. Table of Contents
8.12.3.6.2. 1. Overview
The ondevice_training_data.h and ondevice_training_data.c files provide embedded datasets that the microcontroller uses for on-device training, validation, and testing. These files are auto-generated by Modelzoo based on the export_samples_per_class parameter in the YAML configuration.
In a real deployment, training data would come from live sensor readings. However, for development, testing, and reproducibility, the example applications use pre-collected data compiled directly into the firmware. The on-device training library APIs accept data from any source — the embedded arrays are simply a convenient way to provide known data during development.
For context on how these files are generated, see Running ModelZoo for On-Device Training.
8.12.3.6.3. 2. ondevice_training_data.h
8.12.3.6.3.1. 2.1 Dimension Defines
#define NUM_TRAIN_SAMPLES 10
#define NUM_VALIDATION_SAMPLES 6
#define NUM_TEST_SAMPLES 12
#define RAW_INPUT_SIZE 768
#define NUM_CLASSES 2
Define |
Meaning |
|---|---|
|
Number of samples available for training. Used to cycle through training data across epochs. |
|
Number of samples available for validation during training and for threshold calculation after training. |
|
Number of samples available for pre-training and post-training evaluation. Includes both normal and anomaly samples. |
|
Total number of floats per sample. This is the raw sensor data size before feature extraction. |
|
Number of classes in the dataset . |
8.12.3.6.3.2. 2.2 How RAW_INPUT_SIZE is Calculated
The raw input size depends on the sensor configuration and feature extraction settings:
RAW_INPUT_SIZE = num_channels × num_frame_concat × frame_size
For the fan blade example:
RAW_INPUT_SIZE = 3 channels (X, Y, Z) × 1 frame_concat × 256 frame_size = 768
Each sample contains the complete raw sensor data needed to produce one model input. When num_frame_concat > 1, multiple consecutive frames are included in a single sample so that the on-device feature extraction can concatenate them for temporal context.
8.12.3.6.3.3. 2.3 Extern Declarations
extern const float TRAIN_INPUTS[NUM_TRAIN_SAMPLES][RAW_INPUT_SIZE];
extern const int16_t TRAIN_LABELS[NUM_TRAIN_SAMPLES];
extern const float VALIDATION_INPUTS[NUM_VALIDATION_SAMPLES][RAW_INPUT_SIZE];
extern const int16_t VALIDATION_LABELS[NUM_VALIDATION_SAMPLES];
extern const float TEST_INPUTS[NUM_TEST_SAMPLES][RAW_INPUT_SIZE];
extern const int16_t TEST_LABELS[NUM_TEST_SAMPLES];
The arrays are declared const because the training data itself is never modified — only the model weights change during training. This allows the linker to place the data in Flash memory if desired, saving RAM.
8.12.3.6.4. 3. ondevice_training_data.c
8.12.3.6.4.1. 3.1 Data Format
Each input sample is a flat array of RAW_INPUT_SIZE floats containing raw sensor readings. The data is organized as:
Sample layout (for 3 channels, 1 frame_concat, 256 frame_size):
[channel_0_frame_0 (256 floats)] [channel_1_frame_0 (256 floats)] [channel_2_frame_0 (256 floats)]
|<─────────────────────────────── RAW_INPUT_SIZE = 768 ──────────────────────────────────────────>|
When num_frame_concat > 1 (e.g., 4 frames):
Sample layout (for 3 channels, 4 frame_concat, 256 frame_size):
[ch0_frame0..ch0_frame3 (1024 floats)] [ch1_frame0..ch1_frame3 (1024 floats)] [ch2_frame0..ch2_frame3 (1024 floats)]
|<────────────────────────────────────── RAW_INPUT_SIZE = 3072 ──────────────────────────────────────────────────>|
The data is stored channel-first: all frames for channel 0, then all frames for channel 1, and so on. When reading the frame by frame data for feature extraction, this structure is important as it tells how the frames are stored.
8.12.3.6.4.2. 3.2 Label Encoding
const int16_t TRAIN_LABELS[NUM_TRAIN_SAMPLES] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
const int16_t TEST_LABELS[NUM_TEST_SAMPLES] = { 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1 };
For anomaly detection:
Training and validation samples are all normal (label = 1). The autoencoder learns to reconstruct normal patterns — it never sees anomaly data during training.
Test samples contain a mix of normal and anomaly samples to evaluate detection accuracy.
Label Value |
Meaning |
|---|---|
|
Anomaly |
|
Normal |
8.12.3.6.4.3. 3.3 Data Arrays
const float TRAIN_INPUTS[NUM_TRAIN_SAMPLES][RAW_INPUT_SIZE] = {
{ /* sample 0: 768 floats of raw sensor data */ },
{ /* sample 1: 768 floats of raw sensor data */ },
// ... 10 samples total
};
const float VALIDATION_INPUTS[NUM_VALIDATION_SAMPLES][RAW_INPUT_SIZE] = {
{ /* sample 0: 768 floats of raw sensor data */ },
// ... 6 samples total
};
const float TEST_INPUTS[NUM_TEST_SAMPLES][RAW_INPUT_SIZE] = {
{ /* sample 0: 768 floats of raw sensor data */ },
// ... 12 samples total
};
8.12.3.6.5. 4. How export_samples_per_class Maps to These Arrays
The YAML field export_samples_per_class: [10, 6, 6] specifies [train, validation, test] counts.
8.12.3.6.5.1. For anomaly detection
Split |
YAML Count |
What Gets Exported |
Resulting Define |
|---|---|---|---|
Train |
10 |
10 normal samples |
|
Validation |
6 |
6 normal samples |
|
Test |
6 |
6 normal + 6 anomaly = 12 samples |
|
Key points:
Training and validation samples are drawn from the normal class only (the autoencoder trains on normal data).
Test samples include both normal and anomaly classes for evaluation.
For test data, the YAML count applies per class, so
6means 6 normal + 6 anomaly samples.
8.12.3.6.6. 5. How the Application Uses This Data
8.12.3.6.6.1. 5.1 DatasetIterator_t Pattern
The example application wraps these arrays in a simple iterator structure:
typedef struct {
const float (*inputs)[RAW_INPUT_SIZE]; // Pointer to 2D input array
const int16_t* labels; // Pointer to labels array
uint16_t num_samples; // Total samples in this split
uint16_t current_index; // Current position (circular)
} DatasetIterator_t;
Three iterators are initialized — one each for training, validation, and test data:
train_iter.inputs = TRAIN_INPUTS;
train_iter.labels = TRAIN_LABELS;
train_iter.num_samples = NUM_TRAIN_SAMPLES;
train_iter.current_index = 0;
8.12.3.6.6.2. 5.2 Circular Iteration
The iterators wrap around when they reach the end of the dataset:
iter->current_index++;
if (iter->current_index >= iter->num_samples) {
iter->current_index = 0; // Wrap around
}
This means:
During training: The 10 training samples are reused across epochs. With
batches_per_epoch: 10andbatch_size: 1, each epoch uses all 10 samples exactly once.
8.12.3.6.7. 6. Memory Impact
The embedded training data is typically the largest artifact in an on-device training project.
Formula:
Memory (bytes) = (NUM_TRAIN + NUM_VAL + NUM_TEST) × RAW_INPUT_SIZE × 4 bytes/float
Fan blade example:
(10 + 6 + 12) × 768 × 4 = 28 × 768 × 4 = 86,016 bytes ≈ 84 KB
8.12.3.6.7.1. Guidance on choosing sample counts
More samples |
Fewer samples |
|---|---|
Better training convergence |
Less flash memory usage |
More representative threshold calculation |
Faster threshold calculation |
Better test evaluation statistics |
— |
May exceed flash budget on small MCUs |
May under-represent data distribution |
8.12.3.6.8. 7. Further Reading
How these files are generated → Running ModelZoo for On-Device Training
All generated artifacts at a glance → Generated Artifacts Overview
How the trainable model uses this data → Anomaly Detection ODT Library
See the data in action → Application Example — Fan Blade