5from typing
import List, Optional, Tuple, Union
9import qbruntime.qbruntime
as _cQbRuntime
10from .accelerator
import Accelerator
12from .model_variant_handle
import *
13from .pinned_memory
import PinnedMemory
16_Shape = Tuple[int, ...]
18__all__ = [
"Model",
"load"]
26def _is_valid_shape(input_shape: _Shape, shape: _Shape) -> bool:
27 if (len(input_shape) < len(shape))
or (len(input_shape) > len(shape) + 1):
30 offset = 1
if len(input_shape) > len(shape)
else 0
31 for s1, s2
in zip(input_shape[offset:], shape):
34 if s1 % s2 != 0
or (s2 > 0
and s1 != s2):
41def _find_memory_format(
42 inputs: List[np.ndarray], shapes: List[_Shape]
43) -> Optional[Tuple[bool, bool]]:
44 if len(inputs) != len(shapes):
49 for arr, shape
in zip(inputs, shapes):
50 shape_hwc = (shape[0], shape[1], shape[2])
51 shape_chw = (shape[2], shape[0], shape[1])
52 is_hwc = is_hwc
and _is_valid_shape(arr.shape, shape_hwc)
53 is_chw = is_chw
and _is_valid_shape(arr.shape, shape_chw)
55 if not is_hwc
and not is_chw:
61def _find_matching_variant_idx_and_memory_format(
62 model, inputs: List[np.ndarray]
63) -> Tuple[int, Tuple[bool, bool]]:
67 for i
in range(model.get_num_model_variants()):
68 res = _find_memory_format(
69 inputs, model.get_model_variant_handle(i).get_model_input_shape()
76 if variant_idx
is None:
77 raise ValueError(
"Input shape is invalid.")
78 return variant_idx, (is_hwc, is_chw)
83 shapes: List[_Shape], is_hwc: bool, dtype: np.dtype
88 shape = (shape[0], shape[1], shape[2])
90 shape = (shape[2], shape[0], shape[1])
91 outputs.append(np.empty(shape, dtype=dtype))
96def _check_output_shapes(
97 outputs: List[np.ndarray], shapes: List[_Shape], is_hwc: bool, dtype: np.dtype
99 if len(outputs) != len(shapes):
100 raise ValueError(
"The number of outputs is different.")
102 for output, shape
in zip(outputs, shapes):
103 if output.dtype != dtype:
104 raise ValueError(
"Output dtype mismatch.")
107 shape = (shape[0], shape[1], shape[2])
109 shape = (shape[2], shape[0], shape[1])
110 if output.shape != shape:
111 raise ValueError(
"Output shape mismatch.")
116 @brief Represents an AI model loaded from an MXQ file.
118 This class loads an AI model from an MXQ file and provides functions to launch it
119 on the NPU and perform inference.
122 def __init__(self, path: str, model_config: Optional[ModelConfig] =
None):
124 @brief Creates a Model object from the specified MXQ model file and configuration.
126 Parses the MXQ file and constructs a Model object using the provided configuration,
127 initializing the model with the given settings.
129 @note The created Model object must be launched before performing inference.
130 See Model.launch for more details.
132 @param[in] path The path to the MXQ model file.
133 @param[in] model_config The configuration settings to initialize the Model.
135 if model_config
is None:
136 self.
_model = _cQbRuntime.Model(path)
138 self.
_model = _cQbRuntime.Model(path, model_config._model_config)
145 def launch(self, acc: Accelerator) ->
None:
147 @brief Launches the model on the specified Accelerator, which represents
150 @param[in] acc The accelerator on which to launch the model.
157 @brief Disposes of the model loaded onto the NPU.
159 Releases any resources associated with the model on the NPU.
166 @brief Checks if the NPU core specified by CoreId is the target of the model.
167 In other words, whether the model is configured to use the given NPU core.
169 @param[in] core_id The CoreId to check.
170 @return True if the model is configured to use the specified CoreId, false
177 @brief Retrieves the core mode of the model.
179 @return The CoreMode of the model.
185 @brief Returns the NPU cores the model is configured to use.
187 @return A list of CoreIds representing the target NPU cores.
189 return [CoreId.from_cpp(target)
for target
in self.
_model.target_cores]
194 return [CoreId.from_cpp(target)
for target
in self.
_model.target_cores]
198 inputs: Union[np.ndarray, List[np.ndarray]],
199 outputs: Optional[List[np.ndarray]] =
None,
201 params: Optional[List[BatchParam]] =
None,
202 ) -> Optional[List[np.ndarray]]:
204 @brief Performs inference.
206 Fowllowing types of inference supported.
207 1. infer(in:List[numpy]) -> List[numpy] (float / int)
208 2. infer(in:numpy) -> List[numpy] (float / int)
209 3. infer(in:List[numpy], out:List[numpy]) (float / int)
210 4. infer(in:List[numpy], out:List[]) (float / int)
211 5. infer(in:numpy, out:List[numpy]) (float / int)
212 6. infer(in:numpy, out:List[]) (float / int)
214 @param[in] inputs Input data as a single numpy.ndarray or a list
216 @param[out] outputs Optional pre-allocated list of numpy.ndarray's
217 to store inference results.
218 @param[in] cache_size The number of tokens accumulated in the KV cache so far.
219 @param[in] params A List of `BatchParam`, specifying each batch's information
220 for BatchLLM inference. If `params` is specified,
221 `cache_size` is ignored.
222 @return Inference results as a list of numpy.ndarray.
224 return self.
_infer(inputs, outputs, cache_size, params=params)
228 inputs: Union[np.ndarray, List[np.ndarray]],
229 outputs: Optional[List[np.ndarray]] =
None,
231 params: Optional[List[BatchParam]] =
None,
232 ) -> Optional[List[np.ndarray]]:
233 return self.
_infer(inputs, outputs, cache_size,
True, params)
237 inputs: Union[np.ndarray, List[np.ndarray]],
238 outputs: Optional[List[np.ndarray]] =
None,
240 params: Optional[List[BatchParam]] =
None,
241 ) -> Optional[List[np.ndarray]]:
242 return self.
_infer(inputs, outputs, cache_size,
False, params)
246 inputs: Union[np.ndarray, List[np.ndarray]],
247 outputs: Optional[List[np.ndarray]],
249 is_target_hwc: Optional[bool] =
None,
250 params: Optional[List[BatchParam]] =
None,
251 ) -> Optional[List[np.ndarray]]:
252 if not isinstance(inputs, list):
255 variant_idx, (is_hwc, is_chw) = _find_matching_variant_idx_and_memory_format(
258 if (is_target_hwc
is not None)
and (
259 (is_target_hwc != is_hwc)
and (is_target_hwc == is_chw)
261 raise ValueError(
"Input shape is invalid.")
262 elif is_target_hwc
is None:
263 is_target_hwc = is_hwc
264 inputs = [np.ascontiguousarray(i)
for i
in inputs]
266 infer_func = self.
_model.infer
if is_target_hwc
else self.
_model.infer_chw
270 return [np.asarray(o)
for o
in infer_func(inputs, cache_size)]
275 inputs, [param._batch_param
for param
in params]
280 _check_output_shapes(
286 for oi
in range(len(outputs)):
287 outputs[oi] = np.ascontiguousarray(outputs[oi])
289 outputs[:] = _build_outputs(
296 infer_func(inputs, outputs, cache_size)
298 infer_func(inputs, outputs, [param._batch_param
for param
in params])
307 ) -> List[np.ndarray]:
309 @brief int8_t-to-float inference
310 Performs inference with input and output elements of type `int8_t`
312 Using these inference APIs requires manual scaling (quantization)
313 of float values to `int8_t` for input.
315 @note These APIs are intended for advanced use rather than typical usage.
319 def infer_hwc_to_float(
326 ) -> List[np.ndarray]:
329 def infer_chw_to_float(
336 ) -> List[np.ndarray]:
346 is_target_hwc: Optional[bool] =
None,
347 ) -> List[np.ndarray]:
349 @brief int8_t-to-float inference
350 Performs inference with input and output elements of type `int8_t`
352 Using these inference APIs requires manual scaling (quantization)
353 of float values to `int8_t` for input.
355 @note These APIs are intended for advanced use rather than typical usage.
357 if not isinstance(inputs, list):
360 _, (is_hwc, is_chw) = _find_matching_variant_idx_and_memory_format(self, inputs)
361 if (is_target_hwc
is not None)
and (
362 (is_target_hwc != is_hwc)
and (is_target_hwc == is_chw)
364 raise ValueError(
"Input shape is invalid.")
365 elif is_target_hwc
is None:
366 is_target_hwc = is_hwc
367 inputs = [np.ascontiguousarray(i)
for i
in inputs]
372 outputs = self.
_model.infer_chw_to_float(inputs, cache_size)
374 return [np.asarray(o)
for o
in outputs]
378 inputs: List[Buffer],
379 outputs: List[Buffer],
380 shape: List[List[int]] = [],
384 @brief Buffer-to-Buffer inference
386 Performs inference using input and output elements in the NPU’s internal data type.
387 The inference operates on buffers allocated via the following APIs:
389 - `Model.acquire_input_buffer()`
390 - `Model.acquire_output_buffer()`
391 - `ModelVariantHandle.acquire_input_buffer()`
392 - `ModelVariantHandle.acquire_output_buffer()`
394 Additionally, `Model.reposition_inputs()`, `Model.reposition_outputs()`,
395 `ModelVariantHandle.reposition_inputs()`, `ModelVariantHandle.reposition_outputs()`
396 must be used properly.
398 @note These APIs are intended for advanced use rather than typical usage.
401 [i._buffer
for i
in inputs], [o._buffer
for o
in outputs], shape, cache_size
406 @brief Development-only API for measuring pure NPU inference speed.
408 Runs NPU inference without uploading inputs and without retrieving outputs.
414 inputs: List[PinnedMemory],
415 outputs: Optional[List[PinnedMemory]] =
None,
417 ) -> Optional[List[PinnedMemory]]:
419 @brief Performs inference directly on pinned memory buffers (zero-copy).
421 The NPU reads the inputs from and writes the outputs into the pinned
422 buffers in place, avoiding host-to-device copies of the I/O tensors. Write
423 the input data into each input buffer via indexing (e.g. `pm[...] = data`)
424 before calling, and read the results from the output buffers afterwards.
426 @note This is an experimental API and is only supported on Regulus hardware.
427 It is not supported for models that use CPU offload.
429 @param inputs A list of PinnedMemory buffers holding the input data. All
430 inputs must share the same dtype (`numpy.float32` or
432 @param outputs A list of pre-allocated PinnedMemory buffers (dtype
433 `numpy.float32`) that will receive the output data. If `None`
434 (the default), the output buffers are allocated internally and
435 returned by this method.
436 @param cache_size The size of the cache to use for inference.
437 @return If `outputs` is `None`, a list of newly allocated PinnedMemory
438 buffers (dtype `numpy.float32`) holding the output data; otherwise
439 `None` (the given `outputs` are filled in place).
443 [pm._pinned_memory
for pm
in inputs],
450 [pm._pinned_memory
for pm
in inputs],
451 [pm._pinned_memory
for pm
in outputs],
458 inputs: Union[np.ndarray, List[np.ndarray]],
461 @brief Asynchronous Inference
463 Performs inference asynchronously.
465 To use asynchronous inference, the model must be created using a `ModelConfig`
466 object with the async pipeline configured to be enabled. This is done by calling
467 @ref ModelConfig.set_async_pipeline_enabled
468 "ModelConfig.set_async_pipeline_enabled(True)" before passing the configuration to
475 mc = qbruntime.ModelConfig()
476 mc.set_async_pipeline_enabled(True)
478 model = qbruntime.Model(MXQ_PATH, mc)
479 acc = qbruntime.Accelerator()
483 future = model.infer_async(inputs)
488 @note Currently, only CNN-based models are supported, as asynchronous execution is
489 particularly effective for this type of workload.
492 - RNN/LSTM and LLM models are not supported yet.
493 - Models requiring CPU offloading are not supported yet.
494 - Currently, only single-batch inference is supported (i.e., N = 1).
495 - Currently, Buffer inference is not supported. The following types
496 are supported in the synchronous API for advanced use cases, but are not
497 yet available for asynchronous inference:
501 if not isinstance(inputs, list):
503 _, (is_hwc, _) = _find_matching_variant_idx_and_memory_format(self, inputs)
504 inputs = [np.ascontiguousarray(i)
for i
in inputs]
506 self.
_model.infer_async
if is_hwc
else self.
_model.infer_async_chw
508 return Future.from_cpp(infer_async_func(inputs), inputs)
512 inputs: Union[np.ndarray, List[np.ndarray]],
515 @brief This method supports int8_t-to-float asynchronous inference.
517 @param[in] inputs Input data as a single numpy.ndarray or a list
520 @return A future that can be used to retrieve the inference result.
522 if not isinstance(inputs, list):
524 _, (is_hwc, _) = _find_matching_variant_idx_and_memory_format(self, inputs)
525 inputs = [np.ascontiguousarray(i)
for i
in inputs]
527 self.
_model.infer_async_to_float
529 else self.
_model.infer_async_chw_to_float
531 return Future.from_cpp(infer_async_func(inputs), inputs)
535 inputs: List[np.ndarray],
536 input_bufs: List[Buffer],
537 seqlens: List[List[int]] = [],
539 """Reposition input"""
540 inputs = [np.ascontiguousarray(i)
for i
in inputs]
542 inputs, [buf._buffer
for buf
in input_bufs], seqlens
547 output_bufs: List[Buffer],
548 outputs: List[np.ndarray],
549 seqlens: List[List[int]] = [],
551 """Reposition output"""
555 outputs.append(np.empty(shape=shape, dtype=np.float32))
557 for oi
in range(len(outputs)):
558 outputs[oi] = np.ascontiguousarray(outputs[oi])
560 [buf._buffer
for buf
in output_bufs], outputs, seqlens
565 @brief Returns the total number of model variants available in this model.
567 The `variant_idx` parameter passed to `Model.get_model_variant_handle()` must be
568 in the range [0, return value of this function).
570 @return The total number of model variants.
576 @brief Retrieves a handle to the specified model variant.
578 Use the returned `ModelVariantHandle` to query details such as input and output
579 shapes for the selected variant.
581 @param[in] variant_idx Index of the model variant to retrieve.
582 Must be in the range [0, getNumModelVariants()).
584 @return A `ModelVariantHandle` object if successful;
585 otherwise, raise qbruntime.QbRuntimeError "Model_InvalidVariantIdx".
587 return ModelVariantHandle.from_cpp(
593 @brief Returns the input shape of the model.
595 @return A list of input shape of the model.
601 @brief Returns the output shape of the model.
603 @return A list of output shape of the model.
609 @brief Returns the input quantization scale(s) of the model.
611 @return A list of input scales.
617 @brief Returns the output quantization scale(s) of the model.
619 @return A list of output scales.
625 @brief Returns the input buffer information for the model.
627 @return A list of input buffer information.
633 @brief Returns the output buffer information of the model.
635 @return A list of output buffer information.
641 @brief Returns a data type for model inputs.
643 @return An input data type.
649 @brief Returns a data type for model outputs.
651 @return An output data type.
657 @brief Buffer Management API
659 Acquires list of `Buffer` for input.
660 These API is required when calling `Model.infer_buffer()`.
662 @note These APIs are intended for advanced use rather than typical usage.
668 @brief Buffer Management API
670 Acquires list of `Buffer` for output.
671 These API is required when calling `Model.infer_buffer()`.
673 @note These APIs are intended for advanced use rather than typical usage.
679 @brief Buffer Management API
681 Deallocate acquired Input/Output buffer
683 @note These APIs are intended for advanced use rather than typical usage.
689 @brief Returns the model's unique identifier.
691 This identifier distinguishes multiple models within a single user program.
692 It is assigned incrementally, starting from 0 (e.g., 0, 1, 2, 3, ...).
694 @return The model identifier.
700 @brief Returns the path to the MXQ model file associated with the Model.
702 @return The MXQ file path.
708 @brief Returns informations of KV-cache of the model.
710 @return A list of CacheInfo objects.
724 @brief Dumps the KV cache memory into buffers.
726 Writes the current KV cache data into provided buffers.
728 @param[in] cache_id Index of target cache.
730 @return A list of bytes containing the KV cache data.
733 return [np.asarray(buf, np.int8).tobytes()
for buf
in bufs]
737 @brief Loads the KV cache memory from buffers.
739 Restores the KV cache from the provided buffers.
741 @param[in] bufs A list of bytes containing the KV cache
744 [np.frombuffer(buf, dtype=np.int8)
for buf
in bufs], cache_id
749 @brief Dumps KV cache memory to files in the specified directory.
751 Writes the KV cache data to binary files within the given directory.
752 Each file is named using the format: `cache_<layer_hash>.bin`.
754 @param[in] cache_dir Path to the directory where KV cache files will be saved.
755 @param[in] cache_id Index of target cache.
761 @brief Loads the KV cache memory from files in the specified directory.
763 Reads KV cache data from files within the given directory and restores them.
764 Each file is named using the format: `cache_<layer_hash>.bin`.
766 @param[in] cache_dir Path to the directory where KV cache files are saved.
771 self, cache_size: int, tail_size: int, mask: List[bool]
774 @brief Filter the tail of the KV cache memory
776 Retains the desired caches in the tail of the KV cache memory, excludes the others,
777 and shifts the remaining caches forward.
779 @param[in] cache_size The number of tokens accumulated in the KV cache so far.
780 @param[in] tail_size The tail size of the KV cache to filter (<=32).
781 @param[in] mask A mask indicating tokens to retain or exclude at the tail of the KV
784 @return New cache size after tail filtering.
790 @brief Moves the tail of the KV cache memory to the end of the head.
792 Slice the tail of the KV cache memory up to the specified size
793 and moves it to the designated cache position.
795 @param[in] num_head The size of the KV cache head where the tail is appended.
796 @param[in] num_tail The size of the KV cache tail to be moved.
797 @param[in] cache_size The total number of tokens accumulated in the KV cache so
800 @return The updated cache size after moving the tail.
805def load(path: str, model_config: Optional[ModelConfig] =
None) -> Model:
807 @brief Single-step inference API. Creates model and uploads the model
808 into NPU immediately.
810 This operation performs the Accelerator declaration, Model declaration,
811 and launch in a single step.
814 model =
Model(path, model_config)
Represents an accelerator, i.e., an NPU, used for executing models.
Represents an AI model loaded from an MXQ file.
DataType get_model_input_data_type(self)
Returns a data type for model inputs.
None launch(self, Accelerator acc)
Launches the model on the specified Accelerator, which represents the actual NPU.
None reposition_outputs(self, List[Buffer] output_bufs, List[np.ndarray] outputs, List[List[int]] seqlens=[])
Reposition output.
List[Scale] get_input_scale(self)
Returns the input quantization scale(s) of the model.
CoreMode get_core_mode(self)
Retrieves the core mode of the model.
List[CoreId] get_target_cores(self)
Returns the NPU cores the model is configured to use.
List[_Shape] _input_shape
List[CoreId] target_cores(self)
List[_Shape] _output_shape
List[Buffer] acquire_input_buffer(self, List[List[int]] seqlens=[])
Buffer Management API.
Optional[List[PinnedMemory]] infer_pinned_memory(self, List[PinnedMemory] inputs, Optional[List[PinnedMemory]] outputs=None, int cache_size=0)
Performs inference directly on pinned memory buffers (zero-copy).
List[BufferInfo] get_output_buffer_info(self)
Returns the output buffer information of the model.
str get_model_path(self)
Returns the path to the MXQ model file associated with the Model.
Future infer_async(self, Union[np.ndarray, List[np.ndarray]] inputs)
Asynchronous Inference.
DataType get_model_output_data_type(self)
Returns a data type for model outputs.
List[Buffer] acquire_output_buffer(self, List[List[int]] seqlens=[])
Buffer Management API.
int filter_cache_tail(self, int cache_size, int tail_size, List[bool] mask)
Filter the tail of the KV cache memory.
List[np.ndarray] _infer_to_float(self, Union[np.ndarray, List[np.ndarray],] inputs, int cache_size, Optional[bool] is_target_hwc=None)
int8_t-to-float inference Performs inference with input and output elements of type int8_t
int get_num_model_variants(self)
Returns the total number of model variants available in this model.
None load_cache_memory_from(self, str cache_dir, int cache_id=0)
Loads the KV cache memory from files in the specified directory.
bool is_target(self, CoreId core_id)
Checks if the NPU core specified by CoreId is the target of the model.
None infer_speedrun(self)
Development-only API for measuring pure NPU inference speed.
int get_latency_consumed(self)
None dump_cache_memory_to(self, str cache_dir, int cache_id=0)
Dumps KV cache memory to files in the specified directory.
Future infer_async_to_float(self, Union[np.ndarray, List[np.ndarray]] inputs)
This method supports int8_t-to-float asynchronous inference.
ModelVariantHandle get_model_variant_handle(self, variant_idx)
Retrieves a handle to the specified model variant.
None load_cache_memory(self, List[bytes] bufs, int cache_id=0)
Loads the KV cache memory from buffers.
List[_Shape] get_model_output_shape(self)
Returns the output shape of the model.
List[CacheInfo] get_cache_infos(self)
Returns informations of KV-cache of the model.
int get_latency_finished(self)
None release_buffer(self, List[Buffer] buffer)
Buffer Management API.
List[bytes] dump_cache_memory(self, int cache_id=0)
Dumps the KV cache memory into buffers.
None dispose(self)
Disposes of the model loaded onto the NPU.
List[_Shape] get_model_input_shape(self)
Returns the input shape of the model.
List[Scale] get_output_scale(self)
Returns the output quantization scale(s) of the model.
None infer_buffer(self, List[Buffer] inputs, List[Buffer] outputs, List[List[int]] shape=[], int cache_size=0)
Buffer-to-Buffer inference.
List[np.ndarray] infer_to_float(self, Union[np.ndarray, List[np.ndarray],] inputs, int cache_size=0)
int8_t-to-float inference Performs inference with input and output elements of type int8_t
__init__(self, str path, Optional[ModelConfig] model_config=None)
Creates a Model object from the specified MXQ model file and configuration.
Optional[List[np.ndarray]] _infer(self, Union[np.ndarray, List[np.ndarray]] inputs, Optional[List[np.ndarray]] outputs, int cache_size, Optional[bool] is_target_hwc=None, Optional[List[BatchParam]] params=None)
Optional[List[np.ndarray]] infer(self, Union[np.ndarray, List[np.ndarray]] inputs, Optional[List[np.ndarray]] outputs=None, int cache_size=0, Optional[List[BatchParam]] params=None)
Performs inference.
None reposition_inputs(self, List[np.ndarray] inputs, List[Buffer] input_bufs, List[List[int]] seqlens=[])
Reposition input.
List[BufferInfo] get_input_buffer_info(self)
Returns the input buffer information for the model.
int get_identifier(self)
Returns the model's unique identifier.
int move_cache_tail(self, int num_head, int num_tail, int cache_size)
Moves the tail of the KV cache memory to the end of the head.
An NPU-accessible pinned (physically contiguous) memory buffer.
A simple byte-sized buffer.
Defines the core mode for NPU execution.
Model load(str path, Optional[ModelConfig] model_config=None)
Single-step inference API.