Runtime Basic Example
January 23, 2026 · View on GitHub
This example demonstrates how to use ONNXRT, TFLiteRT, TVM RT and TIDLRT wrapper modules for model inference with TIDL acceleration. It provides a command-line interface to run ONNX and TFLite models with various configuration options.
Overview
The basic_example.cpp showcases:
- Model inference with TIDL acceleration
- Support for both ONNX and TFLite models
- Model inference with TVM runtime.
- Handling different input data sources (.bin or .npz files)
- Processing multiple models defined in a configuration file
- Saving inference outputs as binary files
- Runtime-specific handling for different model formats
- Detailed model information display in verbose mode
Requirements
- C++17 compatible compiler
- ONNX Runtime (for ONNX models)
- TFLite Runtime (for TFLite models)
- TVM Runtime (with TVM artifacts and ONNX model)
- YAML-CPP library
- CNPY library (for NPZ file loading)
- TIDL Tools (for model compilation)
Directory Structure
Example directory
runtimes/
├── examples/
│ ├── cpp/
│ │ ├── basic_example/ # This example
│ │ | ├── basic_example.cpp # Main example source
│ │ | ├── basic_example.h # Example header
│ │ | ├── config.yaml # Configuration file for models and options
│ │ | ├── outputs/ # Output directory for inference results
│ │ | └── README.md # This file
| | |
| | └── utils/ # Utility functions
│ | ├── argsparser.h # Command-line argument parser
│ | ├── utils.h # General utility functions
│ | └── datasetloader/ # Input data loading utilities
│ | ├── dataset_loader.h # Factory for creating data loaders
│ | ├── bin_loader.h # Binary file loader
│ | └── npz_loader.h # NumPy .npz file loader
│ |
│ ├── model-artifacts/ # Generated Model artifacts
│ │
│ └── data/
│ ├── inputs/ # Sample input files
| └── models/ # Sample models
|
└── tidl_wrapper/
└── cpp/
├── onnxrt/ # ONNXRT wrapper module
├── tflitert/ # TFLiteRT wrapper module
└── tidlrt/ # TIDLRT wrapper module
└── tvmrt/ # TVMRT wrapper module
Command-Line Arguments
The program supports the following command-line arguments:
-h, --help: Display help message and exit-d, --disable_tidl_offload: Disable offload to TIDL (runs on CPU only)-v, --verbose: Enable verbose output with detailed model and tensor information-x, --config: Path to config.yaml file (default:<executable_dir>/config.yaml)-m, --models [MODEL_NAMES ...]: Filter model keys to run from the config file-r, --runtimes [RUNTIME_TYPES ...]: Filter by runtime types ('onnxrt', 'tflitert', 'tvmrt' or 'tidlrt')
Configuration File
The config.yaml file defines:
- Global inference options applied to all models
- List of models with their paths, runtime type, and input data sources
- Model-specific inference options (which override global options)
Important: The name you give to each model in the configuration file is used to locate its artifacts directory. For each model, the program looks for artifacts in <artifacts_base_dir>/<model_name>/artifacts/, where <model_name> is the key used in the YAML configuration.
Example structure:
infer_options: # Global inference options
"debug_level": 0
# ... other options
models:
# ONNX model example
cl-ort-resnet18-v1:
path: ../../data/models/resnet18_opset9.onnx
inputs: ../../data/inputs/cl-ort-resnet18-v1.bin
# Optional: Model-specific options that override global options
infer_options:
"option1": value1
# TFLite model example
cl-tfl-mobilenet_v1_1.0_224:
path: ../../data/models/mobilenet_v1_1.0_224.tflite
inputs: ../../data/inputs/cl-tfl-mobilenet_v1_1.0_224.npz
# ONNX model directly with TIDLRT
cl-ort-resnet18-v1:
# Path is not required while running with tidlrt
inputs: input_directory
runtime: tidlrt
# ONNX model with tvmrt based inference
cl-tvm-ort-resnet18-v1:
path: ../../data/models/resnet18_opset9.onnx
inputs: ../../data/inputs/cl-ort-resnet18-v1.npz
runtime: tvmrt
Runtime Specification
runtime needs to be explicitly specified as onnxrt, tflitert, tvmrt or tidlrt
Number of Frames
The num_frames option in the model configuration determines how many frames will be processed for each model. This value is determined as follows:
- If
num_framesis explicitly specified in the model configuration, that value is used - Otherwise, it defaults to the number of inputs provided in the
inputsfield
For example:
models:
model-1:
path: ../../data/models/model1.onnx
inputs: ../../data/inputs/input1.npz
num_frames: 10 # Will process 10 frames, repeating the input if necessary
model-2:
path: ../../data/models/model2.tflite
inputs: [input1.npz, input2.npz, input3.npz] # Will process 3 frames by default
model-3:
path: ../../data/models/model3.onnx
runtime: tvmrt
inputs: [input1.npz, input2.npz, input3.npz] # Will process 3 frames by default
Usage Examples
Environment Setup (Only for x86 runs)
Before running the example, set the TIDL_TOOLS_PATH and LD_LIBRARY_PATH environment variables:
export TIDL_TOOLS_PATH=/path/to/tidl_tools
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TIDL_TOOLS_PATH
Building the Example
cd runtimes
mkdir build && cd build
cmake ..
make
Running the Example
To run all models defined in the config file:
./examples/cpp/basic_example/basic_example
To run specific models:
./examples/cpp/basic_example/basic_example --models cl-ort-resnet18-v1 cl-tfl-mobilenet_v1_1.0_224
To run models using ONNX runtime:
./examples/cpp/basic_example/basic_example --runtimes onnxrt
To run models using TFLite runtime:
./examples/cpp/basic_example/basic_example --runtimes tflitert
To run models using TIDL runtime:
./examples/cpp/basic_example/basic_example --runtimes tidlrt
To run models using TVM runtime:
./examples/cpp/basic_example/basic_example --runtimes tvmrt
To run with verbose output showing detailed model information:
./examples/cpp/basic_example/basic_example --verbose
To use a custom configuration file:
./examples/cpp/basic_example/basic_example --config /path/to/custom_config.yaml
CPU-Only Inference
To run inference without TIDL acceleration (CPU only):
./examples/cpp/basic_example/basic_example --disable_tidl_offload
Note: TIDLRT models always run with TIDL acceleration and ignore the
--disable_tidl_offload flag.
TVMRT models expect this option to be specified as part of compilation to generate relevant artifacts, this option does not take effect at inference time.
Workflow
-
Initialization:
- Parses the config.yaml file
- Determines runtime for each model (explicit or auto-detected)
- Filters models based on runtime and model name if specified
- Locates model artifacts based on the model name in the YAML configuration
- The artifacts are expected to be in
<artifacts_base_dir>/<model_name>/artifacts/
-
Inference:
- Creates runtime-specific inference sessions
- If verbose mode is enabled, displays detailed model and tensor information
- Loads input data from .npz or .bin files
- Runs inference on the models
- Saves outputs as binary files
Input Data
The example supports two types of input data:
- .npz files: Loads input data from NumPy .npz files, supporting multiple arrays in a single file
- .bin files: Loads input data from binary files, supporting continuous loading with different datatypes
Input data is specified in the config.yaml file for each model in several ways:
models:
model-name:
# Single input file
inputs: ../../data/inputs/input_data.npz # Load from .npz file
# Multiple input files as space-separated string
inputs: ../../data/inputs/input1.npz ../../data/inputs/input2.npz
# Multiple input files as a list
inputs: [../../data/inputs/input1.bin, ../../data/inputs/input2.bin]
# Directory containing input files
inputs: ../../data/inputs/ # Will process all .bin and .npz files in this directory
The example supports both relative and absolute paths for input files. Relative paths are resolved relative to the location of the config.yaml file.
.NPZ Files
When using .npz files as input data, the following requirements must be met:
-
Multiple Inputs: The NPZ loader supports cycling through multiple arrays in a single file. Important Note: The data will be loaded in sequence as arrays appear in the file, NOT based on the keys in the npz file. Make sure to have the same number of numpy arrays in the same order as the inputs in the model.
-
Shape and Data Type: Each array in the .npz file must have the same shape and data type as expected by the corresponding model input. For example, if the model expects a float32 tensor with shape (1, 3, 224, 224), the array in the .npz file must have the same shape and be of type np.float32.
-
Padding Support: The NPZ loader supports padding options for top, bottom, left, and right padding.
.BIN Files
Binary files provide a more flexible and memory-efficient way to load input data, especially for large datasets. The BIN loader supports continuous loading from a long binary file with different datatypes for each call.
-
Multiple Inputs: The BIN loader supports continuous data loading from a single file. The loader maintains a position pointer in the binary file, allowing it to load data sequentially across multiple loads. For example, if the first call loads data of 100 bytes, the next call will load data starting from the 101st byte position.
-
Shape and Data Type: Each call can load the binary file into different data types and reshape it.
Output Files
When running in inference mode, the program saves output tensors as binary files in:
<example_directory>/outputs/{model_name}/offload/frame_{frame_num}/(when using TIDL acceleration)<example_directory>/outputs/{model_name}/no_offload/frame_{frame_num}/(when running on CPU only)
Where:
<example_directory>is the directory containing the basic_example executable{model_name}is the name of the model as specified in the config fileframe_{frame_num}is the frame number directory (e.g., "frame_1", "frame_2", etc.)
Output filenames follow the pattern:
{output_tensor_name}.bin
Where:
output_tensor_nameis the name of the output tensor from the model, with any '/' characters replaced by '_'. For example, if a model has an output tensor namedoutput/Softmax, the output file would be namedoutput_Softmax.bin.
All output tensors are automatically converted to float32 format before saving, regardless of their original data type. This ensures a consistent output format that can be easily processed by other tools or applications.
The program will display the full path of each saved output file at the end of inference execution.
Verbose Mode
The --verbose or -v option enables detailed output about the model and its tensors. When this option is enabled, the program will call the dumpInfo() method of the runtime session after creating it, which displays:
- Model path
- Number of input tensors
- For each input tensor:
- Name
- Data type
- Shape
- Number of dimensions
- Total number of elements
- Number of output tensors
- For each output tensor:
- Name
- Data type
- Shape
- Number of dimensions
- Total number of elements
This information is particularly useful for:
- Debugging model loading issues
- Understanding the expected input and output formats
- Verifying tensor shapes and types
Runtime-Specific Handling
The example handles runtime-specific differences transparently:
ONNX Runtime:
- Uses ONNXRT class for model handling
- Uses ONNX-specific tensor details format
- Uses TIDLExecutionProvider for TIDL acceleration
TFLite Runtime:
- Uses TFLiteRT class for model handling
- Uses TFLite-specific tensor details format
- Uses TFLite delegates for TIDL acceleration
TIDL Runtime:
- Uses TIDLRT class for direct TIDL acceleration
- Provides a consistent interface with the other runtimes
TVM Runtime
- Uses TVMRT class for model handling.
- Uses ONNX models as input and for tensor details format.
- The model-artifacts from TVM compilation is expected to specify various compilation options, including TIDL offload, c7x offload etc. The tvmrt wrapper uses these model artifacts to perform inference accordingly.
These differences are handled internally, providing a consistent user experience regardless of the model format being used.
Memory Management
The example demonstrates proper memory management techniques:
- Aligned Memory Allocation: Uses
posix_memalignto ensure proper memory alignment for tensors - Shared Memory: Uses TIDL shared memory allocation when TIDL offload is enabled
- Proper Cleanup: Ensures all allocated memory is properly freed after use
Error Handling
The example includes robust error handling:
- Configuration Validation: Validates all configuration parameters before running
- File Existence Checks: Verifies that all model and input files exist
- Path Resolution: Automatically resolves relative paths to absolute paths
- Size Validation: Ensures input data size matches expected tensor sizes
- Exception Handling: Uses try-catch blocks to handle exceptions gracefully
- Detailed Error Messages: Provides specific error messages for different failure scenarios