wallaroo.inference_result

 1import datetime
 2import pprint
 3from typing import Any, Dict, List, Optional, Tuple, Union
 4
 5import gql  # type: ignore
 6import numpy
 7
 8from .inference_decode import decode_inference_result, to_nd_array_list
 9from .object import InferenceError
10
11
12class InferenceResult(object):
13    def __init__(self, gql_client: Optional[gql.Client], data: Dict[str, Any]) -> None:
14        """Initializes an InferenceResult.
15
16        :param gql.Client gql_client: GQL client that this can pass to created objects.
17        :param Dict[str, Any] data: Response parsed from JSON inference result body.
18        """
19        if "error" in data:
20            raise InferenceError(data)
21
22        self._model = (data["model_name"], data["model_version"])
23        self._input_data = data["original_data"]
24        # Assumes that timestamp comes back in integer milliseconds since epoch
25        self._timestamp = datetime.datetime.fromtimestamp(data["time"] / 1000)
26        # Assumes that elapsed time comes back in integer nanoseconds
27        self._time_elapsed = datetime.timedelta(microseconds=data["elapsed"] / 1000)
28
29        # TODO: we may want to match on key types and special case them, but
30        # this handles all types in a reasonable fashion (i.e. exactly the
31        # same)
32        self._data: List[numpy.ndarray] = to_nd_array_list(
33            decode_inference_result(data)
34        )
35        if "shadow_data" in data:
36            self._shadow_data: Union[Dict[str, numpy.ndarray], None] = {
37                shadow_model: sd for shadow_model, sd in data["shadow_data"].items()
38            }
39        else:
40            self._shadow_data = None
41        self.raw = data
42
43    def data(self) -> List[numpy.ndarray]:
44        """Returns the inference result data."""
45        return self._data
46
47    def model(self) -> Tuple[str, str]:
48        """Returns the model this inference was generated by."""
49        # Model is currently passed back as model class + model name, which will
50        # necessitate passing the client through the deployment to here in order
51        # to call `model_by_name`. Better is to pass the DB surrogate key, which
52        # we can construct the object off of.
53        #
54        # For now, just return the two names, and the caller can use a client to
55        # turn this back into a Model if they wish.
56        return self._model
57
58    def time_elapsed(self) -> datetime.timedelta:
59        """Returns the length of time required for inference."""
60        return self._time_elapsed
61
62    def timestamp(self) -> datetime.datetime:
63        """Returns the time at which this inference occurred."""
64        return self._timestamp
65
66    def input_data(self) -> Dict[str, Any]:
67        """Returns the input data for this inference result."""
68        return self._input_data
69
70    def __repr__(self) -> str:
71        return f"InferenceResult({pprint.pformat(self.raw)})"
72
73    def __str__(self) -> str:
74        return repr(self)
75
76    def shadow_data(self) -> Union[Dict[str, numpy.ndarray], None]:
77        return self._shadow_data
class InferenceResult:
13class InferenceResult(object):
14    def __init__(self, gql_client: Optional[gql.Client], data: Dict[str, Any]) -> None:
15        """Initializes an InferenceResult.
16
17        :param gql.Client gql_client: GQL client that this can pass to created objects.
18        :param Dict[str, Any] data: Response parsed from JSON inference result body.
19        """
20        if "error" in data:
21            raise InferenceError(data)
22
23        self._model = (data["model_name"], data["model_version"])
24        self._input_data = data["original_data"]
25        # Assumes that timestamp comes back in integer milliseconds since epoch
26        self._timestamp = datetime.datetime.fromtimestamp(data["time"] / 1000)
27        # Assumes that elapsed time comes back in integer nanoseconds
28        self._time_elapsed = datetime.timedelta(microseconds=data["elapsed"] / 1000)
29
30        # TODO: we may want to match on key types and special case them, but
31        # this handles all types in a reasonable fashion (i.e. exactly the
32        # same)
33        self._data: List[numpy.ndarray] = to_nd_array_list(
34            decode_inference_result(data)
35        )
36        if "shadow_data" in data:
37            self._shadow_data: Union[Dict[str, numpy.ndarray], None] = {
38                shadow_model: sd for shadow_model, sd in data["shadow_data"].items()
39            }
40        else:
41            self._shadow_data = None
42        self.raw = data
43
44    def data(self) -> List[numpy.ndarray]:
45        """Returns the inference result data."""
46        return self._data
47
48    def model(self) -> Tuple[str, str]:
49        """Returns the model this inference was generated by."""
50        # Model is currently passed back as model class + model name, which will
51        # necessitate passing the client through the deployment to here in order
52        # to call `model_by_name`. Better is to pass the DB surrogate key, which
53        # we can construct the object off of.
54        #
55        # For now, just return the two names, and the caller can use a client to
56        # turn this back into a Model if they wish.
57        return self._model
58
59    def time_elapsed(self) -> datetime.timedelta:
60        """Returns the length of time required for inference."""
61        return self._time_elapsed
62
63    def timestamp(self) -> datetime.datetime:
64        """Returns the time at which this inference occurred."""
65        return self._timestamp
66
67    def input_data(self) -> Dict[str, Any]:
68        """Returns the input data for this inference result."""
69        return self._input_data
70
71    def __repr__(self) -> str:
72        return f"InferenceResult({pprint.pformat(self.raw)})"
73
74    def __str__(self) -> str:
75        return repr(self)
76
77    def shadow_data(self) -> Union[Dict[str, numpy.ndarray], None]:
78        return self._shadow_data
InferenceResult(gql_client: Optional[gql.client.Client], data: Dict[str, Any])
14    def __init__(self, gql_client: Optional[gql.Client], data: Dict[str, Any]) -> None:
15        """Initializes an InferenceResult.
16
17        :param gql.Client gql_client: GQL client that this can pass to created objects.
18        :param Dict[str, Any] data: Response parsed from JSON inference result body.
19        """
20        if "error" in data:
21            raise InferenceError(data)
22
23        self._model = (data["model_name"], data["model_version"])
24        self._input_data = data["original_data"]
25        # Assumes that timestamp comes back in integer milliseconds since epoch
26        self._timestamp = datetime.datetime.fromtimestamp(data["time"] / 1000)
27        # Assumes that elapsed time comes back in integer nanoseconds
28        self._time_elapsed = datetime.timedelta(microseconds=data["elapsed"] / 1000)
29
30        # TODO: we may want to match on key types and special case them, but
31        # this handles all types in a reasonable fashion (i.e. exactly the
32        # same)
33        self._data: List[numpy.ndarray] = to_nd_array_list(
34            decode_inference_result(data)
35        )
36        if "shadow_data" in data:
37            self._shadow_data: Union[Dict[str, numpy.ndarray], None] = {
38                shadow_model: sd for shadow_model, sd in data["shadow_data"].items()
39            }
40        else:
41            self._shadow_data = None
42        self.raw = data

Initializes an InferenceResult.

Parameters
  • gql.Client gql_client: GQL client that this can pass to created objects.
  • Dict[str, Any] data: Response parsed from JSON inference result body.
def data(self) -> List[numpy.ndarray]:
44    def data(self) -> List[numpy.ndarray]:
45        """Returns the inference result data."""
46        return self._data

Returns the inference result data.

def model(self) -> Tuple[str, str]:
48    def model(self) -> Tuple[str, str]:
49        """Returns the model this inference was generated by."""
50        # Model is currently passed back as model class + model name, which will
51        # necessitate passing the client through the deployment to here in order
52        # to call `model_by_name`. Better is to pass the DB surrogate key, which
53        # we can construct the object off of.
54        #
55        # For now, just return the two names, and the caller can use a client to
56        # turn this back into a Model if they wish.
57        return self._model

Returns the model this inference was generated by.

def time_elapsed(self) -> datetime.timedelta:
59    def time_elapsed(self) -> datetime.timedelta:
60        """Returns the length of time required for inference."""
61        return self._time_elapsed

Returns the length of time required for inference.

def timestamp(self) -> datetime.datetime:
63    def timestamp(self) -> datetime.datetime:
64        """Returns the time at which this inference occurred."""
65        return self._timestamp

Returns the time at which this inference occurred.

def input_data(self) -> Dict[str, Any]:
67    def input_data(self) -> Dict[str, Any]:
68        """Returns the input data for this inference result."""
69        return self._input_data

Returns the input data for this inference result.

def shadow_data(self) -> Optional[Dict[str, numpy.ndarray]]:
77    def shadow_data(self) -> Union[Dict[str, numpy.ndarray], None]:
78        return self._shadow_data