Multi-input Inference Guide
This section describes how to use DX-RT’s inference APIs with models that require multiple input tensors. It covers methods for executing multi-input inference in both synchronous and asynchronous modes, with or without user-managed output buffers. Support for batch processing formats is also explained to help optimize throughput and integration flexibility.
Identifying a Multi-Input Model
C++
dxrt::InferenceEngine ie(modelPath);
// Check if the model is multi-input
bool isMultiInput = ie.IsMultiInputModel();
// Get the number of input tensors
int inputCount = ie.GetInputTensorCount();
// Get the input tensor names
std::vector<std::string> inputNames = ie.GetInputTensorNames();
// Get the input tensor to task mapping
std::map<std::string, std::string> mapping = ie.GetInputTensorToTaskMapping();
Python
from dx_engine import InferenceEngine
ie = InferenceEngine(model_path)
# Check if the model is multi-input
is_multi_input = ie.is_multi_input_model()
# Get the number of input tensors
input_count = ie.get_input_tensor_count()
# Get the input tensor names
input_names = ie.get_input_tensor_names()
# Get the input tensor to task mapping
mapping = ie.get_input_tensor_to_task_mapping()
Multi-Input Inference
This section describes how to perform inference on multi-input models using either auto-allocated or user-provided output buffers for single-sample execution.
Without Output Buffers (Auto-Allocation)
In this method, the inference engine automatically allocates memory for outputs, allowing you to omit output buffer management. Supported input formats include dictionary-based, vector-based, and auto-split inputs.
Dictionary Format (Recommended)
This method involves providing input tensors mapped by their names. It is the most explicit and least error-prone method.
C++
// Using Dictionary format (auto-allocation)
std::map<std::string, void*> inputTensors;
inputTensors["input1"] = input1_data;
inputTensors["input2"] = input2_data;
// Synchronous inference without output buffers (auto-allocation)
auto outputs = ie.RunMultiInput(inputTensors);
Python
# Using Dictionary format (auto-allocation)
input_tensors = {
"input1": input1_array,
"input2": input2_array
}
# Synchronous inference without output buffers (auto-allocation)
outputs = ie.run_multi_input(input_tensors)
Vector Format
This method involves providing input tensors in a vector/list. The order must match the order returned by GetInputTensorNames().
C++
// Using Vector format (must match the order of GetInputTensorNames())
std::vector<void*> inputPtrs = {input1_data, input2_data};
// Synchronous inference without output buffers (auto-allocation)
auto outputs = ie.RunMultiInput(inputPtrs);
Python
# Using Vector format (must match the order of get_input_tensor_names())
input_list = [input1_array, input2_array]
# Synchronous inference without output buffers (auto-allocation)
outputs = ie.run(input_list)
Auto-Split Format
This method automatically splits a single concatenated buffer into multiple inputs. It is applied automatically when the total size of the provided buffer matches the model's total input size.
C++
// A single buffer with all inputs concatenated
std::vector<uint8_t> concatenatedInput(ie.GetInputSize());
// ... fill data ...
// Processed via auto-split (output buffers auto-allocated)
auto outputs = ie.Run(concatenatedInput.data());
Python
# A single array with all inputs concatenated
concatenated_input = np.zeros(ie.get_input_size(), dtype=np.uint8)
# ... fill data ...
# Processed via auto-split (output buffers auto-allocated)
outputs = ie.run(concatenated_input)
With User-Provided Output Buffers
In this method, the user supplies pre-allocated output buffers, offering greater control over memory usage and improved performance. Supported input formats include dictionary, vector, and auto-split.
Dictionary Format
C++
// Using Dictionary format
std::map<std::string, void*> inputTensors;
inputTensors["input1"] = input1_data;
inputTensors["input2"] = input2_data;
// Create output buffer
std::vector<uint8_t> outputBuffer(ie.GetOutputSize());
// Synchronous inference (with user-provided output buffer)
auto outputs = ie.RunMultiInput(inputTensors, userArg, outputBuffer.data());
Python
# Using Dictionary format
input_tensors = {
"input1": input1_array,
"input2": input2_array
}
# Create output buffers
output_buffers = [np.zeros(size, dtype=np.uint8) for size in ie.get_output_tensor_sizes()]
# Synchronous inference (with user-provided output buffers)
outputs = ie.run_multi_input(input_tensors, output_buffers=output_buffers)
Vector Format
C++
// Using Vector format (must match the order of GetInputTensorNames())
std::vector<void*> inputPtrs = {input1_data, input2_data};
// Create output buffer
std::vector<uint8_t> outputBuffer(ie.GetOutputSize());
// Synchronous inference (with user-provided output buffer)
auto outputs = ie.RunMultiInput(inputPtrs, userArg, outputBuffer.data());
Python
# Using Vector format (must match the order of get_input_tensor_names())
input_list = [input1_array, input2_array]
# Create output buffers
output_buffers = [np.zeros(size, dtype=np.uint8) for size in ie.get_output_tensor_sizes()]
# Synchronous inference (with user-provided output buffers)
outputs = ie.run(input_list, output_buffers=output_buffers)
Auto-Split Format
C++
// A single buffer with all inputs concatenated
std::vector<uint8_t> concatenatedInput(ie.GetInputSize());
// ... fill data ...
// Create output buffer
std::vector<uint8_t> outputBuffer(ie.GetOutputSize());
// Processed via auto-split (with user-provided output buffer)
auto outputs = ie.Run(concatenatedInput.data(), userArg, outputBuffer.data());
Python
# A single array with all inputs concatenated
concatenated_input = np.zeros(ie.get_input_size(), dtype=np.uint8)
# ... fill data ...
# Create output buffers
output_buffers = [np.zeros(size, dtype=np.uint8) for size in ie.get_output_tensor_sizes()]
# Processed via auto-split (with user-provided output buffers)
outputs = ie.run(concatenated_input, output_buffers=output_buffers)
Multi-Input Batch Inference
This section explains how to perform batch inference on multi-input models. The SDK supports two input formatting styles: explicit batch format, where each sample’s inputs are grouped clearly, and flattened batch format, where all inputs are provided as a flat list.
Explicit Batch Format
This method requires grouping input tensors per sample, allowing the inference engine to clearly distinguish each item in the batch.
C++
// Batch input buffers (concatenated format)
std::vector<void*> batchInputs = {sample1_ptr, sample2_ptr, sample3_ptr};
std::vector<void*> batchOutputs = {output1_ptr, output2_ptr, output3_ptr};
std::vector<void*> userArgs = {userArg1, userArg2, userArg3};
// Batch inference
auto results = ie.Run(batchInputs, batchOutputs, userArgs);
Python
# Format: List[List[np.ndarray]]
batch_inputs = [
[sample1_input1, sample1_input2], # First sample
[sample2_input1, sample2_input2], # Second sample
[sample3_input1, sample3_input2] # Third sample
]
batch_outputs = [
[sample1_output1, sample1_output2], # Output buffers for the first sample
[sample2_output1, sample2_output2], # Output buffers for the second sample
[sample3_output1, sample3_output2] # Output buffers for the third sample
]
# Batch inference
results = ie.run(batch_inputs, output_buffers=batch_outputs)
Flattened Batch Format
This method provides all input tensors as a single flattened list, with inputs from all batch samples arranged sequentially.
Python
# Flattened format: [sample1_input1, sample1_input2, sample2_input1, sample2_input2, ...]
flattened_inputs = [
sample1_input1, sample1_input2, # First sample
sample2_input1, sample2_input2, # Second sample
sample_input1, sample3_input2 # Third sample
]
# Automatically recognized as a batch (input count is a multiple of the model's input count)
results = ie.run(flattened_inputs, output_buffers=batch_outputs)
Multi-Input Asynchronous Inference
This section describes how to perform asynchronous inference on multi-input models using the DX-RT API. Two methods are supported: callback-based execution for event-driven workflows and simplified execution using job IDs and polling via wait().
Callback-Based Asynchronous Execution
This method registers a user-defined callback to handle inference results asynchronously, allowing the engine to automatically invoke the callback when each job completes.
C++
// Register callback function
ie.RegisterCallback([](dxrt::TensorPtrs& outputs, void* userArg) -> int {
// Process outputs
return 0;
});
// Dictionary format asynchronous inference
int jobId = ie.RunAsyncMultiInput(inputTensors, userArg);
// Vector format asynchronous inference
int jobId = ie.RunAsyncMultiInput(inputPtrs, userArg);
Python
# Define callback function
def callback_handler(outputs, user_arg):
# Process and validate outputs
return 0
# Register callback
ie.register_callback(callback_handler)
# Dictionary format asynchronous inference
job_id = ie.run_async_multi_input(input_tensors, user_arg=user_arg)
# Vector format asynchronous inference
job_id = ie.run_async(input_list, user_arg=user_arg)
Simplified Asynchronous Execution
This method performs asynchronous inference using job IDs and retrieves results manually via wait(), providing a simple and non-callback-based alternative.
C++
// Single buffer asynchronous inference
int jobId = ie.RunAsync(inputPtr, userArg);
// Wait for the result
auto outputs = ie.Wait(jobId);
Python
# Single buffer asynchronous inference
job_id = ie.run_async(input_buffer, user_arg=user_arg)
# Wait for the result
outputs = ie.wait(job_id)