diff --git a/custom-wrapper/airline-sentiment-custom-wrapper.ipynb b/custom-wrapper/airline-sentiment-custom-wrapper.ipynb new file mode 100644 index 0000000..a16226c --- /dev/null +++ b/custom-wrapper/airline-sentiment-custom-wrapper.ipynb @@ -0,0 +1,676 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "20eec117", + "metadata": { + "_cell_guid": "b1076dfc-b9ad-4769-8c92-a6c4dae69d19", + "_uuid": "8f2839f25d086af736a60e9eeb907d3b93b6e0e5", + "execution": { + "iopub.execute_input": "2021-11-15T07:48:52.44714Z", + "iopub.status.busy": "2021-11-15T07:48:52.446721Z", + "iopub.status.idle": "2021-11-15T07:48:52.478971Z", + "shell.execute_reply": "2021-11-15T07:48:52.4775Z", + "shell.execute_reply.started": "2021-11-15T07:48:52.447038Z" + }, + "papermill": { + "duration": 0.032152, + "end_time": "2021-11-15T08:54:16.800827", + "exception": false, + "start_time": "2021-11-15T08:54:16.768675", + "status": "completed" + }, + "tags": [] + }, + "source": [ + "# Hands-On NLP Workshop: *Detecting Sentiment Using Tweets to US Airlines*\n", + "\n", + "Within this hands-on workshop you will analyse tweets from customers of airlines about their performance. These were scraped from Twitter in 2015, and will be categorised in positive, neutral or negative sentiment. \n", + " \n", + "The steps which have been carried out\n", + "1. Load The Data \n", + "2. Data Visualization \n", + "3. Text Preprocessing and Cleaning \n", + "4. Handling Imbalance \n", + "5. Model Building \n", + "\n", + "The code in this notebook has been adapted from the brilliant work done by [Meisam Raz](https://www.kaggle.com/meisamraz/sentiment-analysis-96-acc-eda-text-preprocessing/notebook). " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8974c403", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# Colab has a load of packages pre-loaded into the environment. Installing the additional ones we require here.\n", + "!pip install seldon-deploy-sdk==1.4.1\n", + "!pip install google-cloud-storage" + ] + }, + { + "cell_type": "markdown", + "id": "7f045f80", + "metadata": {}, + "source": [ + "## Deploying the Model\n", + "As we have seen in the previous sections the tweets are pre-processed using a variety of techniques. In order to account for this we have 2 options for how to account for the pre-processing logic in production:\n", + "1. **Custom Model:** Incorporate the pre-processing directly in the `predict` method of a custom model. This provides simplicity when creating the deployment as there is only a single code base to worry about and a single component to be deployed.\n", + "2. **Input Transformer:** Make use of a separate container to perform all of the input transformation and then pass the vectors to the model for prediction. The schematic below outlines how this would work. \n", + "```\n", + " ________________________________________\n", + " | SeldonDeployment |\n", + " | |\n", + "Request --> Input transformer --> Model --> Response\n", + " | (Pre-processing) (SKLearn) |\n", + " |______________________________________|\n", + "```\n", + "The use of an input transformer allows us to separate the pre-processing logic from the prediction logic. This means we can leverage the pre-packaged SKLearn server provided by Seldon to serve our model, and each of the components can be upgraded independently of one another. However, it does introduce additional complexity in the deployment which is generated, and how that then interacts with advanced monitoring components such as outlier and drift detectors. \n", + "\n", + "This workshop will focus on the generation of a **custom model for this case**, therefore we need to define an `__init__` and `predict` method which shall load and perform inference respectively in our new deployment. \n", + "\n", + "--------- " + ] + }, + { + "cell_type": "markdown", + "id": "1fa02e77", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "We then define our Seldon custom model. The component parts required to build the custom model are outlined below. Each of the files play a key part in building the eventual Seldon docker container.\n", + "\n", + "---\n", + "### TweetSentiment.py\n", + "This is the critical file as it contains the logic associated with the deployment wrapped as part of a class by the same name as the Python file. \n", + "\n", + "A key thing to note about the way this has been structured is that we have focused on making this deployment reusable. The `__init__` method accepts two custom predictor parameters; one for the saved model (`model_path`), and the other for the TF-IDF vectorizer (`tfidf_path`). \n", + "\n", + "The advantage of this is that it allows us to upgrade the model or vectorizer without having to re-build the container image. Additionally, if the logic was more general it could be used to accept a wider variety of objects for greater reusability. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "8fe4755d", + "metadata": {}, + "outputs": [], + "source": [ + "from seldon_deploy_sdk import EnvironmentApi, Configuration, ApiClient, SeldonDeploymentsApi, OutlierDetectorApi, DriftDetectorApi, ModelMetadataServiceApi\n", + "from seldon_deploy_sdk.auth import OIDCAuthenticator\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e693c01d", + "metadata": {}, + "outputs": [], + "source": [ + "%%writefile TweetSentiment.py\n", + "\n", + "from joblib import load\n", + "import logging\n", + "import pandas as pd\n", + "import numpy as np\n", + "import re\n", + "\n", + "# For downloading the model and OHE encoder from GCS\n", + "from io import BytesIO\n", + "from google.cloud import storage\n", + "\n", + "import nltk\n", + "from nltk.corpus import stopwords\n", + "nltk.download(\"stopwords\", download_dir=\"./nltk\")\n", + "nltk.data.path.append(\"./nltk\")\n", + "\n", + "logger = logging.getLogger(__name__)\n", + "\n", + "\n", + "class TweetSentiment(object):\n", + "\n", + " def __init__(self, model_path, tfidf_path):\n", + " logger.info(f\"Connecting to GCS\")\n", + " self.client = storage.Client.create_anonymous_client()\n", + " self.bucket = self.client.bucket('tom-seldon-examples')\n", + "\n", + " logger.info(f\"Model name: {model_path}\")\n", + " self.model_path = model_path\n", + "\n", + " logger.info(f\"TF-IDF Name: {tfidf_path}\")\n", + " self.tfidf_path = tfidf_path\n", + "\n", + " logger.info(\"Loading model file and TF-IDF vectorizer.\")\n", + " self.load_deployment_artefacts()\n", + " self.ready = False\n", + "\n", + " def load_deployment_artefacts(self):\n", + " logger.info(\"Loading model\")\n", + " model_file = BytesIO()\n", + " model_blob = self.bucket.get_blob(f'{self.model_path}')\n", + " model_blob.download_to_file(model_file)\n", + " self.model = load(model_file)\n", + "\n", + " logger.info(\"Loading TF-IDF vectorizer\")\n", + " tfidf_file = BytesIO()\n", + " tfidf_blob = self.bucket.get_blob(f'{self.tfidf_path}')\n", + " tfidf_blob.download_to_file(tfidf_file)\n", + " self.tfidf = load(tfidf_file)\n", + " \n", + " self.ready = True\n", + "\n", + " # Remove stop words\n", + " def remove_stopwords(self, text):\n", + " text = ' '.join([word for word in text.split() if word not in (stopwords.words('english'))])\n", + " return text\n", + "\n", + " \n", + " def char(self, text):\n", + " substitute = re.sub(r'[^a-zA-Z]',' ',text)\n", + " return substitute\n", + "\n", + " def predict(self, tweets, names=[], meta={}):\n", + " try:\n", + " if not self.ready:\n", + " self.load_deployment_artefacts()\n", + " else:\n", + " final_text = []\n", + "\n", + " for text in tweets:\n", + " # Apply functions to tweets\n", + " text = self.remove_username(text)\n", + " text = self.remove_url(text)\n", + " text = self.remove_emoji(text)\n", + " text = self.decontraction(text)\n", + " text = self.seperate_alphanumeric(text)\n", + " text = self.unique_char(self.cont_rep_char,text)\n", + " text = self.char(text)\n", + " text = text.lower()\n", + " text = self.remove_stopwords(text)\n", + " final_text.append(text)\n", + "\n", + " logger.info(f\"Final text to be embedded: {final_text}\")\n", + " embeddings = self.tfidf.transform(final_text)\n", + " sentiment = self.model.predict(embeddings)\n", + " return sentiment\n", + "\n", + " except Exception as ex:\n", + " logging.exception(f\"Failed during predict: {ex}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "f49f48e6", + "metadata": {}, + "source": [ + "## Testing Locally\n", + "In order to ensure that we have gotten the `TweetClassifier.py` working correctly we can use the `seldon_core` Python package to run our model locally and test the endpoint. \n", + "```\n", + "seldon-core-microservice TweetSentiment --service-type MODEL\n", + " --parameters='[{ \n", + " \"name\": \"model_path\",\n", + " \"value\": \"nlp-workshop//model.joblib\",\n", + " \"type\": \"STRING\"\n", + " }, {\n", + " \"name\": \"tfidf_path\",\n", + " \"value\": \"nlp-workshop//tfidf.joblib\",\n", + " \"type\": \"STRING\"\n", + " }]'\n", + "```\n", + "This endpoint can then be tested by posting cURL commands to the local endpoint: \n", + "```\n", + "curl -H 'Content-Type: application/json' -d '{\"data\": {\"ndarray\": [\"@united how can you not put my bag on plane to Seattle. Flight 1212. Waiting in line to talk to someone about my bag. Status should matter.\"]}}' http://localhost:9000/api/v1.0/predictions\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "d18dee70", + "metadata": {}, + "source": [ + "### .s2i/environment\n", + "In order for the Seldon base image to correctly convert your source code to an image it requires certain environment variables. In this case it is only 3 variables. \n", + "* `MODEL_NAME`: The model name matches the name of the Python file and class which is created. \n", + "* `SERVICE_TYPE`: Seldon allows you to create many different components each specialised for a different purpose e.g. `TRANSFORMER` for performing pre or post-processing steps. \n", + "* `PERSISTENCE`: In some cases you would like to save the state of your deployments to Redis e.g. when scaling up multi-armed bandits\n", + "\n", + "This is our environment file:\n", + "```\n", + "MODEL_NAME=TweetSentiment\n", + "SERVICE_TYPE=MODEL\n", + "PERSISTENCE=0\n", + "```\n", + "---\n", + "### requirements.txt\n", + "List of Python packages which the deployment requires to run.\n", + "```\n", + "joblib\n", + "pandas\n", + "numpy\n", + "seldon_core\n", + "google-cloud-storage\n", + "scikit-learn\n", + "nltk\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "988862c0", + "metadata": {}, + "source": [ + "## Building the Image\n", + "\n", + "We can then build the custom model using source 2 image technology. Firstly, installing it locally as per [the documentation](https://github.com/openshift/source-to-image), and then by running this command: \n", + "```\n", + "s2i build . seldonio/seldon-core-s2i-python3:1.12.0-dev tweet-sentiment:0.3\n", + "```\n", + "\n", + "The built image is then pushed to Dockerhub where it can be pulled ready for deployment. In an enterprise setting, the container registry would be customised to the client's needs. \n", + "```\n", + "docker tag tweet-sentiment:0.3 tomfarrand/tweet-sentiment:0.3\n", + "docker push tomfarrand/tweet-sentiment:0.3\n", + "```\n", + "\n", + "In this case we will use my pre-built container image for speed and simplicity, which we can now deploy using the SDK. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a957ead1", + "metadata": {}, + "outputs": [], + "source": [ + "!s2i build . seldonio/seldon-core-s2i-python3:1.12.0-dev tweet-sentiment:0.3" + ] + }, + { + "cell_type": "markdown", + "id": "cf376647", + "metadata": {}, + "source": [ + "## Using the SDK\n", + "Now that we have our trained model artefact and preprocessor, alongside our custom built container we can now use the Seldon Deploy SDK to deploy our model! \n", + "\n", + "Initially we setup some authentication: " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "fd51dc3c", + "metadata": {}, + "outputs": [], + "source": [ + "SD_IP = \"34.73.238.47\"\n", + "\n", + "config = Configuration()\n", + "config.host = f\"http://{SD_IP}/seldon-deploy/api/v1alpha1\"\n", + "config.oidc_client_id = \"sd-api\"\n", + "config.oidc_server = f\"http://{SD_IP}/auth/realms/deploy-realm\"\n", + "config.oidc_client_secret = \"sd-api-secret\"\n", + "config.auth_method = 'client_credentials'\n", + "\n", + "def auth():\n", + " auth = OIDCAuthenticator(config)\n", + " config.id_token = auth.authenticate()\n", + " api_client = ApiClient(configuration=config, authenticator=auth)\n", + " return api_client\n" + ] + }, + { + "cell_type": "markdown", + "id": "9dc14b53", + "metadata": {}, + "source": [ + "Next, we define the parameters which we shall feed to the SDK.\n", + "\n", + "!!! Again, remember to fill in the `YOUR_NAME` parameter !!!" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "cfc7d155", + "metadata": {}, + "outputs": [], + "source": [ + "YOUR_NAME = \"jman\"\n", + "MODEL_NAME = \"tweet-sentiment\"\n", + "\n", + "DEPLOYMENT_NAME = f\"airline-sentiment\"\n", + "CONTAINER_NAME = f\"tomfarrand/tweet-sentiment:0.3\"\n", + "\n", + "NAMESPACE = \"seldon-demos\"\n", + "\n", + "CPU_REQUESTS = \"0.1\"\n", + "MEMORY_REQUESTS = \"1Gi\"\n", + "\n", + "CPU_LIMITS = \"0.1\"\n", + "MEMORY_LIMITS = \"1Gi\"\n", + "\n", + "MODEL_PATH = f\"nlp-workshop/tom-farrand/model.joblib\"\n", + "TFIDF_PATH = f\"nlp-workshop/tom-farrand/tfidf.joblib\"" + ] + }, + { + "cell_type": "markdown", + "id": "a1194566", + "metadata": {}, + "source": [ + "The deployment specification is then defined. " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "e67912bc", + "metadata": {}, + "outputs": [], + "source": [ + "mldeployment = {\n", + " \"kind\": \"SeldonDeployment\",\n", + " \"metadata\": {\n", + " \"name\": DEPLOYMENT_NAME,\n", + " \"namespace\": NAMESPACE,\n", + " \"labels\": {\n", + " \"fluentd\": \"true\"\n", + " }\n", + " },\n", + " \"apiVersion\": \"machinelearning.seldon.io/v1alpha2\",\n", + " \"spec\": {\n", + " \"name\": DEPLOYMENT_NAME,\n", + " \"annotations\": {\n", + " \"seldon.io/engine-seldon-log-messages-externally\": \"true\"\n", + " },\n", + " \"protocol\": \"seldon\",\n", + " \"predictors\": [\n", + " {\n", + " \"componentSpecs\": [\n", + " {\n", + " \"spec\": {\n", + " \"containers\": [\n", + " {\n", + " \"name\": f\"{DEPLOYMENT_NAME}-container\",\n", + " \"image\": CONTAINER_NAME,\n", + " \"resources\": {\n", + " \"requests\": {\n", + " \"cpu\": CPU_REQUESTS,\n", + " \"memory\": MEMORY_REQUESTS\n", + " },\n", + " \"limits\": {\n", + " \"cpu\": CPU_LIMITS,\n", + " \"memory\": MEMORY_LIMITS\n", + " }\n", + " }\n", + " }\n", + " ]\n", + " }\n", + " }\n", + " ],\n", + " \"name\": \"default\",\n", + " \"replicas\": 1,\n", + " \"traffic\": 100,\n", + " \"graph\": {\n", + " \"name\": f\"{DEPLOYMENT_NAME}-container\",\n", + " \"parameters\": [\n", + " {\n", + " \"name\":\"model_path\",\n", + " \"value\":MODEL_PATH,\n", + " \"type\":\"STRING\"\n", + " },\n", + " {\n", + " \"name\":\"tfidf_path\",\n", + " \"value\":TFIDF_PATH,\n", + " \"type\":\"STRING\"\n", + " }\n", + " ],\n", + " \"children\": [],\n", + " \"logger\": {\n", + " \"mode\": \"all\"\n", + " }\n", + " }\n", + " }\n", + " ]\n", + " },\n", + " \"status\": {}\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "bae9630a", + "metadata": {}, + "source": [ + "Finally, we deploy the model using a few simple API calls. " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "c822fb8a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'api_version': 'machinelearning.seldon.io/v1alpha2',\n", + " 'kind': 'SeldonDeployment',\n", + " 'metadata': {'annotations': None,\n", + " 'cluster_name': None,\n", + " 'creation_timestamp': None,\n", + " 'deletion_grace_period_seconds': None,\n", + " 'deletion_timestamp': None,\n", + " 'finalizers': None,\n", + " 'generate_name': None,\n", + " 'generation': None,\n", + " 'labels': {'fluentd': 'true'},\n", + " 'managed_fields': None,\n", + " 'name': 'airline-sentiment',\n", + " 'namespace': 'seldon-demos',\n", + " 'owner_references': None,\n", + " 'resource_version': None,\n", + " 'self_link': None,\n", + " 'uid': None},\n", + " 'spec': {'annotations': {'seldon.io/engine-seldon-log-messages-externally': 'true'},\n", + " 'name': 'airline-sentiment',\n", + " 'oauth_key': None,\n", + " 'oauth_secret': None,\n", + " 'predictors': [{'annotations': None,\n", + " 'component_specs': [{'hpa_spec': None,\n", + " 'keda_spec': None,\n", + " 'metadata': {'annotations': None,\n", + " 'cluster_name': None,\n", + " 'creation_timestamp': '2022-04-27T17:54:25Z',\n", + " 'deletion_grace_period_seconds': None,\n", + " 'deletion_timestamp': None,\n", + " 'finalizers': None,\n", + " 'generate_name': None,\n", + " 'generation': None,\n", + " 'labels': None,\n", + " 'managed_fields': None,\n", + " 'name': None,\n", + " 'namespace': None,\n", + " 'owner_references': None,\n", + " 'resource_version': None,\n", + " 'self_link': None,\n", + " 'uid': None},\n", + " 'pdb_spec': None,\n", + " 'replicas': None,\n", + " 'spec': {'active_deadline_seconds': None,\n", + " 'affinity': None,\n", + " 'automount_service_account_token': None,\n", + " 'containers': [{'args': None,\n", + " 'command': None,\n", + " 'env': None,\n", + " 'env_from': None,\n", + " 'image': 'tomfarrand/tweet-sentiment:0.3',\n", + " 'image_pull_policy': None,\n", + " 'lifecycle': None,\n", + " 'liveness_probe': None,\n", + " 'name': 'airline-sentiment-container',\n", + " 'ports': None,\n", + " 'readiness_probe': None,\n", + " 'resources': {'limits': {'cpu': '100m',\n", + " 'memory': '1Gi'},\n", + " 'requests': {'cpu': '100m',\n", + " 'memory': '1Gi'}},\n", + " 'security_context': None,\n", + " 'startup_probe': None,\n", + " 'stdin': None,\n", + " 'stdin_once': None,\n", + " 'termination_message_path': None,\n", + " 'termination_message_policy': None,\n", + " 'tty': None,\n", + " 'volume_devices': None,\n", + " 'volume_mounts': None,\n", + " 'working_dir': None}],\n", + " 'dns_config': None,\n", + " 'dns_policy': None,\n", + " 'enable_service_links': None,\n", + " 'ephemeral_containers': None,\n", + " 'host_aliases': None,\n", + " 'host_ipc': None,\n", + " 'host_network': None,\n", + " 'host_pid': None,\n", + " 'hostname': None,\n", + " 'image_pull_secrets': None,\n", + " 'init_containers': None,\n", + " 'node_name': None,\n", + " 'node_selector': None,\n", + " 'overhead': None,\n", + " 'preemption_policy': None,\n", + " 'priority': None,\n", + " 'priority_class_name': None,\n", + " 'readiness_gates': None,\n", + " 'restart_policy': None,\n", + " 'runtime_class_name': None,\n", + " 'scheduler_name': None,\n", + " 'security_context': None,\n", + " 'service_account': None,\n", + " 'service_account_name': None,\n", + " 'set_hostname_as_fqdn': None,\n", + " 'share_process_namespace': None,\n", + " 'subdomain': None,\n", + " 'termination_grace_period_seconds': None,\n", + " 'tolerations': None,\n", + " 'topology_spread_constraints': None,\n", + " 'volumes': None}}],\n", + " 'engine_resources': {'limits': None,\n", + " 'requests': None},\n", + " 'explainer': None,\n", + " 'graph': {'children': None,\n", + " 'endpoint': None,\n", + " 'env_secret_ref_name': None,\n", + " 'implementation': None,\n", + " 'logger': {'mode': 'all', 'url': None},\n", + " 'methods': None,\n", + " 'model_uri': None,\n", + " 'name': 'airline-sentiment-container',\n", + " 'parameters': [{'name': 'model_path',\n", + " 'type': 'STRING',\n", + " 'value': 'nlp-workshop/tom-farrand/model.joblib'},\n", + " {'name': 'tfidf_path',\n", + " 'type': 'STRING',\n", + " 'value': 'nlp-workshop/tom-farrand/tfidf.joblib'}],\n", + " 'service_account_name': None,\n", + " 'storage_initializer_image': None,\n", + " 'type': None},\n", + " 'labels': None,\n", + " 'name': 'default',\n", + " 'replicas': 1,\n", + " 'shadow': None,\n", + " 'ssl': None,\n", + " 'svc_orch_spec': {'env': None,\n", + " 'replicas': None,\n", + " 'resources': None},\n", + " 'traffic': 100}],\n", + " 'protocol': 'seldon',\n", + " 'replicas': None,\n", + " 'server_type': None,\n", + " 'transport': None},\n", + " 'status': {'address': None,\n", + " 'annotations': None,\n", + " 'conditions': None,\n", + " 'deployment_status': None,\n", + " 'description': None,\n", + " 'observed_generation': None,\n", + " 'replicas': None,\n", + " 'service_status': None,\n", + " 'state': None}}" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "deployment_api = SeldonDeploymentsApi(auth())\n", + "deployment_api.create_seldon_deployment(namespace=NAMESPACE, mldeployment=mldeployment)" + ] + }, + { + "cell_type": "markdown", + "id": "61951499", + "metadata": {}, + "source": [ + "Once our endpoint becomes available we can then test the deployment using the following request: \n", + "\n", + "```\n", + "{\n", + " \"data\":{\n", + " \"ndarray\":[\n", + " \"@united how can you not put my bag on plane to Seattle. Flight 1212. Waiting in line to talk to someone about my bag. Status should matter.\"\n", + " ]\n", + " }\n", + "}\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "417f22c7", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.10" + }, + "papermill": { + "default_parameters": {}, + "duration": 279.948311, + "end_time": "2021-11-15T08:58:48.814352", + "environment_variables": {}, + "exception": null, + "input_path": "__notebook__.ipynb", + "output_path": "__notebook__.ipynb", + "parameters": {}, + "start_time": "2021-11-15T08:54:08.866041", + "version": "2.3.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/finance/fraud-detection.ipynb b/finance/fraud-detection.ipynb index 1cb934b..c44adfe 100644 --- a/finance/fraud-detection.ipynb +++ b/finance/fraud-detection.ipynb @@ -1043,7 +1043,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.9.7" } }, "nbformat": 4, diff --git a/manufacturing/manufacturing-workshop.ipynb b/manufacturing/manufacturing-workshop.ipynb index 4bdde9c..5ea9a5f 100644 --- a/manufacturing/manufacturing-workshop.ipynb +++ b/manufacturing/manufacturing-workshop.ipynb @@ -35,19 +35,28 @@ }, "outputs": [], "source": [ - "# Colab has a load of packages pre-loaded into the environment. \n", + "# Colab has a load of packages pre-loaded into the environment.\n", "# Installing the additional ones we require.\n", "!pip install seldon_deploy_sdk\n", - "!pip install alibi_detect==0.6.1\n", + "!pip install alibi_detect == 0.6.1\n", "!pip install dill\n", - "!pip install tensorflow==2.4.4" + "!pip install tensorflow == 2.4.4\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-03-28 22:35:57.965024: I tensorflow/core/platform/cpu_feature_guard.cc:151] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX2 AVX512F FMA\n", + "To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.\n" + ] + } + ], "source": [ "# General Packages\n", "import os\n", @@ -67,19 +76,33 @@ "from tensorflow.keras.applications.inception_v3 import InceptionV3\n", "from tensorflow.keras.models import Model\n", "\n", + "# Explainer\n", + "from alibi.explainers import AnchorImage\n", + "from skimage import color\n", + "from skimage import morphology\n", + "from skimage import segmentation\n", + "\n", + "# Outlier Detection\n", + "from alibi_detect.models.tensorflow.losses import elbo\n", + "from alibi_detect.od import OutlierVAE\n", + "from alibi_detect.utils.fetching import fetch_detector\n", + "from alibi_detect.utils.perturbation import apply_mask\n", + "from alibi_detect.utils.saving import save_detector, load_detector\n", + "from alibi_detect.utils.visualize import plot_instance_score, plot_feature_outlier_image\n", + "\n", "# Drift Detection\n", "from alibi_detect.cd import MMDDrift\n", "from alibi_detect.cd.tensorflow import preprocess_drift\n", "from alibi_detect.utils.saving import save_detector, load_detector\n", "\n", "# Seldon Deploy SDK\n", - "from seldon_deploy_sdk import Configuration, ApiClient, SeldonDeploymentsApi, OutlierDetectorApi, DriftDetectorApi, ModelMetadataServiceApi\n", + "from seldon_deploy_sdk import EnvironmentApi, Configuration, ApiClient, SeldonDeploymentsApi, OutlierDetectorApi, DriftDetectorApi, ModelMetadataServiceApi\n", "from seldon_deploy_sdk.auth import OIDCAuthenticator\n", "\n", "# Logging and Clearing Session\n", "tf.keras.backend.clear_session()\n", "logger = tf.get_logger()\n", - "logger.setLevel(logging.ERROR)" + "logger.setLevel(logging.ERROR)\n" ] }, { @@ -95,9 +118,9 @@ "metadata": {}, "outputs": [], "source": [ - "!wget https://storage.googleapis.com/tom-seldon-examples/workshops/manufactoring/data.zip\n", + "!wget https: // storage.googleapis.com/tom-seldon-examples/workshops/manufactoring/data.zip\n", "!mkdir data\n", - "!unzip -o 'data.zip' -d data" + "!unzip - o 'data.zip' - d data\n" ] }, { @@ -111,34 +134,50 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 1440 images belonging to 6 classes.\n" + ] + } + ], "source": [ "train_datagen = ImageDataGenerator(rescale=1/255)\n", - "data_dir='data/train/images/'\n", + "data_dir = 'data/train/images/'\n", "train_ds = train_datagen.flow_from_directory(\n", - " directory = data_dir,\n", - " target_size = (224, 224),\n", - " batch_size = 32,\n", - " class_mode = 'categorical'\n", - ")" + " directory=data_dir,\n", + " target_size=(224, 224),\n", + " batch_size=32,\n", + " class_mode='categorical'\n", + ")\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 360 images belonging to 6 classes.\n" + ] + } + ], "source": [ "val_datagen = ImageDataGenerator(rescale=1/255)\n", - "data_dir='data/validation/images/'\n", + "data_dir = 'data/validation/images/'\n", "val_ds = train_datagen.flow_from_directory(\n", - " directory = data_dir,\n", - " target_size = (224, 224),\n", - " batch_size = 32,\n", - " class_mode = 'categorical'\n", - ")" + " directory=data_dir,\n", + " target_size=(224, 224),\n", + " batch_size=32,\n", + " class_mode='categorical'\n", + ")\n" ] }, { @@ -150,15 +189,31 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{0: 'crazing',\n", + " 1: 'inclusion',\n", + " 2: 'patches',\n", + " 3: 'pitted_surface',\n", + " 4: 'rolled-in_scale',\n", + " 5: 'scratches'}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "categories = (train_ds.class_indices)\n", - "categories = dict((v,k) for k,v in categories.items())\n", - "categories" + "categories = dict((v, k) for k, v in categories.items())\n", + "categories\n" ] }, { @@ -170,13 +225,43 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(224, 224, 3)\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], "source": [ "example_image = train_ds.next()[0][0]\n", "print(example_image.shape)\n", - "plt.imshow(example_image[:,:])" + "plt.imshow(example_image[:, :])\n" ] }, { @@ -218,11 +303,12 @@ "source": [ "class myCallback(tf.keras.callbacks.Callback):\n", " def on_epoch_end(self, epoch, logs={}):\n", - " if(logs.get('val_accuracy') > 0.90 ):\n", + " if(logs.get('val_accuracy') > 0.90):\n", " print(\"\\nReached 90% validation accuracy so cancelling training!\")\n", - " self.model.stop_training = True \n", - " \n", - "callbacks = myCallback()" + " self.model.stop_training = True\n", + "\n", + "\n", + "callbacks = myCallback()\n" ] }, { @@ -245,11 +331,13 @@ "outputs": [], "source": [ "simple_cnn = tf.keras.models.Sequential([\n", - " tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)), # First Convolution\n", + " tf.keras.layers.Conv2D(32, (3, 3), activation='relu',\n", + " input_shape=(224, 224, 3)), # First Convolution\n", " tf.keras.layers.MaxPooling2D(2, 2),\n", - " tf.keras.layers.Conv2D(32, (3, 3), activation='relu'), # Second Convolution\n", + " # Second Convolution\n", + " tf.keras.layers.Conv2D(32, (3, 3), activation='relu'),\n", " tf.keras.layers.MaxPooling2D(2, 2),\n", - " tf.keras.layers.Conv2D(32, (3, 3), activation='relu'), # Third Convolution\n", + " tf.keras.layers.Conv2D(32, (3, 3), activation='relu'), # Third Convolution\n", " tf.keras.layers.MaxPooling2D(2, 2),\n", " tf.keras.layers.Flatten(),\n", " tf.keras.layers.Dense(512, activation='relu'),\n", @@ -257,7 +345,7 @@ " tf.keras.layers.Dense(6, activation='softmax'),\n", "])\n", "\n", - "simple_cnn.summary()" + "simple_cnn.summary()\n" ] }, { @@ -275,17 +363,17 @@ }, "outputs": [], "source": [ - "simple_cnn.compile(loss = 'categorical_crossentropy',\n", - " optimizer = 'adam',\n", - " metrics = ['accuracy'])\n", + "simple_cnn.compile(loss='categorical_crossentropy',\n", + " optimizer='adam',\n", + " metrics=['accuracy'])\n", "\n", "simple_cnn_history = simple_cnn.fit(train_ds,\n", - " batch_size = 32,\n", - " epochs = 20,\n", - " validation_data = val_ds,\n", - " callbacks = [callbacks],\n", - " verbose = 1,\n", - " shuffle=True)" + " batch_size=32,\n", + " epochs=20,\n", + " validation_data=val_ds,\n", + " callbacks=[callbacks],\n", + " verbose=1,\n", + " shuffle=True)\n" ] }, { @@ -302,16 +390,16 @@ "outputs": [], "source": [ "!mkdir simple-cnn/\n", - "!gsutil cp -r gs://tom-seldon-examples/workshops/manufacturing/pretrained/simple-cnn/1 simple-cnn/" + "!gsutil cp - r gs: // tom-seldon-examples/workshops/manufacturing/pretrained/simple-cnn/1 simple-cnn/\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ - "simple_cnn = load_model(\"simple-cnn/1\")" + "simple_cnn = load_model(\"simple-cnn/1\")\n" ] }, { @@ -332,12 +420,12 @@ "\n", "test_scratches = img_to_array(test_scratches)\n", "test_scratches = test_scratches / 255\n", - "test_scratches = test_scratches.reshape((-1,) + test_scratches.shape)\n", + "test_scratches = test_scratches.reshape((-1,) + test_scratches.shape)\n", "\n", "simple_preds = simple_cnn.predict(test_scratches)[0]\n", "\n", "for v, i in enumerate(simple_preds):\n", - " print(f\"{categories[v]}: {i:.2f}\")" + " print(f\"{categories[v]}: {i:.2f}\")\n" ] }, { @@ -396,13 +484,13 @@ "\n", "# define the input and output of the model\n", "inception = Model(inputs=InceptionV3_model.input, outputs=custom_output)\n", - " \n", + "\n", "# compile the model\n", "inception.compile(loss='categorical_crossentropy',\n", " optimizer='adam',\n", " metrics=['accuracy'])\n", "\n", - "inception.summary()" + "inception.summary()\n" ] }, { @@ -416,8 +504,8 @@ " epochs=20,\n", " validation_data=val_ds,\n", " callbacks=[callbacks],\n", - " verbose=1, \n", - " shuffle=True)" + " verbose=1,\n", + " shuffle=True)\n" ] }, { @@ -429,21 +517,39 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mkdir: inception/: File exists\n", + "Copying gs://tom-seldon-examples/workshops/manufacturing/pretrained/inception/1/saved_model.pb...\n", + "Copying gs://tom-seldon-examples/workshops/manufacturing/pretrained/inception/1/variables/variables.data-00000-of-00001...\n", + "==> NOTE: You are downloading one or more large file(s), which would \n", + "run significantly faster if you enabled sliced object downloads. This\n", + "feature is enabled by default but requires that compiled crcmod be\n", + "installed (see \"gsutil help crcmod\").\n", + "\n", + "Copying gs://tom-seldon-examples/workshops/manufacturing/pretrained/inception/1/variables/variables.index...\n", + "| [3 files][268.9 MiB/268.9 MiB] 3.4 MiB/s \n", + "Operation completed over 3 objects/268.9 MiB. \n" + ] + } + ], "source": [ "!mkdir inception/\n", - "!gsutil cp -r gs://tom-seldon-examples/workshops/manufacturing/pretrained/inception/1 inception/" + "!gsutil cp - r gs: // tom-seldon-examples/workshops/manufacturing/pretrained/inception/1 inception/\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ - "inception = load_model(\"inception/1\")" + "inception = load_model(\"inception/1\")\n" ] }, { @@ -455,14 +561,36 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "crazing: 0.00\n", + "inclusion: 0.00\n", + "patches: 0.00\n", + "pitted_surface: 0.00\n", + "rolled-in_scale: 0.00\n", + "scratches: 1.00\n" + ] + } + ], "source": [ "inception_preds = inception.predict(test_scratches)[0]\n", "\n", "for v, i in enumerate(inception_preds):\n", - " print(f\"{categories[v]}: {i:.2f}\")" + " print(f\"{categories[v]}: {i:.2f}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "inception_preds\n" ] }, { @@ -506,14 +634,43 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 57, "metadata": { "scrolled": true }, - "outputs": [], - "source": [ - "# !gsutil cp -r simple-cnn/1/ gs://tom-seldon-examples/workshops/manufacturing//simple-cnn/\n", - "# !gsutil cp -r inception/1/ gs://tom-seldon-examples/workshops/manufacturing//inception/" + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Copying file://simple-cnn/1/saved_model.pb [Content-Type=application/octet-stream]...\n", + "Copying file://simple-cnn/1/variables/variables.data-00000-of-00001 [Content-Type=application/octet-stream]...\n", + "Copying file://simple-cnn/1/variables/variables.index [Content-Type=application/octet-stream]...\n", + "\\ [3 files][130.2 MiB/130.2 MiB] 3.1 MiB/s \n", + "Operation completed over 3 objects/130.2 MiB. \n", + "Copying file://inception/1/saved_model.pb [Content-Type=application/octet-stream]...\n", + "Copying file://inception/1/variables/variables.data-00000-of-00001 [Content-Type=application/octet-stream]...\n", + "==> NOTE: You are uploading one or more large file(s), which would run \n", + "significantly faster if you enable parallel composite uploads. This\n", + "feature can be enabled by editing the\n", + "\"parallel_composite_upload_threshold\" value in your .boto\n", + "configuration file. However, note that if you do this large files will\n", + "be uploaded as `composite objects\n", + "`_,which\n", + "means that any user who downloads such objects will need to have a\n", + "compiled crcmod installed (see \"gsutil help crcmod\"). This is because\n", + "without a compiled crcmod, computing checksums on composite objects is\n", + "so slow that gsutil disables downloads of composite objects.\n", + "\n", + "Copying file://inception/1/variables/variables.index [Content-Type=application/octet-stream]...\n", + "| [3 files][268.9 MiB/268.9 MiB] 3.1 MiB/s \n", + "Operation completed over 3 objects/268.9 MiB. \n" + ] + } + ], + "source": [ + "!gsutil cp - r simple-cnn/1 / gs: // tom-seldon-examples/workshops/manufacturing/josh/simple-cnn/\n", + "!gsutil cp - r inception/1 / gs: // tom-seldon-examples/workshops/manufacturing/josh/inception/\n" ] }, { @@ -527,11 +684,11 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ - "SD_IP = \"34.147.53.165\"\n", + "SD_IP = \"34.139.213.176\"\n", "config = Configuration()\n", "config.host = f\"http://{SD_IP}/seldon-deploy/api/v1alpha1\"\n", "config.oidc_client_id = \"sd-api\"\n", @@ -543,7 +700,7 @@ " auth = OIDCAuthenticator(config)\n", " config.id_token = auth.authenticate()\n", " api_client = ApiClient(configuration=config, authenticator=auth)\n", - " return api_client" + " return api_client\n" ] }, { @@ -575,13 +732,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ - "YOUR_NAME = \n", - "DEPLOYMENT_NAME = f\"{YOUR_NAME}-test\"\n", - "NAMESPACE = \"default\"\n", + "YOUR_NAME = \"josh\"\n", + "DEPLOYMENT_NAME = f\"manu-run\"\n", + "NAMESPACE = \"seldon-demos\"\n", "\n", "MODEL_NAME = \"inception\"\n", "MODEL_LOCATION = f\"gs://tom-seldon-examples/workshops/manufacturing/{YOUR_NAME}/{MODEL_NAME}/\"\n", @@ -589,16 +746,16 @@ "CANARY_NAME = \"simple-cnn\"\n", "CANARY_LOCATION = f\"gs://tom-seldon-examples/workshops/manufacturing/{YOUR_NAME}/{CANARY_NAME}/\"\n", "\n", - "CPU_REQUESTS = \"1\"\n", - "MEMORY_REQUESTS = \"1Gi\"\n", + "CPU_REQUESTS = \"2\"\n", + "MEMORY_REQUESTS = \"8Gi\"\n", "\n", - "CPU_LIMITS = \"1\"\n", - "MEMORY_LIMITS = \"1Gi\"" + "CPU_LIMITS = \"2\"\n", + "MEMORY_LIMITS = \"8Gi\"\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -671,8 +828,8 @@ " ],\n", " \"name\": \"canary\",\n", " \"replicas\": 1,\n", - " \"annotations\":{\n", - " \"seldon.io/canary\":\"true\"\n", + " \"annotations\": {\n", + " \"seldon.io/canary\": \"true\"\n", " },\n", " \"traffic\": 30,\n", " \"graph\": {\n", @@ -682,11 +839,11 @@ " \"logger\": {\n", " \"mode\": \"all\"\n", " }\n", - " }\n", " }\n", + " }\n", " ]\n", " }\n", - "}" + "}\n" ] }, { @@ -698,12 +855,265 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'api_version': 'machinelearning.seldon.io/v1alpha2',\n", + " 'kind': 'SeldonDeployment',\n", + " 'metadata': {'annotations': None,\n", + " 'cluster_name': None,\n", + " 'creation_timestamp': None,\n", + " 'deletion_grace_period_seconds': None,\n", + " 'deletion_timestamp': None,\n", + " 'finalizers': None,\n", + " 'generate_name': None,\n", + " 'generation': None,\n", + " 'labels': None,\n", + " 'managed_fields': None,\n", + " 'name': 'manu-run',\n", + " 'namespace': 'seldon-demos',\n", + " 'owner_references': None,\n", + " 'resource_version': None,\n", + " 'self_link': None,\n", + " 'uid': None},\n", + " 'spec': {'annotations': None,\n", + " 'name': 'manu-run',\n", + " 'oauth_key': None,\n", + " 'oauth_secret': None,\n", + " 'predictors': [{'annotations': None,\n", + " 'component_specs': [{'hpa_spec': None,\n", + " 'keda_spec': None,\n", + " 'metadata': {'annotations': None,\n", + " 'cluster_name': None,\n", + " 'creation_timestamp': '2022-03-29T14:10:32Z',\n", + " 'deletion_grace_period_seconds': None,\n", + " 'deletion_timestamp': None,\n", + " 'finalizers': None,\n", + " 'generate_name': None,\n", + " 'generation': None,\n", + " 'labels': None,\n", + " 'managed_fields': None,\n", + " 'name': None,\n", + " 'namespace': None,\n", + " 'owner_references': None,\n", + " 'resource_version': None,\n", + " 'self_link': None,\n", + " 'uid': None},\n", + " 'pdb_spec': None,\n", + " 'replicas': None,\n", + " 'spec': {'active_deadline_seconds': None,\n", + " 'affinity': None,\n", + " 'automount_service_account_token': None,\n", + " 'containers': [{'args': None,\n", + " 'command': None,\n", + " 'env': None,\n", + " 'env_from': None,\n", + " 'image': None,\n", + " 'image_pull_policy': None,\n", + " 'lifecycle': None,\n", + " 'liveness_probe': None,\n", + " 'name': 'inception',\n", + " 'ports': None,\n", + " 'readiness_probe': None,\n", + " 'resources': {'limits': {'cpu': '2',\n", + " 'memory': '8Gi'},\n", + " 'requests': {'cpu': '2',\n", + " 'memory': '8Gi'}},\n", + " 'security_context': None,\n", + " 'startup_probe': None,\n", + " 'stdin': None,\n", + " 'stdin_once': None,\n", + " 'termination_message_path': None,\n", + " 'termination_message_policy': None,\n", + " 'tty': None,\n", + " 'volume_devices': None,\n", + " 'volume_mounts': None,\n", + " 'working_dir': None}],\n", + " 'dns_config': None,\n", + " 'dns_policy': None,\n", + " 'enable_service_links': None,\n", + " 'ephemeral_containers': None,\n", + " 'host_aliases': None,\n", + " 'host_ipc': None,\n", + " 'host_network': None,\n", + " 'host_pid': None,\n", + " 'hostname': None,\n", + " 'image_pull_secrets': None,\n", + " 'init_containers': None,\n", + " 'node_name': None,\n", + " 'node_selector': None,\n", + " 'overhead': None,\n", + " 'preemption_policy': None,\n", + " 'priority': None,\n", + " 'priority_class_name': None,\n", + " 'readiness_gates': None,\n", + " 'restart_policy': None,\n", + " 'runtime_class_name': None,\n", + " 'scheduler_name': None,\n", + " 'security_context': None,\n", + " 'service_account': None,\n", + " 'service_account_name': None,\n", + " 'set_hostname_as_fqdn': None,\n", + " 'share_process_namespace': None,\n", + " 'subdomain': None,\n", + " 'termination_grace_period_seconds': None,\n", + " 'tolerations': None,\n", + " 'topology_spread_constraints': None,\n", + " 'volumes': None}}],\n", + " 'engine_resources': {'limits': None,\n", + " 'requests': None},\n", + " 'explainer': None,\n", + " 'graph': {'children': None,\n", + " 'endpoint': None,\n", + " 'env_secret_ref_name': None,\n", + " 'implementation': 'TENSORFLOW_SERVER',\n", + " 'logger': {'mode': 'all', 'url': None},\n", + " 'methods': None,\n", + " 'model_uri': 'gs://tom-seldon-examples/workshops/manufacturing/josh/inception/',\n", + " 'name': 'inception',\n", + " 'parameters': None,\n", + " 'service_account_name': None,\n", + " 'storage_initializer_image': None,\n", + " 'type': None},\n", + " 'labels': None,\n", + " 'name': 'default',\n", + " 'replicas': 1,\n", + " 'shadow': None,\n", + " 'ssl': None,\n", + " 'svc_orch_spec': {'env': None,\n", + " 'replicas': None,\n", + " 'resources': None},\n", + " 'traffic': 70},\n", + " {'annotations': {'seldon.io/canary': 'true'},\n", + " 'component_specs': [{'hpa_spec': None,\n", + " 'keda_spec': None,\n", + " 'metadata': {'annotations': None,\n", + " 'cluster_name': None,\n", + " 'creation_timestamp': '2022-03-29T14:10:32Z',\n", + " 'deletion_grace_period_seconds': None,\n", + " 'deletion_timestamp': None,\n", + " 'finalizers': None,\n", + " 'generate_name': None,\n", + " 'generation': None,\n", + " 'labels': None,\n", + " 'managed_fields': None,\n", + " 'name': None,\n", + " 'namespace': None,\n", + " 'owner_references': None,\n", + " 'resource_version': None,\n", + " 'self_link': None,\n", + " 'uid': None},\n", + " 'pdb_spec': None,\n", + " 'replicas': None,\n", + " 'spec': {'active_deadline_seconds': None,\n", + " 'affinity': None,\n", + " 'automount_service_account_token': None,\n", + " 'containers': [{'args': None,\n", + " 'command': None,\n", + " 'env': None,\n", + " 'env_from': None,\n", + " 'image': None,\n", + " 'image_pull_policy': None,\n", + " 'lifecycle': None,\n", + " 'liveness_probe': None,\n", + " 'name': 'simple-cnn',\n", + " 'ports': None,\n", + " 'readiness_probe': None,\n", + " 'resources': {'limits': {'cpu': '2',\n", + " 'memory': '8Gi'},\n", + " 'requests': {'cpu': '2',\n", + " 'memory': '8Gi'}},\n", + " 'security_context': None,\n", + " 'startup_probe': None,\n", + " 'stdin': None,\n", + " 'stdin_once': None,\n", + " 'termination_message_path': None,\n", + " 'termination_message_policy': None,\n", + " 'tty': None,\n", + " 'volume_devices': None,\n", + " 'volume_mounts': None,\n", + " 'working_dir': None}],\n", + " 'dns_config': None,\n", + " 'dns_policy': None,\n", + " 'enable_service_links': None,\n", + " 'ephemeral_containers': None,\n", + " 'host_aliases': None,\n", + " 'host_ipc': None,\n", + " 'host_network': None,\n", + " 'host_pid': None,\n", + " 'hostname': None,\n", + " 'image_pull_secrets': None,\n", + " 'init_containers': None,\n", + " 'node_name': None,\n", + " 'node_selector': None,\n", + " 'overhead': None,\n", + " 'preemption_policy': None,\n", + " 'priority': None,\n", + " 'priority_class_name': None,\n", + " 'readiness_gates': None,\n", + " 'restart_policy': None,\n", + " 'runtime_class_name': None,\n", + " 'scheduler_name': None,\n", + " 'security_context': None,\n", + " 'service_account': None,\n", + " 'service_account_name': None,\n", + " 'set_hostname_as_fqdn': None,\n", + " 'share_process_namespace': None,\n", + " 'subdomain': None,\n", + " 'termination_grace_period_seconds': None,\n", + " 'tolerations': None,\n", + " 'topology_spread_constraints': None,\n", + " 'volumes': None}}],\n", + " 'engine_resources': {'limits': None,\n", + " 'requests': None},\n", + " 'explainer': None,\n", + " 'graph': {'children': None,\n", + " 'endpoint': None,\n", + " 'env_secret_ref_name': None,\n", + " 'implementation': 'TENSORFLOW_SERVER',\n", + " 'logger': {'mode': 'all', 'url': None},\n", + " 'methods': None,\n", + " 'model_uri': 'gs://tom-seldon-examples/workshops/manufacturing/josh/simple-cnn/',\n", + " 'name': 'simple-cnn',\n", + " 'parameters': None,\n", + " 'service_account_name': None,\n", + " 'storage_initializer_image': None,\n", + " 'type': None},\n", + " 'labels': None,\n", + " 'name': 'canary',\n", + " 'replicas': 1,\n", + " 'shadow': None,\n", + " 'ssl': None,\n", + " 'svc_orch_spec': {'env': None,\n", + " 'replicas': None,\n", + " 'resources': None},\n", + " 'traffic': 30}],\n", + " 'protocol': 'seldon',\n", + " 'replicas': None,\n", + " 'server_type': None,\n", + " 'transport': None},\n", + " 'status': {'address': None,\n", + " 'annotations': None,\n", + " 'conditions': None,\n", + " 'deployment_status': None,\n", + " 'description': None,\n", + " 'observed_generation': None,\n", + " 'replicas': None,\n", + " 'service_status': None,\n", + " 'state': None}}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "deployment_api = SeldonDeploymentsApi(auth())\n", - "deployment_api.create_seldon_deployment(namespace=NAMESPACE, mldeployment=mldeployment)" + "deployment_api.create_seldon_deployment(namespace=NAMESPACE, mldeployment=mldeployment)\n" ] }, { @@ -727,22 +1137,29 @@ "outputs": [], "source": [ "seldon_sample = {\n", - " \"data\": {\n", - " \"names\": [\n", - " ],\n", - " \"ndarray\": test_scratches.tolist()\n", - " }\n", + " \"data\": {\n", + " \"names\": [\n", + " ],\n", + " \"ndarray\": test_scratches.tolist()\n", + " }\n", "}\n", "\n", "with open('test-scratches.json', 'w', encoding='utf-8') as f:\n", - " json.dump(seldon_sample, f, ensure_ascii=False, indent=1)" + " json.dump(seldon_sample, f, ensure_ascii=False, indent=1)\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding Model Metadata\n", + "# Adding Model Metadata\n", "\n", "You have now created 2 new models within a single deployment. Both of these models have been automatically added to the model catalog. The model catalog acts as a centralised repository for metadata associated with models. Models can be easily deployed directly from the catalog, while metadata acts to speed knowledge transfer between teams and to track models across tools.\n", "\n", @@ -756,19 +1173,19 @@ "outputs": [], "source": [ "model_catalog_metadata = {\n", - " \"URI\": MODEL_LOCATION,\n", - " \"name\": \"InceptionV3\",\n", - " \"version\": \"v1.0\",\n", - " \"artifactType\": \"TENSORFLOW\",\n", - " \"taskType\": \"defect classification\",\n", - " \"tags\": {\n", + " \"URI\": MODEL_LOCATION,\n", + " \"name\": \"InceptionV3\",\n", + " \"version\": \"v1.0\",\n", + " \"artifactType\": \"TENSORFLOW\",\n", + " \"taskType\": \"defect classification\",\n", + " \"tags\": {\n", " \"auto_created\": \"true\",\n", " \"author\": f\"{YOUR_NAME}\"\n", - " },\n", - " \"metrics\": {},\n", - " \"creationTime\": \"2022-02-15T15:26:26.630592Z\",\n", - " \"project\": \"default\"\n", - " }" + " },\n", + " \"metrics\": {},\n", + " \"creationTime\": \"2022-02-15T15:26:26.630592Z\",\n", + " \"project\": \"default\"\n", + "}\n" ] }, { @@ -778,7 +1195,8 @@ "outputs": [], "source": [ "api_instance = ModelMetadataServiceApi(auth())\n", - "api_response = api_instance.model_metadata_service_update_model_metadata(model_catalog_metadata)" + "api_response = api_instance.model_metadata_service_update_model_metadata(\n", + " model_catalog_metadata)\n" ] }, { @@ -794,8 +1212,9 @@ "metadata": {}, "outputs": [], "source": [ - "api_response = api_instance.model_metadata_service_list_model_metadata(uri=MODEL_LOCATION)\n", - "api_response" + "api_response = api_instance.model_metadata_service_list_model_metadata(\n", + " uri=MODEL_LOCATION)\n", + "api_response\n" ] }, { @@ -823,9 +1242,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "(160, 224, 224, 3)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "train_ds.reset()\n", "\n", @@ -834,7 +1264,7 @@ "for i in range(4):\n", " drift_ref = np.concatenate((drift_ref, train_ds.next()[0]))\n", "\n", - "drift_ref.shape" + "drift_ref.shape\n" ] }, { @@ -850,25 +1280,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# define encoder\n", "encoding_dim = 32\n", "encoder_net = tf.keras.Sequential(\n", - " [\n", - " InputLayer(input_shape=(224, 224, 3)),\n", - " Conv2D(64, 4, strides=2, padding='same', activation=tf.nn.relu),\n", - " Conv2D(128, 4, strides=2, padding='same', activation=tf.nn.relu),\n", - " Conv2D(512, 4, strides=2, padding='same', activation=tf.nn.relu),\n", - " Flatten(),\n", - " Dense(encoding_dim,)\n", - " ]\n", + " [\n", + " InputLayer(input_shape=(224, 224, 3)),\n", + " Conv2D(64, 4, strides=2, padding='same', activation=tf.nn.relu),\n", + " Conv2D(128, 4, strides=2, padding='same', activation=tf.nn.relu),\n", + " Conv2D(512, 4, strides=2, padding='same', activation=tf.nn.relu),\n", + " Flatten(),\n", + " Dense(encoding_dim,)\n", + " ]\n", ")\n", "\n", "# define preprocessing function\n", - "preprocess_fn = partial(preprocess_drift, model=encoder_net, batch_size=160)" + "preprocess_fn = partial(preprocess_drift, model=encoder_net, batch_size=160)\n" ] }, { @@ -885,12 +1315,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "# initialise drift detector\n", - "cd = MMDDrift(drift_ref, backend='tensorflow', p_val=.05, preprocess_fn=preprocess_fn, n_permutations=100)" + "cd = MMDDrift(drift_ref, backend='tensorflow', p_val=.05,\n", + " preprocess_fn=preprocess_fn, n_permutations=100)\n" ] }, { @@ -902,13 +1333,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], - "source": [ - "new_batch = train_ds.next()[0]\n", + "outputs": [ + { + "data": { + "text/plain": [ + "{'data': {'is_drift': 1,\n", + " 'distance': 0.053456962,\n", + " 'p_val': 0.0,\n", + " 'threshold': 0.05,\n", + " 'distance_threshold': 0.019707084},\n", + " 'meta': {'name': 'MMDDriftTF',\n", + " 'detector_type': 'offline',\n", + " 'data_type': None,\n", + " 'version': '0.8.1',\n", + " 'backend': 'tensorflow'}}" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "new_batch = val_ds.next()[0]\n", "preds = cd.predict(new_batch, return_p_val=True, return_distance=True)\n", - "preds" + "preds\n" ] }, { @@ -925,7 +1376,974 @@ "outputs": [], "source": [ "filepath = 'defect-drift'\n", - "save_detector(cd, filepath)" + "save_detector(cd, filepath)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!gsutil cp - r defect-drift gs://tom-seldon-examples/workshops/manufacturing/drift/tom-farrand/defect-drift\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "f\"gs://tom-seldon-examples/manufacturing/workshops/drift//{filepath}\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# \"DD_URI = 'gs://tom-seldon-examples/datareply-workshop/models/sgreaves/lr/drift'\\n\",\n", + "# \"DD_NAME = 'KSDrift-Detector'\\n\",\n", + "# \"\\n\",\n", + "# \"dd_config = {'deployment': DEPLOYMENT_NAME,\\n\",\n", + "# \" 'deployment_namespace': None,\\n\",\n", + "# \" 'namespace': 'seldon-logs',\\n\",\n", + "# \" 'params': {'drift_batch_size': '10',\\n\",\n", + "# \" 'env_secret_ref': None,\\n\",\n", + "# \" 'event_source': f'io.seldon.serving.dev-seldondeployment-{DEPLOYMENT_NAME}-drift',\\n\",\n", + "# \" 'event_type': 'io.seldon.serving.inference.drift',\\n\",\n", + "# \" 'http_port': '8080',\\n\",\n", + "# \" 'model_name': DD_NAME,\\n\",\n", + "# \" 'protocol': 'seldon.http',\\n\",\n", + "# \" 'reply_url': 'http://seldon-request-logger.seldon-logs',\\n\",\n", + "# \" 'storage_uri': DD_URI,\\n\",\n", + "# \" 'user_permission': None},\\n\",\n", + "# \" 'prom_scraping': None,\\n\",\n", + "# \" 'url': None}\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Explainer " + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "def predict_fn(x): return inception.predict(x)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "def slicMask(image):\n", + " # Compute a mask\n", + " lum = color.rgb2gray(image)\n", + " mask = morphology.remove_small_holes(\n", + " morphology.remove_small_objects(\n", + " lum < 0.7, 500),\n", + " 500)\n", + "\n", + " mask = morphology.opening(mask, morphology.disk(3))\n", + " return mask\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/josh/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/alibi/explainers/anchor_image.py:284: FutureWarning: skimage.measure.label's indexing starts from 0. In future version it will start from 1. To disable this warning, explicitely set the `start_label` parameter to 1.\n", + " return self.segmentation_fn(image_preproc)\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Best: 11 (mean:1.0000000000, n: 5, lb:0.0674) Worst: 12 (mean:0.6667, n: 3, ub:1.0000) B = 0.93\n", + "Best: 11 (mean:1.0000000000, n: 6, lb:0.0920) Worst: 10 (mean:0.7500, n: 4, ub:1.0000) B = 0.91\n", + "Best: 11 (mean:1.0000000000, n: 7, lb:0.1208) Worst: 10 (mean:0.8000, n: 5, ub:1.0000) B = 0.88\n", + "Best: 11 (mean:1.0000000000, n: 8, lb:0.1507) Worst: 10 (mean:0.8333, n: 6, ub:1.0000) B = 0.85\n", + "Best: 11 (mean:1.0000000000, n: 9, lb:0.1806) Worst: 3 (mean:1.0000, n: 1, ub:1.0000) B = 0.82\n", + "Best: 11 (mean:1.0000000000, n: 10, lb:0.2097) Worst: 3 (mean:1.0000, n: 2, ub:1.0000) B = 0.79\n", + "Best: 11 (mean:1.0000000000, n: 11, lb:0.2377) Worst: 3 (mean:1.0000, n: 3, ub:1.0000) B = 0.76\n", + "Best: 11 (mean:1.0000000000, n: 12, lb:0.2645) Worst: 3 (mean:1.0000, n: 4, ub:1.0000) B = 0.74\n", + "Best: 11 (mean:1.0000000000, n: 13, lb:0.2898) Worst: 3 (mean:1.0000, n: 5, ub:1.0000) B = 0.71\n", + "Best: 11 (mean:1.0000000000, n: 14, lb:0.3138) Worst: 3 (mean:1.0000, n: 6, ub:1.0000) B = 0.69\n", + "Best: 11 (mean:1.0000000000, n: 15, lb:0.3365) Worst: 3 (mean:0.8571, n: 7, ub:1.0000) B = 0.66\n", + "Best: 11 (mean:1.0000000000, n: 16, lb:0.3579) Worst: 3 (mean:0.8750, n: 8, ub:1.0000) B = 0.64\n", + "Best: 11 (mean:1.0000000000, n: 17, lb:0.3781) Worst: 5 (mean:1.0000, n: 2, ub:1.0000) B = 0.62\n", + "Best: 11 (mean:1.0000000000, n: 18, lb:0.3972) Worst: 5 (mean:1.0000, n: 3, ub:1.0000) B = 0.60\n", + "Best: 11 (mean:1.0000000000, n: 19, lb:0.4152) Worst: 5 (mean:0.7500, n: 4, ub:1.0000) B = 0.58\n", + "Best: 11 (mean:1.0000000000, n: 20, lb:0.4322) Worst: 5 (mean:0.8000, n: 5, ub:1.0000) B = 0.57\n", + "Best: 11 (mean:1.0000000000, n: 21, lb:0.4483) Worst: 3 (mean:0.7778, n: 9, ub:1.0000) B = 0.55\n", + "Best: 11 (mean:1.0000000000, n: 22, lb:0.4635) Worst: 3 (mean:0.8000, n: 10, ub:1.0000) B = 0.54\n", + "Best: 11 (mean:1.0000000000, n: 23, lb:0.4779) Worst: 10 (mean:0.7143, n: 7, ub:1.0000) B = 0.52\n", + "Best: 11 (mean:1.0000000000, n: 24, lb:0.4916) Worst: 10 (mean:0.7500, n: 8, ub:1.0000) B = 0.51\n", + "Best: 11 (mean:1.0000000000, n: 25, lb:0.5046) Worst: 10 (mean:0.7778, n: 9, ub:1.0000) B = 0.50\n", + "Best: 11 (mean:1.0000000000, n: 26, lb:0.5170) Worst: 4 (mean:0.6667, n: 6, ub:1.0000) B = 0.48\n", + "Best: 11 (mean:1.0000000000, n: 27, lb:0.5287) Worst: 4 (mean:0.7143, n: 7, ub:1.0000) B = 0.47\n", + "Best: 11 (mean:1.0000000000, n: 28, lb:0.5400) Worst: 4 (mean:0.7500, n: 8, ub:1.0000) B = 0.46\n", + "Best: 11 (mean:1.0000000000, n: 29, lb:0.5506) Worst: 4 (mean:0.7778, n: 9, ub:1.0000) B = 0.45\n", + "Best: 11 (mean:1.0000000000, n: 30, lb:0.5608) Worst: 5 (mean:0.6667, n: 6, ub:1.0000) B = 0.44\n", + "Best: 11 (mean:1.0000000000, n: 31, lb:0.5706) Worst: 5 (mean:0.7143, n: 7, ub:1.0000) B = 0.43\n", + "Best: 11 (mean:1.0000000000, n: 32, lb:0.5799) Worst: 5 (mean:0.7500, n: 8, ub:1.0000) B = 0.42\n", + "Best: 11 (mean:1.0000000000, n: 33, lb:0.5888) Worst: 5 (mean:0.7778, n: 9, ub:1.0000) B = 0.41\n", + "Best: 11 (mean:1.0000000000, n: 34, lb:0.5974) Worst: 5 (mean:0.8000, n: 10, ub:1.0000) B = 0.40\n", + "Best: 11 (mean:1.0000000000, n: 35, lb:0.6056) Worst: 8 (mean:0.6667, n: 6, ub:1.0000) B = 0.39\n", + "Best: 11 (mean:1.0000000000, n: 36, lb:0.6134) Worst: 1 (mean:0.6000, n: 5, ub:1.0000) B = 0.39\n", + "Best: 11 (mean:1.0000000000, n: 37, lb:0.6210) Worst: 0 (mean:0.5000, n: 4, ub:1.0000) B = 0.38\n", + "Best: 11 (mean:1.0000000000, n: 38, lb:0.6282) Worst: 0 (mean:0.6000, n: 5, ub:1.0000) B = 0.37\n", + "Best: 11 (mean:1.0000000000, n: 39, lb:0.6352) Worst: 12 (mean:0.5000, n: 4, ub:1.0000) B = 0.36\n", + "Best: 11 (mean:1.0000000000, n: 40, lb:0.6419) Worst: 15 (mean:0.3333, n: 3, ub:0.9999) B = 0.36\n", + "Best: 11 (mean:1.0000000000, n: 41, lb:0.6484) Worst: 15 (mean:0.5000, n: 4, ub:1.0000) B = 0.35\n", + "Best: 11 (mean:1.0000000000, n: 42, lb:0.6546) Worst: 15 (mean:0.6000, n: 5, ub:1.0000) B = 0.35\n", + "Best: 11 (mean:1.0000000000, n: 43, lb:0.6606) Worst: 15 (mean:0.6667, n: 6, ub:1.0000) B = 0.34\n", + "Best: 11 (mean:1.0000000000, n: 44, lb:0.6664) Worst: 15 (mean:0.7143, n: 7, ub:1.0000) B = 0.33\n", + "Best: 11 (mean:1.0000000000, n: 45, lb:0.6720) Worst: 3 (mean:0.7273, n: 11, ub:0.9997) B = 0.33\n", + "Best: 11 (mean:1.0000000000, n: 46, lb:0.6775) Worst: 5 (mean:0.7273, n: 11, ub:0.9997) B = 0.32\n", + "Best: 11 (mean:1.0000000000, n: 47, lb:0.6827) Worst: 5 (mean:0.7500, n: 12, ub:0.9997) B = 0.32\n", + "Best: 11 (mean:1.0000000000, n: 48, lb:0.6878) Worst: 4 (mean:0.7000, n: 10, ub:0.9997) B = 0.31\n", + "Best: 11 (mean:1.0000000000, n: 49, lb:0.6927) Worst: 10 (mean:0.7000, n: 10, ub:0.9997) B = 0.31\n", + "Best: 11 (mean:1.0000000000, n: 50, lb:0.6974) Worst: 15 (mean:0.6250, n: 8, ub:0.9996) B = 0.30\n", + "Best: 11 (mean:1.0000000000, n: 51, lb:0.7020) Worst: 15 (mean:0.6667, n: 9, ub:0.9996) B = 0.30\n", + "Best: 11 (mean:1.0000000000, n: 52, lb:0.7065) Worst: 6 (mean:0.5714, n: 7, ub:0.9995) B = 0.29\n", + "Best: 11 (mean:1.0000000000, n: 53, lb:0.7108) Worst: 8 (mean:0.5714, n: 7, ub:0.9995) B = 0.29\n", + "Best: 11 (mean:1.0000000000, n: 54, lb:0.7150) Worst: 8 (mean:0.6250, n: 8, ub:0.9996) B = 0.28\n", + "Best: 11 (mean:1.0000000000, n: 55, lb:0.7191) Worst: 0 (mean:0.5000, n: 6, ub:0.9994) B = 0.28\n", + "Best: 11 (mean:1.0000000000, n: 56, lb:0.7230) Worst: 0 (mean:0.5714, n: 7, ub:0.9995) B = 0.28\n", + "Best: 11 (mean:1.0000000000, n: 57, lb:0.7268) Worst: 1 (mean:0.5000, n: 6, ub:0.9994) B = 0.27\n", + "Best: 11 (mean:1.0000000000, n: 58, lb:0.7306) Worst: 1 (mean:0.5714, n: 7, ub:0.9995) B = 0.27\n", + "Best: 11 (mean:1.0000000000, n: 59, lb:0.7342) Worst: 1 (mean:0.6250, n: 8, ub:0.9996) B = 0.27\n", + "Best: 11 (mean:1.0000000000, n: 60, lb:0.7377) Worst: 2 (mean:0.5000, n: 6, ub:0.9994) B = 0.26\n", + "Best: 11 (mean:1.0000000000, n: 61, lb:0.7412) Worst: 2 (mean:0.5714, n: 7, ub:0.9995) B = 0.26\n", + "Best: 11 (mean:1.0000000000, n: 62, lb:0.7445) Worst: 2 (mean:0.6250, n: 8, ub:0.9996) B = 0.26\n", + "Best: 11 (mean:1.0000000000, n: 63, lb:0.7478) Worst: 7 (mean:0.5000, n: 6, ub:0.9994) B = 0.25\n", + "Best: 11 (mean:1.0000000000, n: 64, lb:0.7509) Worst: 7 (mean:0.5714, n: 7, ub:0.9995) B = 0.25\n", + "Best: 11 (mean:1.0000000000, n: 65, lb:0.7540) Worst: 7 (mean:0.6250, n: 8, ub:0.9996) B = 0.25\n", + "Best: 11 (mean:1.0000000000, n: 66, lb:0.7571) Worst: 7 (mean:0.6667, n: 9, ub:0.9997) B = 0.24\n", + "Best: 11 (mean:1.0000000000, n: 67, lb:0.7600) Worst: 13 (mean:0.5000, n: 6, ub:0.9995) B = 0.24\n", + "Best: 11 (mean:1.0000000000, n: 68, lb:0.7629) Worst: 13 (mean:0.5714, n: 7, ub:0.9996) B = 0.24\n", + "Best: 11 (mean:1.0000000000, n: 69, lb:0.7657) Worst: 14 (mean:0.5000, n: 6, ub:0.9995) B = 0.23\n", + "Best: 11 (mean:1.0000000000, n: 70, lb:0.7684) Worst: 12 (mean:0.4000, n: 5, ub:0.9993) B = 0.23\n", + "Best: 11 (mean:1.0000000000, n: 71, lb:0.7711) Worst: 5 (mean:0.6923, n: 13, ub:0.9987) B = 0.23\n", + "Best: 11 (mean:1.0000000000, n: 72, lb:0.7737) Worst: 5 (mean:0.7143, n: 14, ub:0.9988) B = 0.23\n", + "Best: 11 (mean:1.0000000000, n: 73, lb:0.7762) Worst: 3 (mean:0.6667, n: 12, ub:0.9985) B = 0.22\n", + "Best: 11 (mean:1.0000000000, n: 74, lb:0.7787) Worst: 3 (mean:0.6923, n: 13, ub:0.9987) B = 0.22\n", + "Best: 11 (mean:1.0000000000, n: 75, lb:0.7811) Worst: 4 (mean:0.6364, n: 11, ub:0.9984) B = 0.22\n", + "Best: 11 (mean:1.0000000000, n: 76, lb:0.7835) Worst: 10 (mean:0.6364, n: 11, ub:0.9984) B = 0.21\n", + "Best: 11 (mean:1.0000000000, n: 77, lb:0.7858) Worst: 7 (mean:0.6000, n: 10, ub:0.9982) B = 0.21\n", + "Best: 11 (mean:1.0000000000, n: 78, lb:0.7881) Worst: 15 (mean:0.6000, n: 10, ub:0.9982) B = 0.21\n", + "Best: 11 (mean:1.0000000000, n: 79, lb:0.7903) Worst: 1 (mean:0.5556, n: 9, ub:0.9980) B = 0.21\n", + "Best: 11 (mean:1.0000000000, n: 80, lb:0.7925) Worst: 1 (mean:0.6000, n: 10, ub:0.9982) B = 0.21\n", + "Best: 11 (mean:1.0000000000, n: 81, lb:0.7946) Worst: 2 (mean:0.5556, n: 9, ub:0.9980) B = 0.20\n", + "Best: 11 (mean:1.0000000000, n: 82, lb:0.7967) Worst: 8 (mean:0.5556, n: 9, ub:0.9980) B = 0.20\n", + "Best: 11 (mean:1.0000000000, n: 83, lb:0.7987) Worst: 8 (mean:0.6000, n: 10, ub:0.9982) B = 0.20\n", + "Best: 11 (mean:1.0000000000, n: 84, lb:0.8007) Worst: 0 (mean:0.5000, n: 8, ub:0.9977) B = 0.20\n", + "Best: 11 (mean:1.0000000000, n: 85, lb:0.8027) Worst: 6 (mean:0.5000, n: 8, ub:0.9977) B = 0.19\n", + "Best: 11 (mean:1.0000000000, n: 86, lb:0.8046) Worst: 6 (mean:0.5556, n: 9, ub:0.9980) B = 0.19\n", + "Best: 11 (mean:1.0000000000, n: 87, lb:0.8065) Worst: 13 (mean:0.5000, n: 8, ub:0.9977) B = 0.19\n", + "Best: 11 (mean:1.0000000000, n: 88, lb:0.8083) Worst: 14 (mean:0.4286, n: 7, ub:0.9972) B = 0.19\n", + "Best: 11 (mean:1.0000000000, n: 89, lb:0.8101) Worst: 5 (mean:0.6667, n: 15, ub:0.9965) B = 0.19\n", + "Best: 11 (mean:1.0000000000, n: 90, lb:0.8119) Worst: 5 (mean:0.6875, n: 16, ub:0.9968) B = 0.18\n", + "Best: 11 (mean:1.0000000000, n: 91, lb:0.8137) Worst: 5 (mean:0.7059, n: 17, ub:0.9970) B = 0.18\n", + "Best: 11 (mean:1.0000000000, n: 92, lb:0.8154) Worst: 5 (mean:0.7222, n: 18, ub:0.9972) B = 0.18\n", + "Best: 11 (mean:1.0000000000, n: 93, lb:0.8170) Worst: 5 (mean:0.7368, n: 19, ub:0.9974) B = 0.18\n", + "Best: 11 (mean:1.0000000000, n: 94, lb:0.8187) Worst: 5 (mean:0.7500, n: 20, ub:0.9975) B = 0.18\n", + "Best: 11 (mean:1.0000000000, n: 95, lb:0.8203) Worst: 5 (mean:0.7619, n: 21, ub:0.9977) B = 0.18\n", + "Best: 11 (mean:1.0000000000, n: 96, lb:0.8219) Worst: 5 (mean:0.7727, n: 22, ub:0.9978) B = 0.18\n", + "Best: 11 (mean:1.0000000000, n: 97, lb:0.8234) Worst: 9 (mean:0.3333, n: 6, ub:0.9965) B = 0.17\n", + "Best: 11 (mean:1.0000000000, n: 98, lb:0.8250) Worst: 12 (mean:0.3333, n: 6, ub:0.9966) B = 0.17\n", + "Best: 11 (mean:1.0000000000, n: 99, lb:0.8265) Worst: 3 (mean:0.6429, n: 14, ub:0.9963) B = 0.17\n", + "Best: 11 (mean:1.0000000000, n: 100, lb:0.8279) Worst: 3 (mean:0.6667, n: 15, ub:0.9966) B = 0.17\n", + "Best: 11 (mean:1.0000000000, n: 101, lb:0.8294) Worst: 4 (mean:0.5833, n: 12, ub:0.9955) B = 0.17\n", + "Best: 11 (mean:1.0000000000, n: 102, lb:0.8308) Worst: 4 (mean:0.6154, n: 13, ub:0.9959) B = 0.17\n", + "Best: 11 (mean:1.0000000000, n: 103, lb:0.8322) Worst: 4 (mean:0.6429, n: 14, ub:0.9963) B = 0.16\n", + "Best: 11 (mean:1.0000000000, n: 104, lb:0.8336) Worst: 4 (mean:0.6667, n: 15, ub:0.9966) B = 0.16\n", + "Best: 11 (mean:1.0000000000, n: 105, lb:0.8350) Worst: 4 (mean:0.6875, n: 16, ub:0.9969) B = 0.16\n", + "Best: 11 (mean:1.0000000000, n: 106, lb:0.8363) Worst: 10 (mean:0.5833, n: 12, ub:0.9955) B = 0.16\n", + "Best: 11 (mean:1.0000000000, n: 107, lb:0.8376) Worst: 10 (mean:0.6154, n: 13, ub:0.9960) B = 0.16\n", + "Best: 11 (mean:1.0000000000, n: 108, lb:0.8389) Worst: 10 (mean:0.6429, n: 14, ub:0.9964) B = 0.16\n", + "Best: 11 (mean:1.0000000000, n: 109, lb:0.8402) Worst: 10 (mean:0.6667, n: 15, ub:0.9967) B = 0.16\n", + "Best: 11 (mean:1.0000000000, n: 110, lb:0.8414) Worst: 10 (mean:0.6875, n: 16, ub:0.9969) B = 0.16\n", + "Best: 11 (mean:1.0000000000, n: 111, lb:0.8426) Worst: 5 (mean:0.7391, n: 23, ub:0.9953) B = 0.15\n", + "Best: 11 (mean:1.0000000000, n: 112, lb:0.8438) Worst: 5 (mean:0.7500, n: 24, ub:0.9955) B = 0.15\n", + "Best: 11 (mean:1.0000000000, n: 113, lb:0.8450) Worst: 5 (mean:0.7600, n: 25, ub:0.9957) B = 0.15\n", + "Best of size 1 :\n", + "11 1.0 0.9800042323501885 1.0\n", + "(11,) mean = 1.00 lb = 0.98 ub = 1.00 coverage: 0.50 n: 114\n", + "Found eligible result (11,) Coverage: 0.5 Is best? True\n" + ] + } + ], + "source": [ + "example_image = load_img('data/validation/images/inclusion/inclusion_285.jpg',\n", + " target_size=(224, 224, 3))\n", + "example_image = img_to_array(example_image) / 255\n", + "segmentation_fn = 'slic'\n", + "kwargs = {'n_segments': 15, 'compactness': 10, 'sigma': 0.5}\n", + "explainer = AnchorImage(lambda x: inception.predict(x), example_image.shape, segmentation_fn=segmentation_fn,\n", + " segmentation_kwargs=kwargs, images_background=None)\n", + "explanation = explainer.explain(example_image, threshold=.90, p_sample=.5,\n", + " seed=0, batch_size=1, coverage_samples=2, min_samples_start=10, verbose=True)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/josh/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/ipykernel_launcher.py:9: UserWarning: No contour levels were found within the data range.\n", + " if __name__ == '__main__':\n" + ] + }, + { + "data": { + "text/plain": [ + "(-0.5, 223.5, 223.5, -0.5)" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# Add Mask for graph using Sciimage\n", + "example_image_mask = slicMask(example_image)\n", + "\n", + "fig, ax_arr = plt.subplots(2, 2, sharex=True, sharey=True, figsize=(10, 10))\n", + "ax1, ax2, ax3, ax4 = ax_arr.ravel()\n", + "\n", + "\n", + "ax1.imshow(segmentation.mark_boundaries(example_image, explanation.segments))\n", + "ax1.contour(example_image_mask, colors='red', linewidths=1)\n", + "ax1.set_title('SLIC Segmentation')\n", + "ax1.axis('off')\n", + "\n", + "ax2.imshow(explanation.segments)\n", + "# ax1.contour(example_image_mask, colors='red', linewidths=1)\n", + "ax2.set_title('Explanation Segmentation')\n", + "ax2.axis('off')\n", + "\n", + "ax3.set_title('Anchor')\n", + "ax3.imshow(explanation.anchor[:, :])\n", + "ax3.axis('off')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Save and Upload Explainer Artifact" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "dill.dump(explainer, open(\"explainer.dill\", \"wb\"))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Copying file://explainer.dill [Content-Type=application/octet-stream]...\n", + "/ [1 files][ 1.0 KiB/ 1.0 KiB] \n", + "Operation completed over 1 objects/1.0 KiB. \n" + ] + } + ], + "source": [ + "!gsutil cp explainer.dill gs: // tom-seldon-examples/workshops/manufacturing/pretrained/explainer/explainer.dill\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "EXPLAINER_TYPE = \"AnchorImages\"\n", + "EXPLAINER_URI = \"gs://tom-seldon-examples/workshops/manufacturing/pretrained/explainer\"\n", + "\n", + "EXPLAINER_BATCH_SIZE = \"1\"\n", + "EXPLAINER_COVERAGE_SAMPLES = \"1\"\n", + "EXPLAINER_MIN_SAMPLES_START = \"5\"\n", + "\n", + "CPU_REQUESTS = \"1\"\n", + "MEMORY_REQUESTS = \"4Gi\"\n", + "\n", + "CPU_LIMITS = \"2\"\n", + "MEMORY_LIMITS = \"4Gi\"\n", + "\n", + "explainer_spec = {\n", + " \"type\": EXPLAINER_TYPE,\n", + " \"modelUri\": EXPLAINER_URI,\n", + " \"config\": {\n", + " \"batch_size\": EXPLAINER_BATCH_SIZE,\n", + " \"coverage_samples\": EXPLAINER_COVERAGE_SAMPLES,\n", + " \"min_samples_start\": EXPLAINER_MIN_SAMPLES_START,\n", + " \"start_label\": \"1\"\n", + " },\n", + " \"containerSpec\": {\n", + " \"name\": \"\",\n", + " \"resources\": {\n", + " \"requests\":\n", + " {\n", + " \"cpu\": CPU_REQUESTS,\n", + " \"memory\": MEMORY_REQUESTS\n", + " },\n", + " \"limits\": {\n", + " \"cpu\": CPU_LIMITS,\n", + " \"memory\": MEMORY_LIMITS\n", + " }\n", + " }\n", + " }\n", + "}\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "Gr7cIsDPOZ0T" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'kind': 'SeldonDeployment',\n", + " 'metadata': {'name': 'manu-run', 'namespace': 'seldon-demos'},\n", + " 'apiVersion': 'machinelearning.seldon.io/v1alpha2',\n", + " 'spec': {'name': 'manu-run',\n", + " 'protocol': 'seldon',\n", + " 'predictors': [{'componentSpecs': [{'spec': {'containers': [{'name': 'inception',\n", + " 'resources': {'requests': {'cpu': '2', 'memory': '8Gi'},\n", + " 'limits': {'cpu': '2', 'memory': '8Gi'}}}]}}],\n", + " 'name': 'default',\n", + " 'replicas': 1,\n", + " 'traffic': 70,\n", + " 'graph': {'implementation': 'TENSORFLOW_SERVER',\n", + " 'modelUri': 'gs://tom-seldon-examples/workshops/manufacturing/josh/inception/',\n", + " 'name': 'inception',\n", + " 'logger': {'mode': 'all'}},\n", + " 'explainer': {'type': 'AnchorImages',\n", + " 'modelUri': 'gs://tom-seldon-examples/workshops/manufacturing/pretrained/explainer',\n", + " 'config': {'batch_size': '1',\n", + " 'coverage_samples': '1',\n", + " 'min_samples_start': '5',\n", + " 'start_label': '1'},\n", + " 'containerSpec': {'name': '',\n", + " 'resources': {'requests': {'cpu': '1', 'memory': '4Gi'},\n", + " 'limits': {'cpu': '2', 'memory': '4Gi'}}}}},\n", + " {'componentSpecs': [{'spec': {'containers': [{'name': 'simple-cnn',\n", + " 'resources': {'requests': {'cpu': '2', 'memory': '8Gi'},\n", + " 'limits': {'cpu': '2', 'memory': '8Gi'}}}]}}],\n", + " 'name': 'canary',\n", + " 'replicas': 1,\n", + " 'annotations': {'seldon.io/canary': 'true'},\n", + " 'traffic': 30,\n", + " 'graph': {'implementation': 'TENSORFLOW_SERVER',\n", + " 'modelUri': 'gs://tom-seldon-examples/workshops/manufacturing/josh/simple-cnn/',\n", + " 'name': 'simple-cnn',\n", + " 'logger': {'mode': 'all'}}}]}}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mldeployment['spec']['predictors'][0]['explainer'] = explainer_spec\n", + "mldeployment\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "ZEE1Ng-IOeR_" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'api_version': 'machinelearning.seldon.io/v1alpha2',\n", + " 'kind': 'SeldonDeployment',\n", + " 'metadata': {'annotations': None,\n", + " 'cluster_name': None,\n", + " 'creation_timestamp': None,\n", + " 'deletion_grace_period_seconds': None,\n", + " 'deletion_timestamp': None,\n", + " 'finalizers': None,\n", + " 'generate_name': None,\n", + " 'generation': None,\n", + " 'labels': None,\n", + " 'managed_fields': None,\n", + " 'name': 'manu-run',\n", + " 'namespace': 'seldon-demos',\n", + " 'owner_references': None,\n", + " 'resource_version': None,\n", + " 'self_link': None,\n", + " 'uid': None},\n", + " 'spec': {'annotations': None,\n", + " 'name': 'manu-run',\n", + " 'oauth_key': None,\n", + " 'oauth_secret': None,\n", + " 'predictors': [{'annotations': None,\n", + " 'component_specs': [{'hpa_spec': None,\n", + " 'keda_spec': None,\n", + " 'metadata': {'annotations': None,\n", + " 'cluster_name': None,\n", + " 'creation_timestamp': '2022-03-29T02:36:39Z',\n", + " 'deletion_grace_period_seconds': None,\n", + " 'deletion_timestamp': None,\n", + " 'finalizers': None,\n", + " 'generate_name': None,\n", + " 'generation': None,\n", + " 'labels': None,\n", + " 'managed_fields': None,\n", + " 'name': None,\n", + " 'namespace': None,\n", + " 'owner_references': None,\n", + " 'resource_version': None,\n", + " 'self_link': None,\n", + " 'uid': None},\n", + " 'pdb_spec': None,\n", + " 'replicas': None,\n", + " 'spec': {'active_deadline_seconds': None,\n", + " 'affinity': None,\n", + " 'automount_service_account_token': None,\n", + " 'containers': [{'args': None,\n", + " 'command': None,\n", + " 'env': None,\n", + " 'env_from': None,\n", + " 'image': None,\n", + " 'image_pull_policy': None,\n", + " 'lifecycle': None,\n", + " 'liveness_probe': None,\n", + " 'name': 'inception',\n", + " 'ports': None,\n", + " 'readiness_probe': None,\n", + " 'resources': {'limits': {'cpu': '2',\n", + " 'memory': '8Gi'},\n", + " 'requests': {'cpu': '2',\n", + " 'memory': '8Gi'}},\n", + " 'security_context': None,\n", + " 'startup_probe': None,\n", + " 'stdin': None,\n", + " 'stdin_once': None,\n", + " 'termination_message_path': None,\n", + " 'termination_message_policy': None,\n", + " 'tty': None,\n", + " 'volume_devices': None,\n", + " 'volume_mounts': None,\n", + " 'working_dir': None}],\n", + " 'dns_config': None,\n", + " 'dns_policy': None,\n", + " 'enable_service_links': None,\n", + " 'ephemeral_containers': None,\n", + " 'host_aliases': None,\n", + " 'host_ipc': None,\n", + " 'host_network': None,\n", + " 'host_pid': None,\n", + " 'hostname': None,\n", + " 'image_pull_secrets': None,\n", + " 'init_containers': None,\n", + " 'node_name': None,\n", + " 'node_selector': None,\n", + " 'overhead': None,\n", + " 'preemption_policy': None,\n", + " 'priority': None,\n", + " 'priority_class_name': None,\n", + " 'readiness_gates': None,\n", + " 'restart_policy': None,\n", + " 'runtime_class_name': None,\n", + " 'scheduler_name': None,\n", + " 'security_context': None,\n", + " 'service_account': None,\n", + " 'service_account_name': None,\n", + " 'set_hostname_as_fqdn': None,\n", + " 'share_process_namespace': None,\n", + " 'subdomain': None,\n", + " 'termination_grace_period_seconds': None,\n", + " 'tolerations': None,\n", + " 'topology_spread_constraints': None,\n", + " 'volumes': None}}],\n", + " 'engine_resources': {'limits': None,\n", + " 'requests': None},\n", + " 'explainer': {'config': {'batch_size': '1',\n", + " 'coverage_samples': '1',\n", + " 'min_samples_start': '5',\n", + " 'start_label': '1'},\n", + " 'container_spec': {'args': None,\n", + " 'command': None,\n", + " 'env': None,\n", + " 'env_from': None,\n", + " 'image': None,\n", + " 'image_pull_policy': None,\n", + " 'lifecycle': None,\n", + " 'liveness_probe': None,\n", + " 'name': '',\n", + " 'ports': None,\n", + " 'readiness_probe': None,\n", + " 'resources': {'limits': {'cpu': '2',\n", + " 'memory': '4Gi'},\n", + " 'requests': {'cpu': '1',\n", + " 'memory': '4Gi'}},\n", + " 'security_context': None,\n", + " 'startup_probe': None,\n", + " 'stdin': None,\n", + " 'stdin_once': None,\n", + " 'termination_message_path': None,\n", + " 'termination_message_policy': None,\n", + " 'tty': None,\n", + " 'volume_devices': None,\n", + " 'volume_mounts': None,\n", + " 'working_dir': None},\n", + " 'endpoint': None,\n", + " 'env_secret_ref_name': None,\n", + " 'model_uri': 'gs://tom-seldon-examples/workshops/manufacturing/pretrained/explainer',\n", + " 'replicas': None,\n", + " 'service_account_name': None,\n", + " 'storage_initializer_image': None,\n", + " 'type': 'AnchorImages'},\n", + " 'graph': {'children': None,\n", + " 'endpoint': None,\n", + " 'env_secret_ref_name': None,\n", + " 'implementation': 'TENSORFLOW_SERVER',\n", + " 'logger': {'mode': 'all', 'url': None},\n", + " 'methods': None,\n", + " 'model_uri': 'gs://tom-seldon-examples/workshops/manufacturing/josh/inception/',\n", + " 'name': 'inception',\n", + " 'parameters': None,\n", + " 'service_account_name': None,\n", + " 'storage_initializer_image': None,\n", + " 'type': None},\n", + " 'labels': None,\n", + " 'name': 'default',\n", + " 'replicas': 1,\n", + " 'shadow': None,\n", + " 'ssl': None,\n", + " 'svc_orch_spec': {'env': None,\n", + " 'replicas': None,\n", + " 'resources': None},\n", + " 'traffic': 70},\n", + " {'annotations': {'seldon.io/canary': 'true'},\n", + " 'component_specs': [{'hpa_spec': None,\n", + " 'keda_spec': None,\n", + " 'metadata': {'annotations': None,\n", + " 'cluster_name': None,\n", + " 'creation_timestamp': '2022-03-29T02:36:39Z',\n", + " 'deletion_grace_period_seconds': None,\n", + " 'deletion_timestamp': None,\n", + " 'finalizers': None,\n", + " 'generate_name': None,\n", + " 'generation': None,\n", + " 'labels': None,\n", + " 'managed_fields': None,\n", + " 'name': None,\n", + " 'namespace': None,\n", + " 'owner_references': None,\n", + " 'resource_version': None,\n", + " 'self_link': None,\n", + " 'uid': None},\n", + " 'pdb_spec': None,\n", + " 'replicas': None,\n", + " 'spec': {'active_deadline_seconds': None,\n", + " 'affinity': None,\n", + " 'automount_service_account_token': None,\n", + " 'containers': [{'args': None,\n", + " 'command': None,\n", + " 'env': None,\n", + " 'env_from': None,\n", + " 'image': None,\n", + " 'image_pull_policy': None,\n", + " 'lifecycle': None,\n", + " 'liveness_probe': None,\n", + " 'name': 'simple-cnn',\n", + " 'ports': None,\n", + " 'readiness_probe': None,\n", + " 'resources': {'limits': {'cpu': '2',\n", + " 'memory': '8Gi'},\n", + " 'requests': {'cpu': '2',\n", + " 'memory': '8Gi'}},\n", + " 'security_context': None,\n", + " 'startup_probe': None,\n", + " 'stdin': None,\n", + " 'stdin_once': None,\n", + " 'termination_message_path': None,\n", + " 'termination_message_policy': None,\n", + " 'tty': None,\n", + " 'volume_devices': None,\n", + " 'volume_mounts': None,\n", + " 'working_dir': None}],\n", + " 'dns_config': None,\n", + " 'dns_policy': None,\n", + " 'enable_service_links': None,\n", + " 'ephemeral_containers': None,\n", + " 'host_aliases': None,\n", + " 'host_ipc': None,\n", + " 'host_network': None,\n", + " 'host_pid': None,\n", + " 'hostname': None,\n", + " 'image_pull_secrets': None,\n", + " 'init_containers': None,\n", + " 'node_name': None,\n", + " 'node_selector': None,\n", + " 'overhead': None,\n", + " 'preemption_policy': None,\n", + " 'priority': None,\n", + " 'priority_class_name': None,\n", + " 'readiness_gates': None,\n", + " 'restart_policy': None,\n", + " 'runtime_class_name': None,\n", + " 'scheduler_name': None,\n", + " 'security_context': None,\n", + " 'service_account': None,\n", + " 'service_account_name': None,\n", + " 'set_hostname_as_fqdn': None,\n", + " 'share_process_namespace': None,\n", + " 'subdomain': None,\n", + " 'termination_grace_period_seconds': None,\n", + " 'tolerations': None,\n", + " 'topology_spread_constraints': None,\n", + " 'volumes': None}}],\n", + " 'engine_resources': {'limits': None,\n", + " 'requests': None},\n", + " 'explainer': None,\n", + " 'graph': {'children': None,\n", + " 'endpoint': None,\n", + " 'env_secret_ref_name': None,\n", + " 'implementation': 'TENSORFLOW_SERVER',\n", + " 'logger': {'mode': 'all', 'url': None},\n", + " 'methods': None,\n", + " 'model_uri': 'gs://tom-seldon-examples/workshops/manufacturing/josh/simple-cnn/',\n", + " 'name': 'simple-cnn',\n", + " 'parameters': None,\n", + " 'service_account_name': None,\n", + " 'storage_initializer_image': None,\n", + " 'type': None},\n", + " 'labels': None,\n", + " 'name': 'canary',\n", + " 'replicas': 1,\n", + " 'shadow': None,\n", + " 'ssl': None,\n", + " 'svc_orch_spec': {'env': None,\n", + " 'replicas': None,\n", + " 'resources': None},\n", + " 'traffic': 30}],\n", + " 'protocol': 'seldon',\n", + " 'replicas': None,\n", + " 'server_type': None,\n", + " 'transport': None},\n", + " 'status': {'address': None,\n", + " 'annotations': None,\n", + " 'conditions': None,\n", + " 'deployment_status': None,\n", + " 'description': None,\n", + " 'observed_generation': None,\n", + " 'replicas': None,\n", + " 'service_status': None,\n", + " 'state': None}}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "deployment_api = SeldonDeploymentsApi(auth())\n", + "deployment_api.create_seldon_deployment(\n", + " namespace=NAMESPACE, mldeployment=mldeployment)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "ename": "ApiException", + "evalue": "(403)\nReason: Forbidden\nHTTP response headers: HTTPHeaderDict({'content-type': 'application/json', 'date': 'Wed, 23 Mar 2022 13:45:20 GMT', 'content-length': '105', 'x-envoy-upstream-service-time': '7', 'server': 'istio-envoy'})\nHTTP response body: {\"body\":{\"code\":403,\"message\":\"Authorization Denied\",\"requestId\":\"10f007f0-6495-4b6b-b9a3-693f3b09bbfa\"}}\n", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mApiException\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/var/folders/xv/n51qjph14_52lj9y4706w6sc0000gn/T/ipykernel_98013/1372342636.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0mdeployment_api\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mSeldonDeploymentsApi\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mapi_client\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0mdeployment_api\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreate_seldon_deployment\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnamespace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mNAMESPACE\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmldeployment\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmldeployment\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api/seldon_deployments_api.py\u001b[0m in \u001b[0;36mcreate_seldon_deployment\u001b[0;34m(self, namespace, mldeployment, **kwargs)\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreate_seldon_deployment_with_http_info\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnamespace\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmldeployment\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# noqa: E501\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 58\u001b[0;31m \u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreate_seldon_deployment_with_http_info\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnamespace\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmldeployment\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# noqa: E501\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 59\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 60\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api/seldon_deployments_api.py\u001b[0m in \u001b[0;36mcreate_seldon_deployment_with_http_info\u001b[0;34m(self, namespace, mldeployment, **kwargs)\u001b[0m\n\u001b[1;32m 147\u001b[0m \u001b[0m_preload_content\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'_preload_content'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 148\u001b[0m \u001b[0m_request_timeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'_request_timeout'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 149\u001b[0;31m collection_formats=collection_formats)\n\u001b[0m\u001b[1;32m 150\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 151\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdelete_seldon_deployment\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnamespace\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# noqa: E501\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api_client.py\u001b[0m in \u001b[0;36mcall_api\u001b[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, async_req, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 355\u001b[0m \u001b[0mresponse_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mauth_settings\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 356\u001b[0m \u001b[0m_return_http_data_only\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcollection_formats\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 357\u001b[0;31m _preload_content, _request_timeout)\n\u001b[0m\u001b[1;32m 358\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 359\u001b[0m thread = self.pool.apply_async(self.__call_api_with_retry, (resource_path,\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api_client.py\u001b[0m in \u001b[0;36m__call_api_with_retry\u001b[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 125\u001b[0m _preload_content=_preload_content,_request_timeout=_request_timeout)\n\u001b[1;32m 126\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 127\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 128\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 129\u001b[0m def __call_api(\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api_client.py\u001b[0m in \u001b[0;36m__call_api_with_retry\u001b[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 113\u001b[0m \u001b[0mresponse_type\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mresponse_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mauth_settings\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mauth_settings\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 114\u001b[0m \u001b[0m_return_http_data_only\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_return_http_data_only\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcollection_formats\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcollection_formats\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 115\u001b[0;31m _preload_content=_preload_content,_request_timeout=_request_timeout)\n\u001b[0m\u001b[1;32m 116\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mseldon_deploy_sdk\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mApiException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 117\u001b[0m \u001b[0;31m#if unauthenticated and have authenticator try refreshing in case token expired\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api_client.py\u001b[0m in \u001b[0;36m__call_api\u001b[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 186\u001b[0m \u001b[0mpost_params\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mpost_params\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbody\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 187\u001b[0m \u001b[0m_preload_content\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_preload_content\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 188\u001b[0;31m _request_timeout=_request_timeout)\n\u001b[0m\u001b[1;32m 189\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 190\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlast_response\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mresponse_data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api_client.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(self, method, url, query_params, headers, post_params, body, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 398\u001b[0m \u001b[0m_preload_content\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_preload_content\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 399\u001b[0m \u001b[0m_request_timeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_request_timeout\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 400\u001b[0;31m body=body)\n\u001b[0m\u001b[1;32m 401\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmethod\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"PUT\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 402\u001b[0m return self.rest_client.PUT(url,\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/rest.py\u001b[0m in \u001b[0;36mPOST\u001b[0;34m(self, url, headers, query_params, post_params, body, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 273\u001b[0m \u001b[0m_preload_content\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_preload_content\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 274\u001b[0m \u001b[0m_request_timeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_request_timeout\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 275\u001b[0;31m body=body)\n\u001b[0m\u001b[1;32m 276\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 277\u001b[0m def PUT(self, url, headers=None, query_params=None, post_params=None,\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/rest.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(self, method, url, query_params, headers, body, post_params, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 226\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 227\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;36m200\u001b[0m \u001b[0;34m<=\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstatus\u001b[0m \u001b[0;34m<=\u001b[0m \u001b[0;36m299\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 228\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mApiException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhttp_resp\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 229\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 230\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mApiException\u001b[0m: (403)\nReason: Forbidden\nHTTP response headers: HTTPHeaderDict({'content-type': 'application/json', 'date': 'Wed, 23 Mar 2022 13:45:20 GMT', 'content-length': '105', 'x-envoy-upstream-service-time': '7', 'server': 'istio-envoy'})\nHTTP response body: {\"body\":{\"code\":403,\"message\":\"Authorization Denied\",\"requestId\":\"10f007f0-6495-4b6b-b9a3-693f3b09bbfa\"}}\n" + ] + } + ], + "source": [ + "\n", + "config = Configuration()\n", + "config.host = f\"http://{SD_IP}/seldon-deploy/api/v1alpha1\"\n", + "config.oidc_client_id = \"sd-api\"\n", + "config.oidc_server = f\"http://{SD_IP}/auth/realms/deploy-realm\"\n", + "config.oidc_client_secret = \"sd-api-secret\"\n", + "config.auth_method = \"client_credentials\"\n", + "\n", + "auth = OIDCAuthenticator(config)\n", + "config.id_token = auth.authenticate()\n", + "api_client = ApiClient(configuration=config, authenticator=auth)\n", + "\n", + "\n", + "\n", + "deployment_api = SeldonDeploymentsApi(api_client)\n", + "deployment_api.create_seldon_deployment(namespace=NAMESPACE, mldeployment=mldeployment)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "ename": "ApiException", + "evalue": "(403)\nReason: Forbidden\nHTTP response headers: HTTPHeaderDict({'content-type': 'application/json', 'date': 'Wed, 23 Mar 2022 13:46:13 GMT', 'content-length': '105', 'x-envoy-upstream-service-time': '4', 'server': 'istio-envoy'})\nHTTP response body: {\"body\":{\"code\":403,\"message\":\"Authorization Denied\",\"requestId\":\"b05ba0ef-32ef-4dd6-87cd-446a9716fc83\"}}\n", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mApiException\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m/var/folders/xv/n51qjph14_52lj9y4706w6sc0000gn/T/ipykernel_98013/2135827860.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 21\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0mdeployment_api\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mSeldonDeploymentsApi\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mapi_client\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 23\u001b[0;31m \u001b[0mdeployment_api\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreate_seldon_deployment\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnamespace\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mNAMESPACE\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmldeployment\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mmldeployment\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api/seldon_deployments_api.py\u001b[0m in \u001b[0;36mcreate_seldon_deployment\u001b[0;34m(self, namespace, mldeployment, **kwargs)\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreate_seldon_deployment_with_http_info\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnamespace\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmldeployment\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# noqa: E501\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 58\u001b[0;31m \u001b[0;34m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcreate_seldon_deployment_with_http_info\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnamespace\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmldeployment\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# noqa: E501\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 59\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mdata\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 60\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api/seldon_deployments_api.py\u001b[0m in \u001b[0;36mcreate_seldon_deployment_with_http_info\u001b[0;34m(self, namespace, mldeployment, **kwargs)\u001b[0m\n\u001b[1;32m 147\u001b[0m \u001b[0m_preload_content\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'_preload_content'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 148\u001b[0m \u001b[0m_request_timeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparams\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mget\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'_request_timeout'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 149\u001b[0;31m collection_formats=collection_formats)\n\u001b[0m\u001b[1;32m 150\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 151\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdelete_seldon_deployment\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnamespace\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# noqa: E501\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api_client.py\u001b[0m in \u001b[0;36mcall_api\u001b[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, async_req, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 355\u001b[0m \u001b[0mresponse_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mauth_settings\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 356\u001b[0m \u001b[0m_return_http_data_only\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcollection_formats\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 357\u001b[0;31m _preload_content, _request_timeout)\n\u001b[0m\u001b[1;32m 358\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 359\u001b[0m thread = self.pool.apply_async(self.__call_api_with_retry, (resource_path,\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api_client.py\u001b[0m in \u001b[0;36m__call_api_with_retry\u001b[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 125\u001b[0m _preload_content=_preload_content,_request_timeout=_request_timeout)\n\u001b[1;32m 126\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 127\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 128\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 129\u001b[0m def __call_api(\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api_client.py\u001b[0m in \u001b[0;36m__call_api_with_retry\u001b[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 113\u001b[0m \u001b[0mresponse_type\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mresponse_type\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mauth_settings\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mauth_settings\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 114\u001b[0m \u001b[0m_return_http_data_only\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_return_http_data_only\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcollection_formats\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcollection_formats\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 115\u001b[0;31m _preload_content=_preload_content,_request_timeout=_request_timeout)\n\u001b[0m\u001b[1;32m 116\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mseldon_deploy_sdk\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrest\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mApiException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 117\u001b[0m \u001b[0;31m#if unauthenticated and have authenticator try refreshing in case token expired\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api_client.py\u001b[0m in \u001b[0;36m__call_api\u001b[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 186\u001b[0m \u001b[0mpost_params\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mpost_params\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbody\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mbody\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 187\u001b[0m \u001b[0m_preload_content\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_preload_content\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 188\u001b[0;31m _request_timeout=_request_timeout)\n\u001b[0m\u001b[1;32m 189\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 190\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlast_response\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mresponse_data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/api_client.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(self, method, url, query_params, headers, post_params, body, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 398\u001b[0m \u001b[0m_preload_content\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_preload_content\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 399\u001b[0m \u001b[0m_request_timeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_request_timeout\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 400\u001b[0;31m body=body)\n\u001b[0m\u001b[1;32m 401\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mmethod\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0;34m\"PUT\"\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 402\u001b[0m return self.rest_client.PUT(url,\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/rest.py\u001b[0m in \u001b[0;36mPOST\u001b[0;34m(self, url, headers, query_params, post_params, body, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 273\u001b[0m \u001b[0m_preload_content\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_preload_content\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 274\u001b[0m \u001b[0m_request_timeout\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0m_request_timeout\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 275\u001b[0;31m body=body)\n\u001b[0m\u001b[1;32m 276\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 277\u001b[0m def PUT(self, url, headers=None, query_params=None, post_params=None,\n", + "\u001b[0;32m~/opt/anaconda3/envs/manufactoring-workshop/lib/python3.7/site-packages/seldon_deploy_sdk/rest.py\u001b[0m in \u001b[0;36mrequest\u001b[0;34m(self, method, url, query_params, headers, body, post_params, _preload_content, _request_timeout)\u001b[0m\n\u001b[1;32m 226\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 227\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;36m200\u001b[0m \u001b[0;34m<=\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstatus\u001b[0m \u001b[0;34m<=\u001b[0m \u001b[0;36m299\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 228\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mApiException\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mhttp_resp\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 229\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 230\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mApiException\u001b[0m: (403)\nReason: Forbidden\nHTTP response headers: HTTPHeaderDict({'content-type': 'application/json', 'date': 'Wed, 23 Mar 2022 13:46:13 GMT', 'content-length': '105', 'x-envoy-upstream-service-time': '4', 'server': 'istio-envoy'})\nHTTP response body: {\"body\":{\"code\":403,\"message\":\"Authorization Denied\",\"requestId\":\"b05ba0ef-32ef-4dd6-87cd-446a9716fc83\"}}\n" + ] + } + ], + "source": [ + "\n", + "config = Configuration()\n", + "config.host = f\"http://{SD_IP}/seldon-deploy/api/v1alpha1\"\n", + "config.oidc_server = f\"http://{SD_IP}/auth/realms/deploy-realm\"\n", + "\n", + "## These are the updated config values:\n", + "config.oidc_client_id = \"deploy-server\"\n", + "config.oidc_client_secret = \"deploy-secret\"\n", + "config.auth_method = \"password_grant\"\n", + "config.username = \"admin@seldon.io\"\n", + "config.password = \"12341234\"\n", + "\n", + "auth = OIDCAuthenticator(config)\n", + "config.id_token = auth.authenticate()\n", + "api_client = ApiClient(configuration=config, authenticator=auth)\n", + "\n", + "\n", + "# env_api = EnvironmentApi(api_client)\n", + "# user = env_api.read_user()\n", + "# user\n", + "\n", + "\n", + "deployment_api = SeldonDeploymentsApi(api_client)\n", + "deployment_api.create_seldon_deployment(namespace=NAMESPACE, mldeployment=mldeployment)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Outlier Detection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "load_outlier_detector = False\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### AE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from alibi_detect.od import OutlierAE\n", + "\n", + "\n", + "# change to (absolute) directory where model is downloaded\n", + "filepath = 'outlier'\n", + "detector_type = 'outlier'\n", + "dataset = 'test'\n", + "detector_name = 'OutlierAE'\n", + "filepath = os.path.join(filepath, detector_name)\n", + "if load_outlier_detector: # load pretrained outlier detector\n", + " od = fetch_detector(filepath, detector_type, dataset, detector_name)\n", + "else: # define model, initialize, train and save outlier detector\n", + " encoding_dim = 1024\n", + "\n", + " encoder_net = tf.keras.Sequential(\n", + " [\n", + " InputLayer(input_shape=(32, 32, 3)),\n", + " Conv2D(64, 4, strides=2, padding='same', activation=tf.nn.relu),\n", + " Conv2D(128, 4, strides=2, padding='same', activation=tf.nn.relu),\n", + " Conv2D(512, 4, strides=2, padding='same', activation=tf.nn.relu),\n", + " Flatten(),\n", + " Dense(encoding_dim,)\n", + " ])\n", + "\n", + " decoder_net = tf.keras.Sequential(\n", + " [\n", + " InputLayer(input_shape=(encoding_dim,)),\n", + " Dense(4*4*128),\n", + " Reshape(target_shape=(4, 4, 128)),\n", + " Conv2DTranspose(256, 4, strides=2, padding='same',\n", + " activation=tf.nn.relu),\n", + " Conv2DTranspose(64, 4, strides=2, padding='same',\n", + " activation=tf.nn.relu),\n", + " Conv2DTranspose(3, 4, strides=2, padding='same',\n", + " activation='sigmoid')\n", + " ])\n", + "\n", + " # initialize outlier detector\n", + " od = OutlierAE(threshold=.015, # threshold for outlier score\n", + " encoder_net=encoder_net, # can also pass AE model instead\n", + " decoder_net=decoder_net, # of separate encoder and decoder\n", + " )\n", + " # train\n", + " od.fit(train_ds,\n", + " epochs=50,\n", + " verbose=True)\n", + "\n", + " # save the trained outlier detector\n", + " save_detector(od, filepath)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### VAE" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "filepath = 'outlier' # change to directory where model is downloaded\n", + "detector_type = 'outlier'\n", + "dataset = 'test'\n", + "detector_name = 'OutlierVAE'\n", + "filepath = os.path.join(filepath, detector_name)\n", + "if load_outlier_detector: # load pretrained outlier detector\n", + " od = fetch_detector(filepath, detector_type, dataset, detector_name)\n", + "else: # define model, initialize, train and save outlier detector\n", + " latent_dim = 1024\n", + "\n", + " encoder_net = tf.keras.Sequential(\n", + " [\n", + " InputLayer(input_shape=(224, 224, 3)),\n", + " Conv2D(64, 4, strides=2, padding='same', activation=tf.nn.relu),\n", + " Conv2D(128, 4, strides=2, padding='same', activation=tf.nn.relu),\n", + " Conv2D(512, 4, strides=2, padding='same', activation=tf.nn.relu)\n", + " ])\n", + "\n", + " decoder_net = tf.keras.Sequential(\n", + " [\n", + " InputLayer(input_shape=(latent_dim,)),\n", + " Dense(4*4*128),\n", + " Reshape(target_shape=(4, 4, 128)),\n", + " Conv2DTranspose(256, 4, strides=2, padding='same',\n", + " activation=tf.nn.relu),\n", + " Conv2DTranspose(64, 4, strides=2, padding='same',\n", + " activation=tf.nn.relu),\n", + " Conv2DTranspose(3, 4, strides=2, padding='same',\n", + " activation='sigmoid')\n", + " ])\n", + "\n", + " # initialize outlier detector\n", + " od = OutlierVAE(threshold=.015, # threshold for outlier score\n", + " score_type='mse', # use MSE of reconstruction error for outlier detection\n", + " encoder_net=encoder_net, # can also pass VAE model instead\n", + " decoder_net=decoder_net, # of separate encoder and decoder\n", + " latent_dim=latent_dim,\n", + " samples=2)\n", + " # train\n", + " od.fit(train_ds,\n", + " loss_fn=elbo,\n", + " cov_elbo=dict(sim=.05),\n", + " epochs=2,\n", + " verbose=True)\n", + "\n", + " # save the trained outlier detector\n", + " save_detector(od, filepath)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Check quality VAE model" ] }, { @@ -934,7 +2352,116 @@ "metadata": {}, "outputs": [], "source": [ - "!gsutil cp -r defect-drift gs://tom-seldon-examples/workshops/manufacturing//" + "example_image = train_ds.next()\n", + "example_image = example_image[0][0]\n", + "print(example_image.shape)\n", + "plt.imshow(example_image[:, :])\n", + "\n", + "example_image = example_image / 255\n", + "example_image = example_image.reshape((-1,) + test_image.shape)\n", + "\n", + "print(type(example_image))\n", + "print(example_image.shape)\n", + "\n", + "y_pred = np.argmax(model.predict(test_image), axis=-1)\n", + "print(y_pred)\n", + "classname = y_pred[0]\n", + "print(\"Class: \", categories[classname])\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "example_image = val_ds.next()\n", + "# label = --> grab the real label\n", + "example_image_np = example_image[0][0]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "from skimage import data\n", + "from skimage import color\n", + "from skimage import morphology\n", + "from skimage import segmentation\n", + "\n", + "# Input data\n", + "img = example_image_np\n", + "print(type(img))\n", + "# Compute a mask\n", + "lum = color.rgb2gray(img)\n", + "mask = morphology.remove_small_holes(\n", + " morphology.remove_small_objects(\n", + " lum < 0.7, 500),\n", + " 500)\n", + "\n", + "mask = morphology.opening(mask, morphology.disk(3))\n", + "\n", + "# SLIC result\n", + "slic = segmentation.slic(img, n_segments=15, start_label=1)\n", + "\n", + "# maskSLIC result\n", + "m_slic = segmentation.slic(img, n_segments=100, mask=mask, start_label=1)\n", + "\n", + "# Display result\n", + "fig, ax_arr = plt.subplots(2, 2, sharex=True, sharey=True, figsize=(10, 10))\n", + "ax1, ax2, ax3, ax4 = ax_arr.ravel()\n", + "\n", + "ax1.imshow(img)\n", + "ax1.set_title('Original image')\n", + "\n", + "ax2.imshow(mask, cmap='gray')\n", + "ax2.set_title('Mask')\n", + "\n", + "ax3.imshow(segmentation.mark_boundaries(img, slic))\n", + "ax3.contour(mask, colors='red', linewidths=1)\n", + "ax3.set_title('SLIC')\n", + "\n", + "ax4.imshow(segmentation.mark_boundaries(img, m_slic))\n", + "ax4.contour(mask, colors='red', linewidths=1)\n", + "ax4.set_title('maskSLIC')\n", + "\n", + "for ax in ax_arr.ravel():\n", + " ax.set_axis_off()\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n" ] }, { @@ -943,7 +2470,8 @@ "metadata": {}, "outputs": [], "source": [ - "f\"gs://tom-seldon-examples/workshops/manufacturing//{filepath}\"" + "# SLIC result\n", + "segmentation.slic(img, n_segments=15, start_label=1).shape\n" ] }, {