From eda1398a25185eeb054af7488be7a52094b41337 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Thu, 22 Jul 2021 13:58:56 +0100 Subject: [PATCH 01/13] Working updated config --- tempo/__init__.py | 5 +- tempo/aio/deploy.py | 8 +-- tempo/aio/utils.py | 6 +- tempo/docker/utils.py | 4 +- tempo/insights/manager.py | 12 +++- tempo/kfserving/endpoint.py | 6 +- tempo/kfserving/k8s.py | 32 +++++----- tempo/mlserver.py | 4 +- tempo/seldon/__init__.py | 8 ++- tempo/seldon/deploy.py | 37 +++-------- tempo/seldon/docker.py | 6 +- tempo/seldon/endpoint.py | 4 +- tempo/seldon/k8s.py | 20 +++--- tempo/seldon/runtime.py | 6 -- tempo/seldon/specs.py | 22 ++++--- tempo/serve/base.py | 30 ++++----- tempo/serve/deploy.py | 30 +++++++-- tempo/serve/metadata.py | 118 +++++++++++++++++++++++++++--------- tempo/serve/model.py | 4 +- tempo/serve/pipeline.py | 6 +- tempo/serve/utils.py | 6 +- 21 files changed, 228 insertions(+), 146 deletions(-) delete mode 100644 tempo/seldon/runtime.py diff --git a/tempo/__init__.py b/tempo/__init__.py index 82ab7ae1..98ce44cf 100644 --- a/tempo/__init__.py +++ b/tempo/__init__.py @@ -1,4 +1,4 @@ -from .serve.deploy import deploy +from .serve.deploy import deploy_local, deploy_remote from .serve.loader import save, upload from .serve.metadata import ModelFramework from .serve.model import Model @@ -8,7 +8,8 @@ __all__ = [ "__version__", - "deploy", + "deploy_local", + "deploy_remote", "ModelFramework", "Model", "Pipeline", diff --git a/tempo/aio/deploy.py b/tempo/aio/deploy.py index 1e7c0b95..4d824065 100644 --- a/tempo/aio/deploy.py +++ b/tempo/aio/deploy.py @@ -3,7 +3,7 @@ from tempo.serve.base import Runtime from tempo.serve.deploy import RemoteModel -from tempo.serve.metadata import RuntimeOptions +from tempo.serve.metadata import BaseRuntimeOptionsType, DockerOptions class AsyncRemoteModel(RemoteModel): @@ -14,14 +14,14 @@ async def predict(self, *args, **kwargs): return await self.model.remote_with_spec(self.model_spec, *args, **kwargs) -def _get_runtime(cls_path, options: RuntimeOptions) -> Runtime: +def _get_runtime(cls_path, options: BaseRuntimeOptionsType) -> Runtime: cls: Any = locate(cls_path) return cls(options) -def deploy(model: Any, options: RuntimeOptions = None) -> RemoteModel: +def deploy(model: Any, options: BaseRuntimeOptionsType = None) -> RemoteModel: if options is None: - options = RuntimeOptions() + options = DockerOptions() rt: Runtime = _get_runtime(options.runtime, options) rm = RemoteModel(model, rt) rm.deploy() diff --git a/tempo/aio/utils.py b/tempo/aio/utils.py index 4bba76f1..74c1e54a 100644 --- a/tempo/aio/utils.py +++ b/tempo/aio/utils.py @@ -1,7 +1,7 @@ from inspect import isclass from ..kfserving.protocol import KFServingV2Protocol -from ..serve.metadata import ModelFramework, RuntimeOptions +from ..serve.metadata import BaseRuntimeOptionsType, DockerOptions, ModelFramework from ..serve.pipeline import PipelineModels from ..serve.protocol import Protocol from ..serve.types import ModelDataType @@ -19,7 +19,7 @@ def pipeline( inputs: ModelDataType = None, outputs: ModelDataType = None, conda_env: str = None, - runtime_options: RuntimeOptions = RuntimeOptions(), + runtime_options: BaseRuntimeOptionsType = DockerOptions(), description: str = "", ): """ @@ -101,7 +101,7 @@ def model( outputs: ModelDataType = None, conda_env: str = None, protocol: Protocol = KFServingV2Protocol(), - runtime_options: RuntimeOptions = RuntimeOptions(), + runtime_options: BaseRuntimeOptionsType = DockerOptions(), description: str = "", ): """ diff --git a/tempo/docker/utils.py b/tempo/docker/utils.py index f3af4232..f86b19ea 100644 --- a/tempo/docker/utils.py +++ b/tempo/docker/utils.py @@ -22,7 +22,9 @@ def create_network(docker_client: docker.client.DockerClient, network_name=Defau def deploy_insights_message_dumper( - name=DefaultInsightsServiceName, image=DefaultInsightsImage, port=DefaultInsightsPort + name=DefaultInsightsServiceName, + image=DefaultInsightsImage, + port=DefaultInsightsPort, ): docker_client = docker.from_env() try: diff --git a/tempo/insights/manager.py b/tempo/insights/manager.py index b6478ea4..75c093a0 100644 --- a/tempo/insights/manager.py +++ b/tempo/insights/manager.py @@ -33,7 +33,11 @@ def __init__( logger.debug("Initialising async insights worker") self._q = start_insights_worker_from_async(*args) - def log(self, data: Any, insights_type: InsightsTypes = DEFAULT_INSIGHTS_TYPE): + def log( + self, + data: Any, + insights_type: InsightsTypes = DEFAULT_INSIGHTS_TYPE, + ): payload = self._to_payload(data, insights_type=insights_type) asyncio.create_task(self._q.put(payload)) @@ -43,7 +47,11 @@ def log(self, data: Any, insights_type: InsightsTypes = DEFAULT_INSIGHTS_TYPE): logger.debug("Initialising sync insights worker") self._q = start_insights_worker_from_sync(*args) # type: ignore - def log(self, data: Any, insights_type: InsightsTypes = DEFAULT_INSIGHTS_TYPE): + def log( + self, + data: Any, + insights_type: InsightsTypes = DEFAULT_INSIGHTS_TYPE, + ): payload = self._to_payload(data, insights_type=insights_type) self._q.put(payload) diff --git a/tempo/kfserving/endpoint.py b/tempo/kfserving/endpoint.py index e0b2b435..11cf8d91 100644 --- a/tempo/kfserving/endpoint.py +++ b/tempo/kfserving/endpoint.py @@ -27,14 +27,14 @@ def __init__(self): except Exception: logger.warning("Failed to load kubeconfig. Only local mode is possible.") - def get_service_host(self, model_spec: ModelSpec): + def get_service_host(self, model_spec: ModelSpec) -> str: if self.inside_cluster is not None: config.load_incluster_config() api_instance = client.CustomObjectsApi() api_response = api_instance.get_namespaced_custom_object_status( "serving.kubeflow.org", "v1beta1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "inferenceservices", model_spec.model_details.name, ) @@ -59,7 +59,7 @@ def get_url(self, model_spec: ModelSpec): api_response = api_instance.get_namespaced_custom_object_status( "serving.kubeflow.org", "v1beta1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "inferenceservices", model_spec.model_details.name, ) diff --git a/tempo/kfserving/k8s.py b/tempo/kfserving/k8s.py index 7f71d972..fed2e171 100644 --- a/tempo/kfserving/k8s.py +++ b/tempo/kfserving/k8s.py @@ -14,7 +14,7 @@ from tempo.seldon.specs import DefaultModelsPath, DefaultServiceAccountName from tempo.serve.base import DeployedModel, ModelSpec, Runtime from tempo.serve.constants import ENV_TEMPO_RUNTIME_OPTIONS -from tempo.serve.metadata import ModelFramework, RuntimeOptions +from tempo.serve.metadata import KubernetesRuntimeOptions, ModelFramework from tempo.serve.stub import deserialize from tempo.utils import logger @@ -33,14 +33,10 @@ } -class KFServingOptions(RuntimeOptions): - runtime: str = "tempo.kfserving.KFServingKubernetesRuntime" - - class KFServingKubernetesRuntime(Runtime): - def __init__(self, runtime_options: Optional[RuntimeOptions] = None): + def __init__(self, runtime_options: Optional[KubernetesRuntimeOptions] = None): if runtime_options is None: - runtime_options = RuntimeOptions() + runtime_options = KubernetesRuntimeOptions() runtime_options.runtime = "tempo.kfserving.KFServingKubernetesRuntime" super().__init__(runtime_options) @@ -75,7 +71,7 @@ def undeploy_spec(self, model_spec: ModelSpec): api_instance.delete_namespaced_custom_object( "serving.kubeflow.org", "v1beta1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "inferenceservices", model_spec.model_details.name, body=client.V1DeleteOptions(propagation_policy="Foreground"), @@ -91,7 +87,7 @@ def deploy_spec(self, model_spec: ModelSpec): existing = api_instance.get_namespaced_custom_object( "serving.kubeflow.org", "v1beta1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "inferenceservices", model_spec.model_details.name, ) @@ -99,7 +95,7 @@ def deploy_spec(self, model_spec: ModelSpec): api_instance.replace_namespaced_custom_object( "serving.kubeflow.org", "v1beta1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "inferenceservices", model_spec.model_details.name, spec, @@ -109,7 +105,7 @@ def deploy_spec(self, model_spec: ModelSpec): api_instance.create_namespaced_custom_object( "serving.kubeflow.org", "v1beta1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "inferenceservices", spec, ) @@ -125,7 +121,7 @@ def wait_ready_spec(self, model_spec: ModelSpec, timeout_secs=None) -> bool: existing = api_instance.get_namespaced_custom_object( "serving.kubeflow.org", "v1beta1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "inferenceservices", model_spec.model_details.name, ) @@ -153,7 +149,7 @@ def wait_ready_spec(self, model_spec: ModelSpec, timeout_secs=None) -> bool: def _get_spec(self, model_spec: ModelSpec) -> dict: if model_spec.model_details.platform == ModelFramework.TempoPipeline: - serviceAccountName = model_spec.runtime_options.k8s_options.serviceAccountName + serviceAccountName = model_spec.runtime_options.serviceAccountName # type: ignore if serviceAccountName is None: serviceAccountName = DefaultServiceAccountName return { @@ -161,7 +157,7 @@ def _get_spec(self, model_spec: ModelSpec) -> dict: "kind": "InferenceService", "metadata": { "name": model_spec.model_details.name, - "namespace": model_spec.runtime_options.k8s_options.namespace, + "namespace": model_spec.runtime_options.namespace, # type: ignore "labels": { TempoK8sLabel: "true", }, @@ -219,7 +215,7 @@ def _get_spec(self, model_spec: ModelSpec) -> dict: "kind": "InferenceService", "metadata": { "name": model_spec.model_details.name, - "namespace": model_spec.runtime_options.k8s_options.namespace, + "namespace": model_spec.runtime_options.namespace, # type: ignore "labels": { TempoK8sLabel: "true", }, @@ -234,10 +230,10 @@ def _get_spec(self, model_spec: ModelSpec) -> dict: }, }, } - if model_spec.runtime_options.k8s_options.serviceAccountName is not None: + if model_spec.runtime_options.serviceAccountName is not None: # type: ignore spec["spec"]["predictor"][ "serviceAccountName" - ] = model_spec.runtime_options.k8s_options.serviceAccountName + ] = model_spec.runtime_options.serviceAccountName # type: ignore if isinstance(model_spec.protocol, KFServingV2Protocol): spec["spec"]["predictor"][model_implementation]["protocolVersion"] = "v2" return spec @@ -256,7 +252,7 @@ def list_models(self, namespace: Optional[str] = None) -> Sequence[DeployedModel api_instance = client.CustomObjectsApi() if namespace is None and self.runtime_options is not None: - namespace = self.runtime_options.k8s_options.namespace + namespace = self.runtime_options.namespace # type: ignore if namespace is None: return [] diff --git a/tempo/mlserver.py b/tempo/mlserver.py index 69dd4812..7f722e16 100644 --- a/tempo/mlserver.py +++ b/tempo/mlserver.py @@ -13,7 +13,7 @@ from .serve.base import BaseModel from .serve.constants import ENV_TEMPO_RUNTIME_OPTIONS from .serve.loader import load -from .serve.metadata import InsightRequestModes, InsightsTypes, ModelFramework, RuntimeOptions +from .serve.metadata import InsightRequestModes, InsightsTypes, ModelFramework, dict_to_runtime from .serve.utils import PredictMethodAttr from .state.state import BaseState @@ -77,7 +77,7 @@ async def _load_insights(self): async def _load_runtime(self): rt_options_str = os.getenv(ENV_TEMPO_RUNTIME_OPTIONS) if rt_options_str: - rt_options = RuntimeOptions(**json.loads(rt_options_str)) + rt_options = dict_to_runtime(json.loads(rt_options_str)) self._model.set_runtime_options_override(rt_options) async def predict(self, request: InferenceRequest) -> InferenceResponse: diff --git a/tempo/seldon/__init__.py b/tempo/seldon/__init__.py index 448ac7ae..e6aaf359 100644 --- a/tempo/seldon/__init__.py +++ b/tempo/seldon/__init__.py @@ -1,5 +1,11 @@ +from .deploy import SeldonDeployRuntime from .docker import SeldonDockerRuntime from .k8s import SeldonKubernetesRuntime from .protocol import SeldonProtocol -__all__ = ["SeldonDockerRuntime", "SeldonProtocol", "SeldonKubernetesRuntime"] +__all__ = [ + "SeldonDockerRuntime", + "SeldonProtocol", + "SeldonKubernetesRuntime", + "SeldonDeployRuntime", +] diff --git a/tempo/seldon/deploy.py b/tempo/seldon/deploy.py index 4457bb37..5485bd03 100644 --- a/tempo/seldon/deploy.py +++ b/tempo/seldon/deploy.py @@ -1,10 +1,8 @@ import os import time -from enum import Enum from http import cookies from typing import Dict, Sequence -from pydantic import BaseModel from seldon_deploy_sdk import ApiClient, Configuration, EnvironmentApi, SeldonDeploymentsApi from seldon_deploy_sdk.auth import OIDCAuthenticator, SessionAuthenticator from seldon_deploy_sdk.models.object_meta import ObjectMeta @@ -17,25 +15,10 @@ from tempo.seldon.k8s import SeldonKubernetesRuntime from tempo.seldon.specs import KubernetesSpec from tempo.serve.base import DeployedModel, ModelSpec, Runtime +from tempo.serve.metadata import EnterpriseRuntimeAuthType, EnterpriseRuntimeOptions -class SeldonDeployAuthType(Enum): - session_cookie = "session_cookie" - oidc = "oidc" - - -class SeldonDeployConfig(BaseModel): - - host: str - user: str - password: str - auth_type: SeldonDeployAuthType = SeldonDeployAuthType.session_cookie - oidc_client_id: str - oidc_server: str - verify_ssl: bool = True - - -# FIXME: Needs updating for runtime options to include SeldonDeployConfig +# FIXME: Needs updating for runtime options to include EnterpriseRuntimeOptions class SeldonDeployRuntime(Runtime): def list_models(self) -> Sequence[DeployedModel]: pass @@ -43,11 +26,11 @@ def list_models(self) -> Sequence[DeployedModel]: def __init__(self): self.api_client = None - def authenticate(self, settings: SeldonDeployConfig): + def authenticate(self, settings: EnterpriseRuntimeOptions): config = Configuration() config.host = settings.host config.verify_ssl = settings.verify_ssl - if settings.auth_type == SeldonDeployAuthType.session_cookie: + if settings.auth_type == EnterpriseRuntimeAuthType.session_cookie: auth = SessionAuthenticator(config) # TODO can we use just cookie_str in API client cookie_str = auth.authenticate(settings.user, settings.password) @@ -57,7 +40,7 @@ def authenticate(self, settings: SeldonDeployConfig): cookie_str = f"authservice_session={token}" api_client = ApiClient(config, cookie=cookie_str) self.api_client = api_client - elif settings.auth_type == SeldonDeployAuthType.oidc: + elif settings.auth_type == EnterpriseRuntimeAuthType.oidc: if not settings.verify_ssl: os.environ["CURL_CA_BUNDLE"] = "" config.oidc_client_id = settings.oidc_client_id @@ -89,7 +72,7 @@ def deploy_spec(self, model_spec: ModelSpec): api_version="machinelearning.seldon.io/v1", metadata=ObjectMeta( name=model_spec.model_details.name, - namespace=model_spec.runtime_options.k8s_options.namespace, + namespace=model_spec.runtime_options.namespace, # type: ignore ), spec=SeldonDeploymentSpec( predictors=[ @@ -100,14 +83,14 @@ def deploy_spec(self, model_spec: ModelSpec): name="model", ), name="default", - replicas=model_spec.runtime_options.k8s_options.replicas, + replicas=model_spec.runtime_options.replicas, # type: ignore ) ] ), ) dep_instance = SeldonDeploymentsApi(self.api_client) - dep_instance.create_seldon_deployment(model_spec.runtime_options.k8s_options.namespace, sd) + dep_instance.create_seldon_deployment(model_spec.runtime_options.namespace, sd) # type: ignore def wait_ready_spec(self, model_spec: ModelSpec, timeout_secs=None) -> bool: self._create_api_client() @@ -117,7 +100,7 @@ def wait_ready_spec(self, model_spec: ModelSpec, timeout_secs=None) -> bool: while not ready: sdep: SeldonDeployment = dep_instance.read_seldon_deployment( model_spec.model_details.name, - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore ) sdep_dict = sdep.to_dict() ready = sdep_dict["status"]["state"] == "Available" @@ -132,7 +115,7 @@ def undeploy_spec(self, model_spec: ModelSpec): dep_instance = SeldonDeploymentsApi(self.api_client) dep_instance.delete_seldon_deployment( model_spec.model_details.name, - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore _preload_content=False, ) diff --git a/tempo/seldon/docker.py b/tempo/seldon/docker.py index 3fcc9277..23c60470 100644 --- a/tempo/seldon/docker.py +++ b/tempo/seldon/docker.py @@ -10,16 +10,16 @@ from tempo.docker.utils import create_network from tempo.seldon.specs import DefaultHTTPPort, DefaultModelsPath, get_container_spec from tempo.serve.base import DeployedModel, ModelSpec, Runtime -from tempo.serve.metadata import RuntimeOptions +from tempo.serve.metadata import DockerOptions class SeldonDockerRuntime(Runtime): def list_models(self) -> Sequence[DeployedModel]: pass - def __init__(self, runtime_options: Optional[RuntimeOptions] = None): + def __init__(self, runtime_options: Optional[DockerOptions] = None): if runtime_options is None: - runtime_options = RuntimeOptions() + runtime_options = DockerOptions() runtime_options.runtime = "tempo.seldon.SeldonDockerRuntime" super().__init__(runtime_options) diff --git a/tempo/seldon/endpoint.py b/tempo/seldon/endpoint.py index 39522edf..d6136c98 100644 --- a/tempo/seldon/endpoint.py +++ b/tempo/seldon/endpoint.py @@ -35,7 +35,7 @@ def get_url(self, model_spec: ModelSpec): ingress_host_url = ingress.get_external_host_url(model_spec) return ( f"{ingress_host_url}" - + f"/seldon/{model_spec.runtime_options.k8s_options.namespace}/" + + f"/seldon/{model_spec.runtime_options.namespace}/" # type: ignore + f"{model_spec.model_details.name}" + model_spec.protocol.get_predict_path(model_spec.model_details) ) @@ -46,7 +46,7 @@ def get_url(self, model_spec: ModelSpec): api_response = api_instance.get_namespaced_custom_object_status( "machinelearning.seldon.io", "v1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "seldondeployments", model_spec.model_details.name, ) diff --git a/tempo/seldon/k8s.py b/tempo/seldon/k8s.py index 31f2c327..3913880d 100644 --- a/tempo/seldon/k8s.py +++ b/tempo/seldon/k8s.py @@ -9,20 +9,20 @@ from tempo.k8s.constants import TempoK8sLabel, TempoK8sModelSpecAnnotation from tempo.k8s.utils import create_k8s_client from tempo.seldon.endpoint import Endpoint -from tempo.seldon.runtime import SeldonCoreOptions from tempo.seldon.specs import KubernetesSpec from tempo.serve.base import DeployedModel, ModelSpec, Runtime +from tempo.serve.metadata import KubernetesRuntimeOptions from tempo.serve.stub import deserialize from tempo.utils import logger class SeldonKubernetesRuntime(Runtime): - def __init__(self, runtime_options: Optional[SeldonCoreOptions] = None): + def __init__(self, runtime_options: Optional[KubernetesRuntimeOptions] = None): if runtime_options is None: - runtime_options = SeldonCoreOptions() + runtime_options = KubernetesRuntimeOptions() runtime_options.runtime = "tempo.seldon.SeldonKubernetesRuntime" super().__init__(runtime_options) - self.seldon_core_options: SeldonCoreOptions = runtime_options + self.seldon_core_options: KubernetesRuntimeOptions = runtime_options def get_endpoint_spec(self, model_spec: ModelSpec) -> str: create_k8s_client() @@ -35,7 +35,7 @@ def undeploy_spec(self, model_spec: ModelSpec): api_instance.delete_namespaced_custom_object( "machinelearning.seldon.io", "v1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "seldondeployments", model_spec.model_details.name, body=client.V1DeleteOptions(propagation_policy="Foreground"), @@ -53,7 +53,7 @@ def deploy_spec(self, model_spec: ModelSpec): existing = api_instance.get_namespaced_custom_object( "machinelearning.seldon.io", "v1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "seldondeployments", model_spec.model_details.name, ) @@ -61,7 +61,7 @@ def deploy_spec(self, model_spec: ModelSpec): api_instance.replace_namespaced_custom_object( "machinelearning.seldon.io", "v1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "seldondeployments", model_spec.model_details.name, k8s_spec, @@ -71,7 +71,7 @@ def deploy_spec(self, model_spec: ModelSpec): api_instance.create_namespaced_custom_object( "machinelearning.seldon.io", "v1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "seldondeployments", k8s_spec, ) @@ -87,7 +87,7 @@ def wait_ready_spec(self, model_spec: ModelSpec, timeout_secs=None) -> bool: existing = api_instance.get_namespaced_custom_object( "machinelearning.seldon.io", "v1", - model_spec.runtime_options.k8s_options.namespace, + model_spec.runtime_options.namespace, # type: ignore "seldondeployments", model_spec.model_details.name, ) @@ -108,7 +108,7 @@ def list_models(self, namespace: Optional[str] = None) -> Sequence[DeployedModel api_instance = client.CustomObjectsApi() if namespace is None and self.runtime_options is not None: - namespace = self.runtime_options.k8s_options.namespace + namespace = self.runtime_options.namespace # type: ignore if namespace is None: return [] diff --git a/tempo/seldon/runtime.py b/tempo/seldon/runtime.py deleted file mode 100644 index d62b931c..00000000 --- a/tempo/seldon/runtime.py +++ /dev/null @@ -1,6 +0,0 @@ -from tempo.serve.metadata import RuntimeOptions - - -class SeldonCoreOptions(RuntimeOptions): - runtime: str = "tempo.seldon.SeldonKubernetesRuntime" - add_svc_orchestrator: bool = False diff --git a/tempo/seldon/specs.py b/tempo/seldon/specs.py index 37582ef1..df2a229c 100644 --- a/tempo/seldon/specs.py +++ b/tempo/seldon/specs.py @@ -2,11 +2,15 @@ from tempo.k8s.constants import TempoK8sDescriptionAnnotation, TempoK8sLabel, TempoK8sModelSpecAnnotation from tempo.kfserving.protocol import KFServingV1Protocol, KFServingV2Protocol +<<<<<<< HEAD from tempo.seldon.constants import MLSERVER_IMAGE, TRITON_IMAGE from tempo.seldon.runtime import SeldonCoreOptions +======= +from tempo.seldon.constants import MLSERVER_IMAGE +>>>>>>> 81ad7f4 (Working updated config) from tempo.serve.base import ModelSpec from tempo.serve.constants import ENV_TEMPO_RUNTIME_OPTIONS -from tempo.serve.metadata import ModelDetails, ModelFramework, RuntimeOptions +from tempo.serve.metadata import BaseRuntimeOptionsType, KubernetesRuntimeOptions, ModelDetails, ModelFramework DefaultHTTPPort = "9000" DefaultGRPCPort = "9500" @@ -76,7 +80,7 @@ class _V2ContainerFactory: } @classmethod - def get_container_spec(cls, model_details: ModelDetails, runtime_options: RuntimeOptions) -> dict: + def get_container_spec(cls, model_details: ModelDetails, runtime_options: BaseRuntimeOptionsType) -> dict: if ( model_details.platform == ModelFramework.PyTorch or model_details.platform == ModelFramework.TensorRT @@ -126,7 +130,7 @@ class KubernetesSpec: def __init__( self, model_details: ModelSpec, - runtime_options: SeldonCoreOptions, + runtime_options: KubernetesRuntimeOptions, ): self._details = model_details self._runtime_options = runtime_options @@ -141,7 +145,7 @@ def spec(self) -> dict: "kind": "SeldonDeployment", "metadata": { "name": self._details.model_details.name, - "namespace": self._details.runtime_options.k8s_options.namespace, + "namespace": self._details.runtime_options.namespace, # type: ignore "labels": { TempoK8sLabel: "true", }, @@ -162,8 +166,8 @@ def _get_predictor(self) -> dict: "type": "MODEL", } - if self._details.runtime_options.k8s_options.authSecretName: - graph["envSecretRefName"] = self._details.runtime_options.k8s_options.authSecretName + if self._details.runtime_options.authSecretName: # type: ignore + graph["envSecretRefName"] = self._details.runtime_options.authSecretName # type: ignore if self._details.model_details.platform in self.Implementations: model_implementation = self.Implementations[self._details.model_details.platform] @@ -173,7 +177,7 @@ def _get_predictor(self) -> dict: self._details.model_details.platform == ModelFramework.TempoPipeline or self._details.model_details.platform == ModelFramework.Custom ): - serviceAccountName = self._details.runtime_options.k8s_options.serviceAccountName + serviceAccountName = self._details.runtime_options.serviceAccountName # type: ignore if serviceAccountName is None: serviceAccountName = DefaultServiceAccountName graph["serviceAccountName"] = serviceAccountName @@ -181,10 +185,10 @@ def _get_predictor(self) -> dict: predictor = { "graph": graph, "name": "default", - "replicas": self._details.runtime_options.k8s_options.replicas, + "replicas": self._details.runtime_options.replicas, # type: ignore } - if not self._runtime_options.add_svc_orchestrator: + if not self._runtime_options.add_svc_orchestrator: # type: ignore predictor["annotations"] = { "seldon.io/no-engine": "true", } diff --git a/tempo/serve/base.py b/tempo/serve/base.py index a66aac29..f936d979 100644 --- a/tempo/serve/base.py +++ b/tempo/serve/base.py @@ -13,16 +13,23 @@ import requests from pydantic import validator -from ..conf import settings from ..errors import UndefinedCustomImplementation from ..insights.manager import InsightsManager from ..magic import PayloadContext, TempoContextWrapper, tempo_context from ..state.state import BaseState from ..utils import logger from .args import infer_args, process_datatypes -from .constants import ENV_K8S_SERVICE_HOST, DefaultCondaFile, DefaultEnvFilename, DefaultModelFilename +from .constants import DefaultCondaFile, DefaultEnvFilename, DefaultModelFilename from .loader import load_custom, save_custom, save_environment -from .metadata import InsightRequestModes, ModelDataArg, ModelDataArgs, ModelDetails, ModelFramework, RuntimeOptions +from .metadata import ( + BaseRuntimeOptionsType, + DockerOptions, + InsightRequestModes, + ModelDataArg, + ModelDataArgs, + ModelDetails, + ModelFramework, +) from .protocol import Protocol from .types import LoadMethodSignature, ModelDataType, PredictMethodSignature from .typing import fullname @@ -41,7 +48,7 @@ def __init__( outputs: ModelDataType = None, conda_env: str = None, protocol: Protocol = None, - runtime_options: RuntimeOptions = RuntimeOptions(), + runtime_options: BaseRuntimeOptionsType = DockerOptions(), model_spec: ModelSpec = None, description: str = "", ): @@ -78,7 +85,7 @@ def __init__( ) self.use_remote: bool = False - self.runtime_options_override: Optional[RuntimeOptions] = None + self.runtime_options_override: Optional[BaseRuntimeOptionsType] = None insights_params = runtime_options.insights_options.dict() self.insights_manager = InsightsManager(**insights_params) @@ -95,7 +102,7 @@ def __init__( def set_remote(self, val: bool): self.use_remote = val - def set_runtime_options_override(self, runtime_options: RuntimeOptions): + def set_runtime_options_override(self, runtime_options: BaseRuntimeOptionsType): self.runtime_options_override = runtime_options def _get_args( @@ -212,12 +219,7 @@ def _get_model_spec(self, runtime: Optional[Runtime]) -> ModelSpec: return self.model_spec def _create_remote(self, model_spec: ModelSpec) -> Runtime: - if settings.use_kubernetes or os.getenv(ENV_K8S_SERVICE_HOST): - cls_path = model_spec.runtime_options.k8s_options.runtime - else: - cls_path = model_spec.runtime_options.runtime - if cls_path is None: - cls_path = model_spec.runtime_options.docker_options.runtime + cls_path = model_spec.runtime_options.runtime logger.debug("Using remote class %s", cls_path) cls: Any = locate(cls_path) return cls(model_spec.runtime_options) @@ -312,7 +314,7 @@ class ModelSpec(pydantic.BaseModel): model_details: ModelDetails protocol: Protocol - runtime_options: RuntimeOptions + runtime_options: BaseRuntimeOptionsType @validator("protocol", pre=True) def ensure_type(cls, v): @@ -331,7 +333,7 @@ class Config: class Deployer(object): - def __init__(self, runtime_options: Optional[RuntimeOptions]): + def __init__(self, runtime_options: Optional[BaseRuntimeOptionsType]): self.runtime_options = runtime_options def deploy(self, model: Any): diff --git a/tempo/serve/deploy.py b/tempo/serve/deploy.py index 1fd679bc..e841f8c9 100644 --- a/tempo/serve/deploy.py +++ b/tempo/serve/deploy.py @@ -2,7 +2,7 @@ from typing import Any from .base import BaseModel, ModelSpec, Runtime -from .metadata import RuntimeOptions +from .metadata import BaseProductOptionsType, BaseRuntimeOptionsType, DockerOptions, KubernetesRuntimeOptions class RemoteModel: @@ -32,15 +32,37 @@ def undeploy(self): self.model.undeploy(self.runtime) -def _get_runtime(cls_path, options: RuntimeOptions) -> Runtime: +def _get_runtime(cls_path, options: BaseRuntimeOptionsType) -> Runtime: cls: Any = locate(cls_path) return cls(options) -def deploy(model: Any, options: RuntimeOptions = None) -> RemoteModel: +def deploy(model: Any, options: BaseRuntimeOptionsType = None) -> RemoteModel: if options is None: - options = RuntimeOptions() + options = DockerOptions() rt: Runtime = _get_runtime(options.runtime, options) rm = RemoteModel(model, rt) rm.deploy() return rm + + +def deploy_local(model: Any, options: BaseProductOptionsType = None) -> RemoteModel: + if options is None: + runtime_options = DockerOptions() + else: + runtime_options = options.local_options + rt: Runtime = _get_runtime(runtime_options.runtime, runtime_options) + rm = RemoteModel(model, rt) + rm.deploy() + return rm + + +def deploy_remote(model: Any, options: BaseProductOptionsType = None) -> RemoteModel: + if options is None: + runtime_options = KubernetesRuntimeOptions() + else: + runtime_options = options.remote_options # type: ignore + rt: Runtime = _get_runtime(runtime_options.runtime, runtime_options) + rm = RemoteModel(model, rt) + rm.deploy() + return rm diff --git a/tempo/serve/metadata.py b/tempo/serve/metadata.py index 8be34624..3fe79098 100644 --- a/tempo/serve/metadata.py +++ b/tempo/serve/metadata.py @@ -1,6 +1,7 @@ +import abc from enum import Enum from pydoc import locate -from typing import Any, List, Optional, Type, Union +from typing import Any, Dict, List, Optional, Type, Union from pydantic import BaseModel, validator @@ -14,6 +15,22 @@ class InsightsTypes(Enum): DEFAULT_INSIGHTS_TYPE = InsightsTypes.CUSTOM_INSIGHT +def dict_to_runtime(d: Dict) -> "BaseRuntimeOptionsType": + runtime = d.get("runtime") + # TODO update to load class by adding type to each + enterprise_runtimes = ["tempo.seldon.SeldonDeployRunime"] + docker_runtimes = ["tempo.seldon.SeldonDockerRuntime"] + k8s_runtimes = ["tempo.kfserving.KFservingKubernetesRuntime", "tempo.seldon.SeldonKubernetesRuntime"] + if runtime in k8s_runtimes: + return KubernetesRuntimeOptions(**d) + elif runtime in enterprise_runtimes: + return EnterpriseRuntimeOptions(**d) + elif runtime in docker_runtimes: + return DockerOptions(**d) + else: + raise Exception("Runtime not supported: " + str(runtime)) + + class ModelFramework(Enum): SKLearn = "sklearn" XGBoost = "xgboost" @@ -82,26 +99,6 @@ class ModelDetails(BaseModel): # use_enum_values = True -class KubernetesOptions(BaseModel): - runtime: str = "tempo.seldon.SeldonKubernetesRuntime" - replicas: int = 1 - namespace = "default" - minReplicas: Optional[int] = None - maxReplicas: Optional[int] = None - authSecretName: Optional[str] = None - serviceAccountName: Optional[str] = None - - -class DockerOptions(BaseModel): - runtime: str = "tempo.seldon.SeldonDockerRuntime" - - -class IngressOptions(BaseModel): - ingress: str = "tempo.ingress.istio.IstioIngress" - ssl: bool = False - verify_ssl: bool = True - - class InsightRequestModes(Enum): ALL = "ALL" REQUEST = "REQUEST" @@ -150,10 +147,77 @@ class Config: use_enum_values = True -class RuntimeOptions(BaseModel): - runtime: str = "tempo.seldon.SeldonDockerRuntime" - docker_options: DockerOptions = DockerOptions() - k8s_options: KubernetesOptions = KubernetesOptions() - ingress_options: IngressOptions = IngressOptions() - insights_options: InsightsOptions = InsightsOptions() +class IngressOptions(BaseModel): + ingress: str = "tempo.ingress.istio.IstioIngress" + ssl: bool = False + verify_ssl: bool = True + + +class _BaseRuntimeOptions(BaseModel): + runtime: str = "" state_options: StateOptions = StateOptions() + insights_options: InsightsOptions = InsightsOptions() + ingress_options: IngressOptions = IngressOptions() + + class Config: + use_enum_values = True + + +class EnterpriseRuntimeAuthType(Enum): + session_cookie = "session_cookie" + oidc = "oidc" + + +class EnterpriseRuntimeOptions(_BaseRuntimeOptions): + runtime: str = "tempo.seldon.SeldonDeployRunime" + host: str + user: str + password: str + auth_type: EnterpriseRuntimeAuthType = EnterpriseRuntimeAuthType.session_cookie + oidc_client_id: str + oidc_server: str + verify_ssl: bool = True + + +class KubernetesRuntimeOptions(_BaseRuntimeOptions): + runtime: str = "tempo.seldon.SeldonKubernetesRuntime" + # Kubernetes parameters + replicas: int = 1 + namespace = "default" + minReplicas: Optional[int] = None + maxReplicas: Optional[int] = None + authSecretName: Optional[str] = None + serviceAccountName: Optional[str] = None + # TODO move to separate seldonkubernetesruntime + add_svc_orchestrator: bool = True + + +class DockerOptions(_BaseRuntimeOptions): + runtime: str = "tempo.seldon.SeldonDockerRuntime" + + +class _BaseProductOptions(BaseModel, abc.ABC): + # ty: str = "" + local_options: DockerOptions = DockerOptions() + remote_options: Any = KubernetesRuntimeOptions() + + +class SeldonCoreOptions(_BaseProductOptions): + # ty: str = "tempo.serve.metadata.SeldonCoreOptions" + remote_options: KubernetesRuntimeOptions = KubernetesRuntimeOptions(runtime="tempo.seldon.SeldonKubernetesRuntime") + + +class KFServingOptions(_BaseProductOptions): + # ty: str = "tempo.serve.metadata.KFServingOptions" + remote_options: KubernetesRuntimeOptions = KubernetesRuntimeOptions( + runtime="tempo.kfserving.KFservingKubernetesRuntime" + ) + + +class SeldonEnterpriseOptions(_BaseProductOptions): + # ty: str = "tempo.serve.metadata.KFServingOptions" + remote_options: EnterpriseRuntimeOptions + + +BaseRuntimeOptionsType = Union[KubernetesRuntimeOptions, DockerOptions, EnterpriseRuntimeOptions] +BaseProductOptionsType = Union[SeldonCoreOptions, KFServingOptions, SeldonEnterpriseOptions] diff --git a/tempo/serve/model.py b/tempo/serve/model.py index 58b19101..4670b898 100644 --- a/tempo/serve/model.py +++ b/tempo/serve/model.py @@ -2,7 +2,7 @@ from tempo.kfserving.protocol import KFServingV2Protocol from tempo.serve.base import BaseModel -from tempo.serve.metadata import ModelFramework, RuntimeOptions +from tempo.serve.metadata import BaseRuntimeOptionsType, DockerOptions, ModelFramework from tempo.serve.protocol import Protocol from tempo.serve.types import ModelDataType @@ -19,7 +19,7 @@ def __init__( outputs: ModelDataType = None, model_func: Callable[..., Any] = None, conda_env: str = None, - runtime_options: RuntimeOptions = RuntimeOptions(), + runtime_options: BaseRuntimeOptionsType = DockerOptions(), description: str = "", ): """ diff --git a/tempo/serve/pipeline.py b/tempo/serve/pipeline.py index cc5f5444..7e858861 100644 --- a/tempo/serve/pipeline.py +++ b/tempo/serve/pipeline.py @@ -2,7 +2,7 @@ from typing import Any, Callable, Optional from tempo.serve.base import BaseModel, Runtime -from tempo.serve.metadata import ModelFramework, RuntimeOptions +from tempo.serve.metadata import BaseRuntimeOptionsType, DockerOptions, ModelFramework from tempo.serve.model import Model from tempo.serve.protocol import Protocol from tempo.serve.types import ModelDataType @@ -48,7 +48,7 @@ def __init__( inputs: ModelDataType = None, outputs: ModelDataType = None, conda_env: str = None, - runtime_options: RuntimeOptions = RuntimeOptions(), + runtime_options: BaseRuntimeOptionsType = DockerOptions(), description: str = "", ): super().__init__( @@ -84,7 +84,7 @@ def set_remote(self, val: bool): for model in self.models.values(): model.get_tempo().set_remote(val) - def set_runtime_options_override(self, runtime_options: RuntimeOptions): + def set_runtime_options_override(self, runtime_options: BaseRuntimeOptionsType): for model in self.models.values(): model.get_tempo().set_runtime_options_override(runtime_options) super().set_runtime_options_override(runtime_options) diff --git a/tempo/serve/utils.py b/tempo/serve/utils.py index ab89d88e..975b0b67 100644 --- a/tempo/serve/utils.py +++ b/tempo/serve/utils.py @@ -5,7 +5,7 @@ from ..kfserving.protocol import KFServingV2Protocol from .base import BaseModel -from .metadata import ModelFramework, RuntimeOptions +from .metadata import BaseRuntimeOptionsType, DockerOptions, ModelFramework from .model import Model from .pipeline import Pipeline, PipelineModels from .protocol import Protocol @@ -126,7 +126,7 @@ def pipeline( inputs: ModelDataType = None, outputs: ModelDataType = None, conda_env: str = None, - runtime_options: RuntimeOptions = RuntimeOptions(), + runtime_options: BaseRuntimeOptionsType = DockerOptions(), description: str = "", ): """ @@ -208,7 +208,7 @@ def model( outputs: ModelDataType = None, conda_env: str = None, protocol: Protocol = KFServingV2Protocol(), - runtime_options: RuntimeOptions = RuntimeOptions(), + runtime_options: BaseRuntimeOptionsType = DockerOptions(), description: str = "", ): """ From ec0fd2ae8cf3ebc68fe5310a61d525d3f1c6ef3f Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Thu, 22 Jul 2021 13:59:41 +0100 Subject: [PATCH 02/13] Added docs examples for insights --- docs/examples/logging-insights/README.ipynb | 729 ++++++++++++-------- 1 file changed, 455 insertions(+), 274 deletions(-) diff --git a/docs/examples/logging-insights/README.ipynb b/docs/examples/logging-insights/README.ipynb index 88224d9c..1e30b3a6 100644 --- a/docs/examples/logging-insights/README.ipynb +++ b/docs/examples/logging-insights/README.ipynb @@ -59,7 +59,26 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from tempo.serve.metadata import SeldonCoreOptions\n", + "from tempo.serve.constants import DefaultInsightsLocalEndpoint, DefaultInsightsK8sEndpoint\n", + "\n", + "seldon_options = SeldonCoreOptions(**{\n", + " \"local_options\": { \"insights_options\": { \"worker_endpoint\": DefaultInsightsLocalEndpoint } },\n", + " \"remote_options\": {\n", + " \"insights_options\": { \"worker_endpoint\": DefaultInsightsK8sEndpoint },\n", + " \"namespace\": \"seldon\",\n", + " \"authSecretName\": \"minio-secret\",\n", + " },\n", + "})" + ] + }, + { + "cell_type": "code", + "execution_count": 4, "metadata": { "code_folding": [ 0 @@ -69,18 +88,13 @@ "source": [ "import numpy as np\n", "from tempo.serve.utils import pipeline, predictmethod\n", - "from tempo.serve.metadata import InsightRequestModes, RuntimeOptions\n", - "from tempo.serve.constants import DefaultInsightsLocalEndpoint\n", - "\n", "from tempo.magic import t\n", "\n", - "local_options = RuntimeOptions(**{\"insights_options\": {\"worker_endpoint\": DefaultInsightsLocalEndpoint }})\n", - "\n", "@pipeline(\n", " name='insights-pipeline',\n", " uri=\"s3://tempo/insights-pipeline/resources\",\n", " local_folder=ARTIFACTS_FOLDER,\n", - " runtime_options=local_options,\n", + " runtime_options=seldon_options.local_options,\n", ")\n", "class Pipeline:\n", " \n", @@ -102,7 +116,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -118,7 +132,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -136,7 +150,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -163,14 +177,22 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 11, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Attempted to log request but called manager directly, see documentation [TODO]\n", + "Attempted to log response but called manager directly, see documentation [TODO]\n" + ] + }, { "name": "stdout", "output_type": "stream", "text": [ - "._pipeline at 0x7f8171ca34d0>\n" + "[63]\n" ] } ], @@ -196,7 +218,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -208,15 +230,15 @@ " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"0.0.0.0:8080\",\n", - " \"ce-id\": \"ee4c3bf7-760f-4fb5-a39a-9cc5eb3da044\",\n", + " \"ce-id\": \"3254a0e9-d436-4355-b279-dbf44eb1f7de\",\n", " \"ce-specversion\": \"0.3\",\n", " \"ce-source\": \"io.seldon.serving.deployment.NOTIMPLEMENTED.NOTIMPLEMENTED\",\n", " \"ce-type\": \"io.seldon.serving.inference.custominsight\",\n", - " \"requestid\": \"ee4c3bf7-760f-4fb5-a39a-9cc5eb3da044\",\n", - " \"modelid\": \"NOTIMPLEMENTED\",\n", - " \"inferenceservicename\": \"NOTIMPLEMENTED\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"NOTIMPLEMENTED\",\n", + " \"ce-requestid\": \"3254a0e9-d436-4355-b279-dbf44eb1f7de\",\n", + " \"ce-modelid\": \"NOTIMPLEMENTED\",\n", + " \"ce-inferenceservicename\": \"NOTIMPLEMENTED\",\n", + " \"ce-namespace\": \"NOTIMPLEMENTED\",\n", + " \"ce-endpoint\": \"NOTIMPLEMENTED\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.6.2\",\n", @@ -234,14 +256,14 @@ " \"subdomains\": [],\n", " \"xhr\": false,\n", " \"os\": {\n", - " \"hostname\": \"c8008dc7eb3b\"\n", + " \"hostname\": \"fa4f8912b8f8\"\n", " },\n", " \"connection\": {},\n", " \"json\": {\n", " \"log\": \"value\"\n", " }\n", "}\n", - "::ffff:172.18.0.1 - - [20/Jun/2021:11:53:44 +0000] \"POST / HTTP/1.1\" 200 979 \"-\" \"Python/3.7 aiohttp/3.6.2\"\n", + "::ffff:172.18.0.1 - - [22/Jul/2021:12:11:46 +0000] \"POST / HTTP/1.1\" 200 994 \"-\" \"Python/3.7 aiohttp/3.6.2\"\n", "\n" ] } @@ -261,7 +283,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -289,7 +311,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -301,15 +323,15 @@ " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"0.0.0.0:8080\",\n", - " \"ce-id\": \"ee4c3bf7-760f-4fb5-a39a-9cc5eb3da044\",\n", + " \"ce-id\": \"3254a0e9-d436-4355-b279-dbf44eb1f7de\",\n", " \"ce-specversion\": \"0.3\",\n", " \"ce-source\": \"io.seldon.serving.deployment.NOTIMPLEMENTED.NOTIMPLEMENTED\",\n", " \"ce-type\": \"io.seldon.serving.inference.custominsight\",\n", - " \"requestid\": \"ee4c3bf7-760f-4fb5-a39a-9cc5eb3da044\",\n", - " \"modelid\": \"NOTIMPLEMENTED\",\n", - " \"inferenceservicename\": \"NOTIMPLEMENTED\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"NOTIMPLEMENTED\",\n", + " \"ce-requestid\": \"3254a0e9-d436-4355-b279-dbf44eb1f7de\",\n", + " \"ce-modelid\": \"NOTIMPLEMENTED\",\n", + " \"ce-inferenceservicename\": \"NOTIMPLEMENTED\",\n", + " \"ce-namespace\": \"NOTIMPLEMENTED\",\n", + " \"ce-endpoint\": \"NOTIMPLEMENTED\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.6.2\",\n", @@ -327,14 +349,14 @@ " \"subdomains\": [],\n", " \"xhr\": false,\n", " \"os\": {\n", - " \"hostname\": \"c8008dc7eb3b\"\n", + " \"hostname\": \"fa4f8912b8f8\"\n", " },\n", " \"connection\": {},\n", " \"json\": {\n", " \"log\": \"value\"\n", " }\n", "}\n", - "::ffff:172.18.0.1 - - [20/Jun/2021:11:53:44 +0000] \"POST / HTTP/1.1\" 200 979 \"-\" \"Python/3.7 aiohttp/3.6.2\"\n", + "::ffff:172.18.0.1 - - [22/Jul/2021:12:11:46 +0000] \"POST / HTTP/1.1\" 200 994 \"-\" \"Python/3.7 aiohttp/3.6.2\"\n", "\n" ] } @@ -356,7 +378,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -374,7 +396,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -382,8 +404,8 @@ "output_type": "stream", "text": [ "Collecting packages...\n", - "Packing environment at '/home/alejandro/miniconda3/envs/tempo-9b187809-1946-4576-b8fe-38d4fabf3ecf' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/logging-insights/artifacts/environment.tar.gz'\n", - "[########################################] | 100% Completed | 19.6s\n" + "Packing environment at '/home/alejandro/miniconda3/envs/tempo-36a1d148-c285-415e-849c-e56e8e89a9cb' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/logging-insights/artifacts/environment.tar.gz'\n", + "[########################################] | 100% Completed | 13.8s\n" ] } ], @@ -394,30 +416,16 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 19, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "inside deploy: runtime='tempo.seldon.SeldonDockerRuntime' docker_options=DockerOptions(runtime='tempo.seldon.SeldonDockerRuntime') k8s_options=KubernetesOptions(runtime='tempo.seldon.SeldonKubernetesRuntime', replicas=1, minReplicas=None, maxReplicas=None, authSecretName=None, serviceAccountName=None, namespace='default') ingress_options=IngressOptions(ingress='tempo.ingress.istio.IstioIngress', ssl=False, verify_ssl=True) insights_options=InsightsOptions(worker_endpoint='http://insights-dumper:8080', batch_size=1, parallelism=1, retries=3, window_time=0, mode_type=, in_asyncio=False)\n", - "inside deploy: runtime='tempo.seldon.SeldonDockerRuntime' docker_options=DockerOptions(runtime='tempo.seldon.SeldonDockerRuntime') k8s_options=KubernetesOptions(runtime='tempo.seldon.SeldonKubernetesRuntime', replicas=1, minReplicas=None, maxReplicas=None, authSecretName=None, serviceAccountName=None, namespace='default') ingress_options=IngressOptions(ingress='tempo.ingress.istio.IstioIngress', ssl=False, verify_ssl=True) insights_options=InsightsOptions(worker_endpoint='http://insights-dumper:8080', batch_size=1, parallelism=1, retries=3, window_time=0, mode_type=, in_asyncio=False)\n" - ] - } - ], + "outputs": [], "source": [ "from tempo.serve.constants import DefaultInsightsDockerEndpoint\n", - "from tempo.serve.metadata import RuntimeOptions\n", - "from tempo import deploy\n", + "from tempo import deploy_local\n", "\n", - "docker_options = RuntimeOptions(**{\n", - " \"insights_options\": {\n", - " \"worker_endpoint\": DefaultInsightsDockerEndpoint \n", - " }\n", - "})\n", + "seldon_options.local_options.insights_options.worker_endpoint = DefaultInsightsDockerEndpoint\n", "\n", - "remote_model = deploy(pipeline, docker_options)" + "remote_model = deploy_local(pipeline, seldon_options)" ] }, { @@ -436,7 +444,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 20, "metadata": {}, "outputs": [ { @@ -445,7 +453,7 @@ "array([63])" ] }, - "execution_count": 13, + "execution_count": 20, "metadata": {}, "output_type": "execute_result" } @@ -466,7 +474,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 21, "metadata": {}, "outputs": [ { @@ -478,15 +486,15 @@ " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"0.0.0.0:8080\",\n", - " \"ce-id\": \"ee4c3bf7-760f-4fb5-a39a-9cc5eb3da044\",\n", + " \"ce-id\": \"3254a0e9-d436-4355-b279-dbf44eb1f7de\",\n", " \"ce-specversion\": \"0.3\",\n", " \"ce-source\": \"io.seldon.serving.deployment.NOTIMPLEMENTED.NOTIMPLEMENTED\",\n", " \"ce-type\": \"io.seldon.serving.inference.custominsight\",\n", - " \"requestid\": \"ee4c3bf7-760f-4fb5-a39a-9cc5eb3da044\",\n", - " \"modelid\": \"NOTIMPLEMENTED\",\n", - " \"inferenceservicename\": \"NOTIMPLEMENTED\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"NOTIMPLEMENTED\",\n", + " \"ce-requestid\": \"3254a0e9-d436-4355-b279-dbf44eb1f7de\",\n", + " \"ce-modelid\": \"NOTIMPLEMENTED\",\n", + " \"ce-inferenceservicename\": \"NOTIMPLEMENTED\",\n", + " \"ce-namespace\": \"NOTIMPLEMENTED\",\n", + " \"ce-endpoint\": \"NOTIMPLEMENTED\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.6.2\",\n", @@ -504,28 +512,28 @@ " \"subdomains\": [],\n", " \"xhr\": false,\n", " \"os\": {\n", - " \"hostname\": \"c8008dc7eb3b\"\n", + " \"hostname\": \"fa4f8912b8f8\"\n", " },\n", " \"connection\": {},\n", " \"json\": {\n", " \"log\": \"value\"\n", " }\n", "}\n", - "::ffff:172.18.0.1 - - [20/Jun/2021:11:53:44 +0000] \"POST / HTTP/1.1\" 200 979 \"-\" \"Python/3.7 aiohttp/3.6.2\"\n", + "::ffff:172.18.0.1 - - [22/Jul/2021:12:11:46 +0000] \"POST / HTTP/1.1\" 200 994 \"-\" \"Python/3.7 aiohttp/3.6.2\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper:8080\",\n", - " \"ce-id\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", + " \"ce-id\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", " \"ce-specversion\": \"0.3\",\n", " \"ce-source\": \"io.seldon.serving.deployment.NOTIMPLEMENTED.NOTIMPLEMENTED\",\n", " \"ce-type\": \"io.seldon.serving.inference.custominsight\",\n", - " \"requestid\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", - " \"modelid\": \"NOTIMPLEMENTED\",\n", - " \"inferenceservicename\": \"NOTIMPLEMENTED\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"NOTIMPLEMENTED\",\n", + " \"ce-requestid\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", + " \"ce-modelid\": \"NOTIMPLEMENTED\",\n", + " \"ce-inferenceservicename\": \"NOTIMPLEMENTED\",\n", + " \"ce-namespace\": \"NOTIMPLEMENTED\",\n", + " \"ce-endpoint\": \"NOTIMPLEMENTED\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", @@ -536,35 +544,35 @@ " \"body\": \"{\\\"log\\\": \\\"value\\\"}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper\",\n", - " \"ip\": \"::ffff:172.18.0.2\",\n", + " \"ip\": \"::ffff:172.18.0.3\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", " \"subdomains\": [],\n", " \"xhr\": false,\n", " \"os\": {\n", - " \"hostname\": \"c8008dc7eb3b\"\n", + " \"hostname\": \"fa4f8912b8f8\"\n", " },\n", " \"connection\": {},\n", " \"json\": {\n", " \"log\": \"value\"\n", " }\n", "}\n", - "::ffff:172.18.0.2 - - [20/Jun/2021:11:54:03 +0000] \"POST / HTTP/1.1\" 200 1001 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:172.18.0.3 - - [22/Jul/2021:12:15:17 +0000] \"POST / HTTP/1.1\" 200 1016 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper:8080\",\n", - " \"ce-id\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", + " \"ce-id\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", " \"ce-specversion\": \"0.3\",\n", " \"ce-source\": \"io.seldon.serving.deployment.NOTIMPLEMENTED.NOTIMPLEMENTED\",\n", " \"ce-type\": \"io.seldon.serving.inference.request\",\n", - " \"requestid\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", - " \"modelid\": \"NOTIMPLEMENTED\",\n", - " \"inferenceservicename\": \"NOTIMPLEMENTED\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"NOTIMPLEMENTED\",\n", + " \"ce-requestid\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", + " \"ce-modelid\": \"NOTIMPLEMENTED\",\n", + " \"ce-inferenceservicename\": \"NOTIMPLEMENTED\",\n", + " \"ce-namespace\": \"NOTIMPLEMENTED\",\n", + " \"ce-endpoint\": \"NOTIMPLEMENTED\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", @@ -572,21 +580,21 @@ " \"content-type\": \"application/json\"\n", " },\n", " \"method\": \"POST\",\n", - " \"body\": \"{\\\"id\\\": \\\"6960b14c-78e0-495e-bd55-de07c9fe75fb\\\", \\\"parameters\\\": null, \\\"inputs\\\": [{\\\"name\\\": \\\"data\\\", \\\"shape\\\": [1], \\\"datatype\\\": \\\"INT64\\\", \\\"parameters\\\": null, \\\"data\\\": [63]}, {\\\"name\\\": \\\"parameters\\\", \\\"shape\\\": [16], \\\"datatype\\\": \\\"BYTES\\\", \\\"parameters\\\": null, \\\"data\\\": [123, 39, 108, 111, 103, 39, 58, 32, 39, 118, 97, 108, 117, 101, 39, 125]}], \\\"outputs\\\": null}\",\n", + " \"body\": \"{\\\"id\\\": \\\"335f65fa-3629-4db6-b638-3ac0943c23d6\\\", \\\"parameters\\\": null, \\\"inputs\\\": [{\\\"name\\\": \\\"data\\\", \\\"shape\\\": [1], \\\"datatype\\\": \\\"INT64\\\", \\\"parameters\\\": null, \\\"data\\\": [63]}, {\\\"name\\\": \\\"parameters\\\", \\\"shape\\\": [16], \\\"datatype\\\": \\\"BYTES\\\", \\\"parameters\\\": null, \\\"data\\\": [123, 39, 108, 111, 103, 39, 58, 32, 39, 118, 97, 108, 117, 101, 39, 125]}], \\\"outputs\\\": null}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper\",\n", - " \"ip\": \"::ffff:172.18.0.2\",\n", + " \"ip\": \"::ffff:172.18.0.3\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", " \"subdomains\": [],\n", " \"xhr\": false,\n", " \"os\": {\n", - " \"hostname\": \"c8008dc7eb3b\"\n", + " \"hostname\": \"fa4f8912b8f8\"\n", " },\n", " \"connection\": {},\n", " \"json\": {\n", - " \"id\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", + " \"id\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", " \"parameters\": null,\n", " \"inputs\": [\n", " {\n", @@ -630,39 +638,39 @@ " \"outputs\": null\n", " }\n", "}\n", - "::ffff:172.18.0.2 - - [20/Jun/2021:11:54:03 +0000] \"POST / HTTP/1.1\" 200 2044 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:172.18.0.3 - - [22/Jul/2021:12:15:17 +0000] \"POST / HTTP/1.1\" 200 2059 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper:8080\",\n", - " \"ce-id\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", + " \"ce-id\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", " \"ce-specversion\": \"0.3\",\n", " \"ce-source\": \"io.seldon.serving.deployment.NOTIMPLEMENTED.NOTIMPLEMENTED\",\n", " \"ce-type\": \"io.seldon.serving.inference.response\",\n", - " \"requestid\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", - " \"modelid\": \"NOTIMPLEMENTED\",\n", - " \"inferenceservicename\": \"NOTIMPLEMENTED\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"NOTIMPLEMENTED\",\n", + " \"ce-requestid\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", + " \"ce-modelid\": \"NOTIMPLEMENTED\",\n", + " \"ce-inferenceservicename\": \"NOTIMPLEMENTED\",\n", + " \"ce-namespace\": \"NOTIMPLEMENTED\",\n", + " \"ce-endpoint\": \"NOTIMPLEMENTED\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", - " \"content-length\": \"118\",\n", + " \"content-length\": \"153\",\n", " \"content-type\": \"application/json\"\n", " },\n", " \"method\": \"POST\",\n", - " \"body\": \"{\\\"model_name\\\": \\\"insights-pipeline\\\", \\\"outputs\\\": [{\\\"name\\\": \\\"output0\\\", \\\"datatype\\\": \\\"INT64\\\", \\\"data\\\": [63], \\\"shape\\\": [1]}]}\",\n", + " \"body\": \"{\\\"model_name\\\": \\\"insights-pipeline\\\", \\\"outputs\\\": [{\\\"name\\\": \\\"output0\\\", \\\"datatype\\\": \\\"INT64\\\", \\\"data\\\": [63], \\\"shape\\\": [1]}], \\\"model_version\\\": \\\"NOTIMPLEMENTED\\\"}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper\",\n", - " \"ip\": \"::ffff:172.18.0.2\",\n", + " \"ip\": \"::ffff:172.18.0.3\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", " \"subdomains\": [],\n", " \"xhr\": false,\n", " \"os\": {\n", - " \"hostname\": \"c8008dc7eb3b\"\n", + " \"hostname\": \"fa4f8912b8f8\"\n", " },\n", " \"connection\": {},\n", " \"json\": {\n", @@ -678,10 +686,11 @@ " 1\n", " ]\n", " }\n", - " ]\n", + " ],\n", + " \"model_version\": \"NOTIMPLEMENTED\"\n", " }\n", "}\n", - "::ffff:172.18.0.2 - - [20/Jun/2021:11:54:03 +0000] \"POST / HTTP/1.1\" 200 1311 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:172.18.0.3 - - [22/Jul/2021:12:15:17 +0000] \"POST / HTTP/1.1\" 200 1404 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "\n" ] } @@ -699,7 +708,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -708,7 +717,7 @@ "array([63])" ] }, - "execution_count": 15, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -730,7 +739,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -742,15 +751,15 @@ " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"0.0.0.0:8080\",\n", - " \"ce-id\": \"ee4c3bf7-760f-4fb5-a39a-9cc5eb3da044\",\n", + " \"ce-id\": \"3254a0e9-d436-4355-b279-dbf44eb1f7de\",\n", " \"ce-specversion\": \"0.3\",\n", " \"ce-source\": \"io.seldon.serving.deployment.NOTIMPLEMENTED.NOTIMPLEMENTED\",\n", " \"ce-type\": \"io.seldon.serving.inference.custominsight\",\n", - " \"requestid\": \"ee4c3bf7-760f-4fb5-a39a-9cc5eb3da044\",\n", - " \"modelid\": \"NOTIMPLEMENTED\",\n", - " \"inferenceservicename\": \"NOTIMPLEMENTED\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"NOTIMPLEMENTED\",\n", + " \"ce-requestid\": \"3254a0e9-d436-4355-b279-dbf44eb1f7de\",\n", + " \"ce-modelid\": \"NOTIMPLEMENTED\",\n", + " \"ce-inferenceservicename\": \"NOTIMPLEMENTED\",\n", + " \"ce-namespace\": \"NOTIMPLEMENTED\",\n", + " \"ce-endpoint\": \"NOTIMPLEMENTED\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.6.2\",\n", @@ -768,28 +777,28 @@ " \"subdomains\": [],\n", " \"xhr\": false,\n", " \"os\": {\n", - " \"hostname\": \"c8008dc7eb3b\"\n", + " \"hostname\": \"fa4f8912b8f8\"\n", " },\n", " \"connection\": {},\n", " \"json\": {\n", " \"log\": \"value\"\n", " }\n", "}\n", - "::ffff:172.18.0.1 - - [20/Jun/2021:11:53:44 +0000] \"POST / HTTP/1.1\" 200 979 \"-\" \"Python/3.7 aiohttp/3.6.2\"\n", + "::ffff:172.18.0.1 - - [22/Jul/2021:12:11:46 +0000] \"POST / HTTP/1.1\" 200 994 \"-\" \"Python/3.7 aiohttp/3.6.2\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper:8080\",\n", - " \"ce-id\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", + " \"ce-id\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", " \"ce-specversion\": \"0.3\",\n", " \"ce-source\": \"io.seldon.serving.deployment.NOTIMPLEMENTED.NOTIMPLEMENTED\",\n", " \"ce-type\": \"io.seldon.serving.inference.custominsight\",\n", - " \"requestid\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", - " \"modelid\": \"NOTIMPLEMENTED\",\n", - " \"inferenceservicename\": \"NOTIMPLEMENTED\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"NOTIMPLEMENTED\",\n", + " \"ce-requestid\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", + " \"ce-modelid\": \"NOTIMPLEMENTED\",\n", + " \"ce-inferenceservicename\": \"NOTIMPLEMENTED\",\n", + " \"ce-namespace\": \"NOTIMPLEMENTED\",\n", + " \"ce-endpoint\": \"NOTIMPLEMENTED\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", @@ -800,35 +809,35 @@ " \"body\": \"{\\\"log\\\": \\\"value\\\"}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper\",\n", - " \"ip\": \"::ffff:172.18.0.2\",\n", + " \"ip\": \"::ffff:172.18.0.3\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", " \"subdomains\": [],\n", " \"xhr\": false,\n", " \"os\": {\n", - " \"hostname\": \"c8008dc7eb3b\"\n", + " \"hostname\": \"fa4f8912b8f8\"\n", " },\n", " \"connection\": {},\n", " \"json\": {\n", " \"log\": \"value\"\n", " }\n", "}\n", - "::ffff:172.18.0.2 - - [20/Jun/2021:11:54:03 +0000] \"POST / HTTP/1.1\" 200 1001 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:172.18.0.3 - - [22/Jul/2021:12:15:17 +0000] \"POST / HTTP/1.1\" 200 1016 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper:8080\",\n", - " \"ce-id\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", + " \"ce-id\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", " \"ce-specversion\": \"0.3\",\n", " \"ce-source\": \"io.seldon.serving.deployment.NOTIMPLEMENTED.NOTIMPLEMENTED\",\n", " \"ce-type\": \"io.seldon.serving.inference.request\",\n", - " \"requestid\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", - " \"modelid\": \"NOTIMPLEMENTED\",\n", - " \"inferenceservicename\": \"NOTIMPLEMENTED\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"NOTIMPLEMENTED\",\n", + " \"ce-requestid\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", + " \"ce-modelid\": \"NOTIMPLEMENTED\",\n", + " \"ce-inferenceservicename\": \"NOTIMPLEMENTED\",\n", + " \"ce-namespace\": \"NOTIMPLEMENTED\",\n", + " \"ce-endpoint\": \"NOTIMPLEMENTED\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", @@ -836,21 +845,21 @@ " \"content-type\": \"application/json\"\n", " },\n", " \"method\": \"POST\",\n", - " \"body\": \"{\\\"id\\\": \\\"6960b14c-78e0-495e-bd55-de07c9fe75fb\\\", \\\"parameters\\\": null, \\\"inputs\\\": [{\\\"name\\\": \\\"data\\\", \\\"shape\\\": [1], \\\"datatype\\\": \\\"INT64\\\", \\\"parameters\\\": null, \\\"data\\\": [63]}, {\\\"name\\\": \\\"parameters\\\", \\\"shape\\\": [16], \\\"datatype\\\": \\\"BYTES\\\", \\\"parameters\\\": null, \\\"data\\\": [123, 39, 108, 111, 103, 39, 58, 32, 39, 118, 97, 108, 117, 101, 39, 125]}], \\\"outputs\\\": null}\",\n", + " \"body\": \"{\\\"id\\\": \\\"335f65fa-3629-4db6-b638-3ac0943c23d6\\\", \\\"parameters\\\": null, \\\"inputs\\\": [{\\\"name\\\": \\\"data\\\", \\\"shape\\\": [1], \\\"datatype\\\": \\\"INT64\\\", \\\"parameters\\\": null, \\\"data\\\": [63]}, {\\\"name\\\": \\\"parameters\\\", \\\"shape\\\": [16], \\\"datatype\\\": \\\"BYTES\\\", \\\"parameters\\\": null, \\\"data\\\": [123, 39, 108, 111, 103, 39, 58, 32, 39, 118, 97, 108, 117, 101, 39, 125]}], \\\"outputs\\\": null}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper\",\n", - " \"ip\": \"::ffff:172.18.0.2\",\n", + " \"ip\": \"::ffff:172.18.0.3\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", " \"subdomains\": [],\n", " \"xhr\": false,\n", " \"os\": {\n", - " \"hostname\": \"c8008dc7eb3b\"\n", + " \"hostname\": \"fa4f8912b8f8\"\n", " },\n", " \"connection\": {},\n", " \"json\": {\n", - " \"id\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", + " \"id\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", " \"parameters\": null,\n", " \"inputs\": [\n", " {\n", @@ -894,39 +903,39 @@ " \"outputs\": null\n", " }\n", "}\n", - "::ffff:172.18.0.2 - - [20/Jun/2021:11:54:03 +0000] \"POST / HTTP/1.1\" 200 2044 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:172.18.0.3 - - [22/Jul/2021:12:15:17 +0000] \"POST / HTTP/1.1\" 200 2059 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper:8080\",\n", - " \"ce-id\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", + " \"ce-id\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", " \"ce-specversion\": \"0.3\",\n", " \"ce-source\": \"io.seldon.serving.deployment.NOTIMPLEMENTED.NOTIMPLEMENTED\",\n", " \"ce-type\": \"io.seldon.serving.inference.response\",\n", - " \"requestid\": \"6960b14c-78e0-495e-bd55-de07c9fe75fb\",\n", - " \"modelid\": \"NOTIMPLEMENTED\",\n", - " \"inferenceservicename\": \"NOTIMPLEMENTED\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"NOTIMPLEMENTED\",\n", + " \"ce-requestid\": \"335f65fa-3629-4db6-b638-3ac0943c23d6\",\n", + " \"ce-modelid\": \"NOTIMPLEMENTED\",\n", + " \"ce-inferenceservicename\": \"NOTIMPLEMENTED\",\n", + " \"ce-namespace\": \"NOTIMPLEMENTED\",\n", + " \"ce-endpoint\": \"NOTIMPLEMENTED\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", - " \"content-length\": \"118\",\n", + " \"content-length\": \"153\",\n", " \"content-type\": \"application/json\"\n", " },\n", " \"method\": \"POST\",\n", - " \"body\": \"{\\\"model_name\\\": \\\"insights-pipeline\\\", \\\"outputs\\\": [{\\\"name\\\": \\\"output0\\\", \\\"datatype\\\": \\\"INT64\\\", \\\"data\\\": [63], \\\"shape\\\": [1]}]}\",\n", + " \"body\": \"{\\\"model_name\\\": \\\"insights-pipeline\\\", \\\"outputs\\\": [{\\\"name\\\": \\\"output0\\\", \\\"datatype\\\": \\\"INT64\\\", \\\"data\\\": [63], \\\"shape\\\": [1]}], \\\"model_version\\\": \\\"NOTIMPLEMENTED\\\"}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper\",\n", - " \"ip\": \"::ffff:172.18.0.2\",\n", + " \"ip\": \"::ffff:172.18.0.3\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", " \"subdomains\": [],\n", " \"xhr\": false,\n", " \"os\": {\n", - " \"hostname\": \"c8008dc7eb3b\"\n", + " \"hostname\": \"fa4f8912b8f8\"\n", " },\n", " \"connection\": {},\n", " \"json\": {\n", @@ -942,10 +951,11 @@ " 1\n", " ]\n", " }\n", - " ]\n", + " ],\n", + " \"model_version\": \"NOTIMPLEMENTED\"\n", " }\n", "}\n", - "::ffff:172.18.0.2 - - [20/Jun/2021:11:54:03 +0000] \"POST / HTTP/1.1\" 200 1311 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:172.18.0.3 - - [22/Jul/2021:12:15:17 +0000] \"POST / HTTP/1.1\" 200 1404 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "\n" ] } @@ -963,7 +973,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -972,7 +982,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ @@ -1000,7 +1010,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -1017,17 +1027,17 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "secret/minio-secret configured\n", - "serviceaccount/tempo-pipeline unchanged\n", - "role.rbac.authorization.k8s.io/tempo-pipeline unchanged\n", - "rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged\n" + "secret/minio-secret created\r\n", + "serviceaccount/tempo-pipeline created\r\n", + "role.rbac.authorization.k8s.io/tempo-pipeline created\r\n", + "rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding created\r\n" ] } ], @@ -1048,7 +1058,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -1061,27 +1071,6 @@ "execution_count": 11, "metadata": {}, "outputs": [], - "source": [ - "from tempo.serve.metadata import RuntimeOptions, KubernetesOptions, InsightsOptions\n", - "from tempo.serve.constants import DefaultInsightsK8sEndpoint\n", - "from tempo.seldon.k8s import SeldonCoreOptions\n", - "\n", - "kubernetes_options = SeldonCoreOptions(\n", - " k8s_options=KubernetesOptions(\n", - " namespace=\"seldon\",\n", - " authSecretName=\"minio-secret\"\n", - " ),\n", - " insights_options=InsightsOptions(\n", - " worker_endpoint=DefaultInsightsK8sEndpoint\n", - " )\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [], "source": [ "from tempo.k8s.utils import deploy_insights_message_dumper\n", "\n", @@ -1090,7 +1079,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -1109,13 +1098,13 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", + "from tempo import deploy_remote\n", "\n", - "remote_model = deploy(pipeline, kubernetes_options)" + "remote_model = deploy_remote(pipeline, seldon_options)" ] }, { @@ -1127,16 +1116,16 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "array([[63.1 , 62.3 , 0.1234]])" + "array([63])" ] }, - "execution_count": 45, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -1147,10 +1136,229 @@ "remote_model.predict(data=data, parameters=params)" ] }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-----------------\n", + "{\n", + " \"path\": \"/\",\n", + " \"headers\": {\n", + " \"host\": \"insights-dumper.seldon-system:8080\",\n", + " \"ce-id\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", + " \"ce-specversion\": \"0.3\",\n", + " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.seldon\",\n", + " \"ce-type\": \"io.seldon.serving.inference.custominsight\",\n", + " \"ce-requestid\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", + " \"ce-modelid\": \"insights-pipeline\",\n", + " \"ce-inferenceservicename\": \"insights-pipeline\",\n", + " \"ce-namespace\": \"seldon\",\n", + " \"ce-endpoint\": \"default\",\n", + " \"accept\": \"*/*\",\n", + " \"accept-encoding\": \"gzip, deflate\",\n", + " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", + " \"content-length\": \"16\",\n", + " \"content-type\": \"application/json\"\n", + " },\n", + " \"method\": \"POST\",\n", + " \"body\": \"{\\\"log\\\": \\\"value\\\"}\",\n", + " \"fresh\": false,\n", + " \"hostname\": \"insights-dumper.seldon-system\",\n", + " \"ip\": \"::ffff:10.1.15.244\",\n", + " \"ips\": [],\n", + " \"protocol\": \"http\",\n", + " \"query\": {},\n", + " \"subdomains\": [],\n", + " \"xhr\": false,\n", + " \"os\": {\n", + " \"hostname\": \"insights-dumper\"\n", + " },\n", + " \"connection\": {},\n", + " \"json\": {\n", + " \"log\": \"value\"\n", + " }\n", + "}\n", + "::ffff:10.1.15.244 - - [22/Jul/2021:12:37:09 +0000] \"POST / HTTP/1.1\" 200 1034 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "-----------------\n", + "{\n", + " \"path\": \"/\",\n", + " \"headers\": {\n", + " \"host\": \"insights-dumper.seldon-system:8080\",\n", + " \"ce-id\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", + " \"ce-specversion\": \"0.3\",\n", + " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.seldon\",\n", + " \"ce-type\": \"io.seldon.serving.inference.request\",\n", + " \"ce-requestid\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", + " \"ce-modelid\": \"insights-pipeline\",\n", + " \"ce-inferenceservicename\": \"insights-pipeline\",\n", + " \"ce-namespace\": \"seldon\",\n", + " \"ce-endpoint\": \"default\",\n", + " \"accept\": \"*/*\",\n", + " \"accept-encoding\": \"gzip, deflate\",\n", + " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", + " \"content-length\": \"345\",\n", + " \"content-type\": \"application/json\"\n", + " },\n", + " \"method\": \"POST\",\n", + " \"body\": \"{\\\"id\\\": \\\"2180add5-ccdd-48a8-84fc-ce90d689e00e\\\", \\\"parameters\\\": null, \\\"inputs\\\": [{\\\"name\\\": \\\"data\\\", \\\"shape\\\": [1], \\\"datatype\\\": \\\"INT64\\\", \\\"parameters\\\": null, \\\"data\\\": [63]}, {\\\"name\\\": \\\"parameters\\\", \\\"shape\\\": [16], \\\"datatype\\\": \\\"BYTES\\\", \\\"parameters\\\": null, \\\"data\\\": [123, 39, 108, 111, 103, 39, 58, 32, 39, 118, 97, 108, 117, 101, 39, 125]}], \\\"outputs\\\": null}\",\n", + " \"fresh\": false,\n", + " \"hostname\": \"insights-dumper.seldon-system\",\n", + " \"ip\": \"::ffff:10.1.15.244\",\n", + " \"ips\": [],\n", + " \"protocol\": \"http\",\n", + " \"query\": {},\n", + " \"subdomains\": [],\n", + " \"xhr\": false,\n", + " \"os\": {\n", + " \"hostname\": \"insights-dumper\"\n", + " },\n", + " \"connection\": {},\n", + " \"json\": {\n", + " \"id\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", + " \"parameters\": null,\n", + " \"inputs\": [\n", + " {\n", + " \"name\": \"data\",\n", + " \"shape\": [\n", + " 1\n", + " ],\n", + " \"datatype\": \"INT64\",\n", + " \"parameters\": null,\n", + " \"data\": [\n", + " 63\n", + " ]\n", + " },\n", + " {\n", + " \"name\": \"parameters\",\n", + " \"shape\": [\n", + " 16\n", + " ],\n", + " \"datatype\": \"BYTES\",\n", + " \"parameters\": null,\n", + " \"data\": [\n", + " 123,\n", + " 39,\n", + " 108,\n", + " 111,\n", + " 103,\n", + " 39,\n", + " 58,\n", + " 32,\n", + " 39,\n", + " 118,\n", + " 97,\n", + " 108,\n", + " 117,\n", + " 101,\n", + " 39,\n", + " 125\n", + " ]\n", + " }\n", + " ],\n", + " \"outputs\": null\n", + " }\n", + "}\n", + "::ffff:10.1.15.244 - - [22/Jul/2021:12:37:09 +0000] \"POST / HTTP/1.1\" 200 2077 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "-----------------\n", + "{\n", + " \"path\": \"/\",\n", + " \"headers\": {\n", + " \"host\": \"insights-dumper.seldon-system:8080\",\n", + " \"ce-id\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", + " \"ce-specversion\": \"0.3\",\n", + " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.seldon\",\n", + " \"ce-type\": \"io.seldon.serving.inference.response\",\n", + " \"ce-requestid\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", + " \"ce-modelid\": \"insights-pipeline\",\n", + " \"ce-inferenceservicename\": \"insights-pipeline\",\n", + " \"ce-namespace\": \"seldon\",\n", + " \"ce-endpoint\": \"default\",\n", + " \"accept\": \"*/*\",\n", + " \"accept-encoding\": \"gzip, deflate\",\n", + " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", + " \"content-length\": \"153\",\n", + " \"content-type\": \"application/json\"\n", + " },\n", + " \"method\": \"POST\",\n", + " \"body\": \"{\\\"model_name\\\": \\\"insights-pipeline\\\", \\\"outputs\\\": [{\\\"name\\\": \\\"output0\\\", \\\"datatype\\\": \\\"INT64\\\", \\\"data\\\": [63], \\\"shape\\\": [1]}], \\\"model_version\\\": \\\"NOTIMPLEMENTED\\\"}\",\n", + " \"fresh\": false,\n", + " \"hostname\": \"insights-dumper.seldon-system\",\n", + " \"ip\": \"::ffff:10.1.15.244\",\n", + " \"ips\": [],\n", + " \"protocol\": \"http\",\n", + " \"query\": {},\n", + " \"subdomains\": [],\n", + " \"xhr\": false,\n", + " \"os\": {\n", + " \"hostname\": \"insights-dumper\"\n", + " },\n", + " \"connection\": {},\n", + " \"json\": {\n", + " \"model_name\": \"insights-pipeline\",\n", + " \"outputs\": [\n", + " {\n", + " \"name\": \"output0\",\n", + " \"datatype\": \"INT64\",\n", + " \"data\": [\n", + " 63\n", + " ],\n", + " \"shape\": [\n", + " 1\n", + " ]\n", + " }\n", + " ],\n", + " \"model_version\": \"NOTIMPLEMENTED\"\n", + " }\n", + "}\n", + "::ffff:10.1.15.244 - - [22/Jul/2021:12:37:09 +0000] \"POST / HTTP/1.1\" 200 1422 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "\n" + ] + } + ], + "source": [ + "from tempo.k8s.utils import get_logs_insights_message_dumper\n", + "\n", + "print(get_logs_insights_message_dumper())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Don't log" + ] + }, { "cell_type": "code", "execution_count": 21, "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([63])" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "params = { }\n", + "data = np.array([63])\n", + "remote_model.predict(data=data, parameters=params)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -1161,15 +1369,15 @@ " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper.seldon-system:8080\",\n", - " \"ce-id\": \"ebdf84c1-1a63-4ecb-84d4-d5edb5408987\",\n", + " \"ce-id\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", " \"ce-specversion\": \"0.3\",\n", - " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.NOTIMPLEMENTED\",\n", + " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.seldon\",\n", " \"ce-type\": \"io.seldon.serving.inference.custominsight\",\n", - " \"requestid\": \"ebdf84c1-1a63-4ecb-84d4-d5edb5408987\",\n", - " \"modelid\": \"insights-pipeline\",\n", - " \"inferenceservicename\": \"insights-pipeline\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"default\",\n", + " \"ce-requestid\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", + " \"ce-modelid\": \"insights-pipeline\",\n", + " \"ce-inferenceservicename\": \"insights-pipeline\",\n", + " \"ce-namespace\": \"seldon\",\n", + " \"ce-endpoint\": \"default\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", @@ -1180,7 +1388,7 @@ " \"body\": \"{\\\"log\\\": \\\"value\\\"}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper.seldon-system\",\n", - " \"ip\": \"::ffff:10.8.3.26\",\n", + " \"ip\": \"::ffff:10.1.15.244\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", @@ -1194,21 +1402,21 @@ " \"log\": \"value\"\n", " }\n", "}\n", - "::ffff:10.8.3.26 - - [20/Jun/2021:11:02:52 +0000] \"POST / HTTP/1.1\" 200 1033 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:10.1.15.244 - - [22/Jul/2021:12:37:09 +0000] \"POST / HTTP/1.1\" 200 1034 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper.seldon-system:8080\",\n", - " \"ce-id\": \"ebdf84c1-1a63-4ecb-84d4-d5edb5408987\",\n", + " \"ce-id\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", " \"ce-specversion\": \"0.3\",\n", - " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.NOTIMPLEMENTED\",\n", + " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.seldon\",\n", " \"ce-type\": \"io.seldon.serving.inference.request\",\n", - " \"requestid\": \"ebdf84c1-1a63-4ecb-84d4-d5edb5408987\",\n", - " \"modelid\": \"insights-pipeline\",\n", - " \"inferenceservicename\": \"insights-pipeline\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"default\",\n", + " \"ce-requestid\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", + " \"ce-modelid\": \"insights-pipeline\",\n", + " \"ce-inferenceservicename\": \"insights-pipeline\",\n", + " \"ce-namespace\": \"seldon\",\n", + " \"ce-endpoint\": \"default\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", @@ -1216,10 +1424,10 @@ " \"content-type\": \"application/json\"\n", " },\n", " \"method\": \"POST\",\n", - " \"body\": \"{\\\"id\\\": \\\"ebdf84c1-1a63-4ecb-84d4-d5edb5408987\\\", \\\"parameters\\\": null, \\\"inputs\\\": [{\\\"name\\\": \\\"data\\\", \\\"shape\\\": [1], \\\"datatype\\\": \\\"INT64\\\", \\\"parameters\\\": null, \\\"data\\\": [63]}, {\\\"name\\\": \\\"parameters\\\", \\\"shape\\\": [16], \\\"datatype\\\": \\\"BYTES\\\", \\\"parameters\\\": null, \\\"data\\\": [123, 39, 108, 111, 103, 39, 58, 32, 39, 118, 97, 108, 117, 101, 39, 125]}], \\\"outputs\\\": null}\",\n", + " \"body\": \"{\\\"id\\\": \\\"2180add5-ccdd-48a8-84fc-ce90d689e00e\\\", \\\"parameters\\\": null, \\\"inputs\\\": [{\\\"name\\\": \\\"data\\\", \\\"shape\\\": [1], \\\"datatype\\\": \\\"INT64\\\", \\\"parameters\\\": null, \\\"data\\\": [63]}, {\\\"name\\\": \\\"parameters\\\", \\\"shape\\\": [16], \\\"datatype\\\": \\\"BYTES\\\", \\\"parameters\\\": null, \\\"data\\\": [123, 39, 108, 111, 103, 39, 58, 32, 39, 118, 97, 108, 117, 101, 39, 125]}], \\\"outputs\\\": null}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper.seldon-system\",\n", - " \"ip\": \"::ffff:10.8.3.26\",\n", + " \"ip\": \"::ffff:10.1.15.244\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", @@ -1230,7 +1438,7 @@ " },\n", " \"connection\": {},\n", " \"json\": {\n", - " \"id\": \"ebdf84c1-1a63-4ecb-84d4-d5edb5408987\",\n", + " \"id\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", " \"parameters\": null,\n", " \"inputs\": [\n", " {\n", @@ -1274,32 +1482,32 @@ " \"outputs\": null\n", " }\n", "}\n", - "::ffff:10.8.3.26 - - [20/Jun/2021:11:02:52 +0000] \"POST / HTTP/1.1\" 200 2076 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:10.1.15.244 - - [22/Jul/2021:12:37:09 +0000] \"POST / HTTP/1.1\" 200 2077 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper.seldon-system:8080\",\n", - " \"ce-id\": \"ebdf84c1-1a63-4ecb-84d4-d5edb5408987\",\n", + " \"ce-id\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", " \"ce-specversion\": \"0.3\",\n", - " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.NOTIMPLEMENTED\",\n", + " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.seldon\",\n", " \"ce-type\": \"io.seldon.serving.inference.response\",\n", - " \"requestid\": \"ebdf84c1-1a63-4ecb-84d4-d5edb5408987\",\n", - " \"modelid\": \"insights-pipeline\",\n", - " \"inferenceservicename\": \"insights-pipeline\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"default\",\n", + " \"ce-requestid\": \"2180add5-ccdd-48a8-84fc-ce90d689e00e\",\n", + " \"ce-modelid\": \"insights-pipeline\",\n", + " \"ce-inferenceservicename\": \"insights-pipeline\",\n", + " \"ce-namespace\": \"seldon\",\n", + " \"ce-endpoint\": \"default\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", - " \"content-length\": \"118\",\n", + " \"content-length\": \"153\",\n", " \"content-type\": \"application/json\"\n", " },\n", " \"method\": \"POST\",\n", - " \"body\": \"{\\\"model_name\\\": \\\"insights-pipeline\\\", \\\"outputs\\\": [{\\\"name\\\": \\\"output0\\\", \\\"datatype\\\": \\\"INT64\\\", \\\"data\\\": [63], \\\"shape\\\": [1]}]}\",\n", + " \"body\": \"{\\\"model_name\\\": \\\"insights-pipeline\\\", \\\"outputs\\\": [{\\\"name\\\": \\\"output0\\\", \\\"datatype\\\": \\\"INT64\\\", \\\"data\\\": [63], \\\"shape\\\": [1]}], \\\"model_version\\\": \\\"NOTIMPLEMENTED\\\"}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper.seldon-system\",\n", - " \"ip\": \"::ffff:10.8.3.26\",\n", + " \"ip\": \"::ffff:10.1.15.244\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", @@ -1322,24 +1530,25 @@ " 1\n", " ]\n", " }\n", - " ]\n", + " ],\n", + " \"model_version\": \"NOTIMPLEMENTED\"\n", " }\n", "}\n", - "::ffff:10.8.3.26 - - [20/Jun/2021:11:02:52 +0000] \"POST / HTTP/1.1\" 200 1343 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:10.1.15.244 - - [22/Jul/2021:12:37:09 +0000] \"POST / HTTP/1.1\" 200 1422 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper.seldon-system:8080\",\n", - " \"ce-id\": \"a3d9ceff-ac39-4e8c-a6cd-718b9c88e2a9\",\n", + " \"ce-id\": \"210a9db9-e5ef-47c2-988c-e0f54fbc8a13\",\n", " \"ce-specversion\": \"0.3\",\n", - " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.NOTIMPLEMENTED\",\n", + " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.seldon\",\n", " \"ce-type\": \"io.seldon.serving.inference.custominsight\",\n", - " \"requestid\": \"a3d9ceff-ac39-4e8c-a6cd-718b9c88e2a9\",\n", - " \"modelid\": \"insights-pipeline\",\n", - " \"inferenceservicename\": \"insights-pipeline\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"default\",\n", + " \"ce-requestid\": \"210a9db9-e5ef-47c2-988c-e0f54fbc8a13\",\n", + " \"ce-modelid\": \"insights-pipeline\",\n", + " \"ce-inferenceservicename\": \"insights-pipeline\",\n", + " \"ce-namespace\": \"seldon\",\n", + " \"ce-endpoint\": \"default\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", @@ -1350,7 +1559,7 @@ " \"body\": \"{\\\"log\\\": \\\"value\\\"}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper.seldon-system\",\n", - " \"ip\": \"::ffff:10.8.3.27\",\n", + " \"ip\": \"::ffff:10.1.15.244\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", @@ -1364,21 +1573,21 @@ " \"log\": \"value\"\n", " }\n", "}\n", - "::ffff:10.8.3.27 - - [20/Jun/2021:11:12:50 +0000] \"POST / HTTP/1.1\" 200 1033 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:10.1.15.244 - - [22/Jul/2021:12:39:21 +0000] \"POST / HTTP/1.1\" 200 1034 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper.seldon-system:8080\",\n", - " \"ce-id\": \"a3d9ceff-ac39-4e8c-a6cd-718b9c88e2a9\",\n", + " \"ce-id\": \"210a9db9-e5ef-47c2-988c-e0f54fbc8a13\",\n", " \"ce-specversion\": \"0.3\",\n", - " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.NOTIMPLEMENTED\",\n", + " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.seldon\",\n", " \"ce-type\": \"io.seldon.serving.inference.request\",\n", - " \"requestid\": \"a3d9ceff-ac39-4e8c-a6cd-718b9c88e2a9\",\n", - " \"modelid\": \"insights-pipeline\",\n", - " \"inferenceservicename\": \"insights-pipeline\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"default\",\n", + " \"ce-requestid\": \"210a9db9-e5ef-47c2-988c-e0f54fbc8a13\",\n", + " \"ce-modelid\": \"insights-pipeline\",\n", + " \"ce-inferenceservicename\": \"insights-pipeline\",\n", + " \"ce-namespace\": \"seldon\",\n", + " \"ce-endpoint\": \"default\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", @@ -1386,10 +1595,10 @@ " \"content-type\": \"application/json\"\n", " },\n", " \"method\": \"POST\",\n", - " \"body\": \"{\\\"id\\\": \\\"a3d9ceff-ac39-4e8c-a6cd-718b9c88e2a9\\\", \\\"parameters\\\": null, \\\"inputs\\\": [{\\\"name\\\": \\\"data\\\", \\\"shape\\\": [1], \\\"datatype\\\": \\\"INT64\\\", \\\"parameters\\\": null, \\\"data\\\": [63]}, {\\\"name\\\": \\\"parameters\\\", \\\"shape\\\": [16], \\\"datatype\\\": \\\"BYTES\\\", \\\"parameters\\\": null, \\\"data\\\": [123, 39, 108, 111, 103, 39, 58, 32, 39, 118, 97, 108, 117, 101, 39, 125]}], \\\"outputs\\\": null}\",\n", + " \"body\": \"{\\\"id\\\": \\\"210a9db9-e5ef-47c2-988c-e0f54fbc8a13\\\", \\\"parameters\\\": null, \\\"inputs\\\": [{\\\"name\\\": \\\"data\\\", \\\"shape\\\": [1], \\\"datatype\\\": \\\"INT64\\\", \\\"parameters\\\": null, \\\"data\\\": [63]}, {\\\"name\\\": \\\"parameters\\\", \\\"shape\\\": [16], \\\"datatype\\\": \\\"BYTES\\\", \\\"parameters\\\": null, \\\"data\\\": [123, 39, 108, 111, 103, 39, 58, 32, 39, 118, 97, 108, 117, 101, 39, 125]}], \\\"outputs\\\": null}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper.seldon-system\",\n", - " \"ip\": \"::ffff:10.8.3.27\",\n", + " \"ip\": \"::ffff:10.1.15.244\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", @@ -1400,7 +1609,7 @@ " },\n", " \"connection\": {},\n", " \"json\": {\n", - " \"id\": \"a3d9ceff-ac39-4e8c-a6cd-718b9c88e2a9\",\n", + " \"id\": \"210a9db9-e5ef-47c2-988c-e0f54fbc8a13\",\n", " \"parameters\": null,\n", " \"inputs\": [\n", " {\n", @@ -1444,32 +1653,32 @@ " \"outputs\": null\n", " }\n", "}\n", - "::ffff:10.8.3.27 - - [20/Jun/2021:11:12:50 +0000] \"POST / HTTP/1.1\" 200 2076 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:10.1.15.244 - - [22/Jul/2021:12:39:21 +0000] \"POST / HTTP/1.1\" 200 2077 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "-----------------\n", "{\n", " \"path\": \"/\",\n", " \"headers\": {\n", " \"host\": \"insights-dumper.seldon-system:8080\",\n", - " \"ce-id\": \"a3d9ceff-ac39-4e8c-a6cd-718b9c88e2a9\",\n", + " \"ce-id\": \"210a9db9-e5ef-47c2-988c-e0f54fbc8a13\",\n", " \"ce-specversion\": \"0.3\",\n", - " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.NOTIMPLEMENTED\",\n", + " \"ce-source\": \"io.seldon.serving.deployment.insights-pipeline.seldon\",\n", " \"ce-type\": \"io.seldon.serving.inference.response\",\n", - " \"requestid\": \"a3d9ceff-ac39-4e8c-a6cd-718b9c88e2a9\",\n", - " \"modelid\": \"insights-pipeline\",\n", - " \"inferenceservicename\": \"insights-pipeline\",\n", - " \"namespace\": \"NOTIMPLEMENTED\",\n", - " \"endpoint\": \"default\",\n", + " \"ce-requestid\": \"210a9db9-e5ef-47c2-988c-e0f54fbc8a13\",\n", + " \"ce-modelid\": \"insights-pipeline\",\n", + " \"ce-inferenceservicename\": \"insights-pipeline\",\n", + " \"ce-namespace\": \"seldon\",\n", + " \"ce-endpoint\": \"default\",\n", " \"accept\": \"*/*\",\n", " \"accept-encoding\": \"gzip, deflate\",\n", " \"user-agent\": \"Python/3.7 aiohttp/3.7.4.post0\",\n", - " \"content-length\": \"118\",\n", + " \"content-length\": \"153\",\n", " \"content-type\": \"application/json\"\n", " },\n", " \"method\": \"POST\",\n", - " \"body\": \"{\\\"model_name\\\": \\\"insights-pipeline\\\", \\\"outputs\\\": [{\\\"name\\\": \\\"output0\\\", \\\"datatype\\\": \\\"INT64\\\", \\\"data\\\": [63], \\\"shape\\\": [1]}]}\",\n", + " \"body\": \"{\\\"model_name\\\": \\\"insights-pipeline\\\", \\\"outputs\\\": [{\\\"name\\\": \\\"output0\\\", \\\"datatype\\\": \\\"INT64\\\", \\\"data\\\": [63], \\\"shape\\\": [1]}], \\\"model_version\\\": \\\"NOTIMPLEMENTED\\\"}\",\n", " \"fresh\": false,\n", " \"hostname\": \"insights-dumper.seldon-system\",\n", - " \"ip\": \"::ffff:10.8.3.27\",\n", + " \"ip\": \"::ffff:10.1.15.244\",\n", " \"ips\": [],\n", " \"protocol\": \"http\",\n", " \"query\": {},\n", @@ -1492,59 +1701,31 @@ " 1\n", " ]\n", " }\n", - " ]\n", + " ],\n", + " \"model_version\": \"NOTIMPLEMENTED\"\n", " }\n", "}\n", - "::ffff:10.8.3.27 - - [20/Jun/2021:11:12:50 +0000] \"POST / HTTP/1.1\" 200 1343 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", + "::ffff:10.1.15.244 - - [22/Jul/2021:12:39:21 +0000] \"POST / HTTP/1.1\" 200 1422 \"-\" \"Python/3.7 aiohttp/3.7.4.post0\"\n", "\n" ] } ], "source": [ - "from tempo.k8s.utils import get_logs_insights_message_dumper\n", - "\n", "print(get_logs_insights_message_dumper())" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Don't log" - ] - }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ - "params = { }\n", - "data = np.array([63])\n", - "pipeline.remote(data=data, parameters=params)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(get_logs_insights_message_dumper())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "k8s_runtime.undeploy(pipeline)" + "remote_model.undeploy()" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -1577,7 +1758,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.4" + "version": "3.7.10" } }, "nbformat": 4, From d2010b349ca4583cd001a85a3848ea508ba192f3 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Thu, 22 Jul 2021 14:00:06 +0100 Subject: [PATCH 03/13] Updated tests --- docs/examples/explainer/src/model.py | 12 +++++++-- docs/examples/outlier/src/data.py | 13 +++++++++- tests/aio/conftest.py | 4 +-- tests/conftest.py | 6 ++--- tests/seldon/docker/conftest.py | 4 +-- tests/seldon/k8s/conftest.py | 8 +++--- tests/seldon/k8s/test_k8s.py | 6 ++--- tests/seldon/test_deploy.py | 37 +++++++++++++++++----------- tests/seldon/test_specs.py | 8 +++--- tests/serve/test_metadata.py | 8 +++--- tests/serve/test_stub.py | 4 +-- tests/serve/test_yaml.py | 7 ++---- 12 files changed, 68 insertions(+), 49 deletions(-) diff --git a/docs/examples/explainer/src/model.py b/docs/examples/explainer/src/model.py index 165fa11a..f50fb49f 100644 --- a/docs/examples/explainer/src/model.py +++ b/docs/examples/explainer/src/model.py @@ -11,10 +11,18 @@ def train_model(artifacts_folder: str, data: AdultData): ordinal_features = [x for x in range(len(data.feature_names)) if x not in list(data.category_map.keys())] - ordinal_transformer = Pipeline(steps=[("imputer", SimpleImputer(strategy="median")), ("scaler", StandardScaler())]) + ordinal_transformer = Pipeline( + steps=[ + ("imputer", SimpleImputer(strategy="median")), + ("scaler", StandardScaler()), + ] + ) categorical_features = list(data.category_map.keys()) categorical_transformer = Pipeline( - steps=[("imputer", SimpleImputer(strategy="median")), ("onehot", OneHotEncoder(handle_unknown="ignore"))] + steps=[ + ("imputer", SimpleImputer(strategy="median")), + ("onehot", OneHotEncoder(handle_unknown="ignore")), + ] ) preprocessor = ColumnTransformer( transformers=[ diff --git a/docs/examples/outlier/src/data.py b/docs/examples/outlier/src/data.py index 5c43986c..0acafbca 100644 --- a/docs/examples/outlier/src/data.py +++ b/docs/examples/outlier/src/data.py @@ -12,4 +12,15 @@ def __init__( self.X_train = self.X_train.astype("float32") / 255 self.X_test = self.X_test.astype("float32") / 255 print(self.X_train.shape, self.y_train.shape, self.X_test.shape, self.y_test.shape) - self.class_names = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse", "ship", "truck"] + self.class_names = [ + "airplane", + "automobile", + "bird", + "cat", + "deer", + "dog", + "frog", + "horse", + "ship", + "truck", + ] diff --git a/tests/aio/conftest.py b/tests/aio/conftest.py index e2337fed..4f42f76a 100644 --- a/tests/aio/conftest.py +++ b/tests/aio/conftest.py @@ -10,14 +10,14 @@ from tempo.aio.pipeline import Pipeline from tempo.aio.utils import model, pipeline from tempo.seldon import SeldonDockerRuntime -from tempo.serve.metadata import ModelFramework, RuntimeOptions +from tempo.serve.metadata import DockerOptions, ModelFramework from tempo.serve.model import Model as _Model from tempo.serve.pipeline import PipelineModels @pytest.fixture def runtime() -> SeldonDockerRuntime: - return SeldonDockerRuntime(RuntimeOptions()) + return SeldonDockerRuntime(DockerOptions()) @pytest.fixture diff --git a/tests/conftest.py b/tests/conftest.py index 52c16c78..b43704a5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,7 +9,7 @@ from tempo.kfserving import KFServingV1Protocol, KFServingV2Protocol from tempo.seldon import SeldonProtocol from tempo.serve.constants import MLServerEnvDeps -from tempo.serve.metadata import KubernetesOptions, RuntimeOptions +from tempo.serve.metadata import KubernetesRuntimeOptions TESTS_PATH = os.path.dirname(__file__) TESTDATA_PATH = os.path.join(TESTS_PATH, "testdata") @@ -51,9 +51,7 @@ def sklearn_model() -> Model: uri="gs://seldon-models/sklearn/iris", local_folder=model_path, protocol=SeldonProtocol(), - runtime_options=RuntimeOptions( - k8s_options=KubernetesOptions(namespace="production", replicas=1), - ), + runtime_options=KubernetesRuntimeOptions(namespace="production", replicas=1), ) diff --git a/tests/seldon/docker/conftest.py b/tests/seldon/docker/conftest.py index af4d6b17..d8500127 100644 --- a/tests/seldon/docker/conftest.py +++ b/tests/seldon/docker/conftest.py @@ -8,12 +8,12 @@ from tempo.seldon import SeldonDockerRuntime from tempo.serve.deploy import RemoteModel, deploy from tempo.serve.loader import save -from tempo.serve.metadata import RuntimeOptions +from tempo.serve.metadata import DockerOptions @pytest.fixture def runtime() -> SeldonDockerRuntime: - return SeldonDockerRuntime(RuntimeOptions()) + return SeldonDockerRuntime(DockerOptions()) @pytest.fixture diff --git a/tests/seldon/k8s/conftest.py b/tests/seldon/k8s/conftest.py index cf7f85e7..30550d8e 100644 --- a/tests/seldon/k8s/conftest.py +++ b/tests/seldon/k8s/conftest.py @@ -8,9 +8,8 @@ from kubernetes.utils.create_from_yaml import create_from_yaml from tempo import Model, Pipeline -from tempo.kfserving import KFServingV2Protocol from tempo.seldon import SeldonKubernetesRuntime -from tempo.serve.metadata import KubernetesOptions, RuntimeOptions +from tempo.serve.metadata import KubernetesRuntimeOptions from ...conftest import TESTDATA_PATH @@ -40,14 +39,13 @@ def namespace() -> Generator[str, None, None]: @pytest.fixture def runtime(namespace: str) -> SeldonKubernetesRuntime: - return SeldonKubernetesRuntime(runtime_options=RuntimeOptions(k8s_options=KubernetesOptions(namespace=namespace))) + return SeldonKubernetesRuntime(runtime_options=KubernetesRuntimeOptions(namespace=namespace)) @pytest.fixture def runtime_v2(namespace: str) -> SeldonKubernetesRuntime: return SeldonKubernetesRuntime( - k8s_options=KubernetesOptions(namespace=namespace), - protocol=KFServingV2Protocol(), + KubernetesRuntimeOptions(namespace=namespace), ) diff --git a/tests/seldon/k8s/test_k8s.py b/tests/seldon/k8s/test_k8s.py index 37143173..048c6f3f 100644 --- a/tests/seldon/k8s/test_k8s.py +++ b/tests/seldon/k8s/test_k8s.py @@ -3,11 +3,11 @@ from kubernetes import client from tempo.seldon.k8s import SeldonKubernetesRuntime -from tempo.serve.metadata import RuntimeOptions +from tempo.serve.metadata import KubernetesRuntimeOptions def test_create_k8s_runtime(): - rto = RuntimeOptions() + rto = KubernetesRuntimeOptions() rt = SeldonKubernetesRuntime(rto) assert rt.runtime_options.runtime == "tempo.seldon.SeldonKubernetesRuntime" @@ -18,7 +18,7 @@ def test_deploy_k8s(sklearn_model, runtime: SeldonKubernetesRuntime): sdep = crd_api.get_namespaced_custom_object( "machinelearning.seldon.io", "v1", - runtime.k8s_options.namespace, + runtime.namespace, "seldondeployments", sklearn_model.details.name, ) diff --git a/tests/seldon/test_deploy.py b/tests/seldon/test_deploy.py index 3b19bf15..0722a98c 100644 --- a/tests/seldon/test_deploy.py +++ b/tests/seldon/test_deploy.py @@ -1,10 +1,16 @@ import numpy as np import pytest -from tempo.seldon.deploy import SeldonDeployAuthType, SeldonDeployConfig, SeldonDeployRuntime +from tempo.seldon.deploy import SeldonDeployRuntime from tempo.seldon.k8s import SeldonKubernetesRuntime from tempo.seldon.protocol import SeldonProtocol -from tempo.serve.metadata import IngressOptions, KubernetesOptions, ModelFramework, RuntimeOptions +from tempo.serve.metadata import ( + EnterpriseRuntimeAuthType, + EnterpriseRuntimeOptions, + IngressOptions, + KubernetesRuntimeOptions, + ModelFramework, +) from tempo.serve.model import Model @@ -12,21 +18,20 @@ def test_deploy(): rt = SeldonDeployRuntime() - config = SeldonDeployConfig( + config = EnterpriseRuntimeOptions( host="https://34.78.44.92/seldon-deploy/api/v1alpha1", user="admin@seldon.io", password="12341234", oidc_server="https://34.78.44.92/auth/realms/deploy-realm", oidc_client_id="sd-api", verify_ssl=False, - auth_type=SeldonDeployAuthType.oidc, + auth_type=EnterpriseRuntimeAuthType.oidc, ) rt.authenticate(settings=config) - options = RuntimeOptions( - runtime="tempo.seldon.SeldonKubernetesRuntime", - k8s_options=KubernetesOptions(namespace="seldon"), + options = KubernetesRuntimeOptions( + namespace="seldon", ingress_options=IngressOptions(ssl=True, verify_ssl=False), ) @@ -46,18 +51,22 @@ def test_deploy(): @pytest.mark.skip("needs deploy cluster") def test_deploy_yaml(): - rt = SeldonDeployRuntime( - host="http://34.78.44.92/seldon-deploy/api/v1alpha1", - user="admin@kubeflow.org", - oidc_server="https://34.78.44.92/auth/realms/deploy-realm", + rt = SeldonDeployRuntime() + + config = EnterpriseRuntimeOptions( + host="https://34.78.44.92/seldon-deploy/api/v1alpha1", + user="admin@seldon.io", password="12341234", + oidc_server="https://34.78.44.92/auth/realms/deploy-realm", oidc_client_id="sd-api", verify_ssl=False, + auth_type=EnterpriseRuntimeAuthType.oidc, ) - options = RuntimeOptions( - runtime="tempo.seldon.SeldonKubernetesRuntime", - k8s_options=KubernetesOptions(namespace="seldon"), + rt.authenticate(settings=config) + + options = KubernetesRuntimeOptions( + namespace="seldon", ingress_options=IngressOptions(ssl=True, verify_ssl=False), ) diff --git a/tests/seldon/test_specs.py b/tests/seldon/test_specs.py index b912a72a..db1b75ac 100644 --- a/tests/seldon/test_specs.py +++ b/tests/seldon/test_specs.py @@ -1,13 +1,12 @@ from tempo.seldon.protocol import SeldonProtocol -from tempo.seldon.runtime import SeldonCoreOptions from tempo.seldon.specs import KubernetesSpec, get_container_spec from tempo.serve.base import ModelSpec -from tempo.serve.metadata import KubernetesOptions, ModelDataArgs, ModelDetails, ModelFramework, RuntimeOptions +from tempo.serve.metadata import KubernetesRuntimeOptions, ModelDataArgs, ModelDetails, ModelFramework def test_kubernetes_spec(sklearn_model): - k8s_object = KubernetesSpec(sklearn_model.model_spec, SeldonCoreOptions()) + k8s_object = KubernetesSpec(sklearn_model.model_spec, KubernetesRuntimeOptions()) expected = { "spec": { @@ -41,8 +40,7 @@ def test_tensorflow_spec(): outputs=ModelDataArgs(args=[]), ) protocol = SeldonProtocol() - options = KubernetesOptions(namespace="production", replicas=1) - runtime_options = RuntimeOptions(k8s_options=options) + runtime_options = KubernetesRuntimeOptions(namespace="production", replicas=1) model_spec = ModelSpec(model_details=md, protocol=protocol, runtime_options=runtime_options) spec = get_container_spec(model_spec) assert "image" in spec diff --git a/tests/serve/test_metadata.py b/tests/serve/test_metadata.py index 2e74a4d1..8953849e 100644 --- a/tests/serve/test_metadata.py +++ b/tests/serve/test_metadata.py @@ -1,15 +1,15 @@ import pytest -from tempo.serve.metadata import RuntimeOptions +from tempo.serve.metadata import KubernetesRuntimeOptions @pytest.mark.parametrize( "runtime, replicas", [ - ({"k8s_options": {"replicas": 2}}, 2), + ({"replicas": 2}, 2), ({}, 1), ], ) def test_runtime_options(runtime, replicas): - r = RuntimeOptions(**runtime) - assert r.k8s_options.replicas == replicas + r = KubernetesRuntimeOptions(**runtime) + assert r.replicas == replicas diff --git a/tests/serve/test_stub.py b/tests/serve/test_stub.py index c9438bee..9bc4ea1d 100644 --- a/tests/serve/test_stub.py +++ b/tests/serve/test_stub.py @@ -4,7 +4,7 @@ from tempo.kfserving.protocol import KFServingV2Protocol from tempo.serve.base import ModelSpec -from tempo.serve.metadata import ModelDataArg, ModelDataArgs, ModelDetails, ModelFramework, RuntimeOptions +from tempo.serve.metadata import KFServingOptions, ModelDataArg, ModelDataArgs, ModelDetails, ModelFramework def test_model_data_arg(): @@ -40,7 +40,7 @@ def test_model_spec(): outputs=ModelDataArgs(args=[]), ), protocol=KFServingV2Protocol(), - runtime_options=RuntimeOptions(), + runtime_options=KFServingOptions().local_options, ) s = ms.json() j = json.loads(s) diff --git a/tests/serve/test_yaml.py b/tests/serve/test_yaml.py index 5beddc67..cba53c98 100644 --- a/tests/serve/test_yaml.py +++ b/tests/serve/test_yaml.py @@ -3,8 +3,7 @@ from tempo.seldon.k8s import SeldonKubernetesRuntime from tempo.seldon.protocol import SeldonProtocol -from tempo.seldon.runtime import SeldonCoreOptions -from tempo.serve.metadata import KubernetesOptions, ModelFramework +from tempo.serve.metadata import KubernetesRuntimeOptions, ModelFramework from tempo.serve.model import Model @@ -130,9 +129,7 @@ def test_seldon_model_yaml_auth(expected): uri="gs://seldon-models/xgboost/iris", local_folder="/tmp/model", ) - runtime = SeldonKubernetesRuntime( - runtime_options=SeldonCoreOptions(k8s_options=KubernetesOptions(authSecretName="auth")) - ) + runtime = SeldonKubernetesRuntime(runtime_options=KubernetesRuntimeOptions(authSecretName="auth")) yaml_str = runtime.manifest(m) yaml_obj = yaml.safe_load(yaml_str) yaml_obj_expected = yaml.safe_load(expected) From ea81514aa22f2907fac9c1263e82fdead319274c Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Thu, 22 Jul 2021 14:41:18 +0100 Subject: [PATCH 04/13] Passing test --- tempo/serve/metadata.py | 2 +- tests/seldon/test_specs.py | 2 +- tests/serve/test_yaml.py | 6 ++++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tempo/serve/metadata.py b/tempo/serve/metadata.py index 3fe79098..ec97604c 100644 --- a/tempo/serve/metadata.py +++ b/tempo/serve/metadata.py @@ -189,7 +189,7 @@ class KubernetesRuntimeOptions(_BaseRuntimeOptions): authSecretName: Optional[str] = None serviceAccountName: Optional[str] = None # TODO move to separate seldonkubernetesruntime - add_svc_orchestrator: bool = True + add_svc_orchestrator: bool = False class DockerOptions(_BaseRuntimeOptions): diff --git a/tests/seldon/test_specs.py b/tests/seldon/test_specs.py index db1b75ac..f8cb146e 100644 --- a/tests/seldon/test_specs.py +++ b/tests/seldon/test_specs.py @@ -21,7 +21,7 @@ def test_kubernetes_spec(sklearn_model): "implementation": KubernetesSpec.Implementations[sklearn_model.details.platform], }, "name": "default", - "replicas": sklearn_model.model_spec.runtime_options.k8s_options.replicas, + "replicas": sklearn_model.model_spec.runtime_options.replicas, } ], }, diff --git a/tests/serve/test_yaml.py b/tests/serve/test_yaml.py index cba53c98..685fdcc3 100644 --- a/tests/serve/test_yaml.py +++ b/tests/serve/test_yaml.py @@ -47,6 +47,8 @@ def test_seldon_sklearn_model_yaml(expected): yaml_obj = yaml.safe_load(yaml_str) yaml_obj_expected = yaml.safe_load(expected) del yaml_obj["metadata"]["annotations"]["seldon.io/tempo-model"] + print("\n\n" + str(yaml_obj)) + print("\n\n" + str(yaml_obj_expected)) assert yaml_obj == yaml_obj_expected @@ -90,6 +92,8 @@ def test_seldon_xgboost_model_yaml(expected): yaml_obj = yaml.safe_load(yaml_str) yaml_obj_expected = yaml.safe_load(expected) del yaml_obj["metadata"]["annotations"]["seldon.io/tempo-model"] + print("\n\n" + str(yaml_obj)) + print("\n\n" + str(yaml_obj_expected)) assert yaml_obj == yaml_obj_expected @@ -134,4 +138,6 @@ def test_seldon_model_yaml_auth(expected): yaml_obj = yaml.safe_load(yaml_str) yaml_obj_expected = yaml.safe_load(expected) del yaml_obj["metadata"]["annotations"]["seldon.io/tempo-model"] + print("\n\n" + str(yaml_obj)) + print("\n\n" + str(yaml_obj_expected)) assert yaml_obj == yaml_obj_expected From 270783da89268c16c41cb4ef51198286739647e4 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 26 Jul 2021 10:22:44 +0100 Subject: [PATCH 05/13] updated readme docs --- docs/examples/multi-model/README.ipynb | 350 +++++++++++++++++++++---- docs/examples/multi-model/README.md | 232 ++++++++++++++-- 2 files changed, 503 insertions(+), 79 deletions(-) diff --git a/docs/examples/multi-model/README.ipynb b/docs/examples/multi-model/README.ipynb index e3ff2f2e..12f60098 100644 --- a/docs/examples/multi-model/README.ipynb +++ b/docs/examples/multi-model/README.ipynb @@ -43,12 +43,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "b8ca70f9", "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[01;34m.\u001b[00m\r\n", + "├── \u001b[01;34martifacts\u001b[00m\r\n", + "│   ├── \u001b[01;34mclassifier\u001b[00m\r\n", + "│   ├── \u001b[01;34msklearn\u001b[00m\r\n", + "│   └── \u001b[01;34mxgboost\u001b[00m\r\n", + "├── \u001b[01;34mk8s\u001b[00m\r\n", + "│   └── \u001b[01;34mrbac\u001b[00m\r\n", + "├── \u001b[01;34msrc\u001b[00m\r\n", + "│   ├── data.py\r\n", + "│   ├── tempo.py\r\n", + "│   └── train.py\r\n", + "└── \u001b[01;34mtests\u001b[00m\r\n", + " └── test_tempo.py\r\n", + "\r\n", + "8 directories, 4 files\r\n" + ] + } + ], "source": [ "!tree -P \"*.py\" -I \"__init__.py|__pycache__\" -L 2" ] @@ -66,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "42c20ffa", "metadata": {}, "outputs": [], @@ -82,7 +104,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "2e2abd28", "metadata": { "code_folding": [ @@ -116,7 +138,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "aa35a350", "metadata": {}, "outputs": [], @@ -141,7 +163,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "a8345fb6", "metadata": {}, "outputs": [], @@ -152,7 +174,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "c0b0af26", "metadata": { "code_folding": [ @@ -225,7 +247,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "8159cbec", "metadata": { "code_folding": [] @@ -256,10 +278,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "aa78ec19", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mTest session starts (platform: linux, Python 3.7.10, pytest 5.3.1, pytest-sugar 0.9.4)\u001b[0m\n", + "rootdir: /home/alejandro/Programming/kubernetes/seldon/tempo, inifile: setup.cfg\n", + "plugins: cases-3.4.6, sugar-0.9.4, xdist-1.30.0, anyio-3.2.1, requests-mock-1.7.0, django-3.8.0, forked-1.1.3, flaky-3.6.1, asyncio-0.14.0, celery-4.4.0, cov-2.8.1\n", + "\u001b[1mcollecting ... \u001b[0m\n", + " \u001b[36mdocs/examples/multi-model/tests/\u001b[0mtest_tempo.py\u001b[0m \u001b[32m✓\u001b[0m\u001b[32m✓\u001b[0m \u001b[32m100% \u001b[0m\u001b[40m\u001b[32m█\u001b[0m\u001b[40m\u001b[32m████\u001b[0m\u001b[40m\u001b[32m█\u001b[0m\u001b[40m\u001b[32m████\u001b[0m\n", + "\n", + "Results (1.26s):\n", + "\u001b[32m 2 passed\u001b[0m\n" + ] + } + ], "source": [ "!python -m pytest tests/" ] @@ -276,20 +313,45 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "3e1f9017", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "name: tempo\r\n", + "channels:\r\n", + " - defaults\r\n", + "dependencies:\r\n", + " - python=3.7.9\r\n", + " - pip:\r\n", + " - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo\r\n", + " - mlserver==0.3.2\r\n" + ] + } + ], "source": [ "!cat artifacts/classifier/conda.yaml" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "3c23ab3b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting packages...\n", + "Packing environment at '/home/alejandro/miniconda3/envs/tempo-88546d85-d920-4ba5-afbf-2bbf88afebf9' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/multi-model/artifacts/classifier/environment.tar.gz'\n", + "[########################################] | 100% Completed | 11.5s\n" + ] + } + ], "source": [ "from tempo.serve.loader import save\n", "save(classifier)" @@ -307,28 +369,40 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "6b0ca263", "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "remote_model = deploy(classifier)" + "from tempo import deploy_local\n", + "remote_model = deploy_local(classifier)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "bd609448", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'output0': array([[0.00745035, 0.03121155, 0.96133804]], dtype=float32),\n", + " 'output1': 'xgboost prediction'}" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "remote_model.predict(np.array([[1, 2, 3, 4]]))" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "637093d2", "metadata": {}, "outputs": [], @@ -352,17 +426,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "d8d2fb32", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "secret/minio-secret configured\r\n", + "serviceaccount/tempo-pipeline unchanged\r\n", + "role.rbac.authorization.k8s.io/tempo-pipeline unchanged\r\n", + "rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged\r\n" + ] + } + ], "source": [ "!kubectl apply -f k8s/rbac -n production" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "9fa80565", "metadata": {}, "outputs": [], @@ -374,7 +459,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "39ff404c", "metadata": {}, "outputs": [], @@ -387,38 +472,46 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "id": "c56b5ca7", "metadata": {}, "outputs": [], "source": [ - "from tempo.serve.metadata import KubernetesOptions\n", - "from tempo.seldon.k8s import SeldonCoreOptions\n", - "runtime_options = SeldonCoreOptions(\n", - " k8s_options=KubernetesOptions(\n", - " namespace=\"production\",\n", - " authSecretName=\"minio-secret\"\n", - " )\n", - " )" + "from tempo.serve.metadata import SeldonCoreOptions\n", + "runtime_options = SeldonCoreOptions(**{\n", + " \"remote_options\": {\n", + " \"namespace\": \"production\",\n", + " \"authSecretName\": \"minio-secret\"\n", + " }\n", + " })" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "id": "e5cd0834", "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "remote_model = deploy(classifier, options=runtime_options)" + "from tempo import deploy_remote\n", + "remote_model = deploy_remote(classifier, options=runtime_options)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "908fa372", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'output0': array([1.], dtype=float32), 'output1': 'sklearn prediction'}\n", + "{'output0': array([[0.00745035, 0.03121155, 0.96133804]], dtype=float32), 'output1': 'xgboost prediction'}\n" + ] + } + ], "source": [ "print(remote_model.predict(payload=np.array([[0, 0, 0, 0]])))\n", "print(remote_model.predict(payload=np.array([[1, 2, 3, 4]])))" @@ -434,13 +527,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "id": "e4b36170", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Name\tDescription\n", + "classifier\tA pipeline to use either an sklearn or xgboost model for Iris classification\n", + "test-iris-sklearn\tAn SKLearn Iris classification model\n", + "test-iris-xgboost\tAn XGBoost Iris classification model\n" + ] + } + ], "source": [ "from tempo.seldon.k8s import SeldonKubernetesRuntime\n", - "k8s_runtime = SeldonKubernetesRuntime(runtime_options)\n", + "k8s_runtime = SeldonKubernetesRuntime(runtime_options.remote_options)\n", "models = k8s_runtime.list_models(namespace=\"production\")\n", "print(\"Name\\tDescription\")\n", "for model in models:\n", @@ -450,17 +554,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "id": "21b46fdd", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'output0': array([[0.00745035, 0.03121155, 0.96133804]], dtype=float32),\n", + " 'output1': 'xgboost prediction'}" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "models[0].predict(payload=np.array([[1, 2, 3, 4]]))" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "id": "f293a8bf", "metadata": {}, "outputs": [], @@ -481,20 +597,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "id": "69ee5f4a", "metadata": {}, "outputs": [], "source": [ - "from tempo.seldon.k8s import SeldonKubernetesRuntime\n", - "from tempo.serve.metadata import RuntimeOptions, KubernetesOptions\n", - "runtime_options = RuntimeOptions(\n", - " k8s_options=KubernetesOptions(\n", - " namespace=\"production\",\n", - " authSecretName=\"minio-secret\"\n", - " )\n", - " )\n", - "k8s_runtime = SeldonKubernetesRuntime(runtime_options)\n", + "k8s_runtime = SeldonKubernetesRuntime(runtime_options.remote_options)\n", "yaml_str = k8s_runtime.manifest(classifier)\n", "with open(os.getcwd()+\"/k8s/tempo.yaml\",\"w\") as f:\n", " f.write(yaml_str)" @@ -502,10 +610,138 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "id": "748bd754", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "apiVersion: machinelearning.seldon.io/v1\r\n", + "kind: SeldonDeployment\r\n", + "metadata:\r\n", + " annotations:\r\n", + " seldon.io/tempo-description: A pipeline to use either an sklearn or xgboost model\r\n", + " for Iris classification\r\n", + " seldon.io/tempo-model: '{\"model_details\": {\"name\": \"classifier\", \"local_folder\":\r\n", + " \"/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/multi-model/artifacts/classifier\",\r\n", + " \"uri\": \"s3://tempo/basic/pipeline\", \"platform\": \"tempo\", \"inputs\": {\"args\":\r\n", + " [{\"ty\": \"numpy.ndarray\", \"name\": \"payload\"}]}, \"outputs\": {\"args\": [{\"ty\": \"numpy.ndarray\",\r\n", + " \"name\": null}, {\"ty\": \"builtins.str\", \"name\": null}]}, \"description\": \"A pipeline\r\n", + " to use either an sklearn or xgboost model for Iris classification\"}, \"protocol\":\r\n", + " \"tempo.kfserving.protocol.KFServingV2Protocol\", \"runtime_options\": {\"runtime\":\r\n", + " \"tempo.seldon.SeldonKubernetesRuntime\", \"state_options\": {\"state_type\": \"LOCAL\",\r\n", + " \"key_prefix\": \"\", \"host\": \"\", \"port\": \"\"}, \"insights_options\": {\"worker_endpoint\":\r\n", + " \"\", \"batch_size\": 1, \"parallelism\": 1, \"retries\": 3, \"window_time\": 0, \"mode_type\":\r\n", + " \"NONE\", \"in_asyncio\": false}, \"ingress_options\": {\"ingress\": \"tempo.ingress.istio.IstioIngress\",\r\n", + " \"ssl\": false, \"verify_ssl\": true}, \"replicas\": 1, \"minReplicas\": null, \"maxReplicas\":\r\n", + " null, \"authSecretName\": \"minio-secret\", \"serviceAccountName\": null, \"add_svc_orchestrator\":\r\n", + " false, \"namespace\": \"production\"}}'\r\n", + " labels:\r\n", + " seldon.io/tempo: \"true\"\r\n", + " name: classifier\r\n", + " namespace: production\r\n", + "spec:\r\n", + " predictors:\r\n", + " - annotations:\r\n", + " seldon.io/no-engine: \"true\"\r\n", + " componentSpecs:\r\n", + " - spec:\r\n", + " containers:\r\n", + " - name: classifier\r\n", + " resources:\r\n", + " limits:\r\n", + " cpu: 1\r\n", + " memory: 1Gi\r\n", + " requests:\r\n", + " cpu: 500m\r\n", + " memory: 500Mi\r\n", + " graph:\r\n", + " envSecretRefName: minio-secret\r\n", + " implementation: TEMPO_SERVER\r\n", + " modelUri: s3://tempo/basic/pipeline\r\n", + " name: classifier\r\n", + " serviceAccountName: tempo-pipeline\r\n", + " type: MODEL\r\n", + " name: default\r\n", + " replicas: 1\r\n", + " protocol: kfserving\r\n", + "---\r\n", + "apiVersion: machinelearning.seldon.io/v1\r\n", + "kind: SeldonDeployment\r\n", + "metadata:\r\n", + " annotations:\r\n", + " seldon.io/tempo-description: An SKLearn Iris classification model\r\n", + " seldon.io/tempo-model: '{\"model_details\": {\"name\": \"test-iris-sklearn\", \"local_folder\":\r\n", + " \"/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/multi-model/artifacts/sklearn\",\r\n", + " \"uri\": \"s3://tempo/basic/sklearn\", \"platform\": \"sklearn\", \"inputs\": {\"args\":\r\n", + " [{\"ty\": \"numpy.ndarray\", \"name\": null}]}, \"outputs\": {\"args\": [{\"ty\": \"numpy.ndarray\",\r\n", + " \"name\": null}]}, \"description\": \"An SKLearn Iris classification model\"}, \"protocol\":\r\n", + " \"tempo.kfserving.protocol.KFServingV2Protocol\", \"runtime_options\": {\"runtime\":\r\n", + " \"tempo.seldon.SeldonKubernetesRuntime\", \"state_options\": {\"state_type\": \"LOCAL\",\r\n", + " \"key_prefix\": \"\", \"host\": \"\", \"port\": \"\"}, \"insights_options\": {\"worker_endpoint\":\r\n", + " \"\", \"batch_size\": 1, \"parallelism\": 1, \"retries\": 3, \"window_time\": 0, \"mode_type\":\r\n", + " \"NONE\", \"in_asyncio\": false}, \"ingress_options\": {\"ingress\": \"tempo.ingress.istio.IstioIngress\",\r\n", + " \"ssl\": false, \"verify_ssl\": true}, \"replicas\": 1, \"minReplicas\": null, \"maxReplicas\":\r\n", + " null, \"authSecretName\": \"minio-secret\", \"serviceAccountName\": null, \"add_svc_orchestrator\":\r\n", + " false, \"namespace\": \"production\"}}'\r\n", + " labels:\r\n", + " seldon.io/tempo: \"true\"\r\n", + " name: test-iris-sklearn\r\n", + " namespace: production\r\n", + "spec:\r\n", + " predictors:\r\n", + " - annotations:\r\n", + " seldon.io/no-engine: \"true\"\r\n", + " graph:\r\n", + " envSecretRefName: minio-secret\r\n", + " implementation: SKLEARN_SERVER\r\n", + " modelUri: s3://tempo/basic/sklearn\r\n", + " name: test-iris-sklearn\r\n", + " type: MODEL\r\n", + " name: default\r\n", + " replicas: 1\r\n", + " protocol: kfserving\r\n", + "---\r\n", + "apiVersion: machinelearning.seldon.io/v1\r\n", + "kind: SeldonDeployment\r\n", + "metadata:\r\n", + " annotations:\r\n", + " seldon.io/tempo-description: An XGBoost Iris classification model\r\n", + " seldon.io/tempo-model: '{\"model_details\": {\"name\": \"test-iris-xgboost\", \"local_folder\":\r\n", + " \"/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/multi-model/artifacts/xgboost\",\r\n", + " \"uri\": \"s3://tempo/basic/xgboost\", \"platform\": \"xgboost\", \"inputs\": {\"args\":\r\n", + " [{\"ty\": \"numpy.ndarray\", \"name\": null}]}, \"outputs\": {\"args\": [{\"ty\": \"numpy.ndarray\",\r\n", + " \"name\": null}]}, \"description\": \"An XGBoost Iris classification model\"}, \"protocol\":\r\n", + " \"tempo.kfserving.protocol.KFServingV2Protocol\", \"runtime_options\": {\"runtime\":\r\n", + " \"tempo.seldon.SeldonKubernetesRuntime\", \"state_options\": {\"state_type\": \"LOCAL\",\r\n", + " \"key_prefix\": \"\", \"host\": \"\", \"port\": \"\"}, \"insights_options\": {\"worker_endpoint\":\r\n", + " \"\", \"batch_size\": 1, \"parallelism\": 1, \"retries\": 3, \"window_time\": 0, \"mode_type\":\r\n", + " \"NONE\", \"in_asyncio\": false}, \"ingress_options\": {\"ingress\": \"tempo.ingress.istio.IstioIngress\",\r\n", + " \"ssl\": false, \"verify_ssl\": true}, \"replicas\": 1, \"minReplicas\": null, \"maxReplicas\":\r\n", + " null, \"authSecretName\": \"minio-secret\", \"serviceAccountName\": null, \"add_svc_orchestrator\":\r\n", + " false, \"namespace\": \"production\"}}'\r\n", + " labels:\r\n", + " seldon.io/tempo: \"true\"\r\n", + " name: test-iris-xgboost\r\n", + " namespace: production\r\n", + "spec:\r\n", + " predictors:\r\n", + " - annotations:\r\n", + " seldon.io/no-engine: \"true\"\r\n", + " graph:\r\n", + " envSecretRefName: minio-secret\r\n", + " implementation: XGBOOST_SERVER\r\n", + " modelUri: s3://tempo/basic/xgboost\r\n", + " name: test-iris-xgboost\r\n", + " type: MODEL\r\n", + " name: default\r\n", + " replicas: 1\r\n", + " protocol: kfserving\r\n" + ] + } + ], "source": [ "!kustomize build k8s" ] @@ -535,7 +771,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.9" + "version": "3.7.10" } }, "nbformat": 4, diff --git a/docs/examples/multi-model/README.md b/docs/examples/multi-model/README.md index c3566856..2bf2081f 100644 --- a/docs/examples/multi-model/README.md +++ b/docs/examples/multi-model/README.md @@ -26,6 +26,23 @@ conda env create --name tempo-examples --file conda/tempo-examples.yaml !tree -P "*.py" -I "__init__.py|__pycache__" -L 2 ``` + . + ├── artifacts + │   ├── classifier + │   ├── sklearn + │   └── xgboost + ├── k8s + │   └── rbac + ├── src + │   ├── data.py + │   ├── tempo.py + │   └── train.py + └── tests + └── test_tempo.py + + 8 directories, 4 files + + ## Train Models * This section is where as a data scientist you do your work of training models and creating artfacts. @@ -177,6 +194,16 @@ def test_xgboost_model_used(): !python -m pytest tests/ ``` + Test session starts (platform: linux, Python 3.7.10, pytest 5.3.1, pytest-sugar 0.9.4) + rootdir: /home/alejandro/Programming/kubernetes/seldon/tempo, inifile: setup.cfg + plugins: cases-3.4.6, sugar-0.9.4, xdist-1.30.0, anyio-3.2.1, requests-mock-1.7.0, django-3.8.0, forked-1.1.3, flaky-3.6.1, asyncio-0.14.0, celery-4.4.0, cov-2.8.1 + collecting ...  + docs/examples/multi-model/tests/test_tempo.py ✓✓ 100% ██████████ + + Results (1.26s): +  2 passed + + ## Save Classifier Environment * In preparation for running our models we save the Python environment needed for the orchestration to run as defined by a `conda.yaml` in our project. @@ -186,20 +213,35 @@ def test_xgboost_model_used(): !cat artifacts/classifier/conda.yaml ``` + name: tempo + channels: + - defaults + dependencies: + - python=3.7.9 + - pip: + - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo + - mlserver==0.3.2 + + ```python from tempo.serve.loader import save save(classifier) ``` + Collecting packages... + Packing environment at '/home/alejandro/miniconda3/envs/tempo-88546d85-d920-4ba5-afbf-2bbf88afebf9' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/multi-model/artifacts/classifier/environment.tar.gz' + [########################################] | 100% Completed | 11.5s + + ## Test Locally on Docker * Here we test our models using production images but running locally on Docker. This allows us to ensure the final production deployed model will behave as expected when deployed. ```python -from tempo import deploy -remote_model = deploy(classifier) +from tempo import deploy_local +remote_model = deploy_local(classifier) ``` @@ -208,6 +250,14 @@ remote_model.predict(np.array([[1, 2, 3, 4]])) ``` + + + {'output0': array([[0.00745035, 0.03121155, 0.96133804]], dtype=float32), + 'output1': 'xgboost prediction'} + + + + ```python remote_model.undeploy() ``` @@ -225,6 +275,12 @@ Create a Kind Kubernetes cluster with Minio and Seldon Core installed using Ansi !kubectl apply -f k8s/rbac -n production ``` + secret/minio-secret configured + serviceaccount/tempo-pipeline unchanged + role.rbac.authorization.k8s.io/tempo-pipeline unchanged + rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged + + ```python from tempo.examples.minio import create_minio_rclone @@ -242,20 +298,19 @@ upload(classifier) ```python -from tempo.serve.metadata import KubernetesOptions -from tempo.seldon.k8s import SeldonCoreOptions -runtime_options = SeldonCoreOptions( - k8s_options=KubernetesOptions( - namespace="production", - authSecretName="minio-secret" - ) - ) +from tempo.serve.metadata import SeldonCoreOptions +runtime_options = SeldonCoreOptions(**{ + "remote_options": { + "namespace": "production", + "authSecretName": "minio-secret" + } + }) ``` ```python -from tempo import deploy -remote_model = deploy(classifier, options=runtime_options) +from tempo import deploy_remote +remote_model = deploy_remote(classifier, options=runtime_options) ``` @@ -264,12 +319,16 @@ print(remote_model.predict(payload=np.array([[0, 0, 0, 0]]))) print(remote_model.predict(payload=np.array([[1, 2, 3, 4]]))) ``` + {'output0': array([1.], dtype=float32), 'output1': 'sklearn prediction'} + {'output0': array([[0.00745035, 0.03121155, 0.96133804]], dtype=float32), 'output1': 'xgboost prediction'} + + ### Illustrate use of Deployed Model by Remote Client ```python from tempo.seldon.k8s import SeldonKubernetesRuntime -k8s_runtime = SeldonKubernetesRuntime(runtime_options) +k8s_runtime = SeldonKubernetesRuntime(runtime_options.remote_options) models = k8s_runtime.list_models(namespace="production") print("Name\tDescription") for model in models: @@ -277,12 +336,26 @@ for model in models: print(f"{details.name}\t{details.description}") ``` + Name Description + classifier A pipeline to use either an sklearn or xgboost model for Iris classification + test-iris-sklearn An SKLearn Iris classification model + test-iris-xgboost An XGBoost Iris classification model + + ```python models[0].predict(payload=np.array([[1, 2, 3, 4]])) ``` + + + {'output0': array([[0.00745035, 0.03121155, 0.96133804]], dtype=float32), + 'output1': 'xgboost prediction'} + + + + ```python remote_model.undeploy() ``` @@ -294,15 +367,7 @@ remote_model.undeploy() ```python -from tempo.seldon.k8s import SeldonKubernetesRuntime -from tempo.serve.metadata import RuntimeOptions, KubernetesOptions -runtime_options = RuntimeOptions( - k8s_options=KubernetesOptions( - namespace="production", - authSecretName="minio-secret" - ) - ) -k8s_runtime = SeldonKubernetesRuntime(runtime_options) +k8s_runtime = SeldonKubernetesRuntime(runtime_options.remote_options) yaml_str = k8s_runtime.manifest(classifier) with open(os.getcwd()+"/k8s/tempo.yaml","w") as f: f.write(yaml_str) @@ -313,6 +378,129 @@ with open(os.getcwd()+"/k8s/tempo.yaml","w") as f: !kustomize build k8s ``` + apiVersion: machinelearning.seldon.io/v1 + kind: SeldonDeployment + metadata: + annotations: + seldon.io/tempo-description: A pipeline to use either an sklearn or xgboost model + for Iris classification + seldon.io/tempo-model: '{"model_details": {"name": "classifier", "local_folder": + "/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/multi-model/artifacts/classifier", + "uri": "s3://tempo/basic/pipeline", "platform": "tempo", "inputs": {"args": + [{"ty": "numpy.ndarray", "name": "payload"}]}, "outputs": {"args": [{"ty": "numpy.ndarray", + "name": null}, {"ty": "builtins.str", "name": null}]}, "description": "A pipeline + to use either an sklearn or xgboost model for Iris classification"}, "protocol": + "tempo.kfserving.protocol.KFServingV2Protocol", "runtime_options": {"runtime": + "tempo.seldon.SeldonKubernetesRuntime", "state_options": {"state_type": "LOCAL", + "key_prefix": "", "host": "", "port": ""}, "insights_options": {"worker_endpoint": + "", "batch_size": 1, "parallelism": 1, "retries": 3, "window_time": 0, "mode_type": + "NONE", "in_asyncio": false}, "ingress_options": {"ingress": "tempo.ingress.istio.IstioIngress", + "ssl": false, "verify_ssl": true}, "replicas": 1, "minReplicas": null, "maxReplicas": + null, "authSecretName": "minio-secret", "serviceAccountName": null, "add_svc_orchestrator": + false, "namespace": "production"}}' + labels: + seldon.io/tempo: "true" + name: classifier + namespace: production + spec: + predictors: + - annotations: + seldon.io/no-engine: "true" + componentSpecs: + - spec: + containers: + - name: classifier + resources: + limits: + cpu: 1 + memory: 1Gi + requests: + cpu: 500m + memory: 500Mi + graph: + envSecretRefName: minio-secret + implementation: TEMPO_SERVER + modelUri: s3://tempo/basic/pipeline + name: classifier + serviceAccountName: tempo-pipeline + type: MODEL + name: default + replicas: 1 + protocol: kfserving + --- + apiVersion: machinelearning.seldon.io/v1 + kind: SeldonDeployment + metadata: + annotations: + seldon.io/tempo-description: An SKLearn Iris classification model + seldon.io/tempo-model: '{"model_details": {"name": "test-iris-sklearn", "local_folder": + "/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/multi-model/artifacts/sklearn", + "uri": "s3://tempo/basic/sklearn", "platform": "sklearn", "inputs": {"args": + [{"ty": "numpy.ndarray", "name": null}]}, "outputs": {"args": [{"ty": "numpy.ndarray", + "name": null}]}, "description": "An SKLearn Iris classification model"}, "protocol": + "tempo.kfserving.protocol.KFServingV2Protocol", "runtime_options": {"runtime": + "tempo.seldon.SeldonKubernetesRuntime", "state_options": {"state_type": "LOCAL", + "key_prefix": "", "host": "", "port": ""}, "insights_options": {"worker_endpoint": + "", "batch_size": 1, "parallelism": 1, "retries": 3, "window_time": 0, "mode_type": + "NONE", "in_asyncio": false}, "ingress_options": {"ingress": "tempo.ingress.istio.IstioIngress", + "ssl": false, "verify_ssl": true}, "replicas": 1, "minReplicas": null, "maxReplicas": + null, "authSecretName": "minio-secret", "serviceAccountName": null, "add_svc_orchestrator": + false, "namespace": "production"}}' + labels: + seldon.io/tempo: "true" + name: test-iris-sklearn + namespace: production + spec: + predictors: + - annotations: + seldon.io/no-engine: "true" + graph: + envSecretRefName: minio-secret + implementation: SKLEARN_SERVER + modelUri: s3://tempo/basic/sklearn + name: test-iris-sklearn + type: MODEL + name: default + replicas: 1 + protocol: kfserving + --- + apiVersion: machinelearning.seldon.io/v1 + kind: SeldonDeployment + metadata: + annotations: + seldon.io/tempo-description: An XGBoost Iris classification model + seldon.io/tempo-model: '{"model_details": {"name": "test-iris-xgboost", "local_folder": + "/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/multi-model/artifacts/xgboost", + "uri": "s3://tempo/basic/xgboost", "platform": "xgboost", "inputs": {"args": + [{"ty": "numpy.ndarray", "name": null}]}, "outputs": {"args": [{"ty": "numpy.ndarray", + "name": null}]}, "description": "An XGBoost Iris classification model"}, "protocol": + "tempo.kfserving.protocol.KFServingV2Protocol", "runtime_options": {"runtime": + "tempo.seldon.SeldonKubernetesRuntime", "state_options": {"state_type": "LOCAL", + "key_prefix": "", "host": "", "port": ""}, "insights_options": {"worker_endpoint": + "", "batch_size": 1, "parallelism": 1, "retries": 3, "window_time": 0, "mode_type": + "NONE", "in_asyncio": false}, "ingress_options": {"ingress": "tempo.ingress.istio.IstioIngress", + "ssl": false, "verify_ssl": true}, "replicas": 1, "minReplicas": null, "maxReplicas": + null, "authSecretName": "minio-secret", "serviceAccountName": null, "add_svc_orchestrator": + false, "namespace": "production"}}' + labels: + seldon.io/tempo: "true" + name: test-iris-xgboost + namespace: production + spec: + predictors: + - annotations: + seldon.io/no-engine: "true" + graph: + envSecretRefName: minio-secret + implementation: XGBOOST_SERVER + modelUri: s3://tempo/basic/xgboost + name: test-iris-xgboost + type: MODEL + name: default + replicas: 1 + protocol: kfserving + + ```python From 174c44e04c84d1843223e61f4840dfe10071fb65 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 26 Jul 2021 12:01:48 +0100 Subject: [PATCH 06/13] Updated custom model example --- docs/examples/custom-model/README.ipynb | 219 ++++++++++++++++++------ docs/examples/custom-model/README.md | 96 +++++++++-- 2 files changed, 253 insertions(+), 62 deletions(-) diff --git a/docs/examples/custom-model/README.ipynb b/docs/examples/custom-model/README.ipynb index d1b85d5c..808dc99b 100644 --- a/docs/examples/custom-model/README.ipynb +++ b/docs/examples/custom-model/README.ipynb @@ -34,9 +34,42 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "model.pickle numpyro-divorce.json\r\n" + ] + } + ], + "source": [ + "!ls artifacts" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[01;34m.\u001b[00m\r\n", + "├── \u001b[01;34martifacts\u001b[00m\r\n", + "├── \u001b[01;34mk8s\u001b[00m\r\n", + "│   └── \u001b[01;34mrbac\u001b[00m\r\n", + "└── \u001b[01;34msrc\u001b[00m\r\n", + " ├── tempo.py\r\n", + " └── train.py\r\n", + "\r\n", + "4 directories, 2 files\r\n" + ] + } + ], "source": [ "!tree -P \"*.py\" -I \"__init__.py|__pycache__\" -L 2" ] @@ -55,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { "code_folding": [ 0 @@ -115,9 +148,30 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "sample: 100%|██████████| 3000/3000 [00:06<00:00, 433.57it/s, 3 steps of size 7.77e-01. acc. prob=0.91]\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " mean std median 5.0% 95.0% n_eff r_hat\n", + " a -0.00 0.11 -0.00 -0.17 0.17 1794.52 1.00\n", + " bM 0.35 0.13 0.35 0.14 0.56 1748.73 1.00\n", + " sigma 0.94 0.10 0.94 0.77 1.09 2144.79 1.00\n", + "\n", + "Number of divergences: 0\n" + ] + } + ], "source": [ "import os\n", "from tempo.utils import logger\n", @@ -144,7 +198,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -178,7 +232,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": { "code_folding": [ 0 @@ -252,7 +306,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -269,9 +323,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[9.673733]\n" + ] + } + ], "source": [ "marriage = np.array([28.0])\n", "age = np.array([63])\n", @@ -293,18 +355,45 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!cat artifacts/conda.yaml" + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting artifacts/conda.yaml\n" + ] + } + ], + "source": [ + "%%writefile artifacts/conda.yaml\n", + "name: tempo\n", + "channels:\n", + " - defaults\n", + "dependencies:\n", + " - python=3.7.9\n", + " - pip:\n", + " - mlops-tempo\n", + " - mlserver==0.3.2\n", + " - numpyro==0.6.0" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting packages...\n", + "Packing environment at '/home/alejandro/miniconda3/envs/tempo-da8e3d00-850c-4235-b8c4-f2ddcd0f6b41' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/custom-model/artifacts/environment.tar.gz'\n", + "[########################################] | 100% Completed | 17.4s\n" + ] + } + ], "source": [ "from tempo.serve.loader import save\n", "save(numpyro_divorce)" @@ -312,12 +401,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "remote_model = deploy(numpyro_divorce)" + "from tempo import deploy_local\n", + "remote_model = deploy_local(numpyro_divorce)" ] }, { @@ -329,16 +418,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([9.673733], dtype=float32)" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "remote_model.predict(marriage=marriage, age=age)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ @@ -360,16 +460,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "secret/minio-secret configured\r\n", + "serviceaccount/tempo-pipeline unchanged\r\n", + "role.rbac.authorization.k8s.io/tempo-pipeline unchanged\r\n", + "rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged\r\n" + ] + } + ], "source": [ "!kubectl apply -f k8s/rbac -n production" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 29, "metadata": {}, "outputs": [], "source": [ @@ -380,7 +491,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "metadata": {}, "outputs": [], "source": [ @@ -390,42 +501,52 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 31, "metadata": {}, "outputs": [], "source": [ - "from tempo.serve.metadata import KubernetesOptions\n", - "from tempo.seldon.k8s import SeldonCoreOptions\n", - "runtime_options = SeldonCoreOptions(\n", - " k8s_options=KubernetesOptions(\n", - " namespace=\"production\",\n", - " authSecretName=\"minio-secret\"\n", - " )\n", - " )" + "from tempo.serve.metadata import SeldonCoreOptions\n", + "runtime_options = SeldonCoreOptions(**{\n", + " \"remote_options\": {\n", + " \"namespace\": \"production\",\n", + " \"authSecretName\": \"minio-secret\"\n", + " }\n", + " })" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "remote_model = deploy(numpyro_divorce, options=runtime_options)" + "from tempo import deploy_remote\n", + "remote_model = deploy_remote(numpyro_divorce, options=runtime_options)" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([9.673733], dtype=float32)" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "remote_model.predict(marriage=marriage, age=age)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "metadata": {}, "outputs": [], "source": [ @@ -495,7 +616,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.9" + "version": "3.7.10" } }, "nbformat": 4, diff --git a/docs/examples/custom-model/README.md b/docs/examples/custom-model/README.md index 18f38b1d..e3f51903 100644 --- a/docs/examples/custom-model/README.md +++ b/docs/examples/custom-model/README.md @@ -16,10 +16,29 @@ conda env create --name tempo-examples --file conda/tempo-examples.yaml ## Project Structure +```python +!ls artifacts +``` + + model.pickle numpyro-divorce.json + + + ```python !tree -P "*.py" -I "__init__.py|__pycache__" -L 2 ``` + . + ├── artifacts + ├── k8s + │   └── rbac + └── src + ├── tempo.py + └── train.py + + 4 directories, 2 files + + ## Training The first step will be to train our model. @@ -93,6 +112,18 @@ from src.train import train, save, model_function mcmc = train() ``` + sample: 100%|██████████| 3000/3000 [00:06<00:00, 433.57it/s, 3 steps of size 7.77e-01. acc. prob=0.91] + + + + mean std median 5.0% 95.0% n_eff r_hat + a -0.00 0.11 -0.00 -0.17 0.17 1794.52 1.00 + bM 0.35 0.13 0.35 0.14 0.56 1748.73 1.00 + sigma 0.94 0.10 0.94 0.77 1.09 2144.79 1.00 + + Number of divergences: 0 + + ### Saving trained model Now that we have _trained_ our model, the next step will be to save it so that it can be loaded afterwards at serving-time. @@ -204,6 +235,9 @@ pred = numpyro_divorce(marriage=marriage, age=age) print(pred) ``` + [9.673733] + + ### Deploy the Model to Docker Finally, we'll be able to deploy our model using Tempo against one of the available runtimes (i.e. Kubernetes, Docker or Seldon Deploy). @@ -212,19 +246,36 @@ We'll deploy first to Docker to test. ```python -!cat artifacts/conda.yaml +%%writefile artifacts/conda.yaml +name: tempo +channels: + - defaults +dependencies: + - python=3.7.9 + - pip: + - mlops-tempo + - mlserver==0.3.2 + - numpyro==0.6.0 ``` + Overwriting artifacts/conda.yaml + + ```python from tempo.serve.loader import save save(numpyro_divorce) ``` + Collecting packages... + Packing environment at '/home/alejandro/miniconda3/envs/tempo-da8e3d00-850c-4235-b8c4-f2ddcd0f6b41' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/custom-model/artifacts/environment.tar.gz' + [########################################] | 100% Completed | 17.4s + + ```python -from tempo import deploy -remote_model = deploy(numpyro_divorce) +from tempo import deploy_local +remote_model = deploy_local(numpyro_divorce) ``` We can now test our model deployed in Docker as: @@ -235,6 +286,13 @@ remote_model.predict(marriage=marriage, age=age) ``` + + + array([9.673733], dtype=float32) + + + + ```python remote_model.undeploy() ``` @@ -252,6 +310,12 @@ Create a Kind Kubernetes cluster with Minio and Seldon Core installed using Ansi !kubectl apply -f k8s/rbac -n production ``` + secret/minio-secret configured + serviceaccount/tempo-pipeline unchanged + role.rbac.authorization.k8s.io/tempo-pipeline unchanged + rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged + + ```python from tempo.examples.minio import create_minio_rclone @@ -267,20 +331,19 @@ upload(numpyro_divorce) ```python -from tempo.serve.metadata import KubernetesOptions -from tempo.seldon.k8s import SeldonCoreOptions -runtime_options = SeldonCoreOptions( - k8s_options=KubernetesOptions( - namespace="production", - authSecretName="minio-secret" - ) - ) +from tempo.serve.metadata import SeldonCoreOptions +runtime_options = SeldonCoreOptions(**{ + "remote_options": { + "namespace": "production", + "authSecretName": "minio-secret" + } + }) ``` ```python -from tempo import deploy -remote_model = deploy(numpyro_divorce, options=runtime_options) +from tempo import deploy_remote +remote_model = deploy_remote(numpyro_divorce, options=runtime_options) ``` @@ -289,6 +352,13 @@ remote_model.predict(marriage=marriage, age=age) ``` + + + array([9.673733], dtype=float32) + + + + ```python remote_model.undeploy() ``` From 9f6815644a231289de9d7ab83a13e49cf0be9a73 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 26 Jul 2021 13:01:30 +0100 Subject: [PATCH 07/13] Updated reamde for mab --- .../mab-thompson-sampling-tempo/README.ipynb | 408 ++++++++++-------- .../mab-thompson-sampling-tempo/README.md | 362 ++++++---------- 2 files changed, 356 insertions(+), 414 deletions(-) diff --git a/docs/examples/mab-thompson-sampling-tempo/README.ipynb b/docs/examples/mab-thompson-sampling-tempo/README.ipynb index 9a7a15e8..6f66e315 100644 --- a/docs/examples/mab-thompson-sampling-tempo/README.ipynb +++ b/docs/examples/mab-thompson-sampling-tempo/README.ipynb @@ -9,7 +9,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 1, "metadata": {}, "outputs": [ { @@ -29,7 +29,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -49,7 +49,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -60,7 +60,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -70,7 +70,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -79,7 +79,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -121,7 +121,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -130,7 +130,7 @@ "RandomForestClassifier(random_state=1)" ] }, - "execution_count": 4, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -143,9 +143,17 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:numexpr.utils:Note: NumExpr detected 16 cores but \"NUMEXPR_MAX_THREADS\" not set, so enforcing safe limit of 8.\n", + "INFO:numexpr.utils:NumExpr defaulting to 8 threads.\n" + ] + }, { "data": { "text/plain": [ @@ -159,7 +167,7 @@ " tree_method='exact', validate_parameters=1, verbosity=None)" ] }, - "execution_count": 5, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } @@ -172,7 +180,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -182,7 +190,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -191,7 +199,7 @@ "['artifacts/mab/sklearn/model.joblib']" ] }, - "execution_count": 7, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -203,7 +211,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -212,15 +220,17 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Insights Manager not initialised as empty URL provided.\n", - "Insights Manager not initialised as empty URL provided.\n" + "INFO:tempo:Initialising Insights Manager with Args: ('', 1, 1, 3, 0)\n", + "WARNING:tempo:Insights Manager not initialised as empty URL provided.\n", + "INFO:tempo:Initialising Insights Manager with Args: ('', 1, 1, 3, 0)\n", + "WARNING:tempo:Insights Manager not initialised as empty URL provided.\n" ] } ], @@ -244,18 +254,18 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "remote_sklearn = deploy(sklearn_tempo)\n", - "remote_xgboost = deploy(xgboost_tempo)" + "from tempo import deploy_local\n", + "remote_sklearn = deploy_local(sklearn_tempo)\n", + "remote_xgboost = deploy_local(xgboost_tempo)" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 14, "metadata": {}, "outputs": [ { @@ -264,7 +274,7 @@ "array([0.], dtype=float32)" ] }, - "execution_count": 11, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -275,7 +285,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 15, "metadata": {}, "outputs": [ { @@ -284,7 +294,7 @@ "array([0.0865844], dtype=float32)" ] }, - "execution_count": 12, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } @@ -295,7 +305,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ @@ -306,14 +316,15 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "Insights Manager not initialised as empty URL provided.\n" + "INFO:tempo:Initialising Insights Manager with Args: ('', 1, 1, 3, 0)\n", + "WARNING:tempo:Insights Manager not initialised as empty URL provided.\n" ] } ], @@ -322,22 +333,31 @@ "\n", "import numpy as np\n", "from tempo.serve.utils import pipeline, predictmethod\n", - "from tempo.serve.metadata import InsightRequestModes, RuntimeOptions, StateTypes\n", - "from tempo.serve.constants import DefaultRedisLocalHost, DefaultRedisPort\n", + "from tempo.serve.metadata import InsightRequestModes, SeldonCoreOptions, StateTypes\n", + "from tempo.serve.constants import DefaultRedisLocalHost, DefaultRedisPort, DefaultRedisK8sHost\n", "from tempo.serve.pipeline import PipelineModels\n", "\n", "from tempo.magic import t\n", "\n", - "local_options = RuntimeOptions(**{\n", - " \"state_options\": {\n", - " \"state_type\": StateTypes.REDIS,\n", - " \"host\": DefaultRedisLocalHost,\n", - " \"port\": DefaultRedisPort,\n", + "runtime_options = SeldonCoreOptions(**{\n", + " \"local_options\": {\n", + " \"state_options\": {\n", + " \"state_type\": StateTypes.REDIS,\n", + " \"host\": DefaultRedisLocalHost,\n", + " \"port\": DefaultRedisPort,\n", + " }\n", + " },\n", + " \"remote_options\": {\n", + " \"state_options\": {\n", + " \"state_type\": StateTypes.REDIS,\n", + " \"host\": DefaultRedisK8sHost,\n", + " \"port\": DefaultRedisPort,\n", + " }\n", " }\n", "})\n", "\n", "@pipeline(name=\"mab-router\",\n", - " runtime_options=local_options,\n", + " runtime_options=runtime_options.local_options,\n", " uri=\"s3://tempo/mab/route\",\n", " local_folder=os.getcwd()+\"/artifacts/mab/router/\",\n", " models=PipelineModels(sklearn=sklearn_tempo, xgboost=xgboost_tempo))\n", @@ -371,32 +391,68 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 30, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:root:Setting up MAB routing pipeline\n" + ] + } + ], "source": [ "mab_router = MABRouter()" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 31, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:root:routing to branch: 0\n", + "INFO:root:routing to branch: 1\n", + "INFO:root:routing to branch: 1\n", + "INFO:root:routing to branch: 0\n", + "INFO:root:routing to branch: 0\n", + "INFO:root:routing to branch: 0\n" + ] + }, { "name": "stdout", "output_type": "stream", "text": [ "[0.]\n", "[0.0865844]\n", + "[0.0865844]\n", "[0.]\n", - "[0.]\n", - "[0.]\n", + "[0.]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:root:routing to branch: 1\n", + "INFO:root:routing to branch: 1\n", + "INFO:root:routing to branch: 1\n", + "INFO:root:routing to branch: 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ "[0.]\n", "[0.0865844]\n", - "[0.]\n", "[0.0865844]\n", - "[0.]\n" + "[0.0865844]\n", + "[0.0865844]\n" ] } ], @@ -407,7 +463,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 32, "metadata": {}, "outputs": [], "source": [ @@ -421,7 +477,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -432,7 +488,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ @@ -450,7 +506,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 23, "metadata": {}, "outputs": [ { @@ -464,8 +520,8 @@ "INFO:tempo:Saving environment\n", "INFO:tempo:Saving tempo model to /home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/router/model.pickle\n", "INFO:tempo:Using found conda.yaml\n", - "INFO:tempo:Creating conda env with: conda env create --name tempo-aef829c8-5b19-46e9-87fb-0fd162870dd6 --file /tmp/tmpevfpqsrj.yml\n", - "INFO:tempo:packing conda environment from tempo-aef829c8-5b19-46e9-87fb-0fd162870dd6\n" + "INFO:tempo:Creating conda env with: conda env create --name tempo-19693e41-b72f-4055-b068-f31ad3b6b72a --file /tmp/tmpuq95cahi.yml\n", + "INFO:tempo:packing conda environment from tempo-19693e41-b72f-4055-b068-f31ad3b6b72a\n" ] }, { @@ -473,15 +529,15 @@ "output_type": "stream", "text": [ "Collecting packages...\n", - "Packing environment at '/home/alejandro/miniconda3/envs/tempo-aef829c8-5b19-46e9-87fb-0fd162870dd6' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/router/environment.tar.gz'\n", - "[########################################] | 100% Completed | 11.8s\n" + "Packing environment at '/home/alejandro/miniconda3/envs/tempo-19693e41-b72f-4055-b068-f31ad3b6b72a' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/router/environment.tar.gz'\n", + "[########################################] | 100% Completed | 10.8s\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ - "INFO:tempo:Removing conda env with: conda remove --name tempo-aef829c8-5b19-46e9-87fb-0fd162870dd6 --all --yes\n" + "INFO:tempo:Removing conda env with: conda remove --name tempo-19693e41-b72f-4055-b068-f31ad3b6b72a --all --yes\n" ] } ], @@ -492,28 +548,21 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 37, "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "from tempo.serve.constants import DefaultRedisDockerHost, DefaultRedisPort\n", - "from tempo.serve.metadata import RuntimeOptions\n", + "from tempo import deploy_local\n", + "from tempo.serve.constants import DefaultRedisDockerHost\n", "\n", - "docker_options = RuntimeOptions(**{\n", - " \"state_options\": {\n", - " \"state_type\": StateTypes.REDIS,\n", - " \"host\": DefaultRedisDockerHost,\n", - " \"port\": DefaultRedisPort,\n", - " }\n", - "})\n", + "runtime_options.local_options.state_options.host = DefaultRedisDockerHost\n", "\n", - "remote_mab_router = deploy(mab_router, docker_options)" + "remote_mab_router = deploy_local(mab_router, runtime_options)" ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 25, "metadata": {}, "outputs": [ { @@ -524,12 +573,12 @@ "[0.]\n", "[0.]\n", "[0.0865844]\n", - "[0.]\n", - "[0.]\n", - "[0.]\n", + "[0.0865844]\n", + "[0.0865844]\n", "[0.0865844]\n", "[0.]\n", - "[0.]\n" + "[0.0865844]\n", + "[0.0865844]\n" ] } ], @@ -540,7 +589,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -554,7 +603,7 @@ ], "source": [ "@pipeline(name=\"mab-feedback\",\n", - " runtime_options=local_options,\n", + " runtime_options=runtime_options.local_options,\n", " uri=\"s3://tempo/mab/feedback\",\n", " local_folder=os.getcwd()+\"/artifacts/mab/feedback/\")\n", "class MABFeedback(object):\n", @@ -592,13 +641,86 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "mab_feedback = MABFeedback()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Deploy Feedback Pipeline" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "%%writetemplate artifacts/mab/feedback/conda.yaml\n", + "name: tempo-insights\n", + "channels:\n", + " - defaults\n", + "dependencies:\n", + " - pip=21.0.1\n", + " - python=3.7.9\n", + " - pip:\n", + " - mlops-tempo @ file://{TEMPO_DIR}\n", + " - mlserver==0.3.1.dev7" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:tempo:Saving environment\n", + "INFO:tempo:Saving tempo model to /home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/feedback/model.pickle\n", + "INFO:tempo:Using found conda.yaml\n", + "INFO:tempo:Creating conda env with: conda env create --name tempo-f6af8217-c4f4-4ca4-be58-f90623d6e72d --file /tmp/tmp84yifu3l.yml\n", + "INFO:tempo:packing conda environment from tempo-f6af8217-c4f4-4ca4-be58-f90623d6e72d\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting packages...\n", + "Packing environment at '/home/alejandro/miniconda3/envs/tempo-f6af8217-c4f4-4ca4-be58-f90623d6e72d' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/feedback/environment.tar.gz'\n", + "[########################################] | 100% Completed | 11.0s\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:tempo:Removing conda env with: conda remove --name tempo-f6af8217-c4f4-4ca4-be58-f90623d6e72d --all --yes\n" + ] + } + ], + "source": [ + "save(mab_feedback, save_env=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "remote_mab_feedback = deploy_local(mab_feedback, runtime_options)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -608,7 +730,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 39, "metadata": {}, "outputs": [ { @@ -630,7 +752,7 @@ ], "source": [ "for i in range(10):\n", - " print(mab_feedback.predict(payload=X_rest[0:1], parameters={ \"reward\": 1, \"routing\": 0}))" + " print(remote_mab_feedback.predict(payload=X_rest[0:1], parameters={ \"reward\": 1, \"routing\": 0}))" ] }, { @@ -642,7 +764,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 40, "metadata": {}, "outputs": [ { @@ -652,7 +774,7 @@ "[0.]\n", "[0.]\n", "[0.]\n", - "[0.0865844]\n", + "[0.]\n", "[0.]\n", "[0.]\n", "[0.]\n", @@ -667,77 +789,6 @@ " print(remote_mab_router.predict(X_test2[0:1]))" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Deploy Feedback Pipeline" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "%%writetemplate artifacts/mab/feedback/conda.yaml\n", - "name: tempo-insights\n", - "channels:\n", - " - defaults\n", - "dependencies:\n", - " - pip=21.0.1\n", - " - python=3.7.9\n", - " - pip:\n", - " - mlops-tempo @ file://{TEMPO_DIR}\n", - " - mlserver==0.3.1.dev7" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:tempo:Saving environment\n", - "INFO:tempo:Saving tempo model to /home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/feedback/model.pickle\n", - "INFO:tempo:Using found conda.yaml\n", - "INFO:tempo:Creating conda env with: conda env create --name tempo-2f333758-498e-463b-be47-c5224339996e --file /tmp/tmpkku9lavy.yml\n", - "INFO:tempo:packing conda environment from tempo-2f333758-498e-463b-be47-c5224339996e\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Collecting packages...\n", - "Packing environment at '/home/alejandro/miniconda3/envs/tempo-2f333758-498e-463b-be47-c5224339996e' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/feedback/environment.tar.gz'\n", - "[########################################] | 100% Completed | 10.6s\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:tempo:Removing conda env with: conda remove --name tempo-2f333758-498e-463b-be47-c5224339996e --all --yes\n" - ] - } - ], - "source": [ - "save(mab_feedback, save_env=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "remote_mab_feedback = deploy(mab_feedback, docker_options)" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -747,7 +798,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 41, "metadata": {}, "outputs": [ { @@ -791,22 +842,22 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[0.]\n", "[0.]\n", "[0.0865844]\n", "[0.0865844]\n", "[0.0865844]\n", "[0.0865844]\n", - "[0.]\n", "[0.0865844]\n", - "[0.]\n", + "[0.0865844]\n", + "[0.0865844]\n", + "[0.0865844]\n", "[0.]\n" ] } @@ -825,7 +876,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 43, "metadata": {}, "outputs": [ { @@ -846,7 +897,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 44, "metadata": {}, "outputs": [], "source": [ @@ -863,7 +914,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 45, "metadata": {}, "outputs": [ { @@ -880,17 +931,17 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "secret/minio-secret created\r\n", - "serviceaccount/tempo-pipeline created\r\n", - "role.rbac.authorization.k8s.io/tempo-pipeline created\r\n", - "rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding created\r\n" + "secret/minio-secret configured\r\n", + "serviceaccount/tempo-pipeline unchanged\r\n", + "role.rbac.authorization.k8s.io/tempo-pipeline unchanged\r\n", + "rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged\r\n" ] } ], @@ -900,7 +951,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 47, "metadata": {}, "outputs": [], "source": [ @@ -911,7 +962,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 48, "metadata": {}, "outputs": [ { @@ -931,7 +982,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 49, "metadata": {}, "outputs": [], "source": [ @@ -942,36 +993,13 @@ }, { "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [], - "source": [ - "from tempo.serve.metadata import RuntimeOptions, KubernetesOptions, StateOptions, StateTypes\n", - "from tempo.serve.constants import DefaultRedisK8sHost, DefaultRedisPort\n", - "from tempo.seldon.k8s import SeldonCoreOptions\n", - "\n", - "kubernetes_options = SeldonCoreOptions(\n", - " k8s_options=KubernetesOptions(\n", - " namespace=\"default\",\n", - " authSecretName=\"minio-secret\"\n", - " ),\n", - " state_options=StateOptions(\n", - " state_type=StateTypes.REDIS,\n", - " host=DefaultRedisK8sHost,\n", - " port=DefaultRedisPort\n", - " )\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": 50, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "k8s_mab_router = deploy(mab_router, options=kubernetes_options)\n", - "k8s_mab_feedback = deploy(mab_feedback, options=kubernetes_options)" + "from tempo import deploy_remote\n", + "k8s_mab_router = deploy_remote(mab_router, options=runtime_options)\n", + "k8s_mab_feedback = deploy_remote(mab_feedback, options=runtime_options)" ] }, { diff --git a/docs/examples/mab-thompson-sampling-tempo/README.md b/docs/examples/mab-thompson-sampling-tempo/README.md index bdd318f2..72f538d9 100644 --- a/docs/examples/mab-thompson-sampling-tempo/README.md +++ b/docs/examples/mab-thompson-sampling-tempo/README.md @@ -12,32 +12,12 @@ logging.info("test") -```python -!kubectl create ns production -``` - - namespace/production created - - - -```python -!kubectl apply -f ../tempo/tests/testdata/tempo-pipeline-rbac.yaml -n production -``` - - serviceaccount/tempo-pipeline unchanged - role.rbac.authorization.k8s.io/tempo-pipeline unchanged - rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged - - - ```python !kaggle datasets download -d uciml/default-of-credit-card-clients-dataset !unzip -o default-of-credit-card-clients-dataset.zip ``` - Downloading default-of-credit-card-clients-dataset.zip to /home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo - 100%|██████████████████████████████████████| 0.98M/0.98M [00:00<00:00, 2.46MB/s] - 100%|██████████████████████████████████████| 0.98M/0.98M [00:00<00:00, 2.46MB/s] + default-of-credit-card-clients-dataset.zip: Skipping, found more recently modified local copy (use --force to force download) Archive: default-of-credit-card-clients-dataset.zip inflating: UCI_Credit_Card.csv @@ -180,15 +160,17 @@ xgboost_tempo = Model( local_folder=os.getcwd()+"/artifacts/mab/xgboost/") ``` - Insights Manager not initialised as empty URL provided. - Insights Manager not initialised as empty URL provided. + INFO:tempo:Initialising Insights Manager with Args: ('', 1, 1, 3, 0) + WARNING:tempo:Insights Manager not initialised as empty URL provided. + INFO:tempo:Initialising Insights Manager with Args: ('', 1, 1, 3, 0) + WARNING:tempo:Insights Manager not initialised as empty URL provided. ```python -from tempo import deploy -remote_sklearn = deploy(sklearn_tempo) -remote_xgboost = deploy(xgboost_tempo) +from tempo import deploy_local +remote_sklearn = deploy_local(sklearn_tempo) +remote_xgboost = deploy_local(xgboost_tempo) ``` @@ -222,31 +204,37 @@ from tempo.docker.utils import deploy_redis deploy_redis() ``` - INFO:tempo:Attempted to deploy message dumper but already deployed - - ```python import logging import numpy as np from tempo.serve.utils import pipeline, predictmethod -from tempo.serve.metadata import InsightRequestModes, RuntimeOptions, StateTypes -from tempo.serve.constants import DefaultRedisLocalHost, DefaultRedisPort +from tempo.serve.metadata import InsightRequestModes, SeldonCoreOptions, StateTypes +from tempo.serve.constants import DefaultRedisLocalHost, DefaultRedisPort, DefaultRedisK8sHost from tempo.serve.pipeline import PipelineModels from tempo.magic import t -local_options = RuntimeOptions(**{ - "state_options": { - "state_type": StateTypes.REDIS, - "host": DefaultRedisLocalHost, - "port": DefaultRedisPort, +runtime_options = SeldonCoreOptions(**{ + "local_options": { + "state_options": { + "state_type": StateTypes.REDIS, + "host": DefaultRedisLocalHost, + "port": DefaultRedisPort, + } + }, + "remote_options": { + "state_options": { + "state_type": StateTypes.REDIS, + "host": DefaultRedisK8sHost, + "port": DefaultRedisPort, + } } }) @pipeline(name="mab-router", - runtime_options=local_options, + runtime_options=runtime_options.local_options, uri="s3://tempo/mab/route", local_folder=os.getcwd()+"/artifacts/mab/router/", models=PipelineModels(sklearn=sklearn_tempo, xgboost=xgboost_tempo)) @@ -293,24 +281,20 @@ mab_router = MABRouter() ```python for i in range(10): - print(mab_router(X_test2[0:1])) + print(mab_router.predict(X_test2[0:1])) ``` INFO:root:routing to branch: 0 INFO:root:routing to branch: 1 - INFO:root:routing to branch: 0 INFO:root:routing to branch: 1 + INFO:root:routing to branch: 0 + INFO:root:routing to branch: 0 + INFO:root:routing to branch: 0 - [0.0865844] [0.] [0.0865844] - - - INFO:root:routing to branch: 1 - INFO:root:routing to branch: 1 - - + [0.0865844] [0.] [0.] @@ -318,17 +302,13 @@ for i in range(10): INFO:root:routing to branch: 1 INFO:root:routing to branch: 1 INFO:root:routing to branch: 1 + INFO:root:routing to branch: 1 [0.] - [0.] - [0.] - - - INFO:root:routing to branch: 0 - - - [0.] + [0.0865844] + [0.0865844] + [0.0865844] [0.0865844] @@ -369,30 +349,33 @@ from tempo.serve.loader import save save(mab_router, save_env=True) ``` - Insights Manager not initialised as empty URL provided. - Insights Manager not initialised as empty URL provided. + INFO:tempo:Initialising Insights Manager with Args: ('', 1, 1, 3, 0) + WARNING:tempo:Insights Manager not initialised as empty URL provided. + INFO:tempo:Initialising Insights Manager with Args: ('', 1, 1, 3, 0) + WARNING:tempo:Insights Manager not initialised as empty URL provided. + INFO:tempo:Saving environment + INFO:tempo:Saving tempo model to /home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/router/model.pickle + INFO:tempo:Using found conda.yaml + INFO:tempo:Creating conda env with: conda env create --name tempo-19693e41-b72f-4055-b068-f31ad3b6b72a --file /tmp/tmpuq95cahi.yml + INFO:tempo:packing conda environment from tempo-19693e41-b72f-4055-b068-f31ad3b6b72a Collecting packages... - Packing environment at '/home/alejandro/miniconda3/envs/tempo-4885c0a3-34a2-4686-ba64-f90e31b1593d' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/router/environment.tar.gz' - [########################################] | 100% Completed | 18.2s + Packing environment at '/home/alejandro/miniconda3/envs/tempo-19693e41-b72f-4055-b068-f31ad3b6b72a' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/router/environment.tar.gz' + [########################################] | 100% Completed | 10.8s + + + INFO:tempo:Removing conda env with: conda remove --name tempo-19693e41-b72f-4055-b068-f31ad3b6b72a --all --yes ```python -from tempo import deploy -from tempo.serve.constants import DefaultRedisDockerHost, DefaultRedisPort -from tempo.serve.metadata import RuntimeOptions +from tempo import deploy_local +from tempo.serve.constants import DefaultRedisDockerHost -docker_options = RuntimeOptions(**{ - "state_options": { - "state_type": StateTypes.REDIS, - "host": DefaultRedisDockerHost, - "port": DefaultRedisPort, - } -}) +runtime_options.local_options.state_options.host = DefaultRedisDockerHost -remote_mab_router = deploy(mab_router, docker_options) +remote_mab_router = deploy_local(mab_router, runtime_options) ``` @@ -401,22 +384,22 @@ for i in range(10): print(remote_mab_router.predict(X_test2[0:1])) ``` - [0.0865844] [0.0865844] [0.] - [0.0865844] + [0.] [0.0865844] [0.0865844] [0.0865844] [0.0865844] [0.] [0.0865844] + [0.0865844] ```python @pipeline(name="mab-feedback", - runtime_options=local_options, + runtime_options=runtime_options.local_options, uri="s3://tempo/mab/feedback", local_folder=os.getcwd()+"/artifacts/mab/feedback/") class MABFeedback(object): @@ -461,122 +444,6 @@ class MABFeedback(object): mab_feedback = MABFeedback() ``` -## Send feedback showing that route sklearn model performs better - - -```python -for i in range(10): - print(mab_feedback(payload=X_rest[0:1], parameters={ "reward": 1, "routing": 0})) -``` - - INFO:root:Feedback method with truth [[ 2.8590e+03 5.0000e+05 1.0000e+00 1.0000e+00 1.0000e+00 4.0000e+01 - -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 - 5.2550e+03 7.2100e+02 1.7252e+04 7.3880e+03 6.0690e+03 0.0000e+00 - 7.2100e+02 1.7252e+04 7.4210e+03 6.0690e+03 0.0000e+00 0.0000e+00]] and parameters {'reward': 1, 'routing': 0} - INFO:root:Sending feedback with route 0 reward 1 - INFO:root:n_success: 1, n_failures: 0 - INFO:root:LINDEX key beta_params on index 0 - INFO:root:Feedback method with truth [[ 2.8590e+03 5.0000e+05 1.0000e+00 1.0000e+00 1.0000e+00 4.0000e+01 - -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 - 5.2550e+03 7.2100e+02 1.7252e+04 7.3880e+03 6.0690e+03 0.0000e+00 - 7.2100e+02 1.7252e+04 7.4210e+03 6.0690e+03 0.0000e+00 0.0000e+00]] and parameters {'reward': 1, 'routing': 0} - INFO:root:Sending feedback with route 0 reward 1 - INFO:root:n_success: 1, n_failures: 0 - INFO:root:LINDEX key beta_params on index 0 - INFO:root:Feedback method with truth [[ 2.8590e+03 5.0000e+05 1.0000e+00 1.0000e+00 1.0000e+00 4.0000e+01 - -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 - 5.2550e+03 7.2100e+02 1.7252e+04 7.3880e+03 6.0690e+03 0.0000e+00 - 7.2100e+02 1.7252e+04 7.4210e+03 6.0690e+03 0.0000e+00 0.0000e+00]] and parameters {'reward': 1, 'routing': 0} - INFO:root:Sending feedback with route 0 reward 1 - INFO:root:n_success: 1, n_failures: 0 - INFO:root:LINDEX key beta_params on index 0 - INFO:root:Feedback method with truth [[ 2.8590e+03 5.0000e+05 1.0000e+00 1.0000e+00 1.0000e+00 4.0000e+01 - -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 - 5.2550e+03 7.2100e+02 1.7252e+04 7.3880e+03 6.0690e+03 0.0000e+00 - 7.2100e+02 1.7252e+04 7.4210e+03 6.0690e+03 0.0000e+00 0.0000e+00]] and parameters {'reward': 1, 'routing': 0} - INFO:root:Sending feedback with route 0 reward 1 - INFO:root:n_success: 1, n_failures: 0 - INFO:root:LINDEX key beta_params on index 0 - INFO:root:Feedback method with truth [[ 2.8590e+03 5.0000e+05 1.0000e+00 1.0000e+00 1.0000e+00 4.0000e+01 - -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 - 5.2550e+03 7.2100e+02 1.7252e+04 7.3880e+03 6.0690e+03 0.0000e+00 - 7.2100e+02 1.7252e+04 7.4210e+03 6.0690e+03 0.0000e+00 0.0000e+00]] and parameters {'reward': 1, 'routing': 0} - INFO:root:Sending feedback with route 0 reward 1 - INFO:root:n_success: 1, n_failures: 0 - INFO:root:LINDEX key beta_params on index 0 - INFO:root:Feedback method with truth [[ 2.8590e+03 5.0000e+05 1.0000e+00 1.0000e+00 1.0000e+00 4.0000e+01 - -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 - 5.2550e+03 7.2100e+02 1.7252e+04 7.3880e+03 6.0690e+03 0.0000e+00 - 7.2100e+02 1.7252e+04 7.4210e+03 6.0690e+03 0.0000e+00 0.0000e+00]] and parameters {'reward': 1, 'routing': 0} - INFO:root:Sending feedback with route 0 reward 1 - INFO:root:n_success: 1, n_failures: 0 - INFO:root:LINDEX key beta_params on index 0 - INFO:root:Feedback method with truth [[ 2.8590e+03 5.0000e+05 1.0000e+00 1.0000e+00 1.0000e+00 4.0000e+01 - -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 - 5.2550e+03 7.2100e+02 1.7252e+04 7.3880e+03 6.0690e+03 0.0000e+00 - 7.2100e+02 1.7252e+04 7.4210e+03 6.0690e+03 0.0000e+00 0.0000e+00]] and parameters {'reward': 1, 'routing': 0} - INFO:root:Sending feedback with route 0 reward 1 - INFO:root:n_success: 1, n_failures: 0 - INFO:root:LINDEX key beta_params on index 0 - INFO:root:Feedback method with truth [[ 2.8590e+03 5.0000e+05 1.0000e+00 1.0000e+00 1.0000e+00 4.0000e+01 - -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 - 5.2550e+03 7.2100e+02 1.7252e+04 7.3880e+03 6.0690e+03 0.0000e+00 - 7.2100e+02 1.7252e+04 7.4210e+03 6.0690e+03 0.0000e+00 0.0000e+00]] and parameters {'reward': 1, 'routing': 0} - INFO:root:Sending feedback with route 0 reward 1 - INFO:root:n_success: 1, n_failures: 0 - INFO:root:LINDEX key beta_params on index 0 - INFO:root:Feedback method with truth [[ 2.8590e+03 5.0000e+05 1.0000e+00 1.0000e+00 1.0000e+00 4.0000e+01 - -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 - 5.2550e+03 7.2100e+02 1.7252e+04 7.3880e+03 6.0690e+03 0.0000e+00 - 7.2100e+02 1.7252e+04 7.4210e+03 6.0690e+03 0.0000e+00 0.0000e+00]] and parameters {'reward': 1, 'routing': 0} - INFO:root:Sending feedback with route 0 reward 1 - INFO:root:n_success: 1, n_failures: 0 - INFO:root:LINDEX key beta_params on index 0 - - - [1 0] - [1 0] - [1 0] - [1 0] - [1 0] - [1 0] - [1 0] - [1 0] - - - INFO:root:Feedback method with truth [[ 2.8590e+03 5.0000e+05 1.0000e+00 1.0000e+00 1.0000e+00 4.0000e+01 - -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 -2.0000e+00 - 5.2550e+03 7.2100e+02 1.7252e+04 7.3880e+03 6.0690e+03 0.0000e+00 - 7.2100e+02 1.7252e+04 7.4210e+03 6.0690e+03 0.0000e+00 0.0000e+00]] and parameters {'reward': 1, 'routing': 0} - INFO:root:Sending feedback with route 0 reward 1 - INFO:root:n_success: 1, n_failures: 0 - INFO:root:LINDEX key beta_params on index 0 - - - [1 0] - [1 0] - - -## See now most requests being sent to sklearn model - - -```python -for i in range(10): - print(remote_mab_router.predict(X_test2[0:1])) -``` - - [0.0865844] - [0.0865844] - [0.0865844] - [0.0865844] - [0.0865844] - [0.] - [0.0865844] - [0.0865844] - [0.0865844] - [0.0865844] - - ### Deploy Feedback Pipeline @@ -601,23 +468,63 @@ save(mab_feedback, save_env=True) INFO:tempo:Saving environment INFO:tempo:Saving tempo model to /home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/feedback/model.pickle INFO:tempo:Using found conda.yaml - INFO:tempo:Creating conda env with: conda env create --name tempo-a70b0c73-effa-4859-b53a-130341b07f76 --file /tmp/tmpcixe4n_l.yml - INFO:tempo:packing conda environment from tempo-a70b0c73-effa-4859-b53a-130341b07f76 + INFO:tempo:Creating conda env with: conda env create --name tempo-f6af8217-c4f4-4ca4-be58-f90623d6e72d --file /tmp/tmp84yifu3l.yml + INFO:tempo:packing conda environment from tempo-f6af8217-c4f4-4ca4-be58-f90623d6e72d Collecting packages... - Packing environment at '/home/alejandro/miniconda3/envs/tempo-a70b0c73-effa-4859-b53a-130341b07f76' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/feedback/environment.tar.gz' - [########################################] | 100% Completed | 24.1s + Packing environment at '/home/alejandro/miniconda3/envs/tempo-f6af8217-c4f4-4ca4-be58-f90623d6e72d' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/mab-thompson-sampling-tempo/artifacts/mab/feedback/environment.tar.gz' + [########################################] | 100% Completed | 11.0s - INFO:tempo:Removing conda env with: conda remove --name tempo-a70b0c73-effa-4859-b53a-130341b07f76 --all --yes + INFO:tempo:Removing conda env with: conda remove --name tempo-f6af8217-c4f4-4ca4-be58-f90623d6e72d --all --yes ```python -remote_mab_feedback = deploy(mab_feedback, docker_options) +remote_mab_feedback = deploy_local(mab_feedback, runtime_options) ``` +## Send feedback showing that route sklearn model performs better + + +```python +for i in range(10): + print(remote_mab_feedback.predict(payload=X_rest[0:1], parameters={ "reward": 1, "routing": 0})) +``` + + [1 0] + [1 0] + [1 0] + [1 0] + [1 0] + [1 0] + [1 0] + [1 0] + [1 0] + [1 0] + + +## See now most requests being sent to sklearn model + + +```python +for i in range(10): + print(remote_mab_router.predict(X_test2[0:1])) +``` + + [0.] + [0.] + [0.] + [0.] + [0.] + [0.] + [0.] + [0.] + [0.] + [0.] + + ### Now send 20 positive requests showing xgboost performing better @@ -656,15 +563,15 @@ for i in range(10): print(remote_mab_router.predict(X_test2[0:1])) ``` - [0.] [0.] [0.0865844] - [0.] [0.0865844] - [0.] [0.0865844] - [0.] - [0.] + [0.0865844] + [0.0865844] + [0.0865844] + [0.0865844] + [0.0865844] [0.] @@ -700,13 +607,13 @@ undeploy_redis() ```python -!kubectl apply -f k8s/rbac -n production +!kubectl apply -f k8s/rbac -n default ``` - secret/minio-secret configured - serviceaccount/tempo-pipeline unchanged - role.rbac.authorization.k8s.io/tempo-pipeline configured - rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged + secret/minio-secret configured + serviceaccount/tempo-pipeline unchanged + role.rbac.authorization.k8s.io/tempo-pipeline unchanged + rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged @@ -736,40 +643,47 @@ deploy_redis() ```python -from tempo.serve.metadata import RuntimeOptions, KubernetesOptions, StateOptions, StateTypes -from tempo.serve.constants import DefaultRedisK8sHost, DefaultRedisPort -from tempo.seldon.k8s import SeldonCoreOptions - -kubernetes_options = SeldonCoreOptions( - k8s_options=KubernetesOptions( - namespace="production", - authSecretName="minio-secret" - ), - state_options=StateOptions( - state_type=StateTypes.REDIS, - host=DefaultRedisK8sHost, - port=DefaultRedisPort - ) - ) +from tempo import deploy_remote +k8s_mab_router = deploy_remote(mab_router, options=runtime_options) +k8s_mab_feedback = deploy_remote(mab_feedback, options=runtime_options) ``` ```python -from tempo import deploy -k8s_mab_router = deploy(mab_router, options=kubernetes_options) -k8s_mab_feedback = deploy(mab_feedback, options=kubernetes_options) +k8s_mab_router.predict(payload=X_rest[0:1]) ``` + + + array([0.0865844], dtype=float32) + + + + ```python -k8s_mab_router.predict(payload=X_rest[0:1]) +k8s_mab_feedback.predict(payload=X_rest[0:1], parameters={"reward":0.0,"routing":0} ) ``` + + + array([0, 1]) + + + + ```python -k8s_mab_router.predict(payload=X_rest[0:1], parameters={"reward":0.0,"routing":0} ) +k8s_mab_router.undeploy() +k8s_mab_feedback.undeploy() ``` + INFO:tempo:Undeploying mab-router + INFO:tempo:Undeploying test-iris-sklearn + INFO:tempo:Undeploying test-iris-xgboost + INFO:tempo:Undeploying mab-feedback + + ```python From 40e5698292deadb3289084363919b07bb8342703 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 26 Jul 2021 13:05:51 +0100 Subject: [PATCH 08/13] Updated docs --- README.md | 29 +++++++++++++++-------------- docs/overview/runtimes.md | 5 +++-- docs/workflow/workflow.md | 23 +++++++++++------------ 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index a218ac9a..bad23dac 100644 --- a/README.md +++ b/README.md @@ -24,14 +24,14 @@ Tempo provides a unified interface to multiple MLOps projects that enable data s * Outlier detectors with Alibi-Detect. * Explainers with Alibi-Explain. * Test Locally - Deploy to Production - * Run with local unit tests. + * Run with local unit tests. * Deploy locally to Docker to test with Docker runtimes. * Deploy to production on Kubernetes - * Extract declarative Kubernetes yaml to follow GitOps workflows. + * Extract declarative Kubernetes yaml to follow GitOps workflows. * Supporting a wide range of production runtimes * Seldon Core open source * KFServing open source - * Seldon Deploy enterprise + * Seldon Deploy enterprise * Create stateful services. Examples: * Multi-Armed Bandits. @@ -97,8 +97,8 @@ save(classifier) Deploy locally to docker. ```python -from tempo import deploy -remote_model = deploy(classifier) +from tempo import deploy_local +remote_model = deploy_local(classifier) ``` Make predictions on containerized servers that would be used in production. @@ -110,15 +110,16 @@ remote_model.predict(np.array([[1, 2, 3, 4]])) Deploy to Kubernetes for production. ```python -from tempo.serve.metadata import KubernetesOptions -from tempo.seldon.k8s import SeldonCoreOptions -runtime_options = SeldonCoreOptions( - k8s_options=KubernetesOptions( - namespace="production", - authSecretName="minio-secret" - ) -) -remote_model = deploy(classifier, options=runtime_options) +from tempo.serve.metadata import SeldonCoreOptions +from tempo import deploy_remote + +runtime_options = SeldonCoreOptions(**{ + "remote_options": { + "namespace": "production", + "authSecretName": "minio-secret" + } +}) +remote_model = deploy_remote(classifier, options=runtime_options) ``` This is an extract from the [multi-model introduction](https://tempo.readthedocs.io/en/latest/examples/multi-model/README.html) demo. diff --git a/docs/overview/runtimes.md b/docs/overview/runtimes.md index 32672084..3b29357a 100644 --- a/docs/overview/runtimes.md +++ b/docs/overview/runtimes.md @@ -4,7 +4,8 @@ Tempo runtimes provide the core functionality to deploy a tempo Model. They must | Method | Action | |--------|---------| -| deploy | deploy a model | +| deploy_local | deploy a model to the product's local runtime | +| deploy_remote | deploy a model to the product's remote runtime | | undeploy | undeploy a model | | wait_ready | wait for a deployed model to be ready | | endpoint | get the URL for the deployed model so it can be called | @@ -17,4 +18,4 @@ The Runtimes defined within Tempo are: | SeldonDockerRuntime | deploy Tempo models to Docker | [Custom model](../examples/custom-model/README.html) | | SeldonKubernetesRuntime | deploy Tempo models to a Kubernetes cluster with Seldon Core installed | [Multi-model](../examples/multi-model/README.html) | | KFServingKubernetesRuntime | deploy Tempo models to a Kubernetes cluster with KFServing installed | [KFServing](../examples/kfserving/README.html) | -| SeldonDeployRuntime | deploy Tempo models to a Kubernetes cluster with Seldon Deploy installed | | \ No newline at end of file +| SeldonDeployRuntime | deploy Tempo models to a Kubernetes cluster with Seldon Deploy installed | | diff --git a/docs/workflow/workflow.md b/docs/workflow/workflow.md index abf6fd50..85740018 100644 --- a/docs/workflow/workflow.md +++ b/docs/workflow/workflow.md @@ -174,8 +174,8 @@ Once saved you can deploy your artifacts using a Runtime. By default tempo will deploy to Docker: ```python -from tempo import deploy -remote_model = deploy(classifier) +from tempo import deploy_local +remote_model = deploy_local(classifier) ``` The returned RemoteModel can be used to get predictions: @@ -210,22 +210,21 @@ For Kubernetes you can use a Kubernetes Runtime such as [SeldonKubernetesRuntime Create appropriate Kubernetes settings as shown below for your use case. This may require creating the appropriate RBAC to allow components to access the remote bucket storage. ``` -from tempo.serve.metadata import KubernetesOptions -from tempo.seldon.k8s import SeldonCoreOptions -runtime_options = SeldonCoreOptions( - k8s_options=KubernetesOptions( - namespace="production", - authSecretName="minio-secret" - ) -) +from tempo.serve.metadata import SeldonCoreOptions +runtime_options = SeldonCoreOptions(**{ + "remote_options": { + "namespace": "production", + "authSecretName": "minio-secret" + } +}) ``` Then you can deploy directly from tempo: ``` -from tempo import deploy -remote_model = deploy(classifier, options=runtime_options) +from tempo import deploy_remote +remote_model = deploy_remote(classifier, options=runtime_options) ``` And then call prediction as before: From abf23133555c0ab5643664c49097bd3965a9245d Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Mon, 26 Jul 2021 13:14:01 +0100 Subject: [PATCH 09/13] rebased --- tempo/seldon/specs.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tempo/seldon/specs.py b/tempo/seldon/specs.py index df2a229c..2a4253a2 100644 --- a/tempo/seldon/specs.py +++ b/tempo/seldon/specs.py @@ -2,12 +2,7 @@ from tempo.k8s.constants import TempoK8sDescriptionAnnotation, TempoK8sLabel, TempoK8sModelSpecAnnotation from tempo.kfserving.protocol import KFServingV1Protocol, KFServingV2Protocol -<<<<<<< HEAD from tempo.seldon.constants import MLSERVER_IMAGE, TRITON_IMAGE -from tempo.seldon.runtime import SeldonCoreOptions -======= -from tempo.seldon.constants import MLSERVER_IMAGE ->>>>>>> 81ad7f4 (Working updated config) from tempo.serve.base import ModelSpec from tempo.serve.constants import ENV_TEMPO_RUNTIME_OPTIONS from tempo.serve.metadata import BaseRuntimeOptionsType, KubernetesRuntimeOptions, ModelDetails, ModelFramework From 299bbce1ba473619732050aef4386c07a9da0e73 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Tue, 27 Jul 2021 08:56:26 +0100 Subject: [PATCH 10/13] Updated outlier docs --- docs/examples/outlier/README.ipynb | 680 ++++++++++++++++-- docs/examples/outlier/README.md | 488 ++++++++++++- .../outlier/README_files/README_24_0.png | Bin 0 -> 5507 bytes .../outlier/README_files/README_25_0.png | Bin 0 -> 5682 bytes .../outlier/README_files/README_33_0.png | Bin 0 -> 5507 bytes .../outlier/README_files/README_34_0.png | Bin 0 -> 5682 bytes .../outlier/artifacts/outlier/conda.yaml | 6 +- .../examples/outlier/artifacts/svc/conda.yaml | 2 +- 8 files changed, 1106 insertions(+), 70 deletions(-) create mode 100644 docs/examples/outlier/README_files/README_24_0.png create mode 100644 docs/examples/outlier/README_files/README_25_0.png create mode 100644 docs/examples/outlier/README_files/README_33_0.png create mode 100644 docs/examples/outlier/README_files/README_34_0.png diff --git a/docs/examples/outlier/README.ipynb b/docs/examples/outlier/README.ipynb index 0045d5d4..38705d64 100644 --- a/docs/examples/outlier/README.ipynb +++ b/docs/examples/outlier/README.ipynb @@ -45,12 +45,36 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "b8ca70f9", "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[01;34m.\u001b[00m\r\n", + "├── \u001b[01;34martifacts\u001b[00m\r\n", + "│   ├── \u001b[01;34mmodel\u001b[00m\r\n", + "│   ├── \u001b[01;34moutlier\u001b[00m\r\n", + "│   └── \u001b[01;34msvc\u001b[00m\r\n", + "├── \u001b[01;34mk8s\u001b[00m\r\n", + "│   └── \u001b[01;34mrbac\u001b[00m\r\n", + "├── \u001b[01;34msrc\u001b[00m\r\n", + "│   ├── constants.py\r\n", + "│   ├── data.py\r\n", + "│   ├── outlier.py\r\n", + "│   ├── tempo.py\r\n", + "│   └── utils.py\r\n", + "└── \u001b[01;34mtests\u001b[00m\r\n", + " └── test_tempo.py\r\n", + "\r\n", + "8 directories, 6 files\r\n" + ] + } + ], "source": [ "!tree -P \"*.py\" -I \"__init__.py|__pycache__\" -L 2" ] @@ -68,7 +92,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "42c20ffa", "metadata": {}, "outputs": [], @@ -87,10 +111,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "aa35a350", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(50000, 32, 32, 3) (50000, 1) (10000, 32, 32, 3) (10000, 1)\n" + ] + } + ], "source": [ "from src.data import Cifar10\n", "data = Cifar10()" @@ -106,7 +138,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "1ce59700", "metadata": {}, "outputs": [], @@ -124,7 +156,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "e7bafec3", "metadata": {}, "outputs": [], @@ -147,10 +179,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "a8345fb6", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "ERROR:fbprophet:Importing plotly failed. Interactive plots will not work.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading from /home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/outlier/artifacts/outlier\n" + ] + } + ], "source": [ "from src.tempo import create_outlier_cls, create_model, create_svc_cls\n", "\n", @@ -163,7 +210,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "c0b0af26", "metadata": { "code_folding": [ @@ -264,7 +311,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "8159cbec", "metadata": { "code_folding": [ @@ -304,10 +351,341 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "aa78ec19", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mTest session starts (platform: linux, Python 3.7.10, pytest 5.3.1, pytest-sugar 0.9.4)\u001b[0m\n", + "rootdir: /home/alejandro/Programming/kubernetes/seldon/tempo, inifile: setup.cfg\n", + "plugins: cases-3.4.6, sugar-0.9.4, xdist-1.30.0, anyio-3.2.1, requests-mock-1.7.0, django-3.8.0, forked-1.1.3, flaky-3.6.1, asyncio-0.14.0, celery-4.4.0, cov-2.8.1\n", + "\u001b[1mcollecting ... \u001b[0m\n", + " \u001b[36mdocs/examples/outlier/tests/\u001b[0mtest_tempo.py\u001b[0m \u001b[32m✓\u001b[0m\u001b[32m✓\u001b[0m \u001b[32m100% \u001b[0m\u001b[40m\u001b[32m█\u001b[0m\u001b[40m\u001b[32m████\u001b[0m\u001b[40m\u001b[32m█\u001b[0m\u001b[40m\u001b[32m████\u001b[0m\n", + "\u001b[33m=============================== warnings summary ===============================\u001b[0m\n", + "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/autograph/impl/api.py:22\n", + " /home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/autograph/impl/api.py:22: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses\n", + " import imp\n", + "\n", + "/home/alejandro/miniconda3/lib/python3.7/site-packages/packaging/version.py:130\n", + " /home/alejandro/miniconda3/lib/python3.7/site-packages/packaging/version.py:130: DeprecationWarning: Creating a LegacyVersion has been deprecated and will be removed in the next major release\n", + " DeprecationWarning,\n", + "\n", + "-- Docs: https://docs.pytest.org/en/latest/warnings.html\n", + "\n", + "Results (5.21s):\n", + "\u001b[32m 2 passed\u001b[0m\n", + "--- Logging error ---\n", + "Traceback (most recent call last):\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\n", + " stream.write(msg + self.terminator)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\n", + " self.buffer.write(obj)\n", + "ValueError: I/O operation on closed file\n", + "Call stack:\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py\", line 77, in destroy_all\n", + " gc.collect(1)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\n", + " .format(pretty_printer.node_names[node_id]))\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\n", + " get_logger().warning(msg, *args, **kwargs)\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.kernel'\n", + "Arguments: ()\n", + "--- Logging error ---\n", + "Traceback (most recent call last):\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\n", + " stream.write(msg + self.terminator)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\n", + " self.buffer.write(obj)\n", + "ValueError: I/O operation on closed file\n", + "Call stack:\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py\", line 77, in destroy_all\n", + " gc.collect(1)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\n", + " .format(pretty_printer.node_names[node_id]))\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\n", + " get_logger().warning(msg, *args, **kwargs)\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.kernel'\n", + "Arguments: ()\n", + "--- Logging error ---\n", + "Traceback (most recent call last):\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\n", + " stream.write(msg + self.terminator)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\n", + " self.buffer.write(obj)\n", + "ValueError: I/O operation on closed file\n", + "Call stack:\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py\", line 77, in destroy_all\n", + " gc.collect(1)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\n", + " .format(pretty_printer.node_names[node_id]))\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\n", + " get_logger().warning(msg, *args, **kwargs)\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.bias'\n", + "Arguments: ()\n", + "--- Logging error ---\n", + "Traceback (most recent call last):\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\n", + " stream.write(msg + self.terminator)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\n", + " self.buffer.write(obj)\n", + "ValueError: I/O operation on closed file\n", + "Call stack:\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py\", line 77, in destroy_all\n", + " gc.collect(1)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\n", + " .format(pretty_printer.node_names[node_id]))\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\n", + " get_logger().warning(msg, *args, **kwargs)\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.bias'\n", + "Arguments: ()\n", + "--- Logging error ---\n", + "Traceback (most recent call last):\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\n", + " stream.write(msg + self.terminator)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\n", + " self.buffer.write(obj)\n", + "ValueError: I/O operation on closed file\n", + "Call stack:\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py\", line 77, in destroy_all\n", + " gc.collect(1)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\n", + " .format(pretty_printer.node_names[node_id]))\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\n", + " get_logger().warning(msg, *args, **kwargs)\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.kernel'\n", + "Arguments: ()\n", + "--- Logging error ---\n", + "Traceback (most recent call last):\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\n", + " stream.write(msg + self.terminator)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\n", + " self.buffer.write(obj)\n", + "ValueError: I/O operation on closed file\n", + "Call stack:\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py\", line 77, in destroy_all\n", + " gc.collect(1)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\n", + " .format(pretty_printer.node_names[node_id]))\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\n", + " get_logger().warning(msg, *args, **kwargs)\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.kernel'\n", + "Arguments: ()\n", + "--- Logging error ---\n", + "Traceback (most recent call last):\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\n", + " stream.write(msg + self.terminator)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\n", + " self.buffer.write(obj)\n", + "ValueError: I/O operation on closed file\n", + "Call stack:\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py\", line 77, in destroy_all\n", + " gc.collect(1)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\n", + " .format(pretty_printer.node_names[node_id]))\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\n", + " get_logger().warning(msg, *args, **kwargs)\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.bias'\n", + "Arguments: ()\n", + "--- Logging error ---\n", + "Traceback (most recent call last):\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\n", + " stream.write(msg + self.terminator)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\n", + " self.buffer.write(obj)\n", + "ValueError: I/O operation on closed file\n", + "Call stack:\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py\", line 77, in destroy_all\n", + " gc.collect(1)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\n", + " .format(pretty_printer.node_names[node_id]))\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\n", + " get_logger().warning(msg, *args, **kwargs)\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.bias'\n", + "Arguments: ()\n", + "--- Logging error ---\n", + "Traceback (most recent call last):\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\n", + " stream.write(msg + self.terminator)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\n", + " self.buffer.write(obj)\n", + "ValueError: I/O operation on closed file\n", + "Call stack:\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py\", line 77, in destroy_all\n", + " gc.collect(1)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 169, in __del__\n", + " \"A checkpoint was restored (e.g. tf.train.Checkpoint.restore or \"\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\n", + " get_logger().warning(msg, *args, **kwargs)\n", + "Message: 'A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.'\n", + "Arguments: ()\n", + "--- Logging error ---\n", + "Traceback (most recent call last):\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\n", + " stream.write(msg + self.terminator)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\n", + " self.buffer.write(obj)\n", + "ValueError: I/O operation on closed file\n", + "Call stack:\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py\", line 77, in destroy_all\n", + " gc.collect(1)\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 169, in __del__\n", + " \"A checkpoint was restored (e.g. tf.train.Checkpoint.restore or \"\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\n", + " get_logger().warning(msg, *args, **kwargs)\n", + "Message: 'A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.'\n", + "Arguments: ()\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--- Logging error ---\r\n", + "Traceback (most recent call last):\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\r\n", + " stream.write(msg + self.terminator)\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\r\n", + " self.buffer.write(obj)\r\n", + "ValueError: I/O operation on closed file\r\n", + "Call stack:\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\r\n", + " .format(pretty_printer.node_names[node_id]))\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\r\n", + " get_logger().warning(msg, *args, **kwargs)\r\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.kernel'\r\n", + "Arguments: ()\r\n", + "--- Logging error ---\r\n", + "Traceback (most recent call last):\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\r\n", + " stream.write(msg + self.terminator)\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\r\n", + " self.buffer.write(obj)\r\n", + "ValueError: I/O operation on closed file\r\n", + "Call stack:\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\r\n", + " .format(pretty_printer.node_names[node_id]))\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\r\n", + " get_logger().warning(msg, *args, **kwargs)\r\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.kernel'\r\n", + "Arguments: ()\r\n", + "--- Logging error ---\r\n", + "Traceback (most recent call last):\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\r\n", + " stream.write(msg + self.terminator)\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\r\n", + " self.buffer.write(obj)\r\n", + "ValueError: I/O operation on closed file\r\n", + "Call stack:\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\r\n", + " .format(pretty_printer.node_names[node_id]))\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\r\n", + " get_logger().warning(msg, *args, **kwargs)\r\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.bias'\r\n", + "Arguments: ()\r\n", + "--- Logging error ---\r\n", + "Traceback (most recent call last):\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\r\n", + " stream.write(msg + self.terminator)\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\r\n", + " self.buffer.write(obj)\r\n", + "ValueError: I/O operation on closed file\r\n", + "Call stack:\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\r\n", + " .format(pretty_printer.node_names[node_id]))\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\r\n", + " get_logger().warning(msg, *args, **kwargs)\r\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.bias'\r\n", + "Arguments: ()\r\n", + "--- Logging error ---\r\n", + "Traceback (most recent call last):\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\r\n", + " stream.write(msg + self.terminator)\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\r\n", + " self.buffer.write(obj)\r\n", + "ValueError: I/O operation on closed file\r\n", + "Call stack:\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\r\n", + " .format(pretty_printer.node_names[node_id]))\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\r\n", + " get_logger().warning(msg, *args, **kwargs)\r\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.kernel'\r\n", + "Arguments: ()\r\n", + "--- Logging error ---\r\n", + "Traceback (most recent call last):\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\r\n", + " stream.write(msg + self.terminator)\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\r\n", + " self.buffer.write(obj)\r\n", + "ValueError: I/O operation on closed file\r\n", + "Call stack:\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\r\n", + " .format(pretty_printer.node_names[node_id]))\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\r\n", + " get_logger().warning(msg, *args, **kwargs)\r\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.kernel'\r\n", + "Arguments: ()\r\n", + "--- Logging error ---\r\n", + "Traceback (most recent call last):\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\r\n", + " stream.write(msg + self.terminator)\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\r\n", + " self.buffer.write(obj)\r\n", + "ValueError: I/O operation on closed file\r\n", + "Call stack:\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\r\n", + " .format(pretty_printer.node_names[node_id]))\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\r\n", + " get_logger().warning(msg, *args, **kwargs)\r\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.bias'\r\n", + "Arguments: ()\r\n", + "--- Logging error ---\r\n", + "Traceback (most recent call last):\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\r\n", + " stream.write(msg + self.terminator)\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\r\n", + " self.buffer.write(obj)\r\n", + "ValueError: I/O operation on closed file\r\n", + "Call stack:\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 161, in __del__\r\n", + " .format(pretty_printer.node_names[node_id]))\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\r\n", + " get_logger().warning(msg, *args, **kwargs)\r\n", + "Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.bias'\r\n", + "Arguments: ()\r\n", + "--- Logging error ---\r\n", + "Traceback (most recent call last):\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\r\n", + " stream.write(msg + self.terminator)\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\r\n", + " self.buffer.write(obj)\r\n", + "ValueError: I/O operation on closed file\r\n", + "Call stack:\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 169, in __del__\r\n", + " \"A checkpoint was restored (e.g. tf.train.Checkpoint.restore or \"\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\r\n", + " get_logger().warning(msg, *args, **kwargs)\r\n", + "Message: 'A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.'\r\n", + "Arguments: ()\r\n", + "--- Logging error ---\r\n", + "Traceback (most recent call last):\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py\", line 1028, in emit\r\n", + " stream.write(msg + self.terminator)\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py\", line 427, in write\r\n", + " self.buffer.write(obj)\r\n", + "ValueError: I/O operation on closed file\r\n", + "Call stack:\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py\", line 169, in __del__\r\n", + " \"A checkpoint was restored (e.g. tf.train.Checkpoint.restore or \"\r\n", + " File \"/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py\", line 178, in warning\r\n", + " get_logger().warning(msg, *args, **kwargs)\r\n", + "Message: 'A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.'\r\n", + "Arguments: ()\r\n" + ] + } + ], "source": [ "!python -m pytest tests/" ] @@ -322,32 +700,96 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "3e1f9017", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting artifacts/outlier/conda.yaml\n" + ] + } + ], "source": [ - "!cat artifacts/outlier/conda.yaml" + "%%writefile artifacts/outlier/conda.yaml\n", + "name: tempo\n", + "channels:\n", + " - defaults\n", + "dependencies:\n", + " - python=3.7.9\n", + " - pip:\n", + " - alibi-detect==0.6.2\n", + " - dill==0.3.2\n", + " - opencv-python-headless\n", + " - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo\n", + " - mlserver==0.3.2" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "9a515728", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting artifacts/svc/conda.yaml\n" + ] + } + ], "source": [ - "!cat artifacts/svc/conda.yaml" + "%%writefile artifacts/svc/conda.yaml\n", + "name: tempo\n", + "channels:\n", + " - defaults\n", + "dependencies:\n", + " - python=3.7.9\n", + " - pip:\n", + " - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo\n", + " - mlserver==0.3.2" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, + "id": "61e4d540", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting packages...\n", + "Packing environment at '/home/alejandro/miniconda3/envs/tempo-1142b4d9-c66f-47db-bd1a-1eccad0afc0b' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/outlier/artifacts/outlier/environment.tar.gz'\n", + "[########################################] | 100% Completed | 56.8s\n" + ] + } + ], + "source": [ + "tempo.save(OutlierModel)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, "id": "3c23ab3b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting packages...\n", + "Packing environment at '/home/alejandro/miniconda3/envs/tempo-e7f7a0d2-eefe-45cc-8dc9-2be0f74d83a1' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/outlier/artifacts/svc/environment.tar.gz'\n", + "[########################################] | 100% Completed | 10.6s\n" + ] + } + ], "source": [ - "tempo.save(OutlierModel)\n", "tempo.save(Cifar10Svc)" ] }, @@ -363,21 +805,53 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "747d2d82", "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "remote_model = deploy(svc)" + "from tempo import deploy_local\n", + "remote_model = deploy_local(svc)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "b22014e7", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "b'{\"model_name\":\"cifar10-service\",\"model_version\":\"NOTIMPLEMENTED\",\"id\":\"7bfbc51d-c042-4517-9d62-4a757eeb0a5f\",\"parameters\":null,\"outputs\":[{\"name\":\"output0\",\"shape\":[1,10],\"datatype\":\"FP64\",\"parameters\":null,\"data\":[3.92254496e-09,1.2045546e-11,2.66010169e-09,0.999992609,2.52212834e-10,5.40860242e-07,6.75951833e-06,4.75118165e-12,6.90873403e-09,1.07275378e-11]}]}'\n" + ] + }, + { + "data": { + "text/plain": [ + "array([[3.92254496e-09, 1.20455460e-11, 2.66010169e-09, 9.99992609e-01,\n", + " 2.52212834e-10, 5.40860242e-07, 6.75951833e-06, 4.75118165e-12,\n", + " 6.90873403e-09, 1.07275378e-11]])" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from src.utils import show_image\n", "show_image(data.X_test[0:1])\n", @@ -386,10 +860,40 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "03ef662f", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "b'{\"model_name\":\"cifar10-service\",\"model_version\":\"NOTIMPLEMENTED\",\"id\":\"6e0124b8-bbb2-4a82-b167-6008ad17c21a\",\"parameters\":null,\"outputs\":[{\"name\":\"output0\",\"shape\":[0],\"datatype\":\"FP64\",\"parameters\":null,\"data\":[]}]}'\n" + ] + }, + { + "data": { + "text/plain": [ + "array([], dtype=float64)" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from src.utils import create_cifar10_outlier\n", "\n", @@ -400,7 +904,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "6c6ea7c7", "metadata": {}, "outputs": [], @@ -424,17 +928,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "id": "d8d2fb32", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "secret/minio-secret configured\r\n", + "serviceaccount/tempo-pipeline unchanged\r\n", + "role.rbac.authorization.k8s.io/tempo-pipeline unchanged\r\n", + "rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged\r\n" + ] + } + ], "source": [ "!kubectl apply -f k8s/rbac -n production" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "id": "9fa80565", "metadata": {}, "outputs": [], @@ -447,7 +962,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "39ff404c", "metadata": {}, "outputs": [], @@ -459,38 +974,69 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "id": "c56b5ca7", "metadata": {}, "outputs": [], "source": [ - "from tempo.serve.metadata import KubernetesOptions\n", - "from tempo.seldon.k8s import SeldonCoreOptions\n", - "runtime_options = SeldonCoreOptions(\n", - " k8s_options=KubernetesOptions(\n", - " namespace=\"production\",\n", - " authSecretName=\"minio-secret\"\n", - " )\n", - " )" + "from tempo.serve.metadata import SeldonCoreOptions\n", + "runtime_options = SeldonCoreOptions(**{\n", + " \"remote_options\": {\n", + " \"namespace\": \"production\",\n", + " \"authSecretName\": \"minio-secret\"\n", + " }\n", + " })" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "id": "73763aee", "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "remote_model = deploy(svc, options=runtime_options)" + "from tempo import deploy_remote\n", + "remote_model = deploy_remote(svc, options=runtime_options)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "id": "8feb662b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAOcAAADnCAYAAADl9EEgAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAU4UlEQVR4nO2dW49k51WG1z7Wubqqp49z6HbPyZPYgOPERo6MSRBIIQiJCyS45Adww+/gHyDhIHGDLEQUiUQIgaVEyA6OPfYY5uBxe7p7pk/Th+qq7jrs2rUPXITL713S3CRL0ftc7qWvatfe+60trfdba3llWQohxB7+r/sECCFuKE5CjEJxEmIUipMQo1CchBgl1II/+JvXYSrXKwu4Lo7cH+v5+L8gTacwluUz/F1xDGN54T7HssAZas/PYcwPYEjKWQN/puDPjOLEeTxQbo3n4/PPiwzGZhm+Z0XhgS/D55HlYI2ITNHniQiOiBTgufI8vCpN8fOR58p1VJ5hX7lnKXiuRvjSyzjFn/e37z1x/ji+OQkxCsVJiFEoTkKMQnESYhSKkxCjUJyEGEW1UlJFu2U5wQtBqrki2G7wBfsUYajYG9rfC3AcvAgvmqYpjGWFco4l/sxAsWBCsMwrsD0gGbadNAugUM4/9arO43lQwWu0z8vx9fAKfI4esIKqyj0LPRzzQ8V2minX2MO+SAmucamYREHw4u9BvjkJMQrFSYhRKE5CjEJxEmIUipMQo1CchBhFtVJKpcJBSpzOL3P3Oi/Hqfdihi2MoKak5QVXFiALo1BS+XEUwVhW4lgxU36b8n1Z5o55Sm8nX7FtvABX6ZSB2y4REZnkbsvk8BTbDaMUn+NwiNcFJb4erar7OsYevs/teg3GahX8DBc+fuZ81RZxnyN+OkRmSiUUPgdCiEkoTkKMQnESYhSKkxCjUJyEGEXN1oY5zshKoGQTwabtSqBkf0Ols4yyu93XNhSDU8y0zJmPzyOKcVZw5aXbMHbeP4Gxk9Ox+7tCnHX1RdmMnuFbOinx+T/ccZ9jWZmHa2YBLmRImzgzPBz0YGzvqO883qzg35UfuteIiKwt4+t4qYWvYzXUeg+5n+NYeYRzJUON4JuTEKNQnIQYheIkxCgUJyFGoTgJMQrFSYhRVCtFa5zvhR0cA63zM639vY9tljTDG5RjpcdNnoNeL8pGdFHa/sdKH5vf/cM/grFPPvgQxvb7p87jI8USyXJsYezsHsPY1t4ejFU6q87jV5c34Jqy0oKxNMT3JWouwliWDJ3HT4/24Zp6B9s9u8PnMJaAXlciIsstvI29Hrk3vuczty0mIqJM0MBrXnwJIeRXAcVJiFEoTkKMQnESYhSKkxCjUJyEGEW1UqY+TpUPxnUYy8G4gG4T2yXtANsbodJPp1BsFg8s03ojaVUu4/EZjL3/rz+Csed9XN3zfOj+vp09/F07B89gLKg2YSwP2jDWaC84j0d1/HlhFVe5VJQRCVUfW0EnqXvMx+rVNbgmmYxgbGsLWym9gXuquIhI4OHf/dKiOxbl2JrxQF8tDb45CTEKxUmIUShOQoxCcRJiFIqTEKNQnIQYRbVSjid4xEBvhqtSfvbBT53Hv3YLp9C/+4o7lS8i0lWaiRWg8kRExAdt830fVxzkJR4joLgDsrWzBWO9Ca7QKOtd5/GgiVP5fvcCxmqdORhLE2wdpGDcQbuL71m7iWNHh4cwdn6GG3y1YvcjWa1h2+bpGW6gFrWWYOz48CmMNZ/ja7zSdp9LzVMqibRJ5QC+OQkxCsVJiFEoTkKMQnESYhSKkxCjUJyEGEWflTKHmzuNT7GuZ7G7gVNvjK2ZcYpna7RjXHlSgLkV/x90Hg4CXFGTpDhlf6yMjjm5wJaO1oCqu+iuthgV53DNguBzDJRKkTTC1zEZua2DZIjPY335EoyNgSUiInIEKk9ERLzIbTsNerh5ligN2yYjXLESxPg5ODrHVUEHoJplfQE/3z4uWMFrXnwJIeRXAcVJiFEoTkKMQnESYhSKkxCjqNnal3/7TRjb/fkXMNacc2dr33wLf1492IGxFGQSRUT8EG9i9yJ35jIv8ab91tI1GPvs800Ya3Zw5vLK+iswVvru7GSkZFaLqXuEg4hImiojL5RrFYBN2/fvfQ7XtCvKyIIG3hTfUPoS7R+6e/5o08gDkOEVEem2cPZ6kOPN6Gc9HNs6HDiPX15egWtCxXFA8M1JiFEoTkKMQnESYhSKkxCjUJyEGIXiJMQoqpVSn8P2wPr12zA2AVnotY2bcM3CDKfK+1vYZpkpG9/zzL2x+c13/gyuWbv+LRjb+K1tGPvk03sw1m3iFPv+kbv/TVjGcE0lwhaGKBOUh8om8AHo69Nt4O/ShjXnivWxsIgnW09n7vt5cua2L0REPGWERkvpcxQG+PFPE7zR/smzXefxxQ62bW5dxaNNEHxzEmIUipMQo1CchBiF4iTEKBQnIUahOAkximqlBBWleuD5Qxh77ZtvOI835nDPluBiD8byDKflQ6VXzZNn7mqWt7u4N5LUr8JQq4HT69UQX6ua0qumGoOKCqUvzpXLqzD24KuvYCyOcZ+m8wv3tXrp6i245vadr8NYr4d78DTbuCpo//DIedzzcX+eThf3aBoovYACxYKp1fE5Ti7cz8EmeN5ERGrxi78H+eYkxCgUJyFGoTgJMQrFSYhRKE5CjEJxEmIU1UqJqm0YSxLcsGg6dZelRIqlUG/g72ooIwYqAa5KaYbu+Qn/8Hd/D9f86V/8NYxFIzytOa7g/znfx+e4cf2K8/hRbx+uSYa4umRlCU8I751jK2iauu/n9Zu4kujGTVyZNPj0LoyNLoYwdj5yn2OW48Zlkwme2N1RJn3nJbY+2h1cjZOl7vsZ+Hhex+6B2yLS4JuTEKNQnIQYheIkxCgUJyFGoTgJMQrFSYhRVCvFC3A6eayk85Oxe3JxpMy0uDjFVRgSYCslEtz4abXjrmT48iGeebK/i2MyxvbGzu42jH1jBc+IubLubv51+WgZrhlt4oZn8xVlDkwH2yxPnmw7j69edls9IiL9czz1eqZYH8+P8ayXovScxz2lGddYsVI8Hz9X7m/6JQ2lMZgU7iqY2MMTu9NTbMMh+OYkxCgUJyFGoTgJMQrFSYhRKE5CjEJxEmIU1UoRbdR3iVPlqwvuGSv1KrZS3v8cN6bqZvi7bs1ju6dacafR4xCn3o+PtmGsmOJmUWs3cNOwQPnd9XbXeXxhGTcaO+3hqo6BUnmSK27VIphfEir2VwKqM0REUjDzRERkkuDqjQycJDouIpJMcYVUluH3z6WFJRjzPPxcxZ77+al4ytyeEldkIfjmJMQoFCchRqE4CTEKxUmIUShOQoyi9xAKcQv8uSbejN5puWNegbNZ5yXeaHxyhrcoL7TwT2jE7oxb7oPR2yKyvb8NY8td3I9m/SYeTZDgr5OPPnGPtdg7wJnhVtOd4RURiSI8cuH+5lN8IuB/ulD+v6dKtnY4wpvAO/N4fEIGNr4fPMc9eBotfF/CADsO9TrOoMZoTIaIyMy9cT8f9eGS5SVOtibkNwaKkxCjUJyEGIXiJMQoFCchRqE4CTGKPtnawxbGypK7980vPxSk5ZUNz6tX8cbxjxV7o+9hC6YM3H2O5hbwJuq5Nt7wHFVxOvwlxUppzrkLAUREfvDuPzqPj5VrdT7pwdh4gns7RcrdXum6f3fSw/2KRqCwQERkro3vy6MvvoSx58+PncfPlREOnQ7+Ye0GnjgelNjjilJ8HQPQS2qxgT9vrqp1LHLDNychRqE4CTEKxUmIUShOQoxCcRJiFIqTEKOoVoq2M7/dxVZKlrs/thLiz7u9sQZjH3+CLYzzCE9eLjz35OLlK9guefDw5zD27d//Kxj78AO8bjRSxhakJ87jR4fP4BrtP3U4w7FQcKq/67urYK7U8LkPjrElkgW4cmZ5Ccfy3F3pok2vTia4b9JI6YGUFdiemSV7MLYUuStuLjdxlcs0w1U6CL45CTEKxUmIUShOQoxCcRJiFIqTEKNQnIQYRbVStOm+3QU8JTnz3B+b+DFcU222YazTwQ2cnj7DE4PffuMV93kM8XiHestdFSEicrC3C2Objx/DWJbjcQE+6KE2OscTu1uXVmFsMMC2wlwTN/96+farzuO/uPcIrrn7aBvG3v7OH8NYFGPL4cmme7L44AL/Lq0JWTLBdsn6Mrboag3cwG5+3r2uDHHDsyzFjcYQfHMSYhSKkxCjUJyEGIXiJMQoFCchRqE4CTGKaqUUmZKWn8eNk0YTd+Onca5Myg7w/8TaNTzl+fF9XBkxGLstk2YDV8BcuwFDsvMYN7va2z+AsbfeegPGxmN3qr91+QpcM38ZN0N72sPWx2SKLaS44Z5f0l68Btd8o4Xvy/Gxe56IiMj2zj0YG03ctlN/gC0RNJVbRGSuxPdlvYktrqU2nhMUee5KnXSGK08aSrM8BN+chBiF4iTEKBQnIUahOAkxCsVJiFHUbO3FKc501ZTeLNPEnQXzCvx1noczuQvzeJzBY/8JjB313C31TwOctZxr4t5Id17FG/Cf7OCePzM8tUD65+6M+K1bt+CaWxs4pbxzgDfM37//PzB2euLejB5XcFa+28Qbx3fv46zx4SnuS+SB4ohAGYWhjfJYV5Kkay1cCFD18Sb2aeJ+fooC96aaZfjzEHxzEmIUipMQo1CchBiF4iTEKBQnIUahOAkximqlPNnENsXara/BWNV3WylFijcGh1Ulra3EWi2c6m+23X2J7tx5Ga75j3//CYyNB7hfUX1+CcY2d49g7NpV9yb8jZdfh2sqMb5t19fwpv5+zz1yQUTkwUN3AUFRYh9or483jp+D4gcRkSTHNtx5320tLa3gTfZPT3GBxvw1bH+dVvB5SIF/Wz9z/7YyxM/pVPk8BN+chBiF4iTEKBQnIUahOAkxCsVJiFEoTkKMolopn21iC2Dt1TdhrBB3NYin7cwvcFXK+YV7QrWISL/vngwtInJp/jXn8e9/77twzWu/cwfG3vuXH8KY5+GeM3NzeJLzlctui6DZ7sA1Qea+viIi8yv4lq5u4MnWg5rbBvj0Hu73czDEJR9lhMdrzK3gKqOFG27rI1BsirzE5/FFiUeKbB5iuycO8GdOEveU7bHyeGcFfj4QfHMSYhSKkxCjUJyEGIXiJMQoFCchRqE4CTGKaqU8HuDpvic5brhURu5Us5/i5lOlkmr20fhnEbm8iqtBfu/b7sqOaoRT6BvreAzCn/z5X8LYP//wxzB2coh/98HA3SwqSdwTnkVEYsE5+94ExzZ3cFWNpG6bpVzAFTzdJTyhuhBsjXkeboRVVN2fWXh4KvpMGfMxyPF3VSNl0nqIrZSR566CmUX4u8oC21gIvjkJMQrFSYhRKE5CjEJxEmIUipMQo1CchBhFt1L6WLs/+i88d+O19QXn8ZUYVwjUI6WaYgXPL1ldwNUPN66DplAlbrZ0oExkfvefsF1y97MHMIZmx4iIwEKdEl/7Msefl1fw9ch9nOoPxW2bZUq1TeZjq62qPVlKFUmSun936eM1oVKxEhR4Lk6ZYNspE7wuKtznGHj4nqUzTrYm5DcGipMQo1CchBiF4iTEKBQnIUZRs7VDMGVYROQ/7z6GsS+/co9x+N43vw7X3LiM2+ZvPXGPChAReeeNV2GsCjYiX6Q4A/nev/0Cxj59sA9j40xp7a9kE/3I/f9YKD2VfA9nGbWsZl7gDf9TkIGc5XiN5+HN3FNRNoGX+LeFIciEBvg9Uq/j5zQWfP45TshK7mFp5GBhNsP3JW7hnlAIvjkJMQrFSYhRKE5CjEJxEmIUipMQo1CchBhFtVIuLSzCWO8Mp8MPzvrO4x/cewTX5LN15UxwqnxRmXjsBW5746OP/xeu+fH7H8LYtMA9cyTEVorvv/h/YD7Fm9tLxWYpFLtEszDQSIMoxI+IFygjBgJ8z0JlXRC4v0+bYB4o19cvsd2TK8UFhWIFIQ9mZQXbga02jiH45iTEKBQnIUahOAkxCsVJiFEoTkKMQnESYhTVStFS3lGErYMscafRt5+fwzXT0UMYe+f12zBW66zC2CBxp7x/+t8fwzVJiSsLZhlOy1cquPKkUPrYjMfu1v4agVIx4WmtarCTIhVgYXi+8ogoMa+CbadaDfceCoF1M1MqPi5GeNJ3rthO0wzfl7muuw+WiMjyqjvWVBonTZTp7Ai+OQkxCsVJiFEoTkKMQnESYhSKkxCjUJyEGEW1UooMVzho4wKKwG0rpIKtmaPhFMbufoEba31/jFPlF6U7fb13htPalSaufsjG+PyTKT7/el2xDsAYCu3zPGXSt6+MT9AqTEpgi5TK/3ek2EfDGX520gxbH8hm0SpqNEtkpIzCaHawXdJZxCNA0sz9mV88wlVXkVIthOCbkxCjUJyEGIXiJMQoFCchRqE4CTEKxUmIUVQrRZQd/VLi9HUQuJsjFSVO82tTl7ePsPXx7ns/gbE/+M63nMe39o/hmnGuNX1SbIUqbmgVxDhWBzNA4hq2KSYX2IrQqjdKxXKIQEVFEOJ7pn1XoFQ0aXNgJuPhC6/RvqvTnYexS8u4ounktAdj/ZND9/GneKbPzY0NGEPwzUmIUShOQoxCcRJiFIqTEKNQnIQYheIkxCiqlTLfwaOykwTbG6OJe9d+HODqjExJ8/tKM7GfffQ5jG3tu6tZBiPcqKs3nMAYKEYQEZFGQ6lmURp8VSru3xYq9ku1hiscAqViJYzwZ+bgfzpTLAxPiZWlMu59hq9/OnNf5FoVW0sLly7BWHcB2yWpUlk1jZVmXRX3dSxCbAeOEvxcIfjmJMQoFCchRqE4CTEKxUmIUShOQoyiZmunSoaposh6mruzcZEy7ThThiSX2uTiGs6S7oAN7r6ymTub4QykllFOkgTGRsq4ADT1GmVxRUQaMc4K1pQN876Pzz+uur+vVsfXN03xxveTHt44XgheF0bu69FtN+Ca5XnsKqys4I3v/RHu03TRP4Ox4cA9ub0zj7/r5PgExhB8cxJiFIqTEKNQnIQYheIkxCgUJyFGoTgJMYpupUywPVAJ8AjlOvjUYoatGWWKgBSCLYBC6WVUgPEPWaps2M7x79JGAmgxbbI1slLOznAqv6dcx3YTWw5zSj+dNuhlVBVszeQFtiJCT9mcX8E3e5q4P7MS4vuifVc2HigxfP7D/imMFWBzfrWCLa5E6XOE4JuTEKNQnIQYheIkxCgUJyFGoTgJMQrFSYhRPM0CIIT8+uCbkxCjUJyEGIXiJMQoFCchRqE4CTEKxUmIUf4PKnTF0hzppjgAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "b'{\"model_name\":\"cifar10-service\",\"model_version\":\"NOTIMPLEMENTED\",\"id\":\"0a638833-4691-4368-9934-0a8b2db0d69c\",\"parameters\":null,\"outputs\":[{\"name\":\"output0\",\"shape\":[1,10],\"datatype\":\"FP64\",\"parameters\":null,\"data\":[3.92254496e-09,1.2045546e-11,2.66010169e-09,0.999992609,2.52212834e-10,5.40860242e-07,6.75951833e-06,4.75118165e-12,6.90873403e-09,1.07275378e-11]}]}'\n" + ] + }, + { + "data": { + "text/plain": [ + "array([[3.92254496e-09, 1.20455460e-11, 2.66010169e-09, 9.99992609e-01,\n", + " 2.52212834e-10, 5.40860242e-07, 6.75951833e-06, 4.75118165e-12,\n", + " 6.90873403e-09, 1.07275378e-11]])" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from src.utils import show_image\n", "\n", @@ -500,10 +1046,40 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "id": "97b59a44", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "b'{\"model_name\":\"cifar10-service\",\"model_version\":\"NOTIMPLEMENTED\",\"id\":\"4b7a7df0-6f37-4052-b5be-c2cf277bb1ee\",\"parameters\":null,\"outputs\":[{\"name\":\"output0\",\"shape\":[0],\"datatype\":\"FP64\",\"parameters\":null,\"data\":[]}]}'\n" + ] + }, + { + "data": { + "text/plain": [ + "array([], dtype=float64)" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from src.utils import create_cifar10_outlier\n", "\n", @@ -514,7 +1090,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "id": "c789f08b", "metadata": {}, "outputs": [], @@ -584,7 +1160,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.9" + "version": "3.7.10" } }, "nbformat": 4, diff --git a/docs/examples/outlier/README.md b/docs/examples/outlier/README.md index 7e7b2cc1..a6b13769 100644 --- a/docs/examples/outlier/README.md +++ b/docs/examples/outlier/README.md @@ -28,6 +28,25 @@ conda env create --name tempo-examples --file conda/tempo-examples.yaml !tree -P "*.py" -I "__init__.py|__pycache__" -L 2 ``` + . + ├── artifacts + │   ├── model + │   ├── outlier + │   └── svc + ├── k8s + │   └── rbac + ├── src + │   ├── constants.py + │   ├── data.py + │   ├── outlier.py + │   ├── tempo.py + │   └── utils.py + └── tests + └── test_tempo.py + + 8 directories, 6 files + + ## Train Models * This section is where as a data scientist you do your work of training models and creating artfacts. @@ -53,6 +72,9 @@ from src.data import Cifar10 data = Cifar10() ``` + (50000, 32, 32, 3) (50000, 1) (10000, 32, 32, 3) (10000, 1) + + Download pretrained Resnet32 Tensorflow model for CIFAR10 @@ -86,6 +108,12 @@ Cifar10Svc = create_svc_cls(outlier, cifar10_model) svc = Cifar10Svc() ``` + ERROR:fbprophet:Importing plotly failed. Interactive plots will not work. + + + Loading from /home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/outlier/artifacts/outlier + + ```python # %load src/tempo.py @@ -210,33 +238,392 @@ def test_svc_inlier(): !python -m pytest tests/ ``` + Test session starts (platform: linux, Python 3.7.10, pytest 5.3.1, pytest-sugar 0.9.4) + rootdir: /home/alejandro/Programming/kubernetes/seldon/tempo, inifile: setup.cfg + plugins: cases-3.4.6, sugar-0.9.4, xdist-1.30.0, anyio-3.2.1, requests-mock-1.7.0, django-3.8.0, forked-1.1.3, flaky-3.6.1, asyncio-0.14.0, celery-4.4.0, cov-2.8.1 + collecting ...  + docs/examples/outlier/tests/test_tempo.py ✓✓ 100% ██████████ + =============================== warnings summary =============================== + /home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/autograph/impl/api.py:22 + /home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/autograph/impl/api.py:22: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses + import imp + + /home/alejandro/miniconda3/lib/python3.7/site-packages/packaging/version.py:130 + /home/alejandro/miniconda3/lib/python3.7/site-packages/packaging/version.py:130: DeprecationWarning: Creating a LegacyVersion has been deprecated and will be removed in the next major release + DeprecationWarning, + + -- Docs: https://docs.pytest.org/en/latest/warnings.html + + Results (5.21s): +  2 passed + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py", line 77, in destroy_all + gc.collect(1) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.kernel' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py", line 77, in destroy_all + gc.collect(1) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.kernel' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py", line 77, in destroy_all + gc.collect(1) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.bias' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py", line 77, in destroy_all + gc.collect(1) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.bias' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py", line 77, in destroy_all + gc.collect(1) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.kernel' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py", line 77, in destroy_all + gc.collect(1) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.kernel' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py", line 77, in destroy_all + gc.collect(1) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.bias' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py", line 77, in destroy_all + gc.collect(1) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.bias' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py", line 77, in destroy_all + gc.collect(1) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 169, in __del__ + "A checkpoint was restored (e.g. tf.train.Checkpoint.restore or " + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py", line 77, in destroy_all + gc.collect(1) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 169, in __del__ + "A checkpoint was restored (e.g. tf.train.Checkpoint.restore or " + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.kernel' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.kernel' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.bias' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_mean.bias' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.kernel' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.kernel' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.bias' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 161, in __del__ + .format(pretty_printer.node_names[node_id])) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'Unresolved object in checkpoint: (root).encoder.fc_log_var.bias' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 169, in __del__ + "A checkpoint was restored (e.g. tf.train.Checkpoint.restore or " + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.' + Arguments: () + --- Logging error --- + Traceback (most recent call last): + File "/home/alejandro/miniconda3/lib/python3.7/logging/__init__.py", line 1028, in emit + stream.write(msg + self.terminator) + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/_pytest/capture.py", line 427, in write + self.buffer.write(obj) + ValueError: I/O operation on closed file + Call stack: + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/training/tracking/util.py", line 169, in __del__ + "A checkpoint was restored (e.g. tf.train.Checkpoint.restore or " + File "/home/alejandro/miniconda3/lib/python3.7/site-packages/tensorflow/python/platform/tf_logging.py", line 178, in warning + get_logger().warning(msg, *args, **kwargs) + Message: 'A checkpoint was restored (e.g. tf.train.Checkpoint.restore or tf.keras.Model.load_weights) but not all checkpointed values were used. See above for specific issues. Use expect_partial() on the load status object, e.g. tf.train.Checkpoint.restore(...).expect_partial(), to silence these warnings, or use assert_consumed() to make the check explicit. See https://www.tensorflow.org/guide/checkpoint#loading_mechanics for details.' + Arguments: () + + ## Save Outlier and Svc Environments ```python -!cat artifacts/outlier/conda.yaml +%%writefile artifacts/outlier/conda.yaml +name: tempo +channels: + - defaults +dependencies: + - python=3.7.9 + - pip: + - alibi-detect==0.6.2 + - dill==0.3.2 + - opencv-python-headless + - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo + - mlserver==0.3.2 ``` + Overwriting artifacts/outlier/conda.yaml + + ```python -!cat artifacts/svc/conda.yaml +%%writefile artifacts/svc/conda.yaml +name: tempo +channels: + - defaults +dependencies: + - python=3.7.9 + - pip: + - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo + - mlserver==0.3.2 ``` + Overwriting artifacts/svc/conda.yaml + + ```python tempo.save(OutlierModel) +``` + + Collecting packages... + Packing environment at '/home/alejandro/miniconda3/envs/tempo-1142b4d9-c66f-47db-bd1a-1eccad0afc0b' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/outlier/artifacts/outlier/environment.tar.gz' + [########################################] | 100% Completed | 56.8s + + + +```python tempo.save(Cifar10Svc) ``` + Collecting packages... + Packing environment at '/home/alejandro/miniconda3/envs/tempo-e7f7a0d2-eefe-45cc-8dc9-2be0f74d83a1' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/outlier/artifacts/svc/environment.tar.gz' + [########################################] | 100% Completed | 10.6s + + ## Test Locally on Docker Here we test our models using production images but running locally on Docker. This allows us to ensure the final production deployed model will behave as expected when deployed. ```python -from tempo import deploy -remote_model = deploy(svc) +from tempo import deploy_local +remote_model = deploy_local(svc) ``` @@ -247,6 +634,24 @@ remote_model.predict(payload=data.X_test[0:1]) ``` + +![png](README_files/README_24_0.png) + + + + b'{"model_name":"cifar10-service","model_version":"NOTIMPLEMENTED","id":"7bfbc51d-c042-4517-9d62-4a757eeb0a5f","parameters":null,"outputs":[{"name":"output0","shape":[1,10],"datatype":"FP64","parameters":null,"data":[3.92254496e-09,1.2045546e-11,2.66010169e-09,0.999992609,2.52212834e-10,5.40860242e-07,6.75951833e-06,4.75118165e-12,6.90873403e-09,1.07275378e-11]}]}' + + + + + + array([[3.92254496e-09, 1.20455460e-11, 2.66010169e-09, 9.99992609e-01, + 2.52212834e-10, 5.40860242e-07, 6.75951833e-06, 4.75118165e-12, + 6.90873403e-09, 1.07275378e-11]]) + + + + ```python from src.utils import create_cifar10_outlier @@ -256,6 +661,22 @@ remote_model.predict(payload=outlier_img) ``` + +![png](README_files/README_25_0.png) + + + + b'{"model_name":"cifar10-service","model_version":"NOTIMPLEMENTED","id":"6e0124b8-bbb2-4a82-b167-6008ad17c21a","parameters":null,"outputs":[{"name":"output0","shape":[0],"datatype":"FP64","parameters":null,"data":[]}]}' + + + + + + array([], dtype=float64) + + + + ```python remote_model.undeploy() ``` @@ -273,6 +694,12 @@ Create a Kind Kubernetes cluster with Minio and Seldon Core installed using Ansi !kubectl apply -f k8s/rbac -n production ``` + secret/minio-secret configured + serviceaccount/tempo-pipeline unchanged + role.rbac.authorization.k8s.io/tempo-pipeline unchanged + rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged + + ```python from tempo.examples.minio import create_minio_rclone @@ -290,20 +717,19 @@ tempo.upload(svc) ```python -from tempo.serve.metadata import KubernetesOptions -from tempo.seldon.k8s import SeldonCoreOptions -runtime_options = SeldonCoreOptions( - k8s_options=KubernetesOptions( - namespace="production", - authSecretName="minio-secret" - ) - ) +from tempo.serve.metadata import SeldonCoreOptions +runtime_options = SeldonCoreOptions(**{ + "remote_options": { + "namespace": "production", + "authSecretName": "minio-secret" + } + }) ``` ```python -from tempo import deploy -remote_model = deploy(svc, options=runtime_options) +from tempo import deploy_remote +remote_model = deploy_remote(svc, options=runtime_options) ``` @@ -315,6 +741,24 @@ remote_model.predict(payload=data.X_test[0:1]) ``` + +![png](README_files/README_33_0.png) + + + + b'{"model_name":"cifar10-service","model_version":"NOTIMPLEMENTED","id":"0a638833-4691-4368-9934-0a8b2db0d69c","parameters":null,"outputs":[{"name":"output0","shape":[1,10],"datatype":"FP64","parameters":null,"data":[3.92254496e-09,1.2045546e-11,2.66010169e-09,0.999992609,2.52212834e-10,5.40860242e-07,6.75951833e-06,4.75118165e-12,6.90873403e-09,1.07275378e-11]}]}' + + + + + + array([[3.92254496e-09, 1.20455460e-11, 2.66010169e-09, 9.99992609e-01, + 2.52212834e-10, 5.40860242e-07, 6.75951833e-06, 4.75118165e-12, + 6.90873403e-09, 1.07275378e-11]]) + + + + ```python from src.utils import create_cifar10_outlier @@ -324,6 +768,22 @@ remote_model.predict(payload=outlier_img) ``` + +![png](README_files/README_34_0.png) + + + + b'{"model_name":"cifar10-service","model_version":"NOTIMPLEMENTED","id":"4b7a7df0-6f37-4052-b5be-c2cf277bb1ee","parameters":null,"outputs":[{"name":"output0","shape":[0],"datatype":"FP64","parameters":null,"data":[]}]}' + + + + + + array([], dtype=float64) + + + + ```python remote_model.undeploy() ``` diff --git a/docs/examples/outlier/README_files/README_24_0.png b/docs/examples/outlier/README_files/README_24_0.png new file mode 100644 index 0000000000000000000000000000000000000000..8d4241ada9a68bd393bf758b61f064d607e413c4 GIT binary patch literal 5507 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 literal 0 HcmV?d00001 diff --git a/docs/examples/outlier/README_files/README_33_0.png b/docs/examples/outlier/README_files/README_33_0.png new file mode 100644 index 0000000000000000000000000000000000000000..8d4241ada9a68bd393bf758b61f064d607e413c4 GIT binary patch literal 5507 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 literal 0 HcmV?d00001 diff --git a/docs/examples/outlier/artifacts/outlier/conda.yaml b/docs/examples/outlier/artifacts/outlier/conda.yaml index 37a24703..e2062741 100644 --- a/docs/examples/outlier/artifacts/outlier/conda.yaml +++ b/docs/examples/outlier/artifacts/outlier/conda.yaml @@ -4,8 +4,8 @@ channels: dependencies: - python=3.7.9 - pip: - - alibi-detect - - dill + - alibi-detect==0.6.2 + - dill==0.3.2 - opencv-python-headless - - mlops-tempo + - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo - mlserver==0.3.2 diff --git a/docs/examples/outlier/artifacts/svc/conda.yaml b/docs/examples/outlier/artifacts/svc/conda.yaml index 9fc2310e..105ba597 100644 --- a/docs/examples/outlier/artifacts/svc/conda.yaml +++ b/docs/examples/outlier/artifacts/svc/conda.yaml @@ -4,5 +4,5 @@ channels: dependencies: - python=3.7.9 - pip: - - mlops-tempo + - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo - mlserver==0.3.2 From d92b8ecb1f4964c32abeddb4d2162cc1c4bcaaea Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Tue, 27 Jul 2021 09:09:20 +0100 Subject: [PATCH 11/13] Updated outlier example --- docs/examples/outlier/README.ipynb | 8 ++++---- docs/examples/outlier/README.md | 4 ++-- docs/examples/outlier/artifacts/outlier/conda.yaml | 2 +- docs/examples/outlier/artifacts/svc/conda.yaml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/examples/outlier/README.ipynb b/docs/examples/outlier/README.ipynb index 38705d64..7d76eb92 100644 --- a/docs/examples/outlier/README.ipynb +++ b/docs/examples/outlier/README.ipynb @@ -700,7 +700,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 29, "id": "3e1f9017", "metadata": {}, "outputs": [ @@ -723,13 +723,13 @@ " - alibi-detect==0.6.2\n", " - dill==0.3.2\n", " - opencv-python-headless\n", - " - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo\n", + " - mlops-tempo\n", " - mlserver==0.3.2" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 30, "id": "9a515728", "metadata": {}, "outputs": [ @@ -749,7 +749,7 @@ "dependencies:\n", " - python=3.7.9\n", " - pip:\n", - " - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo\n", + " - mlops-tempo\n", " - mlserver==0.3.2" ] }, diff --git a/docs/examples/outlier/README.md b/docs/examples/outlier/README.md index a6b13769..d7899ae8 100644 --- a/docs/examples/outlier/README.md +++ b/docs/examples/outlier/README.md @@ -573,7 +573,7 @@ dependencies: - alibi-detect==0.6.2 - dill==0.3.2 - opencv-python-headless - - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo + - mlops-tempo - mlserver==0.3.2 ``` @@ -589,7 +589,7 @@ channels: dependencies: - python=3.7.9 - pip: - - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo + - mlops-tempo - mlserver==0.3.2 ``` diff --git a/docs/examples/outlier/artifacts/outlier/conda.yaml b/docs/examples/outlier/artifacts/outlier/conda.yaml index e2062741..c649ccc6 100644 --- a/docs/examples/outlier/artifacts/outlier/conda.yaml +++ b/docs/examples/outlier/artifacts/outlier/conda.yaml @@ -7,5 +7,5 @@ dependencies: - alibi-detect==0.6.2 - dill==0.3.2 - opencv-python-headless - - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo + - mlops-tempo - mlserver==0.3.2 diff --git a/docs/examples/outlier/artifacts/svc/conda.yaml b/docs/examples/outlier/artifacts/svc/conda.yaml index 105ba597..9fc2310e 100644 --- a/docs/examples/outlier/artifacts/svc/conda.yaml +++ b/docs/examples/outlier/artifacts/svc/conda.yaml @@ -4,5 +4,5 @@ channels: dependencies: - python=3.7.9 - pip: - - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo + - mlops-tempo - mlserver==0.3.2 From 80cfc6295e94d7dac9f3df1ff8a7ae3aa913da87 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Tue, 27 Jul 2021 09:53:44 +0100 Subject: [PATCH 12/13] Udpated explainer example --- docs/examples/explainer/README.ipynb | 194 ++++++++++++++---- docs/examples/explainer/README.md | 90 ++++++-- .../explainer/artifacts/explainer/conda.yaml | 2 +- 3 files changed, 229 insertions(+), 57 deletions(-) diff --git a/docs/examples/explainer/README.ipynb b/docs/examples/explainer/README.ipynb index 8bfe4c76..acf9dccd 100644 --- a/docs/examples/explainer/README.ipynb +++ b/docs/examples/explainer/README.ipynb @@ -45,12 +45,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "b8ca70f9", "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[01;34m.\u001b[00m\r\n", + "├── \u001b[01;34martifacts\u001b[00m\r\n", + "│   ├── \u001b[01;34mexplainer\u001b[00m\r\n", + "│   └── \u001b[01;34mmodel\u001b[00m\r\n", + "├── \u001b[01;34mk8s\u001b[00m\r\n", + "│   └── \u001b[01;34mrbac\u001b[00m\r\n", + "└── \u001b[01;34msrc\u001b[00m\r\n", + " ├── constants.py\r\n", + " ├── data.py\r\n", + " ├── explainer.py\r\n", + " ├── model.py\r\n", + " └── tempo.py\r\n", + "\r\n", + "6 directories, 5 files\r\n" + ] + } + ], "source": [ "!tree -P \"*.py\" -I \"__init__.py|__pycache__\" -L 2" ] @@ -68,7 +89,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "42c20ffa", "metadata": {}, "outputs": [], @@ -89,7 +110,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "aa35a350", "metadata": {}, "outputs": [], @@ -101,10 +122,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "9bc17ab0", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train accuracy: 0.9656333333333333\n", + "Test accuracy: 0.854296875\n" + ] + } + ], "source": [ "from src.model import train_model\n", "\n", @@ -113,10 +143,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "7afce019", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "AnchorTabular(meta={\n", + " 'name': 'AnchorTabular',\n", + " 'type': ['blackbox'],\n", + " 'explanations': ['local'],\n", + " 'params': {'disc_perc': (25, 50, 75), 'seed': 1}}\n", + ")" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "from src.explainer import train_explainer\n", "\n", @@ -133,7 +179,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "id": "a8345fb6", "metadata": {}, "outputs": [], @@ -147,7 +193,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "id": "c0b0af26", "metadata": { "code_folding": [ @@ -228,20 +274,48 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 48, "id": "3e1f9017", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting artifacts/explainer/conda.yaml\n" + ] + } + ], "source": [ - "!cat artifacts/explainer/conda.yaml" + "%%writefile artifacts/explainer/conda.yaml\n", + "name: tempo\n", + "channels:\n", + " - defaults\n", + "dependencies:\n", + " - python=3.7.9\n", + " - pip:\n", + " - alibi==0.5.8\n", + " - dill\n", + " - mlops-tempo\n", + " - mlserver==0.3.2" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "id": "3c23ab3b", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting packages...\n", + "Packing environment at '/home/alejandro/miniconda3/envs/tempo-56577a22-797a-479e-a1f7-d01eabf38dcb' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/explainer/artifacts/explainer/environment.tar.gz'\n", + "[########################################] | 100% Completed | 1min 12.1s\n" + ] + } + ], "source": [ "tempo.save(Explainer)" ] @@ -258,21 +332,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 33, "id": "a39ade59", "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "remote_model = deploy(explainer)" + "from tempo import deploy_local\n", + "remote_model = deploy_local(explainer)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "id": "fb09a516", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Marital Status = Separated']\n" + ] + } + ], "source": [ "r = json.loads(remote_model.predict(payload=data.X_test[0:1], parameters={\"threshold\":0.90}))\n", "print(r[\"data\"][\"anchor\"])" @@ -280,10 +362,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 35, "id": "b22014e7", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Relationship = Unmarried', 'Sex = Female', 'Capital Gain <= 0.00', 'Marital Status = Separated', 'Education = Associates']\n" + ] + } + ], "source": [ "r = json.loads(remote_model.predict(payload=data.X_test[0:1], parameters={\"threshold\":0.99}))\n", "print(r[\"data\"][\"anchor\"])" @@ -291,7 +381,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "id": "6c6ea7c7", "metadata": {}, "outputs": [], @@ -315,17 +405,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "id": "d8d2fb32", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "secret/minio-secret configured\r\n", + "serviceaccount/tempo-pipeline unchanged\r\n", + "role.rbac.authorization.k8s.io/tempo-pipeline unchanged\r\n", + "rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged\r\n" + ] + } + ], "source": [ "!kubectl apply -f k8s/rbac -n production" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 38, "id": "9fa80565", "metadata": {}, "outputs": [], @@ -337,7 +438,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 42, "id": "39ff404c", "metadata": {}, "outputs": [], @@ -348,38 +449,45 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 44, "id": "c56b5ca7", "metadata": {}, "outputs": [], "source": [ - "from tempo.serve.metadata import KubernetesOptions\n", - "from tempo.seldon.k8s import SeldonCoreOptions\n", - "runtime_options = SeldonCoreOptions(\n", - " k8s_options=KubernetesOptions(\n", - " namespace=\"production\",\n", - " authSecretName=\"minio-secret\"\n", - " )\n", - " )" + "from tempo.serve.metadata import SeldonCoreOptions\n", + "runtime_options = SeldonCoreOptions(**{\n", + " \"remote_options\": {\n", + " \"namespace\": \"production\",\n", + " \"authSecretName\": \"minio-secret\"\n", + " }\n", + " })" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 45, "id": "f59b1d53", "metadata": {}, "outputs": [], "source": [ - "from tempo import deploy\n", - "remote_model = deploy(explainer, options=runtime_options)" + "from tempo import deploy_remote\n", + "remote_model = deploy_remote(explainer, options=runtime_options)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 46, "id": "97b59a44", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Marital Status = Separated', 'Sex = Female', 'Capital Gain <= 0.00']\n" + ] + } + ], "source": [ "r = json.loads(remote_model.predict(payload=data.X_test[0:1], parameters={\"threshold\":0.95}))\n", "print(r[\"data\"][\"anchor\"])" @@ -387,7 +495,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 47, "id": "c789f08b", "metadata": {}, "outputs": [], @@ -457,7 +565,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.9" + "version": "3.7.10" } }, "nbformat": 4, diff --git a/docs/examples/explainer/README.md b/docs/examples/explainer/README.md index 0f4c98fc..2e190e86 100644 --- a/docs/examples/explainer/README.md +++ b/docs/examples/explainer/README.md @@ -28,6 +28,22 @@ conda env create --name tempo-examples --file conda/tempo-examples.yaml !tree -P "*.py" -I "__init__.py|__pycache__" -L 2 ``` + . + ├── artifacts + │   ├── explainer + │   └── model + ├── k8s + │   └── rbac + └── src + ├── constants.py + ├── data.py + ├── explainer.py + ├── model.py + └── tempo.py + + 6 directories, 5 files + + ## Train Models * This section is where as a data scientist you do your work of training models and creating artfacts. @@ -63,6 +79,10 @@ from src.model import train_model adult_model = train_model(ARTIFACTS_FOLDER, data) ``` + Train accuracy: 0.9656333333333333 + Test accuracy: 0.854296875 + + ```python from src.explainer import train_explainer @@ -70,6 +90,18 @@ from src.explainer import train_explainer train_explainer(ARTIFACTS_FOLDER, data, adult_model) ``` + + + + AnchorTabular(meta={ + 'name': 'AnchorTabular', + 'type': ['blackbox'], + 'explanations': ['local'], + 'params': {'disc_perc': (25, 50, 75), 'seed': 1}} + ) + + + ## Create Tempo Artifacts @@ -152,22 +184,40 @@ def create_explainer(model: Model) -> Tuple[Model, Any]: ```python -!cat artifacts/explainer/conda.yaml +%%writefile artifacts/explainer/conda.yaml +name: tempo +channels: + - defaults +dependencies: + - python=3.7.9 + - pip: + - alibi==0.5.8 + - dill + - mlops-tempo @ file:///home/alejandro/Programming/kubernetes/seldon/tempo + - mlserver==0.3.2 ``` + Overwriting artifacts/explainer/conda.yaml + + ```python tempo.save(Explainer) ``` + Collecting packages... + Packing environment at '/home/alejandro/miniconda3/envs/tempo-56577a22-797a-479e-a1f7-d01eabf38dcb' to '/home/alejandro/Programming/kubernetes/seldon/tempo/docs/examples/explainer/artifacts/explainer/environment.tar.gz' + [########################################] | 100% Completed | 1min 12.1s + + ## Test Locally on Docker Here we test our models using production images but running locally on Docker. This allows us to ensure the final production deployed model will behave as expected when deployed. ```python -from tempo import deploy -remote_model = deploy(explainer) +from tempo import deploy_local +remote_model = deploy_local(explainer) ``` @@ -176,12 +226,18 @@ r = json.loads(remote_model.predict(payload=data.X_test[0:1], parameters={"thres print(r["data"]["anchor"]) ``` + ['Marital Status = Separated'] + + ```python r = json.loads(remote_model.predict(payload=data.X_test[0:1], parameters={"threshold":0.99})) print(r["data"]["anchor"]) ``` + ['Relationship = Unmarried', 'Sex = Female', 'Capital Gain <= 0.00', 'Marital Status = Separated', 'Education = Associates'] + + ```python remote_model.undeploy() @@ -200,6 +256,12 @@ Create a Kind Kubernetes cluster with Minio and Seldon Core installed using Ansi !kubectl apply -f k8s/rbac -n production ``` + secret/minio-secret configured + serviceaccount/tempo-pipeline unchanged + role.rbac.authorization.k8s.io/tempo-pipeline unchanged + rolebinding.rbac.authorization.k8s.io/tempo-pipeline-rolebinding unchanged + + ```python from tempo.examples.minio import create_minio_rclone @@ -215,20 +277,19 @@ tempo.upload(explainer) ```python -from tempo.serve.metadata import KubernetesOptions -from tempo.seldon.k8s import SeldonCoreOptions -runtime_options = SeldonCoreOptions( - k8s_options=KubernetesOptions( - namespace="production", - authSecretName="minio-secret" - ) - ) +from tempo.serve.metadata import SeldonCoreOptions +runtime_options = SeldonCoreOptions(**{ + "remote_options": { + "namespace": "production", + "authSecretName": "minio-secret" + } + }) ``` ```python -from tempo import deploy -remote_model = deploy(explainer, options=runtime_options) +from tempo import deploy_remote +remote_model = deploy_remote(explainer, options=runtime_options) ``` @@ -237,6 +298,9 @@ r = json.loads(remote_model.predict(payload=data.X_test[0:1], parameters={"thres print(r["data"]["anchor"]) ``` + ['Marital Status = Separated', 'Sex = Female', 'Capital Gain <= 0.00'] + + ```python remote_model.undeploy() diff --git a/docs/examples/explainer/artifacts/explainer/conda.yaml b/docs/examples/explainer/artifacts/explainer/conda.yaml index 735e4aa6..ce1dbf05 100644 --- a/docs/examples/explainer/artifacts/explainer/conda.yaml +++ b/docs/examples/explainer/artifacts/explainer/conda.yaml @@ -4,7 +4,7 @@ channels: dependencies: - python=3.7.9 - pip: - - alibi + - alibi==0.5.8 - dill - mlops-tempo - mlserver==0.3.2 From 0347de6f23a41de5922cc5ef9e69b924b4c971a0 Mon Sep 17 00:00:00 2001 From: Alejandro Saucedo Date: Tue, 27 Jul 2021 09:58:00 +0100 Subject: [PATCH 13/13] Updated version to 0.3.1.dev1 --- tempo/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tempo/version.py b/tempo/version.py index d3ec452c..58789009 100644 --- a/tempo/version.py +++ b/tempo/version.py @@ -1 +1 @@ -__version__ = "0.2.0" +__version__ = "0.3.0.dev1"