Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 69 additions & 20 deletions model_api/python/model_api/adapters/inference_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
# SPDX-License-Identifier: Apache-2.0
#

from __future__ import annotations # TODO: remove when Python3.9 support is dropped

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Any
from typing import Any, Callable


@dataclass
Expand Down Expand Up @@ -69,7 +71,7 @@ def get_output_layers(self):
"""

@abstractmethod
def reshape_model(self, new_shape):
def reshape_model(self, new_shape: dict):
"""Reshapes the model inputs to fit the new input shape.

Args:
Expand All @@ -83,7 +85,7 @@ def reshape_model(self, new_shape):
"""

@abstractmethod
def infer_sync(self, dict_data) -> dict:
def infer_sync(self, dict_data: dict) -> dict:
"""Performs the synchronous model inference. The infer is a blocking method.

Args:
Expand All @@ -104,7 +106,7 @@ def infer_sync(self, dict_data) -> dict:
"""

@abstractmethod
def infer_async(self, dict_data, callback_data):
def infer_async(self, dict_data: dict, callback_data: Any):
"""
Performs the asynchronous model inference and sets
the callback for inference completion. Also, it should
Expand All @@ -122,11 +124,11 @@ def infer_async(self, dict_data, callback_data):
"""

@abstractmethod
def get_raw_result(self, infer_result) -> dict:
def get_raw_result(self, infer_result: dict) -> dict:
"""Gets raw results from the internal inference framework representation as a dict.

Args:
- infer_result: framework-specific result of inference from the model
- infer_result (dict): framework-specific result of inference from the model

Returns:
- raw result (dict) - model raw output in the following format:
Expand All @@ -138,7 +140,16 @@ def get_raw_result(self, infer_result) -> dict:
"""

@abstractmethod
def is_ready(self):
def set_callback(self, callback_fn: Callable):
"""
Sets callback that grabs results of async inference.

Args:
callback_fn (Callable): Callback function.
"""

@abstractmethod
def is_ready(self) -> bool:
"""In case of asynchronous execution checks if one can submit input data
to the model for inference, or all infer requests are busy.

Expand All @@ -160,29 +171,67 @@ def await_any(self):
"""

@abstractmethod
def get_rt_info(self, path):
"""Forwards to openvino.Model.get_rt_info(path)"""
def get_rt_info(self, path: list[str]) -> Any:
"""
Returns an attribute stored in model info.

Args:
path (list[str]): a sequence of tag names leading to the attribute.

Returns:
Any: a value stored under corresponding tag sequence.
"""

@abstractmethod
def update_model_info(self, model_info: dict[str, Any]):
"""Updates model with the provided model info."""
"""
Updates model with the provided model info. Model info dict can
also contain nested dicts.

Args:
model_info (dict[str, Any]): model info dict to write to the model.
"""

@abstractmethod
def save_model(self, path: str, weights_path: str, version: str):
"""Serializes model to the filesystem."""
def save_model(self, path: str, weights_path: str | None, version: str | None):
"""
Serializes model to the filesystem.

Args:
path (str): Path to write the resulting model.
weights_path (str | None): Optional path to save weights if they are stored separately.
version (str | None): Optional model version.
"""

@abstractmethod
def embed_preprocessing(
self,
layout,
layout: str,
resize_mode: str,
interpolation_mode,
interpolation_mode: str,
target_shape: tuple[int, ...],
pad_value,
pad_value: int,
dtype: type = int,
brg2rgb=False,
mean=None,
scale=None,
input_idx=0,
brg2rgb: bool = False,
mean: list[Any] | None = None,
scale: list[Any] | None = None,
input_idx: int = 0,
):
"""Embeds preprocessing into the model using OpenVINO preprocessing API"""
"""
Embeds preprocessing into the model if possible with the adapter being used.
In some cases, this method would just add extra python preprocessing steps
instaed actuall of embedding it into the model representation.

Args:
layout (str): Layout, for instance NCHW.
resize_mode (str): Resize type to use for preprocessing.
interpolation_mode (str): Resize interpolation mode.
target_shape (tuple[int, ...]): Target resize shape.
pad_value (int): Value to pad with if resize implies padding.
dtype (type, optional): Input data type for the preprocessing module. Defaults to int.
bgr2rgb (bool, optional): Defines if we need to swap R and B channels in case of image input.
Defaults to False.
mean (list[Any] | None, optional): Mean values to perform input normalization. Defaults to None.
scale (list[Any] | None, optional): Scale values to perform input normalization. Defaults to None.
input_idx (int, optional): Index of the model input to apply preprocessing to. Defaults to 0.
"""
47 changes: 34 additions & 13 deletions model_api/python/model_api/adapters/onnx_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import sys
from functools import partial, reduce
from typing import Any
from typing import Any, Callable

import numpy as np

Expand Down Expand Up @@ -111,7 +111,7 @@ def infer_sync(self, dict_data):
def infer_async(self, dict_data, callback_data):
raise NotImplementedError

def set_callback(self, callback_fn):
def set_callback(self, callback_fn: Callable):
self.callback_fn = callback_fn

def is_ready(self):
Expand All @@ -126,22 +126,25 @@ def await_all(self):
def await_any(self):
pass

def get_raw_result(self, infer_result):
def get_raw_result(self, infer_result: dict):
pass

def embed_preprocessing(
self,
layout,
layout: str,
resize_mode: str,
interpolation_mode,
target_shape,
pad_value,
interpolation_mode: str,
target_shape: tuple[int, ...],
pad_value: int,
dtype: type = int,
brg2rgb=False,
mean=None,
scale=None,
input_idx=0,
brg2rgb: bool = False,
mean: list[Any] | None = None,
scale: list[Any] | None = None,
input_idx: int = 0,
):
"""
Adds external preprocessing steps done before ONNX model execution.
"""
preproc_funcs = [np.squeeze]
if resize_mode != "crop":
if resize_mode == "fit_to_window_letterbox":
Expand Down Expand Up @@ -170,13 +173,23 @@ def embed_preprocessing(
)

def get_model(self):
"""Return the reference to the ONNXRuntime session."""
"""Return a reference to the ONNXRuntime session."""
return self.model

def reshape_model(self, new_shape):
""" "Not supported by ONNX adapter."""
raise NotImplementedError

def get_rt_info(self, path):
"""
Returns an attribute stored in model info.

Args:
path (list[str]): a sequence of tag names leading to the attribute.

Returns:
Any: a value stored under corresponding tag sequence.
"""
return get_rt_info_from_dict(self.onnx_metadata, path)

def update_model_info(self, model_info: dict[str, Any]):
Expand All @@ -189,7 +202,15 @@ def update_model_info(self, model_info: dict[str, Any]):
else:
meta.value = str(model_info[item])

def save_model(self, path: str, weights_path: str = "", version: str = "UNSPECIFIED"):
def save_model(self, path: str, weights_path: str | None = None, version: str | None = None):
"""
Serializes model to the filesystem.

Args:
path (str): paths to save .onnx file.
weights_path (str | None): not used by ONNX adapter.
version (str | None): not used by ONNX adapter.
"""
onnx.save(self.model, path)


Expand Down
31 changes: 28 additions & 3 deletions model_api/python/model_api/adapters/openvino_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import logging as log
from pathlib import Path
from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Callable

if TYPE_CHECKING:
from os import PathLike
Expand Down Expand Up @@ -300,7 +300,7 @@ def infer_sync(self, dict_data: dict[str, ndarray]) -> dict[str, ndarray]:
def infer_async(self, dict_data, callback_data) -> None:
self.async_queue.start_async(dict_data, callback_data)

def set_callback(self, callback_fn):
def set_callback(self, callback_fn: Callable):
self.async_queue.set_callback(callback_fn)

def is_ready(self) -> bool:
Expand Down Expand Up @@ -333,6 +333,15 @@ def operations_by_type(self, operation_type):
return layers_info

def get_rt_info(self, path: list[str]) -> OVAny:
"""
Gets an attribute value from OV.model_info structure.

Args:
path (list[str]): a suquence of tag names leading to the attribute.

Returns:
OVAny: attribute value wrapped into OVAny object.
"""
if self.is_onnx_file:
return get_rt_info_from_dict(self.onnx_metadata, path)
return self.model.get_rt_info(path)
Expand All @@ -350,6 +359,9 @@ def embed_preprocessing(
scale: list[Any] | None = None,
input_idx: int = 0,
) -> None:
"""
Embeds OpenVINO PrePostProcessor module into the model.
"""
ppp = PrePostProcessor(self.model)

# Change the input type to the 8-bit image
Expand Down Expand Up @@ -429,7 +441,20 @@ def update_model_info(self, model_info: dict[str, Any]):
for name in model_info:
self.model.set_rt_info(model_info[name], ["model_info", name])

def save_model(self, path: str, weights_path: str = "", version: str = "UNSPECIFIED"):
def save_model(self, path: str, weights_path: str | None = None, version: str | None = None):
"""
Saves OV model as two files: .xml (architecture) and .bin (weights).

Args:
path (str): path to save the model files (.xml and .bin).
weights_path (str, optional): Optional path to save .bin if it differs from .xml path. Defaults to None.
version (str, optional): Output IR model version (for instance, IR_V10). Defaults to None.
"""
if weights_path is None:
weights_path = ""
if version is None:
version = "UNSPECIFIED"

ov.serialize(self.get_model(), path, weights_path, version)


Expand Down
10 changes: 6 additions & 4 deletions model_api/python/model_api/adapters/ovms_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
# SPDX-License-Identifier: Apache-2.0
#

from __future__ import annotations # TODO: remove when Python3.9 support is dropped

import re
from typing import Any
from typing import Any, Callable

import numpy as np

Expand Down Expand Up @@ -79,7 +81,7 @@ def infer_async(self, dict_data, callback_data):
raw_result = {output_name: raw_result}
self.callback_fn(raw_result, (lambda x: x, callback_data))

def set_callback(self, callback_fn):
def set_callback(self, callback_fn: Callable):
self.callback_fn = callback_fn

def is_ready(self):
Expand All @@ -98,7 +100,7 @@ def await_all(self):
def await_any(self):
pass

def get_raw_result(self, infer_result):
def get_raw_result(self, infer_result: dict):
pass

def embed_preprocessing(
Expand Down Expand Up @@ -127,7 +129,7 @@ def update_model_info(self, model_info: dict[str, Any]):
msg = "OVMSAdapter does not support updating model info"
raise NotImplementedError(msg)

def save_model(self, path: str, weights_path: str = "", version: str = "UNSPECIFIED"):
def save_model(self, path: str, weights_path: str | None = None, version: str | None = None):
msg = "OVMSAdapter does not support saving a model"
raise NotImplementedError(msg)

Expand Down
10 changes: 10 additions & 0 deletions model_api/python/model_api/models/image_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,16 @@ def parameters(cls) -> dict[str, Any]:
return parameters

def get_label_name(self, label_id: int) -> str:
"""
Returns a label name by it's index.
If index is out of range, and auto-generated name is returned.

Args:
label_id (int): label index.

Returns:
str: label name.
"""
if self.labels is None:
return f"#{label_id}"
if label_id >= len(self.labels):
Expand Down
Loading
Loading