From a661972b370d884b1b8adae3764def6a030fd00f Mon Sep 17 00:00:00 2001 From: Marco Gorelli Date: Tue, 1 Jun 2021 21:18:28 +0100 Subject: [PATCH] run nbqa-black and nbqa-isort --- .../cifar10/cifar10_drift.ipynb | 83 +- .../nvidia-triton-cifar10/cifar10_drift.ipynb | 114 +- .../cifar10/cifar10_outlier.ipynb | 94 +- .../cifar10_outlier.ipynb | 119 +- .../case_study/credit_card_default.ipynb | 161 +- .../routers/epsilon-greedy/egreedy.ipynb | 49 +- .../ambassador/canary/ambassador_canary.ipynb | 19 +- .../ambassador_circuit_breakers.ipynb | 7 +- .../ambassador/custom/ambassador_custom.ipynb | 12 +- .../headers/ambassador_headers.ipynb | 18 +- .../ambassador/shadow/ambassador_shadow.ipynb | 14 +- .../batch/argo-workflows-batch/README.ipynb | 3 +- .../benchmarking-argo-workflows/README.ipynb | 11 +- .../hdfs-argo-workflows/hdfs-batch.ipynb | 3 +- .../kubeflow-pipelines-batch/README.ipynb | 2 +- .../models/image_classifier/README.ipynb | 9 +- .../models/news_classifier/README.ipynb | 27 +- .../torchserver/test/sklearn_iris.ipynb | 36 +- .../sig-mlops-seldon-jenkins-x/README.ipynb | 27 +- .../feedback-metrics-server/README.ipynb | 460 ++- examples/feedback/metrics-server/README.ipynb | 2 + .../feedback/reward-accuracy/README.ipynb | 444 ++- .../upgrade_1_2_volume_patch/README.ipynb | 4 +- examples/istio/canary/istio_canary.ipynb | 23 +- examples/kafka/cifar10/cifar10_kafka.ipynb | 4 +- .../kubeflow_seldon_e2e_pipeline.ipynb | 2847 +++++++++-------- .../alibaba_cloud_ack_deep_mnist.ipynb | 74 +- .../aws_eks_deep_mnist.ipynb | 72 +- .../azure_aks_deep_mnist.ipynb | 70 +- .../models/chainer_mnist/chainer_mnist.ipynb | 134 +- .../cpp/buildsystem-override/README.ipynb | 2 +- .../models/custom_metrics/customMetrics.ipynb | 21 +- .../custom_metrics/tfservingMetrics.ipynb | 6 +- .../gpu_tensorflow_deep_mnist.ipynb | 26 +- examples/models/h2o_mojo/h2o_model.ipynb | 18 +- examples/models/metadata/graph_metadata.ipynb | 231 +- examples/models/metadata/metadata.ipynb | 101 +- .../metadata/metadata_schema_examples.ipynb | 5 +- .../mlflow_server_ab_test_ambassador.ipynb | 53 +- .../models/openvino/openvino-squeezenet.ipynb | 34 +- .../payload_logging/payload_logging.ipynb | 3 +- examples/models/resnet/reset.ipynb | 135 +- .../models/sklearn_iris/sklearn_iris.ipynb | 31 +- .../sklearn_iris_customdata.ipynb | 38 +- ...klearn_spacy_text_classifier_example.ipynb | 68 +- examples/models/statsmodels/statsmodels.ipynb | 50 +- .../models/tensorrt/triton_tensorrt.ipynb | 815 ++++- .../tfserving-mnist/tfserving-mnist.ipynb | 105 +- examples/models/xss/xss-example.ipynb | 4 +- .../alibi-detect-combiner/notebook.ipynb | 42 +- examples/pachyderm-cd4ml/index.ipynb | 31 +- .../ray/batch-split-proxy/ray-proxy.ipynb | 12 +- examples/security/ssl_requests/README.ipynb | 2 +- .../streaming/knative-eventing/README.ipynb | 2 +- examples/triton_gpt2/README.ipynb | 112 +- .../nodejs_tensorflow/nodejs_tensorflow.ipynb | 2 +- notebooks/backwards_compatability.ipynb | 3 +- notebooks/explainer_examples.ipynb | 318 +- notebooks/helm_examples.ipynb | 30 +- notebooks/istio_example.ipynb | 13 +- notebooks/max_grpc_msg_size.ipynb | 32 +- notebooks/minio_setup.ipynb | 2 +- notebooks/operator_upgrade.ipynb | 22 +- notebooks/seldon_client.ipynb | 62 +- notebooks/server_examples.ipynb | 64 +- notebooks/timeouts.ipynb | 3 +- notebooks/triton_examples.ipynb | 146 +- python/Makefile | 8 +- .../mlflowserver/test/mlflow_example.ipynb | 12 +- servers/sklearnserver/test/sklearn_iris.ipynb | 36 +- servers/xgboostserver/test/xgboost_iris.ipynb | 24 +- testing/benchmarking/svcOrch/svcOrch.ipynb | 23 +- .../benchmarking/tensorflow/tensorflow.ipynb | 15 +- testing/notebooks/microservice_tests.ipynb | 75 +- util/kafka/create_request_datasets.ipynb | 37 +- 75 files changed, 5134 insertions(+), 2682 deletions(-) diff --git a/components/drift-detection/cifar10/cifar10_drift.ipynb b/components/drift-detection/cifar10/cifar10_drift.ipynb index 668eb2e049..7d21828f8b 100644 --- a/components/drift-detection/cifar10/cifar10_drift.ipynb +++ b/components/drift-detection/cifar10/cifar10_drift.ipynb @@ -346,7 +346,7 @@ "metadata": {}, "outputs": [], "source": [ - "#CLUSTER_IP=\"localhost:8004\"" + "# CLUSTER_IP=\"localhost:8004\"" ] }, { @@ -366,56 +366,79 @@ "metadata": {}, "outputs": [], "source": [ + "import json\n", + "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import requests\n", - "import json\n", "import tensorflow as tf\n", + "\n", "tf.keras.backend.clear_session()\n", "\n", "train, test = tf.keras.datasets.cifar10.load_data()\n", "X_train, y_train = train\n", "X_test, y_test = test\n", "\n", - "X_train = X_train.astype('float32') / 255\n", - "X_test = X_test.astype('float32') / 255\n", + "X_train = X_train.astype(\"float32\") / 255\n", + "X_test = X_test.astype(\"float32\") / 255\n", "print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)\n", - "classes = ('plane', 'car', 'bird', 'cat',\n", - " 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')\n", + "classes = (\n", + " \"plane\",\n", + " \"car\",\n", + " \"bird\",\n", + " \"cat\",\n", + " \"deer\",\n", + " \"dog\",\n", + " \"frog\",\n", + " \"horse\",\n", + " \"ship\",\n", + " \"truck\",\n", + ")\n", + "\n", "\n", "def show(X):\n", " plt.imshow(X.reshape(32, 32, 3))\n", - " plt.axis('off')\n", + " plt.axis(\"off\")\n", " plt.show()\n", "\n", + "\n", "def predict(X):\n", - " formData = {\n", - " 'instances': X.tolist()\n", - " }\n", + " formData = {\"instances\": X.tolist()}\n", " headers = {}\n", - " res = requests.post('http://'+CLUSTER_IP+'/seldon/cifar10drift/tfserving-cifar10/v1/models/resnet32/:predict', json=formData, headers=headers)\n", + " res = requests.post(\n", + " \"http://\"\n", + " + CLUSTER_IP\n", + " + \"/seldon/cifar10drift/tfserving-cifar10/v1/models/resnet32/:predict\",\n", + " json=formData,\n", + " headers=headers,\n", + " )\n", " if res.status_code == 200:\n", " j = res.json()\n", " if len(j[\"predictions\"]) == 1:\n", " return classes[np.array(j[\"predictions\"])[0].argmax()]\n", " else:\n", - " print(\"Failed with \",res.status_code)\n", + " print(\"Failed with \", res.status_code)\n", " return []\n", - " \n", + "\n", + "\n", "def drift(X):\n", - " formData = {\n", - " 'instances': X.tolist()\n", - " }\n", + " formData = {\"instances\": X.tolist()}\n", " headers = {}\n", - " headers = { \"ce-namespace\": \"default\",\"ce-modelid\":\"cifar10drift\",\"ce-type\":\"io.seldon.serving.inference.request\", \\\n", - " \"ce-id\":\"1234\",\"ce-source\":\"localhost\",\"ce-specversion\":\"1.0\"}\n", + " headers = {\n", + " \"ce-namespace\": \"default\",\n", + " \"ce-modelid\": \"cifar10drift\",\n", + " \"ce-type\": \"io.seldon.serving.inference.request\",\n", + " \"ce-id\": \"1234\",\n", + " \"ce-source\": \"localhost\",\n", + " \"ce-specversion\": \"1.0\",\n", + " }\n", " headers[\"Host\"] = SERVICE_HOSTNAME_CD\n", - " res = requests.post('http://'+CLUSTER_IP+'/', json=formData, headers=headers)\n", + " res = requests.post(\"http://\" + CLUSTER_IP + \"/\", json=formData, headers=headers)\n", " if res.status_code == 200:\n", " od = res.json()\n", " return od\n", " else:\n", - " print(\"Failed with \",res.status_code)\n", + " print(\"Failed with \", res.status_code)\n", " return []" ] }, @@ -435,7 +458,7 @@ "outputs": [], "source": [ "idx = 1\n", - "X = X_train[idx:idx+1]\n", + "X = X_train[idx : idx + 1]\n", "show(X)\n", "predict(X)" ] @@ -460,7 +483,7 @@ "metadata": {}, "outputs": [], "source": [ - "!kubectl logs -n cifar10drift $(kubectl get pod -n cifar10drift -l app=hello-display -o jsonpath='{.items[0].metadata.name}') " + "!kubectl logs -n cifar10drift $(kubectl get pod -n cifar10drift -l app=hello-display -o jsonpath='{.items[0].metadata.name}')" ] }, { @@ -477,8 +500,9 @@ "outputs": [], "source": [ "from tqdm import tqdm\n", - "for i in tqdm(range(0,5000,100)):\n", - " X = X_train[i:i+100]\n", + "\n", + "for i in tqdm(range(0, 5000, 100)):\n", + " X = X_train[i : i + 100]\n", " predict(X)" ] }, @@ -517,10 +541,11 @@ "metadata": {}, "outputs": [], "source": [ - "from alibi_detect.datasets import fetch_cifar10c, corruption_types_cifar10c\n", - "corruption = ['motion_blur']\n", + "from alibi_detect.datasets import corruption_types_cifar10c, fetch_cifar10c\n", + "\n", + "corruption = [\"motion_blur\"]\n", "X_corr, y_corr = fetch_cifar10c(corruption=corruption, severity=5, return_X_y=True)\n", - "X_corr = X_corr.astype('float32') / 255" + "X_corr = X_corr.astype(\"float32\") / 255" ] }, { @@ -547,8 +572,8 @@ "metadata": {}, "outputs": [], "source": [ - "for i in tqdm(range(0,5000,100)):\n", - " X = X_corr[i:i+100]\n", + "for i in tqdm(range(0, 5000, 100)):\n", + " X = X_corr[i : i + 100]\n", " predict(X)" ] }, diff --git a/components/drift-detection/nvidia-triton-cifar10/cifar10_drift.ipynb b/components/drift-detection/nvidia-triton-cifar10/cifar10_drift.ipynb index 6de1babb45..7f596a2d90 100644 --- a/components/drift-detection/nvidia-triton-cifar10/cifar10_drift.ipynb +++ b/components/drift-detection/nvidia-triton-cifar10/cifar10_drift.ipynb @@ -429,7 +429,7 @@ "metadata": {}, "outputs": [], "source": [ - "#CLUSTER_IP=\"localhost:8004\"" + "# CLUSTER_IP=\"localhost:8004\"" ] }, { @@ -445,7 +445,7 @@ "metadata": {}, "outputs": [], "source": [ - "TOKEN=\"Bearer \"" + "TOKEN = \"Bearer \"" ] }, { @@ -481,73 +481,104 @@ } ], "source": [ + "import json\n", + "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import requests\n", - "import json\n", "import tensorflow as tf\n", + "\n", "tf.keras.backend.clear_session()\n", "\n", "train, test = tf.keras.datasets.cifar10.load_data()\n", "X_train, y_train = train\n", "X_test, y_test = test\n", "\n", - "X_train = X_train.astype('float32') / 255\n", - "X_test = X_test.astype('float32') / 255\n", + "X_train = X_train.astype(\"float32\") / 255\n", + "X_test = X_test.astype(\"float32\") / 255\n", "print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)\n", - "classes = ('plane', 'car', 'bird', 'cat',\n", - " 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')\n", + "classes = (\n", + " \"plane\",\n", + " \"car\",\n", + " \"bird\",\n", + " \"cat\",\n", + " \"deer\",\n", + " \"dog\",\n", + " \"frog\",\n", + " \"horse\",\n", + " \"ship\",\n", + " \"truck\",\n", + ")\n", + "\n", "\n", "def show(X):\n", " plt.imshow(X.reshape(32, 32, 3))\n", - " plt.axis('off')\n", + " plt.axis(\"off\")\n", " plt.show()\n", "\n", + "\n", "def predict(X):\n", " formData = {\n", - " 'inputs': [{\n", - " \"name\":\"input_1\",\n", - " \"datatype\": \"FP32\",\n", - " \"shape\": [X.shape[0], 32, 32, 3],\n", - " \"data\": X.flatten().tolist()\n", - " }]\n", + " \"inputs\": [\n", + " {\n", + " \"name\": \"input_1\",\n", + " \"datatype\": \"FP32\",\n", + " \"shape\": [X.shape[0], 32, 32, 3],\n", + " \"data\": X.flatten().tolist(),\n", + " }\n", + " ]\n", " }\n", " headers = {\n", - " \"Authorization\":\"Bearer \"+TOKEN,\n", - " \"X-Auth-Token\":TOKEN,\n", - " \"Content-Type\": \"application/json\"\n", - " }\n", - " res = requests.post('http://'+CLUSTER_IP+'/seldon/cifar10drift/triton-cifar10/v2/models/cifar10/infer', json=formData, headers=headers)\n", + " \"Authorization\": \"Bearer \" + TOKEN,\n", + " \"X-Auth-Token\": TOKEN,\n", + " \"Content-Type\": \"application/json\",\n", + " }\n", + " res = requests.post(\n", + " \"http://\"\n", + " + CLUSTER_IP\n", + " + \"/seldon/cifar10drift/triton-cifar10/v2/models/cifar10/infer\",\n", + " json=formData,\n", + " headers=headers,\n", + " )\n", " if res.status_code == 200:\n", " j = res.json()\n", " y = np.array(j[\"outputs\"][0][\"data\"])\n", " y.shape = tuple(j[\"outputs\"][0][\"shape\"])\n", " return [classes[x.argmax()] for x in y]\n", " else:\n", - " print(\"Failed with \",res.status_code)\n", + " print(\"Failed with \", res.status_code)\n", " return []\n", - " \n", + "\n", + "\n", "def drift(X):\n", " formData = {\n", - " 'inputs': [{\n", - " \"name\":\"input_1\",\n", - " \"datatype\": \"FP32\",\n", - " \"shape\": [1, 32, 32, 3],\n", - " \"data\": X.flatten().tolist()\n", - " }]\n", + " \"inputs\": [\n", + " {\n", + " \"name\": \"input_1\",\n", + " \"datatype\": \"FP32\",\n", + " \"shape\": [1, 32, 32, 3],\n", + " \"data\": X.flatten().tolist(),\n", + " }\n", + " ]\n", " }\n", " headers = {}\n", - " headers = { \"ce-namespace\": \"default\",\"ce-modelid\":\"cifar10drift\",\"ce-type\":\"io.seldon.serving.inference.request\", \\\n", - " \"ce-id\":\"1234\",\"ce-source\":\"localhost\",\"ce-specversion\":\"1.0\"}\n", + " headers = {\n", + " \"ce-namespace\": \"default\",\n", + " \"ce-modelid\": \"cifar10drift\",\n", + " \"ce-type\": \"io.seldon.serving.inference.request\",\n", + " \"ce-id\": \"1234\",\n", + " \"ce-source\": \"localhost\",\n", + " \"ce-specversion\": \"1.0\",\n", + " }\n", " headers[\"Host\"] = SERVICE_HOSTNAME_CD\n", " headers[\"X-Auth-Token\"] = TOKEN\n", - " headers[\"Authorization\"] = \"Bearer \"+TOKEN\n", - " res = requests.post('http://'+CLUSTER_IP+'/', json=formData, headers=headers)\n", + " headers[\"Authorization\"] = \"Bearer \" + TOKEN\n", + " res = requests.post(\"http://\" + CLUSTER_IP + \"/\", json=formData, headers=headers)\n", " if res.status_code == 200:\n", " od = res.json()\n", " return od\n", " else:\n", - " print(\"Failed with \",res.status_code)\n", + " print(\"Failed with \", res.status_code)\n", " return []" ] }, @@ -590,7 +621,7 @@ ], "source": [ "idx = 1\n", - "X = X_train[idx:idx+1]\n", + "X = X_train[idx : idx + 1]\n", "show(X)\n", "predict(X)" ] @@ -638,8 +669,9 @@ ], "source": [ "from tqdm.notebook import tqdm\n", - "for i in tqdm(range(1,5000,500)):\n", - " X = X_train[i:i+500]\n", + "\n", + "for i in tqdm(range(1, 5000, 500)):\n", + " X = X_train[i : i + 500]\n", " predict(X)" ] }, @@ -686,10 +718,11 @@ "metadata": {}, "outputs": [], "source": [ - "from alibi_detect.datasets import fetch_cifar10c, corruption_types_cifar10c\n", - "corruption = ['motion_blur']\n", + "from alibi_detect.datasets import corruption_types_cifar10c, fetch_cifar10c\n", + "\n", + "corruption = [\"motion_blur\"]\n", "X_corr, y_corr = fetch_cifar10c(corruption=corruption, severity=5, return_X_y=True)\n", - "X_corr = X_corr.astype('float32') / 255" + "X_corr = X_corr.astype(\"float32\") / 255" ] }, { @@ -769,8 +802,9 @@ ], "source": [ "from tqdm.notebook import tqdm\n", - "for i in tqdm(range(0,5000,500)):\n", - " X = X_corr[i:i+500]\n", + "\n", + "for i in tqdm(range(0, 5000, 500)):\n", + " X = X_corr[i : i + 500]\n", " predict(X)" ] }, diff --git a/components/outlier-detection/cifar10/cifar10_outlier.ipynb b/components/outlier-detection/cifar10/cifar10_outlier.ipynb index d71cfd6afc..e2a036d635 100644 --- a/components/outlier-detection/cifar10/cifar10_outlier.ipynb +++ b/components/outlier-detection/cifar10/cifar10_outlier.ipynb @@ -355,7 +355,7 @@ "metadata": {}, "outputs": [], "source": [ - "TOKEN=\"Bearer \"" + "TOKEN = \"Bearer \"" ] }, { @@ -371,7 +371,7 @@ "metadata": {}, "outputs": [], "source": [ - "#CLUSTER_IP=\"localhost:8004\"" + "# CLUSTER_IP=\"localhost:8004\"" ] }, { @@ -391,61 +391,85 @@ "metadata": {}, "outputs": [], "source": [ + "import json\n", + "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", - "import json\n", "import tensorflow as tf\n", + "\n", "tf.keras.backend.clear_session()\n", "\n", + "import requests\n", "from alibi_detect.od.vae import OutlierVAE\n", "from alibi_detect.utils.perturbation import apply_mask\n", "from alibi_detect.utils.visualize import plot_feature_outlier_image\n", - "import requests\n", "\n", "train, test = tf.keras.datasets.cifar10.load_data()\n", "X_train, y_train = train\n", "X_test, y_test = test\n", "\n", - "X_train = X_train.astype('float32') / 255\n", - "X_test = X_test.astype('float32') / 255\n", + "X_train = X_train.astype(\"float32\") / 255\n", + "X_test = X_test.astype(\"float32\") / 255\n", "print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)\n", - "classes = ('plane', 'car', 'bird', 'cat',\n", - " 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')\n", + "classes = (\n", + " \"plane\",\n", + " \"car\",\n", + " \"bird\",\n", + " \"cat\",\n", + " \"deer\",\n", + " \"dog\",\n", + " \"frog\",\n", + " \"horse\",\n", + " \"ship\",\n", + " \"truck\",\n", + ")\n", + "\n", "\n", "def show(X):\n", " plt.imshow(X.reshape(32, 32, 3))\n", - " plt.axis('off')\n", + " plt.axis(\"off\")\n", " plt.show()\n", "\n", + "\n", "def predict(X):\n", - " formData = {\n", - " 'instances': X.tolist()\n", - " }\n", - " headers = {\"Authorization\":TOKEN}\n", - " res = requests.post('http://'+CLUSTER_IP+'/seldon/cifar10/tfserving-cifar10/v1/models/resnet32/:predict', json=formData, headers=headers)\n", + " formData = {\"instances\": X.tolist()}\n", + " headers = {\"Authorization\": TOKEN}\n", + " res = requests.post(\n", + " \"http://\"\n", + " + CLUSTER_IP\n", + " + \"/seldon/cifar10/tfserving-cifar10/v1/models/resnet32/:predict\",\n", + " json=formData,\n", + " headers=headers,\n", + " )\n", " if res.status_code == 200:\n", " return classes[np.array(res.json()[\"predictions\"])[0].argmax()]\n", " else:\n", - " print(\"Failed with \",res.status_code)\n", + " print(\"Failed with \", res.status_code)\n", " return []\n", - " \n", + "\n", + "\n", "def outlier(X):\n", - " formData = {\n", - " 'instances': X.tolist()\n", + " formData = {\"instances\": X.tolist()}\n", + " headers = {\n", + " \"Alibi-Detect-Return-Feature-Score\": \"true\",\n", + " \"Alibi-Detect-Return-Instance-Score\": \"true\",\n", + " \"ce-namespace\": \"default\",\n", + " \"ce-modelid\": \"cifar10\",\n", + " \"ce-type\": \"io.seldon.serving.inference.request\",\n", + " \"ce-id\": \"1234\",\n", + " \"ce-source\": \"localhost\",\n", + " \"ce-specversion\": \"1.0\",\n", " }\n", - " headers = {\"Alibi-Detect-Return-Feature-Score\":\"true\",\"Alibi-Detect-Return-Instance-Score\":\"true\", \\\n", - " \"ce-namespace\": \"default\",\"ce-modelid\":\"cifar10\",\"ce-type\":\"io.seldon.serving.inference.request\", \\\n", - " \"ce-id\":\"1234\",\"ce-source\":\"localhost\",\"ce-specversion\":\"1.0\"}\n", " headers[\"Host\"] = SERVICE_HOSTNAME_VAEOD\n", " headers[\"Authorization\"] = TOKEN\n", - " res = requests.post('http://'+CLUSTER_IP+'/', json=formData, headers=headers)\n", + " res = requests.post(\"http://\" + CLUSTER_IP + \"/\", json=formData, headers=headers)\n", " if res.status_code == 200:\n", " od = res.json()\n", " od[\"data\"][\"feature_score\"] = np.array(od[\"data\"][\"feature_score\"])\n", " od[\"data\"][\"instance_score\"] = np.array(od[\"data\"][\"instance_score\"])\n", " return od\n", " else:\n", - " print(\"Failed with \",res.status_code)\n", + " print(\"Failed with \", res.status_code)\n", " return []" ] }, @@ -465,7 +489,7 @@ "outputs": [], "source": [ "idx = 1\n", - "X = X_train[idx:idx+1]\n", + "X = X_train[idx : idx + 1]\n", "show(X)\n", "predict(X)" ] @@ -505,14 +529,16 @@ "metadata": {}, "outputs": [], "source": [ - "np.random.seed(0) \n", - "X_mask, mask = apply_mask(X.reshape(1, 32, 32, 3),\n", - " mask_size=(10,10),\n", - " n_masks=1,\n", - " channels=[0,1,2],\n", - " mask_type='normal',\n", - " noise_distr=(0,1),\n", - " clip_rng=(0,1))" + "np.random.seed(0)\n", + "X_mask, mask = apply_mask(\n", + " X.reshape(1, 32, 32, 3),\n", + " mask_size=(10, 10),\n", + " n_masks=1,\n", + " channels=[0, 1, 2],\n", + " mask_type=\"normal\",\n", + " noise_distr=(0, 1),\n", + " clip_rng=(0, 1),\n", + ")" ] }, { @@ -576,9 +602,7 @@ "metadata": {}, "outputs": [], "source": [ - "plot_feature_outlier_image(od_preds, \n", - " X_mask, \n", - " X_recon=None)" + "plot_feature_outlier_image(od_preds, X_mask, X_recon=None)" ] }, { diff --git a/components/outlier-detection/nvidia-triton-cifar10/cifar10_outlier.ipynb b/components/outlier-detection/nvidia-triton-cifar10/cifar10_outlier.ipynb index aeba566281..8f76306da3 100644 --- a/components/outlier-detection/nvidia-triton-cifar10/cifar10_outlier.ipynb +++ b/components/outlier-detection/nvidia-triton-cifar10/cifar10_outlier.ipynb @@ -427,7 +427,7 @@ "metadata": {}, "outputs": [], "source": [ - "TOKEN=\"Bearer \"" + "TOKEN = \"Bearer \"" ] }, { @@ -443,7 +443,7 @@ "metadata": {}, "outputs": [], "source": [ - "#CLUSTER_IP=\"localhost:8004\"" + "# CLUSTER_IP=\"localhost:8004\"" ] }, { @@ -479,74 +479,103 @@ } ], "source": [ + "import json\n", + "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", - "import json\n", "import tensorflow as tf\n", + "\n", "tf.keras.backend.clear_session()\n", "\n", + "import requests\n", "from alibi_detect.od.vae import OutlierVAE\n", "from alibi_detect.utils.perturbation import apply_mask\n", "from alibi_detect.utils.visualize import plot_feature_outlier_image\n", - "import requests\n", "\n", "train, test = tf.keras.datasets.cifar10.load_data()\n", "X_train, y_train = train\n", "X_test, y_test = test\n", "\n", - "X_train = X_train.astype('float32') / 255\n", - "X_test = X_test.astype('float32') / 255\n", + "X_train = X_train.astype(\"float32\") / 255\n", + "X_test = X_test.astype(\"float32\") / 255\n", "print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)\n", - "classes = ('plane', 'car', 'bird', 'cat',\n", - " 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')\n", + "classes = (\n", + " \"plane\",\n", + " \"car\",\n", + " \"bird\",\n", + " \"cat\",\n", + " \"deer\",\n", + " \"dog\",\n", + " \"frog\",\n", + " \"horse\",\n", + " \"ship\",\n", + " \"truck\",\n", + ")\n", + "\n", "\n", "def show(X):\n", " plt.imshow(X.reshape(32, 32, 3))\n", - " plt.axis('off')\n", + " plt.axis(\"off\")\n", " plt.show()\n", "\n", + "\n", "def predict(X):\n", " formData = {\n", - " 'inputs': [{\n", - " \"name\":\"input_1\",\n", - " \"datatype\": \"FP32\",\n", - " \"shape\": [1, 32, 32, 3],\n", - " \"data\": X.flatten().tolist()\n", - " }]\n", - " }\n", - " headers = {\n", - " \"Authorization\":TOKEN,\n", - " \"Content-Type\": \"application/json\"\n", + " \"inputs\": [\n", + " {\n", + " \"name\": \"input_1\",\n", + " \"datatype\": \"FP32\",\n", + " \"shape\": [1, 32, 32, 3],\n", + " \"data\": X.flatten().tolist(),\n", " }\n", - " res = requests.post('http://'+CLUSTER_IP+'/seldon/cifar10/triton-cifar10/v2/models/cifar10/infer', json=formData, headers=headers)\n", + " ]\n", + " }\n", + " headers = {\"Authorization\": TOKEN, \"Content-Type\": \"application/json\"}\n", + " res = requests.post(\n", + " \"http://\"\n", + " + CLUSTER_IP\n", + " + \"/seldon/cifar10/triton-cifar10/v2/models/cifar10/infer\",\n", + " json=formData,\n", + " headers=headers,\n", + " )\n", " if res.status_code == 200:\n", " return classes[np.array(res.json()[\"outputs\"][0][\"data\"]).argmax()]\n", " else:\n", - " print(\"Failed with \",res.status_code)\n", + " print(\"Failed with \", res.status_code)\n", " return []\n", - " \n", + "\n", + "\n", "def outlier(X):\n", " formData = {\n", - " 'inputs': [{\n", - " \"name\":\"input_1\",\n", - " \"datatype\": \"FP32\",\n", - " \"shape\": [1, 32, 32, 3],\n", - " \"data\": X.flatten().tolist()\n", - " }]\n", + " \"inputs\": [\n", + " {\n", + " \"name\": \"input_1\",\n", + " \"datatype\": \"FP32\",\n", + " \"shape\": [1, 32, 32, 3],\n", + " \"data\": X.flatten().tolist(),\n", + " }\n", + " ]\n", + " }\n", + " headers = {\n", + " \"Alibi-Detect-Return-Feature-Score\": \"true\",\n", + " \"Alibi-Detect-Return-Instance-Score\": \"true\",\n", + " \"ce-namespace\": \"default\",\n", + " \"ce-modelid\": \"cifar10\",\n", + " \"ce-type\": \"io.seldon.serving.inference.request\",\n", + " \"ce-id\": \"1234\",\n", + " \"ce-source\": \"localhost\",\n", + " \"ce-specversion\": \"1.0\",\n", " }\n", - " headers = {\"Alibi-Detect-Return-Feature-Score\":\"true\",\"Alibi-Detect-Return-Instance-Score\":\"true\", \\\n", - " \"ce-namespace\": \"default\",\"ce-modelid\":\"cifar10\",\"ce-type\":\"io.seldon.serving.inference.request\", \\\n", - " \"ce-id\":\"1234\",\"ce-source\":\"localhost\",\"ce-specversion\":\"1.0\"}\n", " headers[\"Host\"] = SERVICE_HOSTNAME_VAEOD\n", " headers[\"Authorization\"] = TOKEN\n", - " res = requests.post('http://'+CLUSTER_IP+'/', json=formData, headers=headers)\n", + " res = requests.post(\"http://\" + CLUSTER_IP + \"/\", json=formData, headers=headers)\n", " if res.status_code == 200:\n", " od = res.json()\n", " od[\"data\"][\"feature_score\"] = np.array(od[\"data\"][\"feature_score\"])\n", " od[\"data\"][\"instance_score\"] = np.array(od[\"data\"][\"instance_score\"])\n", " return od\n", " else:\n", - " print(\"Failed with \",res.status_code)\n", + " print(\"Failed with \", res.status_code)\n", " return []" ] }, @@ -589,7 +618,7 @@ ], "source": [ "idx = 1\n", - "X = X_train[idx:idx+1]\n", + "X = X_train[idx : idx + 1]\n", "show(X)\n", "predict(X)" ] @@ -637,14 +666,16 @@ "metadata": {}, "outputs": [], "source": [ - "np.random.seed(0) \n", - "X_mask, mask = apply_mask(X.reshape(1, 32, 32, 3),\n", - " mask_size=(10,10),\n", - " n_masks=1,\n", - " channels=[0,1,2],\n", - " mask_type='normal',\n", - " noise_distr=(0,1),\n", - " clip_rng=(0,1))" + "np.random.seed(0)\n", + "X_mask, mask = apply_mask(\n", + " X.reshape(1, 32, 32, 3),\n", + " mask_size=(10, 10),\n", + " n_masks=1,\n", + " channels=[0, 1, 2],\n", + " mask_type=\"normal\",\n", + " noise_distr=(0, 1),\n", + " clip_rng=(0, 1),\n", + ")" ] }, { @@ -752,9 +783,7 @@ } ], "source": [ - "plot_feature_outlier_image(od_preds, \n", - " X_mask, \n", - " X_recon=None)" + "plot_feature_outlier_image(od_preds, X_mask, X_recon=None)" ] }, { diff --git a/components/routers/case_study/credit_card_default.ipynb b/components/routers/case_study/credit_card_default.ipynb index c9d6c816ca..9cf204a4d5 100644 --- a/components/routers/case_study/credit_card_default.ipynb +++ b/components/routers/case_study/credit_card_default.ipynb @@ -72,7 +72,8 @@ "outputs": [], "source": [ "import pandas as pd\n", - "data = pd.read_csv('UCI_Credit_Card.csv')" + "\n", + "data = pd.read_csv(\"UCI_Credit_Card.csv\")" ] }, { @@ -99,7 +100,7 @@ "metadata": {}, "outputs": [], "source": [ - "target = 'default.payment.next.month'" + "target = \"default.payment.next.month\"" ] }, { @@ -124,7 +125,7 @@ "metadata": {}, "outputs": [], "source": [ - "data[target].value_counts().max()/data.shape[0]" + "data[target].value_counts().max() / data.shape[0]" ] }, { @@ -195,17 +196,23 @@ "ROUTE_DATA = 10000\n", "\n", "# get features and target\n", - "X = data.loc[:, data.columns!=target].values\n", + "X = data.loc[:, data.columns != target].values\n", "y = data[target].values\n", "\n", "# observed/unobserved split\n", - "X_obs, X_rest, y_obs, y_rest = train_test_split(X, y, random_state=1, test_size=REST_DATA)\n", + "X_obs, X_rest, y_obs, y_rest = train_test_split(\n", + " X, y, random_state=1, test_size=REST_DATA\n", + ")\n", "\n", "# observed split into train1/test1\n", - "X_train1, X_test1, y_train1, y_test1 = train_test_split(X_obs, y_obs, random_state=1, test_size=TEST_1)\n", + "X_train1, X_test1, y_train1, y_test1 = train_test_split(\n", + " X_obs, y_obs, random_state=1, test_size=TEST_1\n", + ")\n", "\n", "# unobserved split into run/route\n", - "X_run, X_route, y_run, y_route = train_test_split(X_rest, y_rest, random_state=1, test_size=ROUTE_DATA)\n", + "X_run, X_route, y_run, y_route = train_test_split(\n", + " X_rest, y_rest, random_state=1, test_size=ROUTE_DATA\n", + ")\n", "\n", "# observed+run split into train2/test2\n", "X_rest = np.vstack((X_run, X_route))\n", @@ -239,6 +246,7 @@ "outputs": [], "source": [ "from sklearn.ensemble import RandomForestClassifier\n", + "\n", "rf = RandomForestClassifier(random_state=1)\n", "rf.fit(X_train1, y_train1)" ] @@ -256,8 +264,14 @@ "metadata": {}, "outputs": [], "source": [ - "from sklearn.metrics import accuracy_score, precision_score, recall_score, \\\n", - "f1_score, confusion_matrix, classification_report" + "from sklearn.metrics import (\n", + " accuracy_score,\n", + " classification_report,\n", + " confusion_matrix,\n", + " f1_score,\n", + " precision_score,\n", + " recall_score,\n", + ")" ] }, { @@ -277,8 +291,7 @@ }, "outputs": [], "source": [ - "print(classification_report(y_test1, y_preds1,\n", - " target_names=['No default','Default']))" + "print(classification_report(y_test1, y_preds1, target_names=[\"No default\", \"Default\"]))" ] }, { @@ -287,8 +300,14 @@ "metadata": {}, "outputs": [], "source": [ - "for score in [accuracy_score, precision_score, recall_score, f1_score, confusion_matrix]:\n", - " print(score.__name__ + ':\\n', score(y_test1, y_preds1))" + "for score in [\n", + " accuracy_score,\n", + " precision_score,\n", + " recall_score,\n", + " f1_score,\n", + " confusion_matrix,\n", + "]:\n", + " print(score.__name__ + \":\\n\", score(y_test1, y_preds1))" ] }, { @@ -301,7 +320,7 @@ "from utils import plot_confusion_matrix\n", "\n", "cm = confusion_matrix(y_test1, y_preds1)\n", - "plot_confusion_matrix(cm, classes=['No default','Default'], normalize=True)" + "plot_confusion_matrix(cm, classes=[\"No default\", \"Default\"], normalize=True)" ] }, { @@ -325,6 +344,7 @@ "outputs": [], "source": [ "from xgboost import XGBClassifier\n", + "\n", "xgb = XGBClassifier(random_state=1)\n", "xgb.fit(X_train2, y_train2)" ] @@ -346,8 +366,7 @@ }, "outputs": [], "source": [ - "print(classification_report(y_test1, y_preds1,\n", - " target_names=['No default','Default']))" + "print(classification_report(y_test1, y_preds1, target_names=[\"No default\", \"Default\"]))" ] }, { @@ -356,8 +375,14 @@ "metadata": {}, "outputs": [], "source": [ - "for score in [accuracy_score, precision_score, recall_score, f1_score, confusion_matrix]:\n", - " print(score.__name__ + ':\\n', score(y_test1, y_preds1))" + "for score in [\n", + " accuracy_score,\n", + " precision_score,\n", + " recall_score,\n", + " f1_score,\n", + " confusion_matrix,\n", + "]:\n", + " print(score.__name__ + \":\\n\", score(y_test1, y_preds1))" ] }, { @@ -370,7 +395,7 @@ "from utils import plot_confusion_matrix\n", "\n", "cm = confusion_matrix(y_test1, y_preds1)\n", - "plot_confusion_matrix(cm, classes=['No default','Default'], normalize=True)" + "plot_confusion_matrix(cm, classes=[\"No default\", \"Default\"], normalize=True)" ] }, { @@ -387,8 +412,9 @@ "outputs": [], "source": [ "import joblib\n", - "joblib.dump(rf, 'models/rf_model/RFModel.sav')\n", - "joblib.dump(xgb, 'models/xgb_model/XGBModel.sav')" + "\n", + "joblib.dump(rf, \"models/rf_model/RFModel.sav\")\n", + "joblib.dump(xgb, \"models/xgb_model/XGBModel.sav\")" ] }, { @@ -515,25 +541,25 @@ "outputs": [], "source": [ "for i in range(X_run.shape[0]):\n", - " if i%1000 == 0:\n", - " print(f'Processed {i}/{X_run.shape[0]} samples', flush=True)\n", - " \n", + " if i % 1000 == 0:\n", + " print(f\"Processed {i}/{X_run.shape[0]} samples\", flush=True)\n", + "\n", " # fetch sample and make a request payload\n", - " x = X_run[i].reshape(1,-1).tolist()\n", - " request = {'data':{'ndarray':x}}\n", + " x = X_run[i].reshape(1, -1).tolist()\n", + " request = {\"data\": {\"ndarray\": x}}\n", "\n", " # send request to model\n", - " response = rest_request_ambassador('rf-deployment', 'seldon', request)\n", + " response = rest_request_ambassador(\"rf-deployment\", \"seldon\", request)\n", "\n", " # extract prediction\n", - " probs = response.get('data').get('ndarray')[0]\n", + " probs = response.get(\"data\").get(\"ndarray\")[0]\n", " pred = np.argmax(probs)\n", "\n", " # send feedback to the model informing it if it made the right decision\n", " truth_val = int(y_run[i])\n", - " reward = int(pred==truth_val)\n", + " reward = int(pred == truth_val)\n", " truth = [truth_val]\n", - " _ = send_feedback_rest('rf-deployment', 'seldon', request, response, reward, truth)" + " _ = send_feedback_rest(\"rf-deployment\", \"seldon\", request, response, reward, truth)" ] }, { @@ -586,8 +612,7 @@ }, "outputs": [], "source": [ - "print(classification_report(y_test2, y_preds2,\n", - " target_names=['No default','Default']))" + "print(classification_report(y_test2, y_preds2, target_names=[\"No default\", \"Default\"]))" ] }, { @@ -596,8 +621,14 @@ "metadata": {}, "outputs": [], "source": [ - "for score in [accuracy_score, precision_score, recall_score, f1_score, confusion_matrix]:\n", - " print(score.__name__ + ':\\n', score(y_test2, y_preds2))" + "for score in [\n", + " accuracy_score,\n", + " precision_score,\n", + " recall_score,\n", + " f1_score,\n", + " confusion_matrix,\n", + "]:\n", + " print(score.__name__ + \":\\n\", score(y_test2, y_preds2))" ] }, { @@ -607,7 +638,7 @@ "outputs": [], "source": [ "cm = confusion_matrix(y_test2, y_preds2)\n", - "plot_confusion_matrix(cm, classes=['No default','Default'], normalize=True)" + "plot_confusion_matrix(cm, classes=[\"No default\", \"Default\"], normalize=True)" ] }, { @@ -794,33 +825,36 @@ "metadata": {}, "outputs": [], "source": [ - "\n", "for i in range(X_route.shape[0]):\n", - " if i%1000 == 0:\n", - " print(f'Processed {i}/{X_route.shape[0]} samples', flush=True)\n", - " \n", + " if i % 1000 == 0:\n", + " print(f\"Processed {i}/{X_route.shape[0]} samples\", flush=True)\n", + "\n", " # fetch sample and make a request payload\n", - " x = X_route[i].reshape(1,-1).tolist()\n", - " request = {'data':{'ndarray':x}}\n", + " x = X_route[i].reshape(1, -1).tolist()\n", + " request = {\"data\": {\"ndarray\": x}}\n", "\n", " # send request to both deployments\n", - " eg_response = rest_request_ambassador('eg-experiment', 'seldon', request)\n", - " ts_response = rest_request_ambassador('ts-experiment', 'seldon', request)\n", - " \n", + " eg_response = rest_request_ambassador(\"eg-experiment\", \"seldon\", request)\n", + " ts_response = rest_request_ambassador(\"ts-experiment\", \"seldon\", request)\n", + "\n", " # extract predictions\n", - " eg_probs = eg_response.get('data').get('ndarray')[0]\n", - " ts_probs = ts_response.get('data').get('ndarray')[0]\n", + " eg_probs = eg_response.get(\"data\").get(\"ndarray\")[0]\n", + " ts_probs = ts_response.get(\"data\").get(\"ndarray\")[0]\n", " eg_pred = np.argmax(eg_probs)\n", " ts_pred = np.argmax(ts_probs)\n", "\n", " # send feedback to the model informing it if it made the right decision\n", " truth_val = int(y_route[i])\n", - " eg_reward = int(eg_pred==truth_val)\n", - " ts_reward = int(ts_pred==truth_val)\n", + " eg_reward = int(eg_pred == truth_val)\n", + " ts_reward = int(ts_pred == truth_val)\n", " truth = [truth_val]\n", - " \n", - " _ = send_feedback_rest('eg-experiment', 'seldon', request, eg_response, eg_reward, truth)\n", - " _ = send_feedback_rest('ts-experiment', 'seldon', request, ts_response, ts_reward, truth)" + "\n", + " _ = send_feedback_rest(\n", + " \"eg-experiment\", \"seldon\", request, eg_response, eg_reward, truth\n", + " )\n", + " _ = send_feedback_rest(\n", + " \"ts-experiment\", \"seldon\", request, ts_response, ts_reward, truth\n", + " )" ] }, { @@ -922,28 +956,29 @@ "metadata": {}, "outputs": [], "source": [ - "\n", "for i in range(X_route.shape[0]):\n", - " if i%1000 == 0:\n", - " print(f'Processed {i}/{X_route.shape[0]} samples', flush=True)\n", - " \n", + " if i % 1000 == 0:\n", + " print(f\"Processed {i}/{X_route.shape[0]} samples\", flush=True)\n", + "\n", " # fetch sample and make a request payload\n", - " x = X_route[i].reshape(1,-1).tolist()\n", - " request = {'data':{'ndarray':x}}\n", + " x = X_route[i].reshape(1, -1).tolist()\n", + " request = {\"data\": {\"ndarray\": x}}\n", "\n", " # send request to both deployments\n", - " ts_response = rest_request_ambassador('ts-experiment-persistent', 'seldon', request)\n", - " \n", + " ts_response = rest_request_ambassador(\"ts-experiment-persistent\", \"seldon\", request)\n", + "\n", " # extract predictions\n", - " ts_probs = ts_response.get('data').get('ndarray')[0]\n", + " ts_probs = ts_response.get(\"data\").get(\"ndarray\")[0]\n", " ts_pred = np.argmax(ts_probs)\n", "\n", " # send feedback to the model informing it if it made the right decision\n", " truth_val = int(y_route[i])\n", - " ts_reward = int(ts_pred==truth_val)\n", + " ts_reward = int(ts_pred == truth_val)\n", " truth = [truth_val]\n", - " \n", - " _ = send_feedback_rest('ts-experiment-persistent', 'seldon', request, ts_response, ts_reward, truth)" + "\n", + " _ = send_feedback_rest(\n", + " \"ts-experiment-persistent\", \"seldon\", request, ts_response, ts_reward, truth\n", + " )" ] }, { diff --git a/components/routers/epsilon-greedy/egreedy.ipynb b/components/routers/epsilon-greedy/egreedy.ipynb index b5698007e4..b1dbd0454f 100644 --- a/components/routers/epsilon-greedy/egreedy.ipynb +++ b/components/routers/epsilon-greedy/egreedy.ipynb @@ -74,9 +74,10 @@ "source": [ "from IPython.core.magic import register_line_cell_magic\n", "\n", + "\n", "@register_line_cell_magic\n", "def writetemplate(line, cell):\n", - " with open(line, 'w') as f:\n", + " with open(line, \"w\") as f:\n", " f.write(cell.format(**globals()))" ] }, @@ -201,7 +202,7 @@ "metadata": {}, "outputs": [], "source": [ - "rewards = {0:0,1:1,2:0} # make model 1 the best" + "rewards = {0: 0, 1: 1, 2: 0} # make model 1 the best" ] }, { @@ -211,13 +212,22 @@ "outputs": [], "source": [ "import requests\n", - "for i in range(0,50):\n", - " req = {\"data\": {\"ndarray\":[[1.0, 2.0, 5.0]]}}\n", - " res_raw = requests.post(\"http://localhost:8003/seldon/seldon/egreedy/api/v1.0/predictions\",json=req)\n", + "\n", + "for i in range(0, 50):\n", + " req = {\"data\": {\"ndarray\": [[1.0, 2.0, 5.0]]}}\n", + " res_raw = requests.post(\n", + " \"http://localhost:8003/seldon/seldon/egreedy/api/v1.0/predictions\", json=req\n", + " )\n", " res = res_raw.json()\n", - " feedback = {\"request\":req,\"response\":res,\"reward\":rewards[res[\"meta\"][\"routing\"][\"eg-router\"]]}\n", - " res_raw = requests.post(\"http://localhost:8003/seldon/seldon/egreedy/api/v1.0/feedback\",json=feedback)\n", - " assert(res_raw.status_code==200)" + " feedback = {\n", + " \"request\": req,\n", + " \"response\": res,\n", + " \"reward\": rewards[res[\"meta\"][\"routing\"][\"eg-router\"]],\n", + " }\n", + " res_raw = requests.post(\n", + " \"http://localhost:8003/seldon/seldon/egreedy/api/v1.0/feedback\", json=feedback\n", + " )\n", + " assert res_raw.status_code == 200" ] }, { @@ -266,7 +276,7 @@ "metadata": {}, "outputs": [], "source": [ - "rewards = {0:1,1:0,2:0} # make model 0 the best" + "rewards = {0: 1, 1: 0, 2: 0} # make model 0 the best" ] }, { @@ -276,13 +286,22 @@ "outputs": [], "source": [ "import requests\n", - "for i in range(0,100):\n", - " req = {\"data\": {\"ndarray\":[[1.0, 2.0, 5.0]]}}\n", - " res_raw = requests.post(\"http://localhost:8003/seldon/seldon/egreedy/api/v1.0/predictions\",json=req)\n", + "\n", + "for i in range(0, 100):\n", + " req = {\"data\": {\"ndarray\": [[1.0, 2.0, 5.0]]}}\n", + " res_raw = requests.post(\n", + " \"http://localhost:8003/seldon/seldon/egreedy/api/v1.0/predictions\", json=req\n", + " )\n", " res = res_raw.json()\n", - " feedback = {\"request\":req,\"response\":res,\"reward\":rewards[res[\"meta\"][\"routing\"][\"eg-router\"]]}\n", - " res_raw = requests.post(\"http://localhost:8003/seldon/seldon/egreedy/api/v1.0/feedback\",json=feedback)\n", - " assert(res_raw.status_code==200)" + " feedback = {\n", + " \"request\": req,\n", + " \"response\": res,\n", + " \"reward\": rewards[res[\"meta\"][\"routing\"][\"eg-router\"]],\n", + " }\n", + " res_raw = requests.post(\n", + " \"http://localhost:8003/seldon/seldon/egreedy/api/v1.0/feedback\", json=feedback\n", + " )\n", + " assert res_raw.status_code == 200" ] }, { diff --git a/examples/ambassador/canary/ambassador_canary.ipynb b/examples/ambassador/canary/ambassador_canary.ipynb index e880031981..199115fb2f 100644 --- a/examples/ambassador/canary/ambassador_canary.ipynb +++ b/examples/ambassador/canary/ambassador_canary.ipynb @@ -58,9 +58,10 @@ "source": [ "from IPython.core.magic import register_line_cell_magic\n", "\n", + "\n", "@register_line_cell_magic\n", "def writetemplate(line, cell):\n", - " with open(line, 'w') as f:\n", + " with open(line, \"w\") as f:\n", " f.write(cell.format(**globals()))" ] }, @@ -177,7 +178,8 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"example\",namespace=\"seldon\")" + "\n", + "sc = SeldonClient(deployment_name=\"example\", namespace=\"seldon\")" ] }, { @@ -214,8 +216,8 @@ } ], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\")\n", - "assert(r.success==True)\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\")\n", + "assert r.success == True\n", "print(r)" ] }, @@ -353,7 +355,7 @@ } ], "source": [ - "sc.predict(gateway=\"ambassador\",transport=\"rest\")" + "sc.predict(gateway=\"ambassador\", transport=\"rest\")" ] }, { @@ -363,10 +365,11 @@ "outputs": [], "source": [ "from collections import defaultdict\n", + "\n", "counts = defaultdict(int)\n", "n = 100\n", "for i in range(n):\n", - " r = sc.predict(gateway=\"ambassador\",transport=\"rest\")" + " r = sc.predict(gateway=\"ambassador\", transport=\"rest\")" ] }, { @@ -408,9 +411,9 @@ } ], "source": [ - "canary_percentage=float(canary_count[0])/float(default_count[0])\n", + "canary_percentage = float(canary_count[0]) / float(default_count[0])\n", "print(canary_percentage)\n", - "assert(canary_percentage > 0.1 and canary_percentage < 0.5)" + "assert canary_percentage > 0.1 and canary_percentage < 0.5" ] }, { diff --git a/examples/ambassador/circuit_breakers/ambassador_circuit_breakers.ipynb b/examples/ambassador/circuit_breakers/ambassador_circuit_breakers.ipynb index 5a5108aea7..4dab1c2b31 100644 --- a/examples/ambassador/circuit_breakers/ambassador_circuit_breakers.ipynb +++ b/examples/ambassador/circuit_breakers/ambassador_circuit_breakers.ipynb @@ -101,7 +101,8 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"example\",namespace=\"seldon\")" + "\n", + "sc = SeldonClient(deployment_name=\"example\", namespace=\"seldon\")" ] }, { @@ -117,8 +118,8 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\")\n", - "assert(r.success==True)\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\")\n", + "assert r.success == True\n", "print(r)" ] }, diff --git a/examples/ambassador/custom/ambassador_custom.ipynb b/examples/ambassador/custom/ambassador_custom.ipynb index 9a1eeedda4..8dd6dd76e3 100644 --- a/examples/ambassador/custom/ambassador_custom.ipynb +++ b/examples/ambassador/custom/ambassador_custom.ipynb @@ -17,9 +17,10 @@ "source": [ "from IPython.core.magic import register_line_cell_magic\n", "\n", + "\n", "@register_line_cell_magic\n", "def writetemplate(line, cell):\n", - " with open(line, 'w') as f:\n", + " with open(line, \"w\") as f:\n", " f.write(cell.format(**globals()))" ] }, @@ -176,7 +177,8 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"example-custom\",namespace=\"seldon\")" + "\n", + "sc = SeldonClient(deployment_name=\"example-custom\", namespace=\"seldon\")" ] }, { @@ -213,8 +215,8 @@ } ], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\",gateway_prefix=\"/mycompany/ml\")\n", - "assert(r.success==True)\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\", gateway_prefix=\"/mycompany/ml\")\n", + "assert r.success == True\n", "print(r)" ] }, @@ -294,4 +296,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/examples/ambassador/headers/ambassador_headers.ipynb b/examples/ambassador/headers/ambassador_headers.ipynb index fc378db4be..a6cd694a81 100644 --- a/examples/ambassador/headers/ambassador_headers.ipynb +++ b/examples/ambassador/headers/ambassador_headers.ipynb @@ -60,9 +60,10 @@ "source": [ "from IPython.core.magic import register_line_cell_magic\n", "\n", + "\n", "@register_line_cell_magic\n", "def writetemplate(line, cell):\n", - " with open(line, 'w') as f:\n", + " with open(line, \"w\") as f:\n", " f.write(cell.format(**globals()))" ] }, @@ -179,7 +180,8 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"example\",namespace=\"seldon\")" + "\n", + "sc = SeldonClient(deployment_name=\"example\", namespace=\"seldon\")" ] }, { @@ -216,8 +218,8 @@ } ], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\")\n", - "assert(r.success==True)\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\")\n", + "assert r.success == True\n", "print(r)" ] }, @@ -344,7 +346,7 @@ } ], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\")\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\")\n", "print(r)" ] }, @@ -372,7 +374,7 @@ ], "source": [ "print(default_count)\n", - "assert(int(default_count[0]) == 2)" + "assert int(default_count[0]) == 2" ] }, { @@ -409,7 +411,7 @@ } ], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\",headers={\"location\":\"london\"})\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\", headers={\"location\": \"london\"})\n", "print(r)" ] }, @@ -437,7 +439,7 @@ ], "source": [ "print(header_count)\n", - "assert(int(header_count[0]) == 1)" + "assert int(header_count[0]) == 1" ] }, { diff --git a/examples/ambassador/shadow/ambassador_shadow.ipynb b/examples/ambassador/shadow/ambassador_shadow.ipynb index 4905f051d7..7bef4b8d8f 100644 --- a/examples/ambassador/shadow/ambassador_shadow.ipynb +++ b/examples/ambassador/shadow/ambassador_shadow.ipynb @@ -62,9 +62,10 @@ "source": [ "from IPython.core.magic import register_line_cell_magic\n", "\n", + "\n", "@register_line_cell_magic\n", "def writetemplate(line, cell):\n", - " with open(line, 'w') as f:\n", + " with open(line, \"w\") as f:\n", " f.write(cell.format(**globals()))" ] }, @@ -180,7 +181,8 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"example\",namespace=\"seldon\")" + "\n", + "sc = SeldonClient(deployment_name=\"example\", namespace=\"seldon\")" ] }, { @@ -217,7 +219,7 @@ } ], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\")\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\")\n", "print(r)" ] }, @@ -329,7 +331,7 @@ "outputs": [], "source": [ "for i in range(10):\n", - " r = sc.predict(gateway=\"ambassador\",transport=\"rest\")" + " r = sc.predict(gateway=\"ambassador\", transport=\"rest\")" ] }, { @@ -367,8 +369,8 @@ "source": [ "print(shadow_count)\n", "print(default_count)\n", - "assert(int(shadow_count[0])==10)\n", - "assert(int(default_count[0])==11)" + "assert int(shadow_count[0]) == 10\n", + "assert int(default_count[0]) == 11" ] }, { diff --git a/examples/batch/argo-workflows-batch/README.ipynb b/examples/batch/argo-workflows-batch/README.ipynb index 3abad2a63c..f688cfc6ea 100644 --- a/examples/batch/argo-workflows-batch/README.ipynb +++ b/examples/batch/argo-workflows-batch/README.ipynb @@ -230,8 +230,9 @@ "metadata": {}, "outputs": [], "source": [ - "import random\n", "import os\n", + "import random\n", + "\n", "random.seed(0)\n", "with open(\"assets/input-data.txt\", \"w\") as f:\n", " for _ in range(10000):\n", diff --git a/examples/batch/benchmarking-argo-workflows/README.ipynb b/examples/batch/benchmarking-argo-workflows/README.ipynb index e5d9a818b6..50614848d1 100644 --- a/examples/batch/benchmarking-argo-workflows/README.ipynb +++ b/examples/batch/benchmarking-argo-workflows/README.ipynb @@ -78,7 +78,7 @@ " final[\"99th\"] = results[\"latencies\"][\"99th\"] / 1e6\n", " final[\"rate\"] = results[\"throughput\"]\n", " final[\"errors\"] = results[\"errors\"]\n", - " if print_results: \n", + " if print_results:\n", " print(\"Latencies:\")\n", " print(\"\\tmean:\", final[\"mean\"], \"ms\")\n", " print(\"\\t50th:\", final[\"50th\"], \"ms\")\n", @@ -212,7 +212,7 @@ } ], "source": [ - "!argo logs -w seldon-benchmark-process " + "!argo logs -w seldon-benchmark-process" ] }, { @@ -384,7 +384,7 @@ } ], "source": [ - "!argo logs -w seldon-benchmark-process " + "!argo logs -w seldon-benchmark-process" ] }, { @@ -698,6 +698,7 @@ ], "source": [ "import pandas as pd\n", + "\n", "df = pd.DataFrame.from_dict(results)\n", "df.head()" ] @@ -1705,7 +1706,7 @@ } ], "source": [ - "df[df[\"apiType\"]==\"rest\"].sort_values(\"rate\", ascending=False)" + "df[df[\"apiType\"] == \"rest\"].sort_values(\"rate\", ascending=False)" ] }, { @@ -2416,7 +2417,7 @@ } ], "source": [ - "df[df[\"apiType\"]==\"grpc\"].sort_values(\"rate\", ascending=False)" + "df[df[\"apiType\"] == \"grpc\"].sort_values(\"rate\", ascending=False)" ] }, { diff --git a/examples/batch/hdfs-argo-workflows/hdfs-batch.ipynb b/examples/batch/hdfs-argo-workflows/hdfs-batch.ipynb index 0856b949cd..819672b5e2 100644 --- a/examples/batch/hdfs-argo-workflows/hdfs-batch.ipynb +++ b/examples/batch/hdfs-argo-workflows/hdfs-batch.ipynb @@ -292,8 +292,9 @@ "metadata": {}, "outputs": [], "source": [ - "import random\n", "import os\n", + "import random\n", + "\n", "random.seed(0)\n", "with open(\"input-data.txt\", \"w\") as f:\n", " for _ in range(10000):\n", diff --git a/examples/batch/kubeflow-pipelines-batch/README.ipynb b/examples/batch/kubeflow-pipelines-batch/README.ipynb index eaeac82671..08603dee3a 100644 --- a/examples/batch/kubeflow-pipelines-batch/README.ipynb +++ b/examples/batch/kubeflow-pipelines-batch/README.ipynb @@ -113,7 +113,7 @@ "source": [ "with open(\"assets/input-data.txt\", \"w\") as f:\n", " for i in range(10000):\n", - " f.write('[[1, 2, 3, 4]]\\n')" + " f.write(\"[[1, 2, 3, 4]]\\n\")" ] }, { diff --git a/examples/cicd/sig-mlops-jenkins-classic/models/image_classifier/README.ipynb b/examples/cicd/sig-mlops-jenkins-classic/models/image_classifier/README.ipynb index 351c66f5bc..64193dedae 100644 --- a/examples/cicd/sig-mlops-jenkins-classic/models/image_classifier/README.ipynb +++ b/examples/cicd/sig-mlops-jenkins-classic/models/image_classifier/README.ipynb @@ -101,7 +101,7 @@ "metadata": {}, "outputs": [], "source": [ - "from src.data import fetch_training, fetch_test\n", + "from src.data import fetch_test, fetch_training\n", "\n", "training_dataset = fetch_training()\n", "test_dataset = fetch_test()" @@ -143,7 +143,7 @@ } ], "source": [ - "import matplotlib.pyplot as plt \n", + "import matplotlib.pyplot as plt\n", "\n", "x_example, y_example = training_dataset[0]\n", "plt.imshow(x_example.squeeze())" @@ -227,11 +227,10 @@ "source": [ "import torch\n", "import torch.optim as optim\n", - "from torch.optim.lr_scheduler import StepLR\n", - "\n", "from src.data import fetch_test, fetch_training\n", - "from src.train import train_epoch, test_epoch\n", "from src.model import Classifier\n", + "from src.train import test_epoch, train_epoch\n", + "from torch.optim.lr_scheduler import StepLR\n", "\n", "batch_size = 256\n", "epochs = 2\n", diff --git a/examples/cicd/sig-mlops-jenkins-classic/models/news_classifier/README.ipynb b/examples/cicd/sig-mlops-jenkins-classic/models/news_classifier/README.ipynb index 44579eb445..caa9f491da 100644 --- a/examples/cicd/sig-mlops-jenkins-classic/models/news_classifier/README.ipynb +++ b/examples/cicd/sig-mlops-jenkins-classic/models/news_classifier/README.ipynb @@ -163,14 +163,16 @@ ], "source": [ "from sklearn.datasets import fetch_20newsgroups\n", - "categories = ['alt.atheism', 'soc.religion.christian',\n", - " 'comp.graphics', 'sci.med']\n", + "\n", + "categories = [\"alt.atheism\", \"soc.religion.christian\", \"comp.graphics\", \"sci.med\"]\n", "\n", "twenty_train = fetch_20newsgroups(\n", - " subset='train', categories=categories, shuffle=True, random_state=42)\n", + " subset=\"train\", categories=categories, shuffle=True, random_state=42\n", + ")\n", "\n", "twenty_test = fetch_20newsgroups(\n", - " subset='test', categories=categories, shuffle=True, random_state=42)\n", + " subset=\"test\", categories=categories, shuffle=True, random_state=42\n", + ")\n", "\n", "# Printing the top 3 newstories\n", "print(\"\\n\".join(twenty_train.data[0].split(\"\\n\")[:3]))" @@ -207,15 +209,17 @@ } ], "source": [ - "from sklearn.pipeline import Pipeline\n", - "from sklearn.feature_extraction.text import TfidfTransformer, CountVectorizer\n", + "from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer\n", "from sklearn.naive_bayes import MultinomialNB\n", + "from sklearn.pipeline import Pipeline\n", "\n", - "text_clf = Pipeline([\n", - " ('vect', CountVectorizer()),\n", - " ('tfidf', TfidfTransformer()),\n", - " ('clf', MultinomialNB()),\n", - "])\n", + "text_clf = Pipeline(\n", + " [\n", + " (\"vect\", CountVectorizer()),\n", + " (\"tfidf\", TfidfTransformer()),\n", + " (\"clf\", MultinomialNB()),\n", + " ]\n", + ")\n", "\n", "text_clf.fit(twenty_train.data, twenty_train.target)" ] @@ -326,6 +330,7 @@ ], "source": [ "import joblib\n", + "\n", "joblib.dump(text_clf, \"src/model.joblib\")" ] }, diff --git a/examples/cicd/sig-mlops-jenkins-classic/servers/torchserver/test/sklearn_iris.ipynb b/examples/cicd/sig-mlops-jenkins-classic/servers/torchserver/test/sklearn_iris.ipynb index 05e77c4e9e..4296dbcff1 100644 --- a/examples/cicd/sig-mlops-jenkins-classic/servers/torchserver/test/sklearn_iris.ipynb +++ b/examples/cicd/sig-mlops-jenkins-classic/servers/torchserver/test/sklearn_iris.ipynb @@ -36,31 +36,34 @@ } ], "source": [ - "import numpy as np\n", "import os\n", - "from sklearn.linear_model import LogisticRegression\n", - "from sklearn.pipeline import Pipeline\n", + "\n", "import joblib\n", + "import numpy as np\n", "from sklearn import datasets\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.pipeline import Pipeline\n", + "\n", "\n", "def main():\n", " clf = LogisticRegression()\n", - " p = Pipeline([('clf', clf)])\n", - " print('Training model...')\n", + " p = Pipeline([(\"clf\", clf)])\n", + " print(\"Training model...\")\n", " p.fit(X, y)\n", - " print('Model trained!')\n", + " print(\"Model trained!\")\n", "\n", - " filename_p = 'model.joblib'\n", - " print('Saving model in %s' % filename_p)\n", + " filename_p = \"model.joblib\"\n", + " print(\"Saving model in %s\" % filename_p)\n", " joblib.dump(p, filename_p)\n", - " print('Model saved!')\n", - " \n", + " print(\"Model saved!\")\n", + "\n", + "\n", "if __name__ == \"__main__\":\n", - " print('Loading iris data set...')\n", + " print(\"Loading iris data set...\")\n", " iris = datasets.load_iris()\n", " X, y = iris.data, iris.target\n", - " print('Dataset loaded!')\n", - " main()\n" + " print(\"Dataset loaded!\")\n", + " main()" ] }, { @@ -444,9 +447,8 @@ "metadata": {}, "outputs": [], "source": [ - "def x(a=None,b=2):\n", - " print(a,b)\n", - " " + "def x(a=None, b=2):\n", + " print(a, b)" ] }, { @@ -463,7 +465,7 @@ } ], "source": [ - "x(b=3,a=1)" + "x(b=3, a=1)" ] }, { diff --git a/examples/cicd/sig-mlops-seldon-jenkins-x/README.ipynb b/examples/cicd/sig-mlops-seldon-jenkins-x/README.ipynb index 7b74c9522e..e53add05f0 100644 --- a/examples/cicd/sig-mlops-seldon-jenkins-x/README.ipynb +++ b/examples/cicd/sig-mlops-seldon-jenkins-x/README.ipynb @@ -181,14 +181,16 @@ ], "source": [ "from sklearn.datasets import fetch_20newsgroups\n", - "categories = ['alt.atheism', 'soc.religion.christian',\n", - " 'comp.graphics', 'sci.med']\n", + "\n", + "categories = [\"alt.atheism\", \"soc.religion.christian\", \"comp.graphics\", \"sci.med\"]\n", "\n", "twenty_train = fetch_20newsgroups(\n", - " subset='train', categories=categories, shuffle=True, random_state=42)\n", + " subset=\"train\", categories=categories, shuffle=True, random_state=42\n", + ")\n", "\n", "twenty_test = fetch_20newsgroups(\n", - " subset='test', categories=categories, shuffle=True, random_state=42)\n", + " subset=\"test\", categories=categories, shuffle=True, random_state=42\n", + ")\n", "\n", "## Printing the top 3 newstories\n", "print(\"\\n\".join(twenty_train.data[0].split(\"\\n\")[:3]))" @@ -236,15 +238,17 @@ } ], "source": [ - "from sklearn.pipeline import Pipeline\n", - "from sklearn.feature_extraction.text import TfidfTransformer, CountVectorizer\n", + "from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer\n", "from sklearn.naive_bayes import MultinomialNB\n", + "from sklearn.pipeline import Pipeline\n", "\n", - "text_clf = Pipeline([\n", - " ('vect', CountVectorizer()),\n", - " ('tfidf', TfidfTransformer()),\n", - " ('clf', MultinomialNB()),\n", - "])\n", + "text_clf = Pipeline(\n", + " [\n", + " (\"vect\", CountVectorizer()),\n", + " (\"tfidf\", TfidfTransformer()),\n", + " (\"clf\", MultinomialNB()),\n", + " ]\n", + ")\n", "\n", "text_clf.fit(twenty_train.data, twenty_train.target)" ] @@ -349,6 +353,7 @@ ], "source": [ "import joblib\n", + "\n", "joblib.dump(text_clf, \"src/model.joblib\")" ] }, diff --git a/examples/feedback/feedback-metrics-server/README.ipynb b/examples/feedback/feedback-metrics-server/README.ipynb index 44cd099337..0e58c383f1 100644 --- a/examples/feedback/feedback-metrics-server/README.ipynb +++ b/examples/feedback/feedback-metrics-server/README.ipynb @@ -332,6 +332,7 @@ "outputs": [], "source": [ "import requests\n", + "\n", "url = \"http://localhost:8080/seldon/seldon/multiclass-model/api/v1.0\"" ] }, @@ -349,10 +350,10 @@ } ], "source": [ - "pred_req_1 = {\"data\":{\"ndarray\":[[1,2,3,4]]}}\n", + "pred_req_1 = {\"data\": {\"ndarray\": [[1, 2, 3, 4]]}}\n", "pred_resp_1 = requests.post(f\"{url}/predictions\", json=pred_req_1)\n", "print(pred_resp_1.json())\n", - "assert(len(pred_resp_1.json()[\"data\"][\"ndarray\"][0])==3)" + "assert len(pred_resp_1.json()[\"data\"][\"ndarray\"][0]) == 3" ] }, { @@ -376,7 +377,8 @@ "outputs": [], "source": [ "from elasticsearch import Elasticsearch\n", - "es = Elasticsearch(['https://admin:admin@localhost:9200'],verify_certs=False)" + "\n", + "es = Elasticsearch([\"https://admin:admin@localhost:9200\"], verify_certs=False)" ] }, { @@ -451,7 +453,10 @@ } ], "source": [ - "res = es.search(index=\"inference-log-seldon-seldon-multiclass-model-default\", body={\"query\": {\"match_all\": {}}})\n", + "res = es.search(\n", + " index=\"inference-log-seldon-seldon-multiclass-model-default\",\n", + " body={\"query\": {\"match_all\": {}}},\n", + ")\n", "print(\"Logged Request:\")\n", "print(res[\"hits\"][\"hits\"][0][\"_source\"][\"request\"])\n", "print(\"\\nLogged Response:\")\n", @@ -501,10 +506,7 @@ "metadata": {}, "outputs": [], "source": [ - "feedback_tags_1 = {\n", - " \"user\": \"Seldon Admin\",\n", - " \"date\": \"11/07/2020\"\n", - "}" + "feedback_tags_1 = {\"user\": \"Seldon Admin\", \"date\": \"11/07/2020\"}" ] }, { @@ -523,14 +525,9 @@ "feedback_req_1 = {\n", " \"reward\": 0,\n", " \"truth\": {\n", - " 'data': {\n", - " 'names': ['t:0', 't:1', 't:2'], \n", - " 'ndarray': [[0, 0, 1]]\n", - " },\n", - " \"meta\": {\n", - " \"tags\": feedback_tags_1\n", - " }\n", - " }\n", + " \"data\": {\"names\": [\"t:0\", \"t:1\", \"t:2\"], \"ndarray\": [[0, 0, 1]]},\n", + " \"meta\": {\"tags\": feedback_tags_1},\n", + " },\n", "}" ] }, @@ -555,7 +552,9 @@ } ], "source": [ - "feedback_resp_1 = requests.post(f\"{url}/feedback\", json=feedback_req_1, headers={\"seldon-puid\": puid_seldon_1})\n", + "feedback_resp_1 = requests.post(\n", + " f\"{url}/feedback\", json=feedback_req_1, headers={\"seldon-puid\": puid_seldon_1}\n", + ")\n", "print(feedback_resp_1)" ] }, @@ -588,7 +587,10 @@ } ], "source": [ - "res = es.search(index=\"inference-log-seldon-seldon-multiclass-model-default\", body={\"query\": {\"match_all\": {}}})\n", + "res = es.search(\n", + " index=\"inference-log-seldon-seldon-multiclass-model-default\",\n", + " body={\"query\": {\"match_all\": {}}},\n", + ")\n", "\n", "print(res[\"hits\"][\"hits\"][-1][\"_source\"][\"feedback\"])" ] @@ -778,6 +780,7 @@ "outputs": [], "source": [ "import time\n", + "\n", "time.sleep(20)" ] }, @@ -955,7 +958,9 @@ } ], "source": [ - "feedback_resp_1 = requests.post(f\"{url}/feedback\", json=feedback_req_1, headers={\"seldon-puid\": puid_seldon_1})\n", + "feedback_resp_1 = requests.post(\n", + " f\"{url}/feedback\", json=feedback_req_1, headers={\"seldon-puid\": puid_seldon_1}\n", + ")\n", "print(feedback_resp_1)" ] }, @@ -1038,7 +1043,400 @@ "metadata": {}, "outputs": [], "source": [ - "{\"annotations\": {\"list\": [{\"builtIn\": 1,\"datasource\": \"-- Grafana --\",\"enable\": true,\"hide\": true,\"iconColor\": \"rgba(0, 211, 255, 1)\",\"name\": \"Annotations & Alerts\",\"type\": \"dashboard\"}]},\"editable\": true,\"gnetId\": null,\"graphTooltip\": 0,\"id\": 4,\"links\": [],\"panels\": [{\"datasource\": \"prometheus\",\"description\": \"\",\"fieldConfig\": {\"defaults\": {\"custom\": {},\"mappings\": [],\"thresholds\": {\"mode\": \"absolute\",\"steps\": [{\"color\": \"green\",\"value\": null},{\"color\": \"red\",\"value\": 80}]}},\"overrides\": []},\"gridPos\": {\"h\": 5,\"w\": 8,\"x\": 0,\"y\": 0},\"id\": 5,\"options\": {\"colorMode\": \"background\",\"graphMode\": \"area\",\"justifyMode\": \"auto\",\"orientation\": \"auto\",\"reduceOptions\": {\"calcs\": [\"mean\"],\"fields\": \"\",\"values\": false}},\"pluginVersion\": \"7.0.3\",\"targets\": [{\"expr\": \"((sum(seldon_metric_true_positive_total) by (seldon_deployment_name) + sum(seldon_metric_true_negative_total) by (seldon_deployment_name)) / (sum(seldon_metric_true_positive_total) by (seldon_deployment_name) + sum(seldon_metric_false_positive_total) by (seldon_deployment_name) + sum(seldon_metric_false_negative_total) by (seldon_deployment_name))) \",\"format\": \"time_series\",\"instant\": false,\"interval\": \"\",\"legendFormat\": \"{{class}} - {{seldon_app}}\",\"refId\": \"A\"}],\"timeFrom\": null,\"timeShift\": null,\"title\": \"ACCURACY\",\"transparent\": true,\"type\": \"stat\"},{\"datasource\": \"prometheus\",\"description\": \"\",\"fieldConfig\": {\"defaults\": {\"custom\": {},\"mappings\": [],\"thresholds\": {\"mode\": \"absolute\",\"steps\": [{\"color\": \"green\",\"value\": null},{\"color\": \"red\",\"value\": 80}]}},\"overrides\": []},\"gridPos\": {\"h\": 5,\"w\": 8,\"x\": 8,\"y\": 0},\"id\": 6,\"options\": {\"colorMode\": \"value\",\"graphMode\": \"area\",\"justifyMode\": \"auto\",\"orientation\": \"auto\",\"reduceOptions\": {\"calcs\": [\"mean\"],\"fields\": \"\",\"values\": false}},\"pluginVersion\": \"7.0.3\",\"targets\": [{\"expr\": \"(sum(seldon_metric_true_positive_total) by (seldon_deployment_name) / (sum(seldon_metric_true_positive_total) by (seldon_deployment_name) + sum(seldon_metric_false_positive_total) by (seldon_deployment_name))) \",\"instant\": false,\"interval\": \"\",\"legendFormat\": \"{{class}} - {{seldon_deployment_name}}\",\"refId\": \"A\"}],\"timeFrom\": null,\"timeShift\": null,\"title\": \"PRECISION\",\"transparent\": true,\"type\": \"stat\"},{\"datasource\": \"prometheus\",\"description\": \"\",\"fieldConfig\": {\"defaults\": {\"custom\": {},\"mappings\": [],\"thresholds\": {\"mode\": \"absolute\",\"steps\": [{\"color\": \"green\",\"value\": null},{\"color\": \"red\",\"value\": 80}]}},\"overrides\": []},\"gridPos\": {\"h\": 5,\"w\": 8,\"x\": 16,\"y\": 0},\"id\": 7,\"options\": {\"colorMode\": \"value\",\"graphMode\": \"area\",\"justifyMode\": \"auto\",\"orientation\": \"auto\",\"reduceOptions\": {\"calcs\": [\"mean\"],\"fields\": \"\",\"values\": false}},\"pluginVersion\": \"7.0.3\",\"targets\": [{\"expr\": \"(sum(seldon_metric_true_positive_total) by (seldon_deployment_name) / (sum(seldon_metric_true_positive_total) by (seldon_deployment_name) + sum(seldon_metric_false_negative_total) by (seldon_deployment_name))) \",\"instant\": false,\"interval\": \"\",\"legendFormat\": \"{{class}} - {{seldon_app}}\",\"refId\": \"A\"}],\"timeFrom\": null,\"timeShift\": null,\"title\": \"Recall\",\"transparent\": true,\"type\": \"stat\"},{\"aliasColors\": {},\"bars\": false,\"dashLength\": 10,\"dashes\": false,\"datasource\": \"prometheus\",\"description\": \"\",\"fieldConfig\": {\"defaults\": {\"custom\": {}},\"overrides\": []},\"fill\": 1,\"fillGradient\": 0,\"gridPos\": {\"h\": 6,\"w\": 24,\"x\": 0,\"y\": 5},\"hiddenSeries\": false,\"id\": 3,\"legend\": {\"avg\": false,\"current\": false,\"max\": false,\"min\": false,\"show\": true,\"total\": false,\"values\": false},\"lines\": true,\"linewidth\": 1,\"nullPointMode\": \"null\",\"options\": {\"dataLinks\": []},\"percentage\": false,\"pointradius\": 2,\"points\": true,\"renderer\": \"flot\",\"seriesOverrides\": [],\"spaceLength\": 10,\"stack\": false,\"steppedLine\": false,\"targets\": [{\"expr\": \"((sum(seldon_metric_true_positive_total) by (class, seldon_deployment_name) + sum(seldon_metric_true_negative_total) by (class, seldon_deployment_name)) / (sum(seldon_metric_true_positive_total) by (class, seldon_deployment_name) + sum(seldon_metric_false_positive_total) by (class, seldon_deployment_name) + sum(seldon_metric_false_negative_total) by (class, seldon_deployment_name))) \",\"interval\": \"\",\"legendFormat\": \"{{class}} - {{seldon_deployment_name}}\",\"refId\": \"A\"}],\"thresholds\": [],\"timeFrom\": null,\"timeRegions\": [],\"timeShift\": null,\"title\": \"Real Time Model ACCURACY by Class\",\"tooltip\": {\"shared\": true,\"sort\": 0,\"value_type\": \"individual\"},\"transparent\": true,\"type\": \"graph\",\"xaxis\": {\"buckets\": null,\"mode\": \"time\",\"name\": null,\"show\": true,\"values\": []},\"yaxes\": [{\"decimals\": null,\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": \"1\",\"min\": \"0\",\"show\": true},{\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": null,\"min\": null,\"show\": true}],\"yaxis\": {\"align\": false,\"alignLevel\": null}},{\"aliasColors\": {},\"bars\": false,\"dashLength\": 10,\"dashes\": false,\"datasource\": \"prometheus\",\"description\": \"\",\"fieldConfig\": {\"defaults\": {\"custom\": {}},\"overrides\": []},\"fill\": 1,\"fillGradient\": 0,\"gridPos\": {\"h\": 7,\"w\": 12,\"x\": 0,\"y\": 11},\"hiddenSeries\": false,\"id\": 2,\"legend\": {\"avg\": false,\"current\": false,\"max\": false,\"min\": false,\"show\": true,\"total\": false,\"values\": false},\"lines\": true,\"linewidth\": 1,\"nullPointMode\": \"null\",\"options\": {\"dataLinks\": []},\"percentage\": false,\"pointradius\": 2,\"points\": true,\"renderer\": \"flot\",\"seriesOverrides\": [],\"spaceLength\": 10,\"stack\": false,\"steppedLine\": false,\"targets\": [{\"expr\": \"((sum(seldon_metric_true_positive_total) by (class, seldon_deployment_name)) / (sum(seldon_metric_true_positive_total) by (class, seldon_deployment_name) + sum(seldon_metric_false_positive_total) by (class, seldon_deployment_name))) \",\"interval\": \"\",\"legendFormat\": \"{{class}} - {{seldon_deployment_name}}\",\"refId\": \"A\"}],\"thresholds\": [],\"timeFrom\": null,\"timeRegions\": [],\"timeShift\": null,\"title\": \"Real Time Model PRECISION by Class\",\"tooltip\": {\"shared\": true,\"sort\": 0,\"value_type\": \"individual\"},\"type\": \"graph\",\"xaxis\": {\"buckets\": null,\"mode\": \"time\",\"name\": null,\"show\": true,\"values\": []},\"yaxes\": [{\"decimals\": null,\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": \"1\",\"min\": \"0\",\"show\": true},{\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": null,\"min\": null,\"show\": true}],\"yaxis\": {\"align\": false,\"alignLevel\": null}},{\"aliasColors\": {},\"bars\": false,\"dashLength\": 10,\"dashes\": false,\"datasource\": \"prometheus\",\"description\": \"\",\"fieldConfig\": {\"defaults\": {\"custom\": {}},\"overrides\": []},\"fill\": 1,\"fillGradient\": 0,\"gridPos\": {\"h\": 7,\"w\": 12,\"x\": 12,\"y\": 11},\"hiddenSeries\": false,\"id\": 4,\"legend\": {\"avg\": false,\"current\": false,\"max\": false,\"min\": false,\"show\": true,\"total\": false,\"values\": false},\"lines\": true,\"linewidth\": 1,\"nullPointMode\": \"null\",\"options\": {\"dataLinks\": []},\"percentage\": false,\"pointradius\": 2,\"points\": true,\"renderer\": \"flot\",\"seriesOverrides\": [],\"spaceLength\": 10,\"stack\": false,\"steppedLine\": false,\"targets\": [{\"expr\": \"((sum(seldon_metric_true_negative_total) by (class, seldon_deployment_name)) / (sum(seldon_metric_true_positive_total) by (class, seldon_deployment_name) + sum(seldon_metric_false_negative_total) by (class, seldon_deployment_name))) \",\"interval\": \"\",\"legendFormat\": \"{{class}} - {{seldon_deployment_name}}\",\"refId\": \"A\"}],\"thresholds\": [],\"timeFrom\": null,\"timeRegions\": [],\"timeShift\": null,\"title\": \"Real Time Model RECALL by Class\",\"tooltip\": {\"shared\": true,\"sort\": 0,\"value_type\": \"individual\"},\"type\": \"graph\",\"xaxis\": {\"buckets\": null,\"mode\": \"time\",\"name\": null,\"show\": true,\"values\": []},\"yaxes\": [{\"decimals\": null,\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": \"1\",\"min\": \"0\",\"show\": true},{\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": null,\"min\": null,\"show\": true}],\"yaxis\": {\"align\": false,\"alignLevel\": null}}],\"refresh\": false,\"schemaVersion\": 25,\"style\": \"dark\",\"tags\": [],\"templating\": {\"list\": []},\"time\": {\"from\": \"2020-11-03T12:06:17.311Z\",\"to\": \"2020-11-03T13:06:17.315Z\"},\"timepicker\": {\"refresh_intervals\": [\"10s\",\"30s\",\"1m\",\"5m\",\"15m\",\"30m\",\"1h\",\"2h\",\"1d\"]},\"timezone\": \"\",\"title\": \"Real Time Statistical Performance\",\"uid\": \"St9vqHnGk\",\"version\": 1}" + "{\n", + " \"annotations\": {\n", + " \"list\": [\n", + " {\n", + " \"builtIn\": 1,\n", + " \"datasource\": \"-- Grafana --\",\n", + " \"enable\": true,\n", + " \"hide\": true,\n", + " \"iconColor\": \"rgba(0, 211, 255, 1)\",\n", + " \"name\": \"Annotations & Alerts\",\n", + " \"type\": \"dashboard\",\n", + " }\n", + " ]\n", + " },\n", + " \"editable\": true,\n", + " \"gnetId\": null,\n", + " \"graphTooltip\": 0,\n", + " \"id\": 4,\n", + " \"links\": [],\n", + " \"panels\": [\n", + " {\n", + " \"datasource\": \"prometheus\",\n", + " \"description\": \"\",\n", + " \"fieldConfig\": {\n", + " \"defaults\": {\n", + " \"custom\": {},\n", + " \"mappings\": [],\n", + " \"thresholds\": {\n", + " \"mode\": \"absolute\",\n", + " \"steps\": [\n", + " {\"color\": \"green\", \"value\": null},\n", + " {\"color\": \"red\", \"value\": 80},\n", + " ],\n", + " },\n", + " },\n", + " \"overrides\": [],\n", + " },\n", + " \"gridPos\": {\"h\": 5, \"w\": 8, \"x\": 0, \"y\": 0},\n", + " \"id\": 5,\n", + " \"options\": {\n", + " \"colorMode\": \"background\",\n", + " \"graphMode\": \"area\",\n", + " \"justifyMode\": \"auto\",\n", + " \"orientation\": \"auto\",\n", + " \"reduceOptions\": {\"calcs\": [\"mean\"], \"fields\": \"\", \"values\": false},\n", + " },\n", + " \"pluginVersion\": \"7.0.3\",\n", + " \"targets\": [\n", + " {\n", + " \"expr\": \"((sum(seldon_metric_true_positive_total) by (seldon_deployment_name) + sum(seldon_metric_true_negative_total) by (seldon_deployment_name)) / (sum(seldon_metric_true_positive_total) by (seldon_deployment_name) + sum(seldon_metric_false_positive_total) by (seldon_deployment_name) + sum(seldon_metric_false_negative_total) by (seldon_deployment_name))) \",\n", + " \"format\": \"time_series\",\n", + " \"instant\": false,\n", + " \"interval\": \"\",\n", + " \"legendFormat\": \"{{class}} - {{seldon_app}}\",\n", + " \"refId\": \"A\",\n", + " }\n", + " ],\n", + " \"timeFrom\": null,\n", + " \"timeShift\": null,\n", + " \"title\": \"ACCURACY\",\n", + " \"transparent\": true,\n", + " \"type\": \"stat\",\n", + " },\n", + " {\n", + " \"datasource\": \"prometheus\",\n", + " \"description\": \"\",\n", + " \"fieldConfig\": {\n", + " \"defaults\": {\n", + " \"custom\": {},\n", + " \"mappings\": [],\n", + " \"thresholds\": {\n", + " \"mode\": \"absolute\",\n", + " \"steps\": [\n", + " {\"color\": \"green\", \"value\": null},\n", + " {\"color\": \"red\", \"value\": 80},\n", + " ],\n", + " },\n", + " },\n", + " \"overrides\": [],\n", + " },\n", + " \"gridPos\": {\"h\": 5, \"w\": 8, \"x\": 8, \"y\": 0},\n", + " \"id\": 6,\n", + " \"options\": {\n", + " \"colorMode\": \"value\",\n", + " \"graphMode\": \"area\",\n", + " \"justifyMode\": \"auto\",\n", + " \"orientation\": \"auto\",\n", + " \"reduceOptions\": {\"calcs\": [\"mean\"], \"fields\": \"\", \"values\": false},\n", + " },\n", + " \"pluginVersion\": \"7.0.3\",\n", + " \"targets\": [\n", + " {\n", + " \"expr\": \"(sum(seldon_metric_true_positive_total) by (seldon_deployment_name) / (sum(seldon_metric_true_positive_total) by (seldon_deployment_name) + sum(seldon_metric_false_positive_total) by (seldon_deployment_name))) \",\n", + " \"instant\": false,\n", + " \"interval\": \"\",\n", + " \"legendFormat\": \"{{class}} - {{seldon_deployment_name}}\",\n", + " \"refId\": \"A\",\n", + " }\n", + " ],\n", + " \"timeFrom\": null,\n", + " \"timeShift\": null,\n", + " \"title\": \"PRECISION\",\n", + " \"transparent\": true,\n", + " \"type\": \"stat\",\n", + " },\n", + " {\n", + " \"datasource\": \"prometheus\",\n", + " \"description\": \"\",\n", + " \"fieldConfig\": {\n", + " \"defaults\": {\n", + " \"custom\": {},\n", + " \"mappings\": [],\n", + " \"thresholds\": {\n", + " \"mode\": \"absolute\",\n", + " \"steps\": [\n", + " {\"color\": \"green\", \"value\": null},\n", + " {\"color\": \"red\", \"value\": 80},\n", + " ],\n", + " },\n", + " },\n", + " \"overrides\": [],\n", + " },\n", + " \"gridPos\": {\"h\": 5, \"w\": 8, \"x\": 16, \"y\": 0},\n", + " \"id\": 7,\n", + " \"options\": {\n", + " \"colorMode\": \"value\",\n", + " \"graphMode\": \"area\",\n", + " \"justifyMode\": \"auto\",\n", + " \"orientation\": \"auto\",\n", + " \"reduceOptions\": {\"calcs\": [\"mean\"], \"fields\": \"\", \"values\": false},\n", + " },\n", + " \"pluginVersion\": \"7.0.3\",\n", + " \"targets\": [\n", + " {\n", + " \"expr\": \"(sum(seldon_metric_true_positive_total) by (seldon_deployment_name) / (sum(seldon_metric_true_positive_total) by (seldon_deployment_name) + sum(seldon_metric_false_negative_total) by (seldon_deployment_name))) \",\n", + " \"instant\": false,\n", + " \"interval\": \"\",\n", + " \"legendFormat\": \"{{class}} - {{seldon_app}}\",\n", + " \"refId\": \"A\",\n", + " }\n", + " ],\n", + " \"timeFrom\": null,\n", + " \"timeShift\": null,\n", + " \"title\": \"Recall\",\n", + " \"transparent\": true,\n", + " \"type\": \"stat\",\n", + " },\n", + " {\n", + " \"aliasColors\": {},\n", + " \"bars\": false,\n", + " \"dashLength\": 10,\n", + " \"dashes\": false,\n", + " \"datasource\": \"prometheus\",\n", + " \"description\": \"\",\n", + " \"fieldConfig\": {\"defaults\": {\"custom\": {}}, \"overrides\": []},\n", + " \"fill\": 1,\n", + " \"fillGradient\": 0,\n", + " \"gridPos\": {\"h\": 6, \"w\": 24, \"x\": 0, \"y\": 5},\n", + " \"hiddenSeries\": false,\n", + " \"id\": 3,\n", + " \"legend\": {\n", + " \"avg\": false,\n", + " \"current\": false,\n", + " \"max\": false,\n", + " \"min\": false,\n", + " \"show\": true,\n", + " \"total\": false,\n", + " \"values\": false,\n", + " },\n", + " \"lines\": true,\n", + " \"linewidth\": 1,\n", + " \"nullPointMode\": \"null\",\n", + " \"options\": {\"dataLinks\": []},\n", + " \"percentage\": false,\n", + " \"pointradius\": 2,\n", + " \"points\": true,\n", + " \"renderer\": \"flot\",\n", + " \"seriesOverrides\": [],\n", + " \"spaceLength\": 10,\n", + " \"stack\": false,\n", + " \"steppedLine\": false,\n", + " \"targets\": [\n", + " {\n", + " \"expr\": \"((sum(seldon_metric_true_positive_total) by (class, seldon_deployment_name) + sum(seldon_metric_true_negative_total) by (class, seldon_deployment_name)) / (sum(seldon_metric_true_positive_total) by (class, seldon_deployment_name) + sum(seldon_metric_false_positive_total) by (class, seldon_deployment_name) + sum(seldon_metric_false_negative_total) by (class, seldon_deployment_name))) \",\n", + " \"interval\": \"\",\n", + " \"legendFormat\": \"{{class}} - {{seldon_deployment_name}}\",\n", + " \"refId\": \"A\",\n", + " }\n", + " ],\n", + " \"thresholds\": [],\n", + " \"timeFrom\": null,\n", + " \"timeRegions\": [],\n", + " \"timeShift\": null,\n", + " \"title\": \"Real Time Model ACCURACY by Class\",\n", + " \"tooltip\": {\"shared\": true, \"sort\": 0, \"value_type\": \"individual\"},\n", + " \"transparent\": true,\n", + " \"type\": \"graph\",\n", + " \"xaxis\": {\n", + " \"buckets\": null,\n", + " \"mode\": \"time\",\n", + " \"name\": null,\n", + " \"show\": true,\n", + " \"values\": [],\n", + " },\n", + " \"yaxes\": [\n", + " {\n", + " \"decimals\": null,\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": \"1\",\n", + " \"min\": \"0\",\n", + " \"show\": true,\n", + " },\n", + " {\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": null,\n", + " \"min\": null,\n", + " \"show\": true,\n", + " },\n", + " ],\n", + " \"yaxis\": {\"align\": false, \"alignLevel\": null},\n", + " },\n", + " {\n", + " \"aliasColors\": {},\n", + " \"bars\": false,\n", + " \"dashLength\": 10,\n", + " \"dashes\": false,\n", + " \"datasource\": \"prometheus\",\n", + " \"description\": \"\",\n", + " \"fieldConfig\": {\"defaults\": {\"custom\": {}}, \"overrides\": []},\n", + " \"fill\": 1,\n", + " \"fillGradient\": 0,\n", + " \"gridPos\": {\"h\": 7, \"w\": 12, \"x\": 0, \"y\": 11},\n", + " \"hiddenSeries\": false,\n", + " \"id\": 2,\n", + " \"legend\": {\n", + " \"avg\": false,\n", + " \"current\": false,\n", + " \"max\": false,\n", + " \"min\": false,\n", + " \"show\": true,\n", + " \"total\": false,\n", + " \"values\": false,\n", + " },\n", + " \"lines\": true,\n", + " \"linewidth\": 1,\n", + " \"nullPointMode\": \"null\",\n", + " \"options\": {\"dataLinks\": []},\n", + " \"percentage\": false,\n", + " \"pointradius\": 2,\n", + " \"points\": true,\n", + " \"renderer\": \"flot\",\n", + " \"seriesOverrides\": [],\n", + " \"spaceLength\": 10,\n", + " \"stack\": false,\n", + " \"steppedLine\": false,\n", + " \"targets\": [\n", + " {\n", + " \"expr\": \"((sum(seldon_metric_true_positive_total) by (class, seldon_deployment_name)) / (sum(seldon_metric_true_positive_total) by (class, seldon_deployment_name) + sum(seldon_metric_false_positive_total) by (class, seldon_deployment_name))) \",\n", + " \"interval\": \"\",\n", + " \"legendFormat\": \"{{class}} - {{seldon_deployment_name}}\",\n", + " \"refId\": \"A\",\n", + " }\n", + " ],\n", + " \"thresholds\": [],\n", + " \"timeFrom\": null,\n", + " \"timeRegions\": [],\n", + " \"timeShift\": null,\n", + " \"title\": \"Real Time Model PRECISION by Class\",\n", + " \"tooltip\": {\"shared\": true, \"sort\": 0, \"value_type\": \"individual\"},\n", + " \"type\": \"graph\",\n", + " \"xaxis\": {\n", + " \"buckets\": null,\n", + " \"mode\": \"time\",\n", + " \"name\": null,\n", + " \"show\": true,\n", + " \"values\": [],\n", + " },\n", + " \"yaxes\": [\n", + " {\n", + " \"decimals\": null,\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": \"1\",\n", + " \"min\": \"0\",\n", + " \"show\": true,\n", + " },\n", + " {\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": null,\n", + " \"min\": null,\n", + " \"show\": true,\n", + " },\n", + " ],\n", + " \"yaxis\": {\"align\": false, \"alignLevel\": null},\n", + " },\n", + " {\n", + " \"aliasColors\": {},\n", + " \"bars\": false,\n", + " \"dashLength\": 10,\n", + " \"dashes\": false,\n", + " \"datasource\": \"prometheus\",\n", + " \"description\": \"\",\n", + " \"fieldConfig\": {\"defaults\": {\"custom\": {}}, \"overrides\": []},\n", + " \"fill\": 1,\n", + " \"fillGradient\": 0,\n", + " \"gridPos\": {\"h\": 7, \"w\": 12, \"x\": 12, \"y\": 11},\n", + " \"hiddenSeries\": false,\n", + " \"id\": 4,\n", + " \"legend\": {\n", + " \"avg\": false,\n", + " \"current\": false,\n", + " \"max\": false,\n", + " \"min\": false,\n", + " \"show\": true,\n", + " \"total\": false,\n", + " \"values\": false,\n", + " },\n", + " \"lines\": true,\n", + " \"linewidth\": 1,\n", + " \"nullPointMode\": \"null\",\n", + " \"options\": {\"dataLinks\": []},\n", + " \"percentage\": false,\n", + " \"pointradius\": 2,\n", + " \"points\": true,\n", + " \"renderer\": \"flot\",\n", + " \"seriesOverrides\": [],\n", + " \"spaceLength\": 10,\n", + " \"stack\": false,\n", + " \"steppedLine\": false,\n", + " \"targets\": [\n", + " {\n", + " \"expr\": \"((sum(seldon_metric_true_negative_total) by (class, seldon_deployment_name)) / (sum(seldon_metric_true_positive_total) by (class, seldon_deployment_name) + sum(seldon_metric_false_negative_total) by (class, seldon_deployment_name))) \",\n", + " \"interval\": \"\",\n", + " \"legendFormat\": \"{{class}} - {{seldon_deployment_name}}\",\n", + " \"refId\": \"A\",\n", + " }\n", + " ],\n", + " \"thresholds\": [],\n", + " \"timeFrom\": null,\n", + " \"timeRegions\": [],\n", + " \"timeShift\": null,\n", + " \"title\": \"Real Time Model RECALL by Class\",\n", + " \"tooltip\": {\"shared\": true, \"sort\": 0, \"value_type\": \"individual\"},\n", + " \"type\": \"graph\",\n", + " \"xaxis\": {\n", + " \"buckets\": null,\n", + " \"mode\": \"time\",\n", + " \"name\": null,\n", + " \"show\": true,\n", + " \"values\": [],\n", + " },\n", + " \"yaxes\": [\n", + " {\n", + " \"decimals\": null,\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": \"1\",\n", + " \"min\": \"0\",\n", + " \"show\": true,\n", + " },\n", + " {\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": null,\n", + " \"min\": null,\n", + " \"show\": true,\n", + " },\n", + " ],\n", + " \"yaxis\": {\"align\": false, \"alignLevel\": null},\n", + " },\n", + " ],\n", + " \"refresh\": false,\n", + " \"schemaVersion\": 25,\n", + " \"style\": \"dark\",\n", + " \"tags\": [],\n", + " \"templating\": {\"list\": []},\n", + " \"time\": {\"from\": \"2020-11-03T12:06:17.311Z\", \"to\": \"2020-11-03T13:06:17.315Z\"},\n", + " \"timepicker\": {\n", + " \"refresh_intervals\": [\"10s\", \"30s\", \"1m\", \"5m\", \"15m\", \"30m\", \"1h\", \"2h\", \"1d\"]\n", + " },\n", + " \"timezone\": \"\",\n", + " \"title\": \"Real Time Statistical Performance\",\n", + " \"uid\": \"St9vqHnGk\",\n", + " \"version\": 1,\n", + "}" ] }, { @@ -1070,7 +1468,7 @@ "metadata": {}, "outputs": [], "source": [ - "?datasets.load_iris" + "datasets.load_iris?" ] }, { @@ -1095,9 +1493,9 @@ } ], "source": [ - "from sklearn.model_selection import train_test_split\n", - "from sklearn import datasets\n", "import numpy as np\n", + "from sklearn import datasets\n", + "from sklearn.model_selection import train_test_split\n", "\n", "X_test, y_test = datasets.load_iris(return_X_y=True)\n", "\n", @@ -1124,7 +1522,7 @@ "puids = []\n", "\n", "for x in X_test:\n", - " pred_req = {\"data\":{\"ndarray\":[x.tolist()]}}\n", + " pred_req = {\"data\": {\"ndarray\": [x.tolist()]}}\n", " pred_resp = requests.post(f\"{url}/predictions\", json=pred_req)\n", " puid_seldon = pred_resp.headers.get(\"seldon-puid\")\n", " puids.append(puid_seldon)\n", @@ -1160,12 +1558,7 @@ "source": [ "for puid, y in zip(puids, y_test):\n", " data = {\n", - " \"truth\": {\n", - " 'data': {\n", - " 'names': ['t:0', 't:1', 't:2'], \n", - " 'ndarray': [y.tolist()]\n", - " }\n", - " }\n", + " \"truth\": {\"data\": {\"names\": [\"t:0\", \"t:1\", \"t:2\"], \"ndarray\": [y.tolist()]}}\n", " }\n", " requests.post(f\"{url}/feedback\", json=data, headers={\"seldon-puid\": puid})\n", " time.sleep(0.5)" @@ -1187,12 +1580,7 @@ "np.random.shuffle(y_test)\n", "for puid, y in zip(puids, y_test):\n", " data = {\n", - " \"truth\": {\n", - " 'data': {\n", - " 'names': ['t:0', 't:1', 't:2'], \n", - " 'ndarray': [y.tolist()]\n", - " }\n", - " }\n", + " \"truth\": {\"data\": {\"names\": [\"t:0\", \"t:1\", \"t:2\"], \"ndarray\": [y.tolist()]}}\n", " }\n", " requests.post(f\"{url}/feedback\", json=data, headers={\"seldon-puid\": puid})\n", " time.sleep(0.5)" diff --git a/examples/feedback/metrics-server/README.ipynb b/examples/feedback/metrics-server/README.ipynb index 1042ecd82e..f083f82eba 100644 --- a/examples/feedback/metrics-server/README.ipynb +++ b/examples/feedback/metrics-server/README.ipynb @@ -297,6 +297,7 @@ "outputs": [], "source": [ "import time\n", + "\n", "time.sleep(20)" ] }, @@ -337,6 +338,7 @@ "outputs": [], "source": [ "import time\n", + "\n", "time.sleep(3)" ] }, diff --git a/examples/feedback/reward-accuracy/README.ipynb b/examples/feedback/reward-accuracy/README.ipynb index 55888362aa..2679b85ac7 100644 --- a/examples/feedback/reward-accuracy/README.ipynb +++ b/examples/feedback/reward-accuracy/README.ipynb @@ -103,14 +103,20 @@ ], "source": [ "import joblib\n", - "from sklearn.pipeline import Pipeline\n", - "from sklearn.linear_model import LogisticRegression, Perceptron\n", "from sklearn import datasets\n", + "from sklearn.linear_model import LogisticRegression, Perceptron\n", "from sklearn.model_selection import train_test_split\n", + "from sklearn.pipeline import Pipeline\n", "\n", "parameters = [\n", - " {\"clf\": LogisticRegression(solver=\"liblinear\", multi_class=\"ovr\"), \"name\": \"binary-lr.joblib\"},\n", - " {\"clf\": Perceptron(n_iter=40, eta0=0.1, random_state=0), \"name\": \"binary-percept.joblib\"},\n", + " {\n", + " \"clf\": LogisticRegression(solver=\"liblinear\", multi_class=\"ovr\"),\n", + " \"name\": \"binary-lr.joblib\",\n", + " },\n", + " {\n", + " \"clf\": Perceptron(n_iter=40, eta0=0.1, random_state=0),\n", + " \"name\": \"binary-percept.joblib\",\n", + " },\n", "]\n", "\n", "X, y = datasets.load_breast_cancer(return_X_y=True)\n", @@ -121,7 +127,7 @@ " clf.fit(X_train, y_train)\n", "\n", " print(f\"Saving model in {param['name']}\")\n", - " joblib.dump(clf, param['name'])" + " joblib.dump(clf, param[\"name\"])" ] }, { @@ -368,7 +374,12 @@ "source": [ "from seldon_core.seldon_client import SeldonClient\n", "\n", - "sc = SeldonClient(namespace=\"seldon\", gateway_endpoint=\"localhost:80\", deployment_name=\"metrics-model\", payload_type=\"ndarray\")" + "sc = SeldonClient(\n", + " namespace=\"seldon\",\n", + " gateway_endpoint=\"localhost:80\",\n", + " deployment_name=\"metrics-model\",\n", + " payload_type=\"ndarray\",\n", + ")" ] }, { @@ -423,7 +434,10 @@ "url = \"http://localhost:80/seldon/seldon/metrics-model/api/v1.0/feedback\"\n", "\n", "for x_i, y_i in zip(X_test, y_test):\n", - " data = {\"request\": {\"data\": {\"ndarray\": [x_i.tolist()]}}, \"truth\":{\"data\": {\"ndarray\": [[y_i.tolist()]]}}}\n", + " data = {\n", + " \"request\": {\"data\": {\"ndarray\": [x_i.tolist()]}},\n", + " \"truth\": {\"data\": {\"ndarray\": [[y_i.tolist()]]}},\n", + " }\n", " requests.post(f\"{url}\", json=data)" ] }, @@ -461,7 +475,406 @@ "metadata": {}, "outputs": [], "source": [ - "{\"annotations\": {\"list\": [{\"builtIn\": 1,\"datasource\": \"-- Grafana --\",\"enable\": true,\"hide\": true,\"iconColor\": \"rgba(0, 211, 255, 1)\",\"name\": \"Annotations & Alerts\",\"type\": \"dashboard\"}]},\"editable\": true,\"gnetId\": null,\"graphTooltip\": 0,\"id\": 4,\"links\": [],\"panels\": [{\"aliasColors\": {},\"bars\": false,\"dashLength\": 10,\"dashes\": false,\"datasource\": \"prometheus\",\"description\": \"\",\"fieldConfig\": {\"defaults\": {\"custom\": {},\"mappings\": [],\"thresholds\": {\"mode\": \"absolute\",\"steps\": [{\"color\": \"green\",\"value\": null},{\"color\": \"red\",\"value\": 80}]}},\"overrides\": []},\"fill\": 1,\"fillGradient\": 0,\"gridPos\": {\"h\": 8,\"w\": 12,\"x\": 0,\"y\": 0},\"hiddenSeries\": false,\"id\": 2,\"legend\": {\"avg\": false,\"current\": false,\"max\": false,\"min\": false,\"show\": true,\"total\": false,\"values\": false},\"lines\": true,\"linewidth\": 1,\"nullPointMode\": \"null\",\"options\": {\"dataLinks\": []},\"percentage\": false,\"pluginVersion\": \"7.0.3\",\"pointradius\": 2,\"points\": true,\"renderer\": \"flot\",\"seriesOverrides\": [],\"spaceLength\": 10,\"stack\": false,\"steppedLine\": false,\"targets\": [{\"expr\": \"(sum(true_pos{method=\\\"feedback\\\"} + true_neg{method=\\\"feedback\\\"}) by (seldon_app)) / (sum(true_pos{method=\\\"feedback\\\"} + true_neg{method=\\\"feedback\\\"} + false_pos{method=\\\"feedback\\\"} + false_neg{method=\\\"feedback\\\"}) by (seldon_app))\",\"interval\": \"\",\"legendFormat\": \"{{seldon_app}}\",\"refId\": \"A\"}],\"thresholds\": [],\"timeFrom\": null,\"timeRegions\": [],\"timeShift\": null,\"title\": \"Real Time Model Accuracy\",\"tooltip\": {\"shared\": true,\"sort\": 0,\"value_type\": \"individual\"},\"type\": \"graph\",\"xaxis\": {\"buckets\": null,\"mode\": \"time\",\"name\": null,\"show\": true,\"values\": []},\"yaxes\": [{\"decimals\": null,\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": \"1\",\"min\": \"0\",\"show\": true},{\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": null,\"min\": null,\"show\": true}],\"yaxis\": {\"align\": false,\"alignLevel\": null}},{\"aliasColors\": {},\"bars\": false,\"dashLength\": 10,\"dashes\": false,\"datasource\": \"prometheus\",\"description\": \"\",\"fieldConfig\": {\"defaults\": {\"custom\": {\"align\": null},\"mappings\": [],\"thresholds\": {\"mode\": \"absolute\",\"steps\": [{\"color\": \"green\",\"value\": null},{\"color\": \"red\",\"value\": 80}]}},\"overrides\": []},\"fill\": 1,\"fillGradient\": 0,\"gridPos\": {\"h\": 8,\"w\": 12,\"x\": 12,\"y\": 0},\"hiddenSeries\": false,\"id\": 3,\"legend\": {\"avg\": false,\"current\": false,\"max\": false,\"min\": false,\"show\": true,\"total\": false,\"values\": false},\"lines\": true,\"linewidth\": 1,\"nullPointMode\": \"null\",\"options\": {\"dataLinks\": []},\"percentage\": false,\"pluginVersion\": \"7.0.3\",\"pointradius\": 2,\"points\": true,\"renderer\": \"flot\",\"seriesOverrides\": [],\"spaceLength\": 10,\"stack\": false,\"steppedLine\": false,\"targets\": [{\"expr\": \"(sum(true_pos{method=\\\"feedback\\\"}) by (seldon_app)) / (sum(true_pos{method=\\\"feedback\\\"} + false_pos{method=\\\"feedback\\\"}) by (seldon_app))\",\"interval\": \"\",\"legendFormat\": \"{{seldon_app}}\",\"refId\": \"A\"}],\"thresholds\": [],\"timeFrom\": null,\"timeRegions\": [],\"timeShift\": null,\"title\": \"Real Time Model Precision\",\"tooltip\": {\"shared\": true,\"sort\": 0,\"value_type\": \"individual\"},\"type\": \"graph\",\"xaxis\": {\"buckets\": null,\"mode\": \"time\",\"name\": null,\"show\": true,\"values\": []},\"yaxes\": [{\"decimals\": null,\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": \"1\",\"min\": \"0\",\"show\": true},{\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": null,\"min\": null,\"show\": true}],\"yaxis\": {\"align\": false,\"alignLevel\": null}},{\"aliasColors\": {},\"bars\": false,\"dashLength\": 10,\"dashes\": false,\"datasource\": \"prometheus\",\"description\": \"\",\"fieldConfig\": {\"defaults\": {\"custom\": {},\"mappings\": [],\"thresholds\": {\"mode\": \"absolute\",\"steps\": [{\"color\": \"green\",\"value\": null},{\"color\": \"red\",\"value\": 80}]}},\"overrides\": []},\"fill\": 1,\"fillGradient\": 0,\"gridPos\": {\"h\": 8,\"w\": 12,\"x\": 0,\"y\": 8},\"hiddenSeries\": false,\"id\": 5,\"legend\": {\"avg\": false,\"current\": false,\"max\": false,\"min\": false,\"show\": true,\"total\": false,\"values\": false},\"lines\": true,\"linewidth\": 1,\"nullPointMode\": \"null\",\"options\": {\"dataLinks\": []},\"percentage\": false,\"pluginVersion\": \"7.0.3\",\"pointradius\": 2,\"points\": true,\"renderer\": \"flot\",\"seriesOverrides\": [],\"spaceLength\": 10,\"stack\": false,\"steppedLine\": false,\"targets\": [{\"expr\": \"(sum(true_pos{method=\\\"feedback\\\"}) by (seldon_app)) / (sum(true_pos{method=\\\"feedback\\\"} + false_neg{method=\\\"feedback\\\"}) by (seldon_app))\",\"interval\": \"\",\"legendFormat\": \"{{seldon_app}}\",\"refId\": \"A\"}],\"thresholds\": [],\"timeFrom\": null,\"timeRegions\": [],\"timeShift\": null,\"title\": \"Real Time Model Recall\",\"tooltip\": {\"shared\": true,\"sort\": 0,\"value_type\": \"individual\"},\"type\": \"graph\",\"xaxis\": {\"buckets\": null,\"mode\": \"time\",\"name\": null,\"show\": true,\"values\": []},\"yaxes\": [{\"decimals\": null,\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": \"1\",\"min\": \"0\",\"show\": true},{\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": null,\"min\": null,\"show\": true}],\"yaxis\": {\"align\": false,\"alignLevel\": null}},{\"aliasColors\": {},\"bars\": false,\"dashLength\": 10,\"dashes\": false,\"datasource\": \"prometheus\",\"description\": \"\",\"fieldConfig\": {\"defaults\": {\"custom\": {},\"mappings\": [],\"thresholds\": {\"mode\": \"absolute\",\"steps\": [{\"color\": \"green\",\"value\": null},{\"color\": \"red\",\"value\": 80}]}},\"overrides\": []},\"fill\": 1,\"fillGradient\": 0,\"gridPos\": {\"h\": 8,\"w\": 12,\"x\": 12,\"y\": 8},\"hiddenSeries\": false,\"id\": 4,\"legend\": {\"avg\": false,\"current\": false,\"max\": false,\"min\": false,\"show\": true,\"total\": false,\"values\": false},\"lines\": true,\"linewidth\": 1,\"nullPointMode\": \"null\",\"options\": {\"dataLinks\": []},\"percentage\": false,\"pluginVersion\": \"7.0.3\",\"pointradius\": 2,\"points\": true,\"renderer\": \"flot\",\"seriesOverrides\": [],\"spaceLength\": 10,\"stack\": false,\"steppedLine\": false,\"targets\": [{\"expr\": \"(sum(true_neg{method=\\\"feedback\\\"}) by (seldon_app)) / (sum(true_neg{method=\\\"feedback\\\"} + false_pos{method=\\\"feedback\\\"}) by (seldon_app))\",\"interval\": \"\",\"legendFormat\": \"{{seldon_app}}\",\"refId\": \"A\"}],\"thresholds\": [],\"timeFrom\": null,\"timeRegions\": [],\"timeShift\": null,\"title\": \"Real Time Model Specificity\",\"tooltip\": {\"shared\": true,\"sort\": 0,\"value_type\": \"individual\"},\"type\": \"graph\",\"xaxis\": {\"buckets\": null,\"mode\": \"time\",\"name\": null,\"show\": true,\"values\": []},\"yaxes\": [{\"decimals\": null,\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": \"1\",\"min\": \"0\",\"show\": true},{\"format\": \"short\",\"label\": null,\"logBase\": 1,\"max\": null,\"min\": null,\"show\": true}],\"yaxis\": {\"align\": false,\"alignLevel\": null}}],\"refresh\": \"5s\",\"schemaVersion\": 25,\"style\": \"dark\",\"tags\": [],\"templating\": {\"list\": []},\"time\": {\"from\": \"now-5m\",\"to\": \"now\"},\"timepicker\": {\"refresh_intervals\": [\"10s\",\"30s\",\"1m\",\"5m\",\"15m\",\"30m\",\"1h\",\"2h\",\"1d\"],\"time_options\": [\"5m\",\"15m\",\"1h\",\"6h\",\"12h\",\"24h\",\"2d\",\"7d\",\"30d\"]},\"timezone\": \"browser\",\"title\": \"statistical-metrics\",\"uid\": \"zmkrlZ7Gk\",\"version\": 4}" + "{\n", + " \"annotations\": {\n", + " \"list\": [\n", + " {\n", + " \"builtIn\": 1,\n", + " \"datasource\": \"-- Grafana --\",\n", + " \"enable\": true,\n", + " \"hide\": true,\n", + " \"iconColor\": \"rgba(0, 211, 255, 1)\",\n", + " \"name\": \"Annotations & Alerts\",\n", + " \"type\": \"dashboard\",\n", + " }\n", + " ]\n", + " },\n", + " \"editable\": true,\n", + " \"gnetId\": null,\n", + " \"graphTooltip\": 0,\n", + " \"id\": 4,\n", + " \"links\": [],\n", + " \"panels\": [\n", + " {\n", + " \"aliasColors\": {},\n", + " \"bars\": false,\n", + " \"dashLength\": 10,\n", + " \"dashes\": false,\n", + " \"datasource\": \"prometheus\",\n", + " \"description\": \"\",\n", + " \"fieldConfig\": {\n", + " \"defaults\": {\n", + " \"custom\": {},\n", + " \"mappings\": [],\n", + " \"thresholds\": {\n", + " \"mode\": \"absolute\",\n", + " \"steps\": [\n", + " {\"color\": \"green\", \"value\": null},\n", + " {\"color\": \"red\", \"value\": 80},\n", + " ],\n", + " },\n", + " },\n", + " \"overrides\": [],\n", + " },\n", + " \"fill\": 1,\n", + " \"fillGradient\": 0,\n", + " \"gridPos\": {\"h\": 8, \"w\": 12, \"x\": 0, \"y\": 0},\n", + " \"hiddenSeries\": false,\n", + " \"id\": 2,\n", + " \"legend\": {\n", + " \"avg\": false,\n", + " \"current\": false,\n", + " \"max\": false,\n", + " \"min\": false,\n", + " \"show\": true,\n", + " \"total\": false,\n", + " \"values\": false,\n", + " },\n", + " \"lines\": true,\n", + " \"linewidth\": 1,\n", + " \"nullPointMode\": \"null\",\n", + " \"options\": {\"dataLinks\": []},\n", + " \"percentage\": false,\n", + " \"pluginVersion\": \"7.0.3\",\n", + " \"pointradius\": 2,\n", + " \"points\": true,\n", + " \"renderer\": \"flot\",\n", + " \"seriesOverrides\": [],\n", + " \"spaceLength\": 10,\n", + " \"stack\": false,\n", + " \"steppedLine\": false,\n", + " \"targets\": [\n", + " {\n", + " \"expr\": '(sum(true_pos{method=\"feedback\"} + true_neg{method=\"feedback\"}) by (seldon_app)) / (sum(true_pos{method=\"feedback\"} + true_neg{method=\"feedback\"} + false_pos{method=\"feedback\"} + false_neg{method=\"feedback\"}) by (seldon_app))',\n", + " \"interval\": \"\",\n", + " \"legendFormat\": \"{{seldon_app}}\",\n", + " \"refId\": \"A\",\n", + " }\n", + " ],\n", + " \"thresholds\": [],\n", + " \"timeFrom\": null,\n", + " \"timeRegions\": [],\n", + " \"timeShift\": null,\n", + " \"title\": \"Real Time Model Accuracy\",\n", + " \"tooltip\": {\"shared\": true, \"sort\": 0, \"value_type\": \"individual\"},\n", + " \"type\": \"graph\",\n", + " \"xaxis\": {\n", + " \"buckets\": null,\n", + " \"mode\": \"time\",\n", + " \"name\": null,\n", + " \"show\": true,\n", + " \"values\": [],\n", + " },\n", + " \"yaxes\": [\n", + " {\n", + " \"decimals\": null,\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": \"1\",\n", + " \"min\": \"0\",\n", + " \"show\": true,\n", + " },\n", + " {\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": null,\n", + " \"min\": null,\n", + " \"show\": true,\n", + " },\n", + " ],\n", + " \"yaxis\": {\"align\": false, \"alignLevel\": null},\n", + " },\n", + " {\n", + " \"aliasColors\": {},\n", + " \"bars\": false,\n", + " \"dashLength\": 10,\n", + " \"dashes\": false,\n", + " \"datasource\": \"prometheus\",\n", + " \"description\": \"\",\n", + " \"fieldConfig\": {\n", + " \"defaults\": {\n", + " \"custom\": {\"align\": null},\n", + " \"mappings\": [],\n", + " \"thresholds\": {\n", + " \"mode\": \"absolute\",\n", + " \"steps\": [\n", + " {\"color\": \"green\", \"value\": null},\n", + " {\"color\": \"red\", \"value\": 80},\n", + " ],\n", + " },\n", + " },\n", + " \"overrides\": [],\n", + " },\n", + " \"fill\": 1,\n", + " \"fillGradient\": 0,\n", + " \"gridPos\": {\"h\": 8, \"w\": 12, \"x\": 12, \"y\": 0},\n", + " \"hiddenSeries\": false,\n", + " \"id\": 3,\n", + " \"legend\": {\n", + " \"avg\": false,\n", + " \"current\": false,\n", + " \"max\": false,\n", + " \"min\": false,\n", + " \"show\": true,\n", + " \"total\": false,\n", + " \"values\": false,\n", + " },\n", + " \"lines\": true,\n", + " \"linewidth\": 1,\n", + " \"nullPointMode\": \"null\",\n", + " \"options\": {\"dataLinks\": []},\n", + " \"percentage\": false,\n", + " \"pluginVersion\": \"7.0.3\",\n", + " \"pointradius\": 2,\n", + " \"points\": true,\n", + " \"renderer\": \"flot\",\n", + " \"seriesOverrides\": [],\n", + " \"spaceLength\": 10,\n", + " \"stack\": false,\n", + " \"steppedLine\": false,\n", + " \"targets\": [\n", + " {\n", + " \"expr\": '(sum(true_pos{method=\"feedback\"}) by (seldon_app)) / (sum(true_pos{method=\"feedback\"} + false_pos{method=\"feedback\"}) by (seldon_app))',\n", + " \"interval\": \"\",\n", + " \"legendFormat\": \"{{seldon_app}}\",\n", + " \"refId\": \"A\",\n", + " }\n", + " ],\n", + " \"thresholds\": [],\n", + " \"timeFrom\": null,\n", + " \"timeRegions\": [],\n", + " \"timeShift\": null,\n", + " \"title\": \"Real Time Model Precision\",\n", + " \"tooltip\": {\"shared\": true, \"sort\": 0, \"value_type\": \"individual\"},\n", + " \"type\": \"graph\",\n", + " \"xaxis\": {\n", + " \"buckets\": null,\n", + " \"mode\": \"time\",\n", + " \"name\": null,\n", + " \"show\": true,\n", + " \"values\": [],\n", + " },\n", + " \"yaxes\": [\n", + " {\n", + " \"decimals\": null,\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": \"1\",\n", + " \"min\": \"0\",\n", + " \"show\": true,\n", + " },\n", + " {\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": null,\n", + " \"min\": null,\n", + " \"show\": true,\n", + " },\n", + " ],\n", + " \"yaxis\": {\"align\": false, \"alignLevel\": null},\n", + " },\n", + " {\n", + " \"aliasColors\": {},\n", + " \"bars\": false,\n", + " \"dashLength\": 10,\n", + " \"dashes\": false,\n", + " \"datasource\": \"prometheus\",\n", + " \"description\": \"\",\n", + " \"fieldConfig\": {\n", + " \"defaults\": {\n", + " \"custom\": {},\n", + " \"mappings\": [],\n", + " \"thresholds\": {\n", + " \"mode\": \"absolute\",\n", + " \"steps\": [\n", + " {\"color\": \"green\", \"value\": null},\n", + " {\"color\": \"red\", \"value\": 80},\n", + " ],\n", + " },\n", + " },\n", + " \"overrides\": [],\n", + " },\n", + " \"fill\": 1,\n", + " \"fillGradient\": 0,\n", + " \"gridPos\": {\"h\": 8, \"w\": 12, \"x\": 0, \"y\": 8},\n", + " \"hiddenSeries\": false,\n", + " \"id\": 5,\n", + " \"legend\": {\n", + " \"avg\": false,\n", + " \"current\": false,\n", + " \"max\": false,\n", + " \"min\": false,\n", + " \"show\": true,\n", + " \"total\": false,\n", + " \"values\": false,\n", + " },\n", + " \"lines\": true,\n", + " \"linewidth\": 1,\n", + " \"nullPointMode\": \"null\",\n", + " \"options\": {\"dataLinks\": []},\n", + " \"percentage\": false,\n", + " \"pluginVersion\": \"7.0.3\",\n", + " \"pointradius\": 2,\n", + " \"points\": true,\n", + " \"renderer\": \"flot\",\n", + " \"seriesOverrides\": [],\n", + " \"spaceLength\": 10,\n", + " \"stack\": false,\n", + " \"steppedLine\": false,\n", + " \"targets\": [\n", + " {\n", + " \"expr\": '(sum(true_pos{method=\"feedback\"}) by (seldon_app)) / (sum(true_pos{method=\"feedback\"} + false_neg{method=\"feedback\"}) by (seldon_app))',\n", + " \"interval\": \"\",\n", + " \"legendFormat\": \"{{seldon_app}}\",\n", + " \"refId\": \"A\",\n", + " }\n", + " ],\n", + " \"thresholds\": [],\n", + " \"timeFrom\": null,\n", + " \"timeRegions\": [],\n", + " \"timeShift\": null,\n", + " \"title\": \"Real Time Model Recall\",\n", + " \"tooltip\": {\"shared\": true, \"sort\": 0, \"value_type\": \"individual\"},\n", + " \"type\": \"graph\",\n", + " \"xaxis\": {\n", + " \"buckets\": null,\n", + " \"mode\": \"time\",\n", + " \"name\": null,\n", + " \"show\": true,\n", + " \"values\": [],\n", + " },\n", + " \"yaxes\": [\n", + " {\n", + " \"decimals\": null,\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": \"1\",\n", + " \"min\": \"0\",\n", + " \"show\": true,\n", + " },\n", + " {\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": null,\n", + " \"min\": null,\n", + " \"show\": true,\n", + " },\n", + " ],\n", + " \"yaxis\": {\"align\": false, \"alignLevel\": null},\n", + " },\n", + " {\n", + " \"aliasColors\": {},\n", + " \"bars\": false,\n", + " \"dashLength\": 10,\n", + " \"dashes\": false,\n", + " \"datasource\": \"prometheus\",\n", + " \"description\": \"\",\n", + " \"fieldConfig\": {\n", + " \"defaults\": {\n", + " \"custom\": {},\n", + " \"mappings\": [],\n", + " \"thresholds\": {\n", + " \"mode\": \"absolute\",\n", + " \"steps\": [\n", + " {\"color\": \"green\", \"value\": null},\n", + " {\"color\": \"red\", \"value\": 80},\n", + " ],\n", + " },\n", + " },\n", + " \"overrides\": [],\n", + " },\n", + " \"fill\": 1,\n", + " \"fillGradient\": 0,\n", + " \"gridPos\": {\"h\": 8, \"w\": 12, \"x\": 12, \"y\": 8},\n", + " \"hiddenSeries\": false,\n", + " \"id\": 4,\n", + " \"legend\": {\n", + " \"avg\": false,\n", + " \"current\": false,\n", + " \"max\": false,\n", + " \"min\": false,\n", + " \"show\": true,\n", + " \"total\": false,\n", + " \"values\": false,\n", + " },\n", + " \"lines\": true,\n", + " \"linewidth\": 1,\n", + " \"nullPointMode\": \"null\",\n", + " \"options\": {\"dataLinks\": []},\n", + " \"percentage\": false,\n", + " \"pluginVersion\": \"7.0.3\",\n", + " \"pointradius\": 2,\n", + " \"points\": true,\n", + " \"renderer\": \"flot\",\n", + " \"seriesOverrides\": [],\n", + " \"spaceLength\": 10,\n", + " \"stack\": false,\n", + " \"steppedLine\": false,\n", + " \"targets\": [\n", + " {\n", + " \"expr\": '(sum(true_neg{method=\"feedback\"}) by (seldon_app)) / (sum(true_neg{method=\"feedback\"} + false_pos{method=\"feedback\"}) by (seldon_app))',\n", + " \"interval\": \"\",\n", + " \"legendFormat\": \"{{seldon_app}}\",\n", + " \"refId\": \"A\",\n", + " }\n", + " ],\n", + " \"thresholds\": [],\n", + " \"timeFrom\": null,\n", + " \"timeRegions\": [],\n", + " \"timeShift\": null,\n", + " \"title\": \"Real Time Model Specificity\",\n", + " \"tooltip\": {\"shared\": true, \"sort\": 0, \"value_type\": \"individual\"},\n", + " \"type\": \"graph\",\n", + " \"xaxis\": {\n", + " \"buckets\": null,\n", + " \"mode\": \"time\",\n", + " \"name\": null,\n", + " \"show\": true,\n", + " \"values\": [],\n", + " },\n", + " \"yaxes\": [\n", + " {\n", + " \"decimals\": null,\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": \"1\",\n", + " \"min\": \"0\",\n", + " \"show\": true,\n", + " },\n", + " {\n", + " \"format\": \"short\",\n", + " \"label\": null,\n", + " \"logBase\": 1,\n", + " \"max\": null,\n", + " \"min\": null,\n", + " \"show\": true,\n", + " },\n", + " ],\n", + " \"yaxis\": {\"align\": false, \"alignLevel\": null},\n", + " },\n", + " ],\n", + " \"refresh\": \"5s\",\n", + " \"schemaVersion\": 25,\n", + " \"style\": \"dark\",\n", + " \"tags\": [],\n", + " \"templating\": {\"list\": []},\n", + " \"time\": {\"from\": \"now-5m\", \"to\": \"now\"},\n", + " \"timepicker\": {\n", + " \"refresh_intervals\": [\"10s\", \"30s\", \"1m\", \"5m\", \"15m\", \"30m\", \"1h\", \"2h\", \"1d\"],\n", + " \"time_options\": [\"5m\", \"15m\", \"1h\", \"6h\", \"12h\", \"24h\", \"2d\", \"7d\", \"30d\"],\n", + " },\n", + " \"timezone\": \"browser\",\n", + " \"title\": \"statistical-metrics\",\n", + " \"uid\": \"zmkrlZ7Gk\",\n", + " \"version\": 4,\n", + "}" ] }, { @@ -594,7 +1007,12 @@ "source": [ "from seldon_core.seldon_client import SeldonClient\n", "\n", - "sc = SeldonClient(namespace=\"seldon\", gateway_endpoint=\"localhost:80\", deployment_name=\"ab-test\", payload_type=\"ndarray\")\n", + "sc = SeldonClient(\n", + " namespace=\"seldon\",\n", + " gateway_endpoint=\"localhost:80\",\n", + " deployment_name=\"ab-test\",\n", + " payload_type=\"ndarray\",\n", + ")\n", "\n", "y_res = sc.predict(data=X[[101]])\n", "\n", @@ -618,13 +1036,17 @@ "metadata": {}, "outputs": [], "source": [ - "import requests\n", "import time\n", "\n", + "import requests\n", + "\n", "url = \"http://localhost:80/seldon/seldon/ab-test/api/v1.0/feedback\"\n", "\n", "for x_i, y_i in zip(X_test, y_test):\n", - " data = {\"request\": {\"data\": {\"ndarray\": [x_i.tolist()]}}, \"truth\":{\"data\": {\"ndarray\": [y_i.tolist()]}}}\n", + " data = {\n", + " \"request\": {\"data\": {\"ndarray\": [x_i.tolist()]}},\n", + " \"truth\": {\"data\": {\"ndarray\": [y_i.tolist()]}},\n", + " }\n", " requests.post(f\"{url}\", json=data)\n", " time.sleep(0.3)" ] diff --git a/examples/infrastructure/upgrade_1_2_volume_patch/README.ipynb b/examples/infrastructure/upgrade_1_2_volume_patch/README.ipynb index 802fc6272a..bbee0b6b84 100644 --- a/examples/infrastructure/upgrade_1_2_volume_patch/README.ipynb +++ b/examples/infrastructure/upgrade_1_2_volume_patch/README.ipynb @@ -335,7 +335,7 @@ } ], "source": [ - "!kubectl get pods -n default && kubectl get pods -n seldon-system " + "!kubectl get pods -n default && kubectl get pods -n seldon-system" ] }, { @@ -772,7 +772,7 @@ } ], "source": [ - "!kubectl get pods -n default && kubectl get pods -n seldon-system " + "!kubectl get pods -n default && kubectl get pods -n seldon-system" ] }, { diff --git a/examples/istio/canary/istio_canary.ipynb b/examples/istio/canary/istio_canary.ipynb index 8b4af94ba6..fbc922e393 100644 --- a/examples/istio/canary/istio_canary.ipynb +++ b/examples/istio/canary/istio_canary.ipynb @@ -58,9 +58,10 @@ "source": [ "from IPython.core.magic import register_line_cell_magic\n", "\n", + "\n", "@register_line_cell_magic\n", "def writetemplate(line, cell):\n", - " with open(line, 'w') as f:\n", + " with open(line, \"w\") as f:\n", " f.write(cell.format(**globals()))" ] }, @@ -188,7 +189,10 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"example\",namespace=\"seldon\",gateway_endpoint=ISTIO_GATEWAY)" + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"example\", namespace=\"seldon\", gateway_endpoint=ISTIO_GATEWAY\n", + ")" ] }, { @@ -225,8 +229,8 @@ } ], "source": [ - "r = sc.predict(gateway=\"istio\",transport=\"rest\")\n", - "assert(r.success==True)\n", + "r = sc.predict(gateway=\"istio\", transport=\"rest\")\n", + "assert r.success == True\n", "print(r)" ] }, @@ -349,7 +353,7 @@ } ], "source": [ - "sc.predict(gateway=\"istio\",transport=\"rest\")" + "sc.predict(gateway=\"istio\", transport=\"rest\")" ] }, { @@ -359,10 +363,11 @@ "outputs": [], "source": [ "from collections import defaultdict\n", + "\n", "counts = defaultdict(int)\n", "n = 100\n", "for i in range(n):\n", - " r = sc.predict(gateway=\"istio\",transport=\"rest\")" + " r = sc.predict(gateway=\"istio\", transport=\"rest\")" ] }, { @@ -404,9 +409,9 @@ } ], "source": [ - "canary_percentage=float(canary_count[0])/float(default_count[0])\n", + "canary_percentage = float(canary_count[0]) / float(default_count[0])\n", "print(canary_percentage)\n", - "assert(canary_percentage > 0.1 and canary_percentage < 0.5)" + "assert canary_percentage > 0.1 and canary_percentage < 0.5" ] }, { @@ -482,4 +487,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/examples/kafka/cifar10/cifar10_kafka.ipynb b/examples/kafka/cifar10/cifar10_kafka.ipynb index 8158c79df3..3c6da34667 100644 --- a/examples/kafka/cifar10/cifar10_kafka.ipynb +++ b/examples/kafka/cifar10/cifar10_kafka.ipynb @@ -72,8 +72,8 @@ "metadata": {}, "outputs": [], "source": [ - "clusterType=\"kind\"\n", - "#clusterType=\"cloud\"" + "clusterType = \"kind\"\n", + "# clusterType=\"cloud\"" ] }, { diff --git a/examples/kubeflow/kubeflow_seldon_e2e_pipeline.ipynb b/examples/kubeflow/kubeflow_seldon_e2e_pipeline.ipynb index f498408811..97fbaa23f4 100644 --- a/examples/kubeflow/kubeflow_seldon_e2e_pipeline.ipynb +++ b/examples/kubeflow/kubeflow_seldon_e2e_pipeline.ipynb @@ -1,1432 +1,1491 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# End-to-end Reusable ML Pipeline with Seldon and Kubeflow\n", - "\n", - "In this example we showcase how to build re-usable components to build an ML pipeline that can be trained and deployed at scale.\n", - "\n", - "We will automate content moderation on the Reddit comments in /r/science building a machine learning NLP model with the following components:\n", - "\n", - "![completed-pipeline-deploy](img/completed-pipeline-deploy.jpg)\n", - "\n", - "This tutorial will break down in the following sections:\n", - "\n", - "1) Test and build all our reusable pipeline steps\n", - "\n", - "2) Use Kubeflow to Train the Pipeline and Deploy to Seldon\n", - "\n", - "3) Test Seldon Deployed ML REST Endpoints\n", - "\n", - "4) Visualise Seldon's Production ML Pipelines\n", - "\n", - "## Before you start\n", - "\n", - "Make sure you have the following components set-up and running in your Kubernetes cluster:\n", - "\n", - "* [Seldon Core installed](https://docs.seldon.io/projects/seldon-core/en/latest/workflow/install.html#install-seldon-core-with-helm) with an [ingress (Ambassador / Istio) set up](https://docs.seldon.io/projects/seldon-core/en/latest/workflow/install.html#ingress-support)\n", - "* Kubeflow Pipelines [version 1.0.0 Standalone](https://www.kubeflow.org/docs/pipelines/installation/standalone-deployment/#deploying-kubeflow-pipelines) set up\n", - "\n", - "Let's get started! 🚀🔥 We will be building the end-to-end pipeline below:\n", - "\n", - "![kubeflow-seldon-nlp-full](img/kubeflow-seldon-nlp-full.jpg)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": ["Overwriting requirements-dev.txt\n"] - } - ], - "source": [ - "%%writefile requirements-dev.txt\n", - "python-dateutil==2.8.1\n", - "kfp==1.0.0\n", - "kubernetes==11.0.0\n", - "click==7.1.2\n", - "seldon_core==1.2.3\n", - "numpy==1.19.1\n", - "pandas==1.1.1\n", - "spacy==2.3.2\n", - "scikit-learn==0.23.2\n", - "en-core-web-sm==2.3.1" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": ["!pip install -r requirements-dev.txt"] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1) Test and build all our reusable pipeline steps\n", - "\n", - "We will start by building each of the components in our ML pipeline. \n", - "\n", - "![kubeflow-seldon-nlp-reusable-components](img/kubeflow-seldon-nlp-reusable-components.jpg)\n", - "\n", - "### Let's first have a look at our clean_text step:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "clean_text\t lr_text_classifier tfidf_vectorizer\n", - "data_downloader spacy_tokenize\n" - ] - } - ], - "source": ["!ls pipeline/pipeline_steps"] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Like in this step, all of the other steps can be found in the `pipeline/pipeline_steps/` folder, and all have the following structure:\n", - "* `pipeline_step.py` which exposes the functionality through a CLI \n", - "* `Transformer.py` which transforms the data accordingly\n", - "* `requirements.txt` which states the python dependencies to run\n", - "* `build_image.sh` which uses `s2i` to build the image with one line\n", - "\n", - "### Let's check out the CLI for clean_text\n", - "The pipeline_step CLI is the entry point for the kubeflow image as it will be able to pass any relevant parameters\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Usage: pipeline_step.py [OPTIONS]\n", - "\n", - "Options:\n", - " --in-path TEXT\n", - " --out-path TEXT\n", - " --help Show this message and exit.\n" - ] - } - ], - "source": [ - "!python pipeline/pipeline_steps/clean_text/pipeline_step.py --help" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This is actually a very simple file, as we are using the click library to define the commands:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "import dill\n", - "import click\n", - "import dill\n", - "try:\n", - " # Running for tests\n", - " from .Transformer import Transformer\n", - "except:\n", - " # Running from CLI\n", - " from Transformer import Transformer\n", - "\n", - "@click.command()\n", - "@click.option('--in-path', default=\"/mnt/raw_text.data\")\n", - "@click.option('--out-path', default=\"/mnt/clean_text.data\")\n", - "def run_pipeline(in_path, out_path):\n", - " clean_text_transformer = Transformer()\n", - " with open(in_path, 'rb') as in_f:\n", - " x = dill.load(in_f)\n", - " y = clean_text_transformer.predict(x)\n", - " with open(out_path, \"wb\") as out_f:\n", - " dill.dump(y, out_f)\n", - "\n", - "if __name__ == \"__main__\":\n", - " run_pipeline()\n", - "\n" - ] - } - ], - "source": ["!cat pipeline/pipeline_steps/clean_text/pipeline_step.py"] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The Transformer is where the data munging and transformation stage comes in, which will be wrapped by the container and exposed through the Seldon Engine to ensure our pipeline can be used in production.\n", - "\n", - "Seldon provides multiple different features, such as abilities to send custom metrics, pre-process / post-process data and more. In this example we will only be exposing the `predict` step." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "import re \n", - "from html.parser import HTMLParser\n", - "import numpy as np\n", - "import logging\n", - "\n", - "class Transformer():\n", - " __html_parser = HTMLParser()\n", - " __uplus_pattern = \\\n", - " re.compile(\"\\<[uU]\\+(?P[a-zA-Z0-9]+)\\>\")\n", - " __markup_link_pattern = \\\n", - " re.compile(\"\\[(.*)\\]\\((.*)\\)\")\n", - "\n", - " def predict(self, X, feature_names=[]):\n", - " logging.warning(X)\n", - " f = np.vectorize(Transformer.transform_clean_text)\n", - " X_clean = f(X)\n", - " logging.warning(X_clean)\n", - " return X_clean\n", - "\n", - " def fit(self, X, y=None, **fit_params):\n", - " return self\n", - " \n", - " @staticmethod\n", - " def transform_clean_text(raw_text):\n", - " try:\n", - " decoded = raw_text.encode(\"ISO-8859-1\").decode(\"utf-8\")\n", - " except:\n", - " decoded = raw_text.encode(\"ISO-8859-1\").decode(\"cp1252\")\n", - " html_unescaped =Transformer.\\\n", - " __html_parser.unescape(decoded) \n", - " html_unescaped = re.sub(r\"\\r\\n\", \" \", html_unescaped)\n", - " html_unescaped = re.sub(r\"\\r\\r\\n\", \" \", html_unescaped)\n", - " html_unescaped = re.sub(r\"\\r\", \" \", html_unescaped)\n", - " html_unescaped = html_unescaped.replace(\">\", \" > \")\n", - " html_unescaped = html_unescaped.replace(\"<\", \" < \")\n", - " html_unescaped = html_unescaped.replace(\"--\", \" - \")\n", - " html_unescaped = Transformer.__uplus_pattern.sub(\n", - " \" U\\g \", html_unescaped)\n", - " html_unescaped = Transformer.__markup_link_pattern.sub(\n", - " \" \\1 \\2 \", html_unescaped)\n", - " html_unescaped = html_unescaped.replace(\"\\\\\", \"\")\n", - " return html_unescaped\n", - "\n" - ] - } - ], - "source": ["!cat pipeline/pipeline_steps/clean_text/Transformer.py"] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you want to understand how the CLI pipeline talks to each other, have a look at the end to end test in `pipeline/pipeline_tests/`:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[1mTest session starts (platform: linux, Python 3.7.4, pytest 6.0.1, pytest-sugar 0.9.4)\u001b[0m\n", - "rootdir: /home/alejandro/Programming/kubernetes/seldon/seldon-core/examples/kubeflow\n", - "plugins: celery-4.4.0, flaky-3.6.1, cov-2.10.0, django-3.8.0, forked-1.1.3, sugar-0.9.4, xdist-1.30.0\n", - "\u001b[1mcollecting ... \u001b[0m\n", - " \u001b[36mpipeline/pipeline_tests/\u001b[0mtest_pipeline.py\u001b[0m \u001b[32m✓\u001b[0m \u001b[32m100% \u001b[0m\u001b[40m\u001b[32m█\u001b[0m\u001b[40m\u001b[32m█████████\u001b[0m\n", - "\n", - "Results (2.12s):\n", - "\u001b[32m 1 passed\u001b[0m\n" - ] - } - ], - "source": [ - "!pytest ./pipeline/pipeline_tests/. --disable-pytest-warnings" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To build the image we provide a build script in each of the steps that contains the instructions:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#!/bin/bash\n", - "\n", - "s2i build . seldonio/seldon-core-s2i-python3:1.9.0-dev clean_text_transformer:0.1\n", - "\n" - ] - } - ], - "source": ["!cat pipeline/pipeline_steps/clean_text/build_image.sh"] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The only thing you need to make sure is that Seldon knows how to wrap the right model and file.\n", - "\n", - "This can be achieved with the s2i/environment file. \n", - "\n", - "As you can see, here we just tell it we want it to use our `Transformer.py` file:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "MODEL_NAME=Transformer\n", - "API_TYPE=REST\n", - "SERVICE_TYPE=MODEL\n", - "PERSISTENCE=0\n" - ] - } - ], - "source": ["!cat pipeline/pipeline_steps/clean_text/.s2i/environment"] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Once this is defined, the only thing we need to do is to run the `build_image.sh` for all the reusable components.\n", - "\n", - "Here we show the manual way to do it:" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sending build context to Docker daemon 9.728kB\n", - "Step 1/4 : FROM python:3.7-slim\n", - " ---> d3fbf7fff365\n", - "Step 2/4 : COPY . /microservice\n", - " ---> Using cache\n", - " ---> 6e9d7e162536\n", - "Step 3/4 : WORKDIR /microservice\n", - " ---> Using cache\n", - " ---> b3d69a634dd1\n", - "Step 4/4 : RUN pip install -r requirements.txt\n", - " ---> Using cache\n", - " ---> f1c421a68fe7\n", - "Successfully built f1c421a68fe7\n", - "Successfully tagged data_downloader:0.1\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "---> Installing application source...\n", - "---> Installing dependencies ...\n", - "Looking in links: /whl\n", - "Collecting dill==0.3.2 (from -r requirements.txt (line 1))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/e2/96/518a8ea959a734b70d2e95fef98bcbfdc7adad1c1e5f5dd9148c835205a5/dill-0.3.2.zip (177kB)\n", - "Requirement already satisfied: click==7.1.2 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (7.1.2)\n", - "Requirement already satisfied: numpy==1.19.1 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 3)) (1.19.1)\n", - "Building wheels for collected packages: dill\n", - "Building wheel for dill (setup.py): started\n", - "Building wheel for dill (setup.py): finished with status 'done'\n", - "Created wheel for dill: filename=dill-0.3.2-cp37-none-any.whl size=78913 sha256=9f9ec39fffe7a46bdc1a164bc0cd8d61201f04ff0c4bfc68e7dda78d6a4c29cf\n", - "Stored in directory: /root/.cache/pip/wheels/27/4b/a2/34ccdcc2f158742cfe9650675560dea85f78c3f4628f7daad0\n", - "Successfully built dill\n", - "Installing collected packages: dill\n", - "Successfully installed dill-0.3.2\n", - "WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Collecting pip-licenses\n", - "Downloading https://files.pythonhosted.org/packages/c5/50/6c4b4e69a0c43bd9f03a30579695093062ba72da4e3e4026cd2144dbcc71/pip_licenses-2.3.0-py3-none-any.whl\n", - "Collecting PTable (from pip-licenses)\n", - "Downloading https://files.pythonhosted.org/packages/ab/b3/b54301811173ca94119eb474634f120a49cd370f257d1aae5a4abaf12729/PTable-0.9.2.tar.gz\n", - "Building wheels for collected packages: PTable\n", - "Building wheel for PTable (setup.py): started\n", - "Building wheel for PTable (setup.py): finished with status 'done'\n", - "Created wheel for PTable: filename=PTable-0.9.2-cp37-none-any.whl size=22906 sha256=6c6c94080f12738603dbd55c01213f1c28f9922c915c92d72b547e85d229bfba\n", - "Stored in directory: /root/.cache/pip/wheels/22/cc/2e/55980bfe86393df3e9896146a01f6802978d09d7ebcba5ea56\n", - "Successfully built PTable\n", - "Installing collected packages: PTable, pip-licenses\n", - "Successfully installed PTable-0.9.2 pip-licenses-2.3.0\n", - "created path: ./licenses/license_info.csv\n", - "created path: ./licenses/license.txt\n", - "Build completed successfully\n", - "---> Installing application source...\n", - "---> Installing dependencies ...\n", - "Looking in links: /whl\n", - "Collecting dill==0.3.2 (from -r requirements.txt (line 1))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/e2/96/518a8ea959a734b70d2e95fef98bcbfdc7adad1c1e5f5dd9148c835205a5/dill-0.3.2.zip (177kB)\n", - "Requirement already satisfied: click==7.1.2 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (7.1.2)\n", - "Requirement already satisfied: numpy==1.19.1 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 3)) (1.19.1)\n", - "Collecting scikit-learn==0.23.2 (from -r requirements.txt (line 4))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/f4/cb/64623369f348e9bfb29ff898a57ac7c91ed4921f228e9726546614d63ccb/scikit_learn-0.23.2-cp37-cp37m-manylinux1_x86_64.whl (6.8MB)\n", - "Collecting scipy>=0.19.1 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/65/f9/f7a7e5009711579c72da2725174825e5056741bf4001815d097eef1b2e17/scipy-1.5.2-cp37-cp37m-manylinux1_x86_64.whl (25.9MB)\n", - "Collecting joblib>=0.11 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/51/dd/0e015051b4a27ec5a58b02ab774059f3289a94b0906f880a3f9507e74f38/joblib-0.16.0-py3-none-any.whl (300kB)\n", - "Collecting threadpoolctl>=2.0.0 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/f7/12/ec3f2e203afa394a149911729357aa48affc59c20e2c1c8297a60f33f133/threadpoolctl-2.1.0-py3-none-any.whl\n", - "Building wheels for collected packages: dill\n", - "Building wheel for dill (setup.py): started\n", - "Building wheel for dill (setup.py): finished with status 'done'\n", - "Created wheel for dill: filename=dill-0.3.2-cp37-none-any.whl size=78913 sha256=f4aa43d7acbc7953839cc8177c0e03bec249f9a7dffc10c7e9db79201ce519d3\n", - "Stored in directory: /root/.cache/pip/wheels/27/4b/a2/34ccdcc2f158742cfe9650675560dea85f78c3f4628f7daad0\n", - "Successfully built dill\n", - "Installing collected packages: dill, scipy, joblib, threadpoolctl, scikit-learn\n", - "Successfully installed dill-0.3.2 joblib-0.16.0 scikit-learn-0.23.2 scipy-1.5.2 threadpoolctl-2.1.0\n", - "WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Collecting pip-licenses\n", - "Downloading https://files.pythonhosted.org/packages/c5/50/6c4b4e69a0c43bd9f03a30579695093062ba72da4e3e4026cd2144dbcc71/pip_licenses-2.3.0-py3-none-any.whl\n", - "Collecting PTable (from pip-licenses)\n", - "Downloading https://files.pythonhosted.org/packages/ab/b3/b54301811173ca94119eb474634f120a49cd370f257d1aae5a4abaf12729/PTable-0.9.2.tar.gz\n", - "Building wheels for collected packages: PTable\n", - "Building wheel for PTable (setup.py): started\n", - "Building wheel for PTable (setup.py): finished with status 'done'\n", - "Created wheel for PTable: filename=PTable-0.9.2-cp37-none-any.whl size=22906 sha256=e296b386d6581fe3343b84d718f7e7624bdbabfff569c4220a1f2039dd0abbdf\n", - "Stored in directory: /root/.cache/pip/wheels/22/cc/2e/55980bfe86393df3e9896146a01f6802978d09d7ebcba5ea56\n", - "Successfully built PTable\n", - "Installing collected packages: PTable, pip-licenses\n", - "Successfully installed PTable-0.9.2 pip-licenses-2.3.0\n", - "created path: ./licenses/license_info.csv\n", - "created path: ./licenses/license.txt\n", - "Build completed successfully\n", - "---> Installing application source...\n", - "---> Installing dependencies ...\n", - "Looking in links: /whl\n", - "Collecting dill==0.3.2 (from -r requirements.txt (line 1))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/e2/96/518a8ea959a734b70d2e95fef98bcbfdc7adad1c1e5f5dd9148c835205a5/dill-0.3.2.zip (177kB)\n", - "Requirement already satisfied: click==7.1.2 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (7.1.2)\n", - "Requirement already satisfied: numpy==1.19.1 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 3)) (1.19.1)\n", - "Collecting spacy==2.3.2 (from -r requirements.txt (line 4))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/55/24/70c615f5b22440c679a4132b81eee67d1dfd70d159505a28ff949c78a1ac/spacy-2.3.2-cp37-cp37m-manylinux1_x86_64.whl (9.9MB)\n", - "Collecting en-core-web-sm==2.3.1 (from -r requirements.txt (line 5))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - " ERROR: Could not find a version that satisfies the requirement en-core-web-sm==2.3.1 (from -r requirements.txt (line 5)) (from versions: none)\n", - "ERROR: No matching distribution found for en-core-web-sm==2.3.1 (from -r requirements.txt (line 5))\n", - "WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Build failed\n", - "ERROR: An error occurred: non-zero (13) exit code from seldonio/seldon-core-s2i-python37:1.9.0-dev\n", - "---> Installing application source...\n", - "---> Installing dependencies ...\n", - "Looking in links: /whl\n", - "Collecting dill==0.3.2 (from -r requirements.txt (line 1))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/e2/96/518a8ea959a734b70d2e95fef98bcbfdc7adad1c1e5f5dd9148c835205a5/dill-0.3.2.zip (177kB)\n", - "Requirement already satisfied: click==7.1.2 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (7.1.2)\n", - "Requirement already satisfied: numpy==1.19.1 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 3)) (1.19.1)\n", - "Collecting scikit-learn==0.23.2 (from -r requirements.txt (line 4))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/f4/cb/64623369f348e9bfb29ff898a57ac7c91ed4921f228e9726546614d63ccb/scikit_learn-0.23.2-cp37-cp37m-manylinux1_x86_64.whl (6.8MB)\n", - "Collecting joblib>=0.11 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/51/dd/0e015051b4a27ec5a58b02ab774059f3289a94b0906f880a3f9507e74f38/joblib-0.16.0-py3-none-any.whl (300kB)\n", - "Collecting scipy>=0.19.1 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/65/f9/f7a7e5009711579c72da2725174825e5056741bf4001815d097eef1b2e17/scipy-1.5.2-cp37-cp37m-manylinux1_x86_64.whl (25.9MB)\n", - "Collecting threadpoolctl>=2.0.0 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", - " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Downloading https://files.pythonhosted.org/packages/f7/12/ec3f2e203afa394a149911729357aa48affc59c20e2c1c8297a60f33f133/threadpoolctl-2.1.0-py3-none-any.whl\n", - "Building wheels for collected packages: dill\n", - "Building wheel for dill (setup.py): started\n", - "Building wheel for dill (setup.py): finished with status 'done'\n", - "Created wheel for dill: filename=dill-0.3.2-cp37-none-any.whl size=78913 sha256=2bdafea9bf8ead275cf6123cd330c7362915943a397e00ca7b203b9b8759f2a7\n", - "Stored in directory: /root/.cache/pip/wheels/27/4b/a2/34ccdcc2f158742cfe9650675560dea85f78c3f4628f7daad0\n", - "Successfully built dill\n", - "Installing collected packages: dill, joblib, scipy, threadpoolctl, scikit-learn\n", - "Successfully installed dill-0.3.2 joblib-0.16.0 scikit-learn-0.23.2 scipy-1.5.2 threadpoolctl-2.1.0\n", - "WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", - "Collecting pip-licenses\n", - "Downloading https://files.pythonhosted.org/packages/c5/50/6c4b4e69a0c43bd9f03a30579695093062ba72da4e3e4026cd2144dbcc71/pip_licenses-2.3.0-py3-none-any.whl\n", - "Collecting PTable (from pip-licenses)\n", - "Downloading https://files.pythonhosted.org/packages/ab/b3/b54301811173ca94119eb474634f120a49cd370f257d1aae5a4abaf12729/PTable-0.9.2.tar.gz\n", - "Building wheels for collected packages: PTable\n", - "Building wheel for PTable (setup.py): started\n", - "Building wheel for PTable (setup.py): finished with status 'done'\n", - "Created wheel for PTable: filename=PTable-0.9.2-cp37-none-any.whl size=22906 sha256=46a9ca3a63fe171ad06a2e9bbd7f00fba00ca0bb4bbda6177f3571077d79228e\n", - "Stored in directory: /root/.cache/pip/wheels/22/cc/2e/55980bfe86393df3e9896146a01f6802978d09d7ebcba5ea56\n", - "Successfully built PTable\n", - "Installing collected packages: PTable, pip-licenses\n", - "Successfully installed PTable-0.9.2 pip-licenses-2.3.0\n", - "created path: ./licenses/license_info.csv\n", - "created path: ./licenses/license.txt\n", - "Build completed successfully\n" - ] - } - ], - "source": [ - "%%bash\n", - "# we must be in the same directory\n", - "cd pipeline/pipeline_steps/clean_text/ && ./build_image.sh\n", - "cd ../data_downloader && ./build_image.sh\n", - "cd ../lr_text_classifier && ./build_image.sh\n", - "cd ../spacy_tokenize && ./build_image.sh\n", - "cd ../tfidf_vectorizer && ./build_image.sh" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3) Train our NLP Pipeline through the Kubeflow UI\n", - "We can access the Kubeflow dashboard to train our ML pipeline via http://localhost/_/pipeline-dashboard\n", - "\n", - "If you can't edit this, you need to make sure that the ambassador gateway service is accessible:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n", - "ambassador NodePort 10.97.236.196 80:30209/TCP 8m58s\n" - ] - } - ], - "source": ["!kubectl get svc ambassador -n kubeflow"] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In my case, I need to change the kind from `NodePort` into `LoadBalancer` which can be done with the following command:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": ["service/ambassador patched\n"] - } - ], - "source": [ - "!kubectl patch svc ambassador --type='json' -p '[{\"op\":\"replace\",\"path\":\"/spec/type\",\"value\":\"LoadBalancer\"}]' -n kubeflow" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that I've changed it to a loadbalancer, it has allocated the external IP as my localhost so I can access it at http://localhost/_/pipeline-dashboard\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n", - "ambassador LoadBalancer 10.97.236.196 localhost 80:30209/TCP 9m20s\n" - ] - } - ], - "source": ["!kubectl get svc ambassador -n kubeflow"] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If this was successfull, you should be able to access the dashboard\n", - "![kf-pipeline-dashboard](img/k-pipeline-dashboard.jpg)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define the pipeline\n", - "Now we want to generate the pipeline. For this we can use the DSL provided by kubeflow to define the actual steps required. \n", - "\n", - "The pipeline will look as follows:\n", - "\n", - "![kf-seldon-nlp-ml-pipelines](img/kubeflow-seldon-nlp-ml-pipelines.jpg)" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "import kfp.dsl as dsl\n", - "import yaml\n", - "from kubernetes import client as k8s\n", - "\n", - "\n", - "@dsl.pipeline(\n", - " name='NLP',\n", - " description='A pipeline demonstrating reproducible steps for NLP'\n", - ")\n", - "def nlp_pipeline(\n", - " csv_url=\"https://raw.githubusercontent.com/axsauze/reddit-classification-exploration/master/data/reddit_train.csv\",\n", - " csv_encoding=\"ISO-8859-1\",\n", - " features_column=\"BODY\",\n", - " labels_column=\"REMOVED\",\n", - " raw_text_path='/mnt/text.data',\n", - " labels_path='/mnt/labels.data',\n", - " clean_text_path='/mnt/clean.data',\n", - " spacy_tokens_path='/mnt/tokens.data',\n", - " tfidf_vectors_path='/mnt/tfidf.data',\n", - " lr_prediction_path='/mnt/prediction.data',\n", - " tfidf_model_path='/mnt/tfidf.model',\n", - " lr_model_path='/mnt/lr.model',\n", - " lr_c_param=0.1,\n", - " tfidf_max_features=10000,\n", - " tfidf_ngram_range=3,\n", - " batch_size='100'):\n", - " \"\"\"\n", - " Pipeline \n", - " \"\"\"\n", - " vop = dsl.VolumeOp(\n", - " name='my-pvc',\n", - " resource_name=\"my-pvc\",\n", - " modes=[\"ReadWriteMany\"],\n", - " size=\"1Gi\"\n", - " )\n", - "\n", - " download_step = dsl.ContainerOp(\n", - " name='data_downloader',\n", - " image='data_downloader:0.1',\n", - " command=\"python\",\n", - " arguments=[\n", - " \"/microservice/pipeline_step.py\",\n", - " \"--labels-path\", labels_path,\n", - " \"--features-path\", raw_text_path,\n", - " \"--csv-url\", csv_url,\n", - " \"--csv-encoding\", csv_encoding,\n", - " \"--features-column\", features_column,\n", - " \"--labels-column\", labels_column\n", - " ],\n", - " pvolumes={\"/mnt\": vop.volume}\n", - " )\n", - "\n", - " clean_step = dsl.ContainerOp(\n", - " name='clean_text',\n", - " image='clean_text_transformer:0.1',\n", - " command=\"python\",\n", - " arguments=[\n", - " \"/microservice/pipeline_step.py\",\n", - " \"--in-path\", raw_text_path,\n", - " \"--out-path\", clean_text_path,\n", - " ],\n", - " pvolumes={\"/mnt\": download_step.pvolume}\n", - " )\n", - "\n", - " tokenize_step = dsl.ContainerOp(\n", - " name='tokenize',\n", - " image='spacy_tokenizer:0.1',\n", - " command=\"python\",\n", - " arguments=[\n", - " \"/microservice/pipeline_step.py\",\n", - " \"--in-path\", clean_text_path,\n", - " \"--out-path\", spacy_tokens_path,\n", - " ],\n", - " pvolumes={\"/mnt\": clean_step.pvolume}\n", - " )\n", - "\n", - " vectorize_step = dsl.ContainerOp(\n", - " name='vectorize',\n", - " image='tfidf_vectorizer:0.1',\n", - " command=\"python\",\n", - " arguments=[\n", - " \"/microservice/pipeline_step.py\",\n", - " \"--in-path\", spacy_tokens_path,\n", - " \"--out-path\", tfidf_vectors_path,\n", - " \"--max-features\", tfidf_max_features,\n", - " \"--ngram-range\", tfidf_ngram_range,\n", - " \"--action\", \"train\",\n", - " \"--model-path\", tfidf_model_path,\n", - " ],\n", - " pvolumes={\"/mnt\": tokenize_step.pvolume}\n", - " )\n", - "\n", - " predict_step = dsl.ContainerOp(\n", - " name='predictor',\n", - " image='lr_text_classifier:0.1',\n", - " command=\"python\",\n", - " arguments=[\n", - " \"/microservice/pipeline_step.py\",\n", - " \"--in-path\", tfidf_vectors_path,\n", - " \"--labels-path\", labels_path,\n", - " \"--out-path\", lr_prediction_path,\n", - " \"--c-param\", lr_c_param,\n", - " \"--action\", \"train\",\n", - " \"--model-path\", lr_model_path,\n", - " ],\n", - " pvolumes={\"/mnt\": vectorize_step.pvolume}\n", - " )\n", - "\n", - " try:\n", - " seldon_config = yaml.load(open(\"../deploy_pipeline/seldon_production_pipeline.yaml\"))\n", - " except:\n", - " # If this file is run from the project core directory \n", - " seldon_config = yaml.load(open(\"deploy_pipeline/seldon_production_pipeline.yaml\"))\n", - "\n", - " deploy_step = dsl.ResourceOp(\n", - " name=\"seldondeploy\",\n", - " k8s_resource=seldon_config,\n", - " attribute_outputs={\"name\": \"{.metadata.name}\"})\n", - "\n", - " deploy_step.after(predict_step)\n", - "\n", - "if __name__ == '__main__':\n", - " import kfp.compiler as compiler\n", - " compiler.Compiler().compile(nlp_pipeline, __file__ + '.tar.gz')\n" - ] - } - ], - "source": ["!cat train_pipeline/nlp_pipeline.py"] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Breaking down the code\n", - "As you can see in the DSL, we have the ContainerOp - each of those is a step in the Kubeflow pipeline.\n", - "\n", - "At the end we can see the `seldondeploy` step which basically deploys the trained pipeline\n", - "\n", - "The definition of the SeldonDeployment graph is provided in the `deploy_pipeline/seldon_production_pipeline.yaml` file.\n", - "\n", - "The seldondeployment file defines our production execution graph using the same reusable components." - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "---\n", - "apiVersion: machinelearning.seldon.io/v1alpha2\n", - "kind: SeldonDeployment\n", - "metadata:\n", - " labels:\n", - " app: seldon\n", - " name: \"seldon-deployment-{{workflow.name}}\"\n", - " namespace: kubeflow\n", - "spec:\n", - " annotations:\n", - " project_name: NLP Pipeline\n", - " deployment_version: v1\n", - " name: \"seldon-deployment-{{workflow.name}}\"\n", - " predictors:\n", - " - componentSpecs:\n", - " - spec:\n", - " containers:\n", - " - image: clean_text_transformer:0.1\n", - " imagePullPolicy: IfNotPresent\n", - " name: cleantext\n", - " resources:\n", - " requests:\n", - " memory: 1Mi\n", - " - image: spacy_tokenizer:0.1\n", - " imagePullPolicy: IfNotPresent\n", - " name: spacytokenizer\n", - " - image: tfidf_vectorizer:0.1\n", - " imagePullPolicy: IfNotPresent\n", - " name: tfidfvectorizer\n", - " volumeMounts:\n", - " - name: mypvc\n", - " mountPath: /mnt\n", - " - image: lr_text_classifier:0.1\n", - " imagePullPolicy: IfNotPresent\n", - " name: lrclassifier\n", - " volumeMounts:\n", - " - name: mypvc\n", - " mountPath: /mnt\n", - " terminationGracePeriodSeconds: 20\n", - " volumes:\n", - " - name: mypvc\n", - " persistentVolumeClaim:\n", - " claimName: \"{{workflow.name}}-my-pvc\"\n", - " graph:\n", - " children:\n", - " - name: spacytokenizer\n", - " endpoint:\n", - " type: REST\n", - " type: MODEL\n", - " children:\n", - " - name: tfidfvectorizer\n", - " endpoint:\n", - " type: REST\n", - " type: MODEL\n", - " children:\n", - " - name: lrclassifier\n", - " endpoint:\n", - " type: REST\n", - " type: MODEL\n", - " children: []\n", - " name: cleantext\n", - " endpoint:\n", - " type: REST\n", - " type: MODEL\n", - " name: single-model\n", - " replicas: 1\n", - " annotations:\n", - " predictor_version: v1\n", - "\n" - ] - } - ], - "source": ["!cat deploy_pipeline/seldon_production_pipeline.yaml"] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Seldon Production pipeline contents\n", - "If we look at the file we'll be using to deploy our pipeline, we can see that it has the following key points:\n", - "\n", - "1) Reusable components definitions as containerSpecs: cleantext, spacytokenizer, tfidfvectorizer & lrclassifier\n", - "\n", - "2) DAG (directed acyclic graph) definition for REST pipeline: cleantext -> spacytokenizer -> tfidfvectorizer -> lrclassifier\n", - "\n", - "This graph in our production deployment looks as follows:\n", - "\n", - "![kf-seldon-npl-pipelines-deploy](img/kubeflow-seldon-nlp-ml-pipelines-deploy.jpg)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Generate the pipeline files to upload to Kubeflow\n", - "To generate the pipeline we just have to run the pipeline file, which will output the `tar.gz` file that will be uploaded." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": ["nlp_pipeline.py\n", "nlp_pipeline.py.tar.gz\n"] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/alejandro/miniconda3/lib/python3.7/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Float\" based on the value \"0.1\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", - "/home/alejandro/miniconda3/lib/python3.7/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Integer\" based on the value \"10000\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", - "/home/alejandro/miniconda3/lib/python3.7/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Integer\" based on the value \"3\".\n", - " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", - "train_pipeline/nlp_pipeline.py:114: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.\n", - " seldon_config = yaml.load(open(\"deploy_pipeline/seldon_production_pipeline.yaml\"))\n" - ] - } - ], - "source": [ - "%%bash\n", - "# Generating graph definition\n", - "python train_pipeline/nlp_pipeline.py\n", - "ls train_pipeline/" - ] - }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# End-to-end Reusable ML Pipeline with Seldon and Kubeflow\n", + "\n", + "In this example we showcase how to build re-usable components to build an ML pipeline that can be trained and deployed at scale.\n", + "\n", + "We will automate content moderation on the Reddit comments in /r/science building a machine learning NLP model with the following components:\n", + "\n", + "![completed-pipeline-deploy](img/completed-pipeline-deploy.jpg)\n", + "\n", + "This tutorial will break down in the following sections:\n", + "\n", + "1) Test and build all our reusable pipeline steps\n", + "\n", + "2) Use Kubeflow to Train the Pipeline and Deploy to Seldon\n", + "\n", + "3) Test Seldon Deployed ML REST Endpoints\n", + "\n", + "4) Visualise Seldon's Production ML Pipelines\n", + "\n", + "## Before you start\n", + "\n", + "Make sure you have the following components set-up and running in your Kubernetes cluster:\n", + "\n", + "* [Seldon Core installed](https://docs.seldon.io/projects/seldon-core/en/latest/workflow/install.html#install-seldon-core-with-helm) with an [ingress (Ambassador / Istio) set up](https://docs.seldon.io/projects/seldon-core/en/latest/workflow/install.html#ingress-support)\n", + "* Kubeflow Pipelines [version 1.0.0 Standalone](https://www.kubeflow.org/docs/pipelines/installation/standalone-deployment/#deploying-kubeflow-pipelines) set up\n", + "\n", + "Let's get started! 🚀🔥 We will be building the end-to-end pipeline below:\n", + "\n", + "![kubeflow-seldon-nlp-full](img/kubeflow-seldon-nlp-full.jpg)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "### Run the pipeline\n", - "\n", - "You can access the Kubeflow Pipelines UI by forwarding the port with the following command:\n", - "\n", - "```\n", - " kubectl port-forward -n kubeflow svc/ml-pipeline-ui 8000:80\n", - "```\n", - "\n", - "The UI should now be accessible via [http://localhost:8000](http://localhost:8000).\n", - "\n", - "We now need to upload the resulting `nlp_pipeline.py.tar.gz` file generated.\n", - "\n", - "This can be done through the \"Upload PIpeline\" button in the UI.\n", - "\n", - "Once it's uploaded, we want to create and trigger a run! You should now be able to see how each step is executed:\n", - "\n", - "![running-pipeline](img/running-pipeline.jpg)\n", - "\n", - "### Inspecting the data created in the Persistent Volume\n", - "The pipeline saves the output of the pipeline together with the trained model in the persistent volume claim.\n", - "\n", - "The persistent volume claim is the same name as the argo workflow:\n" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Overwriting requirements-dev.txt\n" + ] + } + ], + "source": [ + "%%writefile requirements-dev.txt\n", + "python-dateutil==2.8.1\n", + "kfp==1.0.0\n", + "kubernetes==11.0.0\n", + "click==7.1.2\n", + "seldon_core==1.2.3\n", + "numpy==1.19.1\n", + "pandas==1.1.1\n", + "spacy==2.3.2\n", + "scikit-learn==0.23.2\n", + "en-core-web-sm==2.3.1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "!pip install -r requirements-dev.txt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1) Test and build all our reusable pipeline steps\n", + "\n", + "We will start by building each of the components in our ML pipeline. \n", + "\n", + "![kubeflow-seldon-nlp-reusable-components](img/kubeflow-seldon-nlp-reusable-components.jpg)\n", + "\n", + "### Let's first have a look at our clean_text step:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": ["NAME AGE\n", "nlp-bddff 2m\n"] - } - ], - "source": ["!kubectl get workflow -n kubeflow"] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "clean_text\t lr_text_classifier tfidf_vectorizer\n", + "data_downloader spacy_tokenize\n" + ] + } + ], + "source": [ + "!ls pipeline/pipeline_steps" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Like in this step, all of the other steps can be found in the `pipeline/pipeline_steps/` folder, and all have the following structure:\n", + "* `pipeline_step.py` which exposes the functionality through a CLI \n", + "* `Transformer.py` which transforms the data accordingly\n", + "* `requirements.txt` which states the python dependencies to run\n", + "* `build_image.sh` which uses `s2i` to build the image with one line\n", + "\n", + "### Let's check out the CLI for clean_text\n", + "The pipeline_step CLI is the entry point for the kubeflow image as it will be able to pass any relevant parameters\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our workflow is there! So we can actually access it by running" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Usage: pipeline_step.py [OPTIONS]\n", + "\n", + "Options:\n", + " --in-path TEXT\n", + " --out-path TEXT\n", + " --help Show this message and exit.\n" + ] + } + ], + "source": [ + "!python pipeline/pipeline_steps/clean_text/pipeline_step.py --help" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is actually a very simple file, as we are using the click library to define the commands:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": ["nlp-bddff"] - } - ], - "source": [ - "!kubectl get workflow -n kubeflow -o jsonpath='{.items[0].metadata.name}'" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "import dill\n", + "import click\n", + "import dill\n", + "try:\n", + " # Running for tests\n", + " from .Transformer import Transformer\n", + "except:\n", + " # Running from CLI\n", + " from Transformer import Transformer\n", + "\n", + "@click.command()\n", + "@click.option('--in-path', default=\"/mnt/raw_text.data\")\n", + "@click.option('--out-path', default=\"/mnt/clean_text.data\")\n", + "def run_pipeline(in_path, out_path):\n", + " clean_text_transformer = Transformer()\n", + " with open(in_path, 'rb') as in_f:\n", + " x = dill.load(in_f)\n", + " y = clean_text_transformer.predict(x)\n", + " with open(out_path, \"wb\") as out_f:\n", + " dill.dump(y, out_f)\n", + "\n", + "if __name__ == \"__main__\":\n", + " run_pipeline()\n", + "\n" + ] + } + ], + "source": [ + "!cat pipeline/pipeline_steps/clean_text/pipeline_step.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Transformer is where the data munging and transformation stage comes in, which will be wrapped by the container and exposed through the Seldon Engine to ensure our pipeline can be used in production.\n", + "\n", + "Seldon provides multiple different features, such as abilities to send custom metrics, pre-process / post-process data and more. In this example we will only be exposing the `predict` step." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "scrolled": true + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And we can use good old `sed` to insert this workflow name in our PVC-Access controler which we can use to inspect the contents of the volume:" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "import re \n", + "from html.parser import HTMLParser\n", + "import numpy as np\n", + "import logging\n", + "\n", + "class Transformer():\n", + " __html_parser = HTMLParser()\n", + " __uplus_pattern = \\\n", + " re.compile(\"\\<[uU]\\+(?P[a-zA-Z0-9]+)\\>\")\n", + " __markup_link_pattern = \\\n", + " re.compile(\"\\[(.*)\\]\\((.*)\\)\")\n", + "\n", + " def predict(self, X, feature_names=[]):\n", + " logging.warning(X)\n", + " f = np.vectorize(Transformer.transform_clean_text)\n", + " X_clean = f(X)\n", + " logging.warning(X_clean)\n", + " return X_clean\n", + "\n", + " def fit(self, X, y=None, **fit_params):\n", + " return self\n", + " \n", + " @staticmethod\n", + " def transform_clean_text(raw_text):\n", + " try:\n", + " decoded = raw_text.encode(\"ISO-8859-1\").decode(\"utf-8\")\n", + " except:\n", + " decoded = raw_text.encode(\"ISO-8859-1\").decode(\"cp1252\")\n", + " html_unescaped =Transformer.\\\n", + " __html_parser.unescape(decoded) \n", + " html_unescaped = re.sub(r\"\\r\\n\", \" \", html_unescaped)\n", + " html_unescaped = re.sub(r\"\\r\\r\\n\", \" \", html_unescaped)\n", + " html_unescaped = re.sub(r\"\\r\", \" \", html_unescaped)\n", + " html_unescaped = html_unescaped.replace(\">\", \" > \")\n", + " html_unescaped = html_unescaped.replace(\"<\", \" < \")\n", + " html_unescaped = html_unescaped.replace(\"--\", \" - \")\n", + " html_unescaped = Transformer.__uplus_pattern.sub(\n", + " \" U\\g \", html_unescaped)\n", + " html_unescaped = Transformer.__markup_link_pattern.sub(\n", + " \" \\1 \\2 \", html_unescaped)\n", + " html_unescaped = html_unescaped.replace(\"\\\\\", \"\")\n", + " return html_unescaped\n", + "\n" + ] + } + ], + "source": [ + "!cat pipeline/pipeline_steps/clean_text/Transformer.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you want to understand how the CLI pipeline talks to each other, have a look at the end to end test in `pipeline/pipeline_tests/`:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "apiVersion: v1\n", - "kind: Pod\n", - "metadata:\n", - " name: pvc-access-container\n", - "spec:\n", - " containers:\n", - " - name: pvc-access-container\n", - " image: busybox\n", - " command: [\"/bin/sh\", \"-ec\", \"sleep 1000\"]\n", - " volumeMounts:\n", - " - name: mypvc\n", - " mountPath: /mnt\n", - " volumes:\n", - " - name: mypvc\n", - " persistentVolumeClaim:\n", - " claimName: nlp-b7qt8-my-pvc\n" - ] - } - ], - "source": [ - "!sed \"s/PVC_NAME/\"$(kubectl get workflow -n kubeflow -o jsonpath='{.items[0].metadata.name}')\"-my-pvc/g\" deploy_pipeline/pvc-access.yaml " - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1mTest session starts (platform: linux, Python 3.7.4, pytest 6.0.1, pytest-sugar 0.9.4)\u001b[0m\n", + "rootdir: /home/alejandro/Programming/kubernetes/seldon/seldon-core/examples/kubeflow\n", + "plugins: celery-4.4.0, flaky-3.6.1, cov-2.10.0, django-3.8.0, forked-1.1.3, sugar-0.9.4, xdist-1.30.0\n", + "\u001b[1mcollecting ... \u001b[0m\n", + " \u001b[36mpipeline/pipeline_tests/\u001b[0mtest_pipeline.py\u001b[0m \u001b[32m✓\u001b[0m \u001b[32m100% \u001b[0m\u001b[40m\u001b[32m█\u001b[0m\u001b[40m\u001b[32m█████████\u001b[0m\n", + "\n", + "Results (2.12s):\n", + "\u001b[32m 1 passed\u001b[0m\n" + ] + } + ], + "source": [ + "!pytest ./pipeline/pipeline_tests/. --disable-pytest-warnings" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To build the image we provide a build script in each of the steps that contains the instructions:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We just need to apply this container with our kubectl command, and we can use it to inspect the mounted folder:" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "#!/bin/bash\n", + "\n", + "s2i build . seldonio/seldon-core-s2i-python3:1.9.0-dev clean_text_transformer:0.1\n", + "\n" + ] + } + ], + "source": [ + "!cat pipeline/pipeline_steps/clean_text/build_image.sh" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The only thing you need to make sure is that Seldon knows how to wrap the right model and file.\n", + "\n", + "This can be achieved with the s2i/environment file. \n", + "\n", + "As you can see, here we just tell it we want it to use our `Transformer.py` file:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": ["pod/pvc-access-container created\n"] - } - ], - "source": [ - "!sed \"s/PVC_NAME/\"$(kubectl get workflow -n kubeflow -o jsonpath='{.items[0].metadata.name}')\"-my-pvc/g\" deploy_pipeline/pvc-access.yaml | kubectl -n kubeflow apply -f -" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "MODEL_NAME=Transformer\n", + "API_TYPE=REST\n", + "SERVICE_TYPE=MODEL\n", + "PERSISTENCE=0\n" + ] + } + ], + "source": [ + "!cat pipeline/pipeline_steps/clean_text/.s2i/environment" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once this is defined, the only thing we need to do is to run the `build_image.sh` for all the reusable components.\n", + "\n", + "Here we show the manual way to do it:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "NAME READY STATUS RESTARTS AGE\n", - "pvc-access-container 1/1 Running 0 6s\n" - ] - } - ], - "source": ["!kubectl get pods -n kubeflow pvc-access-container"] + "name": "stdout", + "output_type": "stream", + "text": [ + "Sending build context to Docker daemon 9.728kB\n", + "Step 1/4 : FROM python:3.7-slim\n", + " ---> d3fbf7fff365\n", + "Step 2/4 : COPY . /microservice\n", + " ---> Using cache\n", + " ---> 6e9d7e162536\n", + "Step 3/4 : WORKDIR /microservice\n", + " ---> Using cache\n", + " ---> b3d69a634dd1\n", + "Step 4/4 : RUN pip install -r requirements.txt\n", + " ---> Using cache\n", + " ---> f1c421a68fe7\n", + "Successfully built f1c421a68fe7\n", + "Successfully tagged data_downloader:0.1\n" + ] }, { - "cell_type": "markdown", - "metadata": {}, - "source": ["Now we can run an `ls` command to see what's inside:"] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + "---> Installing application source...\n", + "---> Installing dependencies ...\n", + "Looking in links: /whl\n", + "Collecting dill==0.3.2 (from -r requirements.txt (line 1))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/e2/96/518a8ea959a734b70d2e95fef98bcbfdc7adad1c1e5f5dd9148c835205a5/dill-0.3.2.zip (177kB)\n", + "Requirement already satisfied: click==7.1.2 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (7.1.2)\n", + "Requirement already satisfied: numpy==1.19.1 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 3)) (1.19.1)\n", + "Building wheels for collected packages: dill\n", + "Building wheel for dill (setup.py): started\n", + "Building wheel for dill (setup.py): finished with status 'done'\n", + "Created wheel for dill: filename=dill-0.3.2-cp37-none-any.whl size=78913 sha256=9f9ec39fffe7a46bdc1a164bc0cd8d61201f04ff0c4bfc68e7dda78d6a4c29cf\n", + "Stored in directory: /root/.cache/pip/wheels/27/4b/a2/34ccdcc2f158742cfe9650675560dea85f78c3f4628f7daad0\n", + "Successfully built dill\n", + "Installing collected packages: dill\n", + "Successfully installed dill-0.3.2\n", + "WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Collecting pip-licenses\n", + "Downloading https://files.pythonhosted.org/packages/c5/50/6c4b4e69a0c43bd9f03a30579695093062ba72da4e3e4026cd2144dbcc71/pip_licenses-2.3.0-py3-none-any.whl\n", + "Collecting PTable (from pip-licenses)\n", + "Downloading https://files.pythonhosted.org/packages/ab/b3/b54301811173ca94119eb474634f120a49cd370f257d1aae5a4abaf12729/PTable-0.9.2.tar.gz\n", + "Building wheels for collected packages: PTable\n", + "Building wheel for PTable (setup.py): started\n", + "Building wheel for PTable (setup.py): finished with status 'done'\n", + "Created wheel for PTable: filename=PTable-0.9.2-cp37-none-any.whl size=22906 sha256=6c6c94080f12738603dbd55c01213f1c28f9922c915c92d72b547e85d229bfba\n", + "Stored in directory: /root/.cache/pip/wheels/22/cc/2e/55980bfe86393df3e9896146a01f6802978d09d7ebcba5ea56\n", + "Successfully built PTable\n", + "Installing collected packages: PTable, pip-licenses\n", + "Successfully installed PTable-0.9.2 pip-licenses-2.3.0\n", + "created path: ./licenses/license_info.csv\n", + "created path: ./licenses/license.txt\n", + "Build completed successfully\n", + "---> Installing application source...\n", + "---> Installing dependencies ...\n", + "Looking in links: /whl\n", + "Collecting dill==0.3.2 (from -r requirements.txt (line 1))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/e2/96/518a8ea959a734b70d2e95fef98bcbfdc7adad1c1e5f5dd9148c835205a5/dill-0.3.2.zip (177kB)\n", + "Requirement already satisfied: click==7.1.2 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (7.1.2)\n", + "Requirement already satisfied: numpy==1.19.1 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 3)) (1.19.1)\n", + "Collecting scikit-learn==0.23.2 (from -r requirements.txt (line 4))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/f4/cb/64623369f348e9bfb29ff898a57ac7c91ed4921f228e9726546614d63ccb/scikit_learn-0.23.2-cp37-cp37m-manylinux1_x86_64.whl (6.8MB)\n", + "Collecting scipy>=0.19.1 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/65/f9/f7a7e5009711579c72da2725174825e5056741bf4001815d097eef1b2e17/scipy-1.5.2-cp37-cp37m-manylinux1_x86_64.whl (25.9MB)\n", + "Collecting joblib>=0.11 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/51/dd/0e015051b4a27ec5a58b02ab774059f3289a94b0906f880a3f9507e74f38/joblib-0.16.0-py3-none-any.whl (300kB)\n", + "Collecting threadpoolctl>=2.0.0 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/f7/12/ec3f2e203afa394a149911729357aa48affc59c20e2c1c8297a60f33f133/threadpoolctl-2.1.0-py3-none-any.whl\n", + "Building wheels for collected packages: dill\n", + "Building wheel for dill (setup.py): started\n", + "Building wheel for dill (setup.py): finished with status 'done'\n", + "Created wheel for dill: filename=dill-0.3.2-cp37-none-any.whl size=78913 sha256=f4aa43d7acbc7953839cc8177c0e03bec249f9a7dffc10c7e9db79201ce519d3\n", + "Stored in directory: /root/.cache/pip/wheels/27/4b/a2/34ccdcc2f158742cfe9650675560dea85f78c3f4628f7daad0\n", + "Successfully built dill\n", + "Installing collected packages: dill, scipy, joblib, threadpoolctl, scikit-learn\n", + "Successfully installed dill-0.3.2 joblib-0.16.0 scikit-learn-0.23.2 scipy-1.5.2 threadpoolctl-2.1.0\n", + "WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Collecting pip-licenses\n", + "Downloading https://files.pythonhosted.org/packages/c5/50/6c4b4e69a0c43bd9f03a30579695093062ba72da4e3e4026cd2144dbcc71/pip_licenses-2.3.0-py3-none-any.whl\n", + "Collecting PTable (from pip-licenses)\n", + "Downloading https://files.pythonhosted.org/packages/ab/b3/b54301811173ca94119eb474634f120a49cd370f257d1aae5a4abaf12729/PTable-0.9.2.tar.gz\n", + "Building wheels for collected packages: PTable\n", + "Building wheel for PTable (setup.py): started\n", + "Building wheel for PTable (setup.py): finished with status 'done'\n", + "Created wheel for PTable: filename=PTable-0.9.2-cp37-none-any.whl size=22906 sha256=e296b386d6581fe3343b84d718f7e7624bdbabfff569c4220a1f2039dd0abbdf\n", + "Stored in directory: /root/.cache/pip/wheels/22/cc/2e/55980bfe86393df3e9896146a01f6802978d09d7ebcba5ea56\n", + "Successfully built PTable\n", + "Installing collected packages: PTable, pip-licenses\n", + "Successfully installed PTable-0.9.2 pip-licenses-2.3.0\n", + "created path: ./licenses/license_info.csv\n", + "created path: ./licenses/license.txt\n", + "Build completed successfully\n", + "---> Installing application source...\n", + "---> Installing dependencies ...\n", + "Looking in links: /whl\n", + "Collecting dill==0.3.2 (from -r requirements.txt (line 1))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/e2/96/518a8ea959a734b70d2e95fef98bcbfdc7adad1c1e5f5dd9148c835205a5/dill-0.3.2.zip (177kB)\n", + "Requirement already satisfied: click==7.1.2 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (7.1.2)\n", + "Requirement already satisfied: numpy==1.19.1 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 3)) (1.19.1)\n", + "Collecting spacy==2.3.2 (from -r requirements.txt (line 4))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/55/24/70c615f5b22440c679a4132b81eee67d1dfd70d159505a28ff949c78a1ac/spacy-2.3.2-cp37-cp37m-manylinux1_x86_64.whl (9.9MB)\n", + "Collecting en-core-web-sm==2.3.1 (from -r requirements.txt (line 5))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + " ERROR: Could not find a version that satisfies the requirement en-core-web-sm==2.3.1 (from -r requirements.txt (line 5)) (from versions: none)\n", + "ERROR: No matching distribution found for en-core-web-sm==2.3.1 (from -r requirements.txt (line 5))\n", + "WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Build failed\n", + "ERROR: An error occurred: non-zero (13) exit code from seldonio/seldon-core-s2i-python37:1.9.0-dev\n", + "---> Installing application source...\n", + "---> Installing dependencies ...\n", + "Looking in links: /whl\n", + "Collecting dill==0.3.2 (from -r requirements.txt (line 1))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/e2/96/518a8ea959a734b70d2e95fef98bcbfdc7adad1c1e5f5dd9148c835205a5/dill-0.3.2.zip (177kB)\n", + "Requirement already satisfied: click==7.1.2 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 2)) (7.1.2)\n", + "Requirement already satisfied: numpy==1.19.1 in /opt/conda/lib/python3.7/site-packages (from -r requirements.txt (line 3)) (1.19.1)\n", + "Collecting scikit-learn==0.23.2 (from -r requirements.txt (line 4))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/f4/cb/64623369f348e9bfb29ff898a57ac7c91ed4921f228e9726546614d63ccb/scikit_learn-0.23.2-cp37-cp37m-manylinux1_x86_64.whl (6.8MB)\n", + "Collecting joblib>=0.11 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/51/dd/0e015051b4a27ec5a58b02ab774059f3289a94b0906f880a3f9507e74f38/joblib-0.16.0-py3-none-any.whl (300kB)\n", + "Collecting scipy>=0.19.1 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/65/f9/f7a7e5009711579c72da2725174825e5056741bf4001815d097eef1b2e17/scipy-1.5.2-cp37-cp37m-manylinux1_x86_64.whl (25.9MB)\n", + "Collecting threadpoolctl>=2.0.0 (from scikit-learn==0.23.2->-r requirements.txt (line 4))\n", + " WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Downloading https://files.pythonhosted.org/packages/f7/12/ec3f2e203afa394a149911729357aa48affc59c20e2c1c8297a60f33f133/threadpoolctl-2.1.0-py3-none-any.whl\n", + "Building wheels for collected packages: dill\n", + "Building wheel for dill (setup.py): started\n", + "Building wheel for dill (setup.py): finished with status 'done'\n", + "Created wheel for dill: filename=dill-0.3.2-cp37-none-any.whl size=78913 sha256=2bdafea9bf8ead275cf6123cd330c7362915943a397e00ca7b203b9b8759f2a7\n", + "Stored in directory: /root/.cache/pip/wheels/27/4b/a2/34ccdcc2f158742cfe9650675560dea85f78c3f4628f7daad0\n", + "Successfully built dill\n", + "Installing collected packages: dill, joblib, scipy, threadpoolctl, scikit-learn\n", + "Successfully installed dill-0.3.2 joblib-0.16.0 scikit-learn-0.23.2 scipy-1.5.2 threadpoolctl-2.1.0\n", + "WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.\n", + "Collecting pip-licenses\n", + "Downloading https://files.pythonhosted.org/packages/c5/50/6c4b4e69a0c43bd9f03a30579695093062ba72da4e3e4026cd2144dbcc71/pip_licenses-2.3.0-py3-none-any.whl\n", + "Collecting PTable (from pip-licenses)\n", + "Downloading https://files.pythonhosted.org/packages/ab/b3/b54301811173ca94119eb474634f120a49cd370f257d1aae5a4abaf12729/PTable-0.9.2.tar.gz\n", + "Building wheels for collected packages: PTable\n", + "Building wheel for PTable (setup.py): started\n", + "Building wheel for PTable (setup.py): finished with status 'done'\n", + "Created wheel for PTable: filename=PTable-0.9.2-cp37-none-any.whl size=22906 sha256=46a9ca3a63fe171ad06a2e9bbd7f00fba00ca0bb4bbda6177f3571077d79228e\n", + "Stored in directory: /root/.cache/pip/wheels/22/cc/2e/55980bfe86393df3e9896146a01f6802978d09d7ebcba5ea56\n", + "Successfully built PTable\n", + "Installing collected packages: PTable, pip-licenses\n", + "Successfully installed PTable-0.9.2 pip-licenses-2.3.0\n", + "created path: ./licenses/license_info.csv\n", + "created path: ./licenses/license.txt\n", + "Build completed successfully\n" + ] + } + ], + "source": [ + "%%bash\n", + "# we must be in the same directory\n", + "cd pipeline/pipeline_steps/clean_text/ && ./build_image.sh\n", + "cd ../data_downloader && ./build_image.sh\n", + "cd ../lr_text_classifier && ./build_image.sh\n", + "cd ../spacy_tokenize && ./build_image.sh\n", + "cd ../tfidf_vectorizer && ./build_image.sh" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3) Train our NLP Pipeline through the Kubeflow UI\n", + "We can access the Kubeflow dashboard to train our ML pipeline via http://localhost/_/pipeline-dashboard\n", + "\n", + "If you can't edit this, you need to make sure that the ambassador gateway service is accessible:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[1;32mclean.data\u001b[m \u001b[1;32mlr.model\u001b[m \u001b[1;32mtext.data\u001b[m \u001b[1;32mtfidf.model\u001b[m\n", - "\u001b[1;32mlabels.data\u001b[m \u001b[1;32mprediction.data\u001b[m \u001b[1;32mtfidf.data\u001b[m \u001b[1;32mtokens.data\u001b[m\n" - ] - } - ], - "source": ["!kubectl -n kubeflow exec -it pvc-access-container ls /mnt"] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n", + "ambassador NodePort 10.97.236.196 80:30209/TCP 8m58s\n" + ] + } + ], + "source": [ + "!kubectl get svc ambassador -n kubeflow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In my case, I need to change the kind from `NodePort` into `LoadBalancer` which can be done with the following command:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": ["pod \"pvc-access-container\" deleted\n"] - } - ], - "source": [ - "!kubectl delete -f deploy_pipeline/pvc-access.yaml -n kubeflow" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "service/ambassador patched\n" + ] + } + ], + "source": [ + "!kubectl patch svc ambassador --type='json' -p '[{\"op\":\"replace\",\"path\":\"/spec/type\",\"value\":\"LoadBalancer\"}]' -n kubeflow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that I've changed it to a loadbalancer, it has allocated the external IP as my localhost so I can access it at http://localhost/_/pipeline-dashboard\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5) Test Deployed ML REST Endpoints\n", - "Now that it's running we have a production ML text pipeline that we can Query using REST and GRPC\n" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n", + "ambassador LoadBalancer 10.97.236.196 localhost 80:30209/TCP 9m20s\n" + ] + } + ], + "source": [ + "!kubectl get svc ambassador -n kubeflow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If this was successfull, you should be able to access the dashboard\n", + "![kf-pipeline-dashboard](img/k-pipeline-dashboard.jpg)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Define the pipeline\n", + "Now we want to generate the pipeline. For this we can use the DSL provided by kubeflow to define the actual steps required. \n", + "\n", + "The pipeline will look as follows:\n", + "\n", + "![kf-seldon-nlp-ml-pipelines](img/kubeflow-seldon-nlp-ml-pipelines.jpg)" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": ["First we can check if our Seldon deployment is running with"] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "import kfp.dsl as dsl\n", + "import yaml\n", + "from kubernetes import client as k8s\n", + "\n", + "\n", + "@dsl.pipeline(\n", + " name='NLP',\n", + " description='A pipeline demonstrating reproducible steps for NLP'\n", + ")\n", + "def nlp_pipeline(\n", + " csv_url=\"https://raw.githubusercontent.com/axsauze/reddit-classification-exploration/master/data/reddit_train.csv\",\n", + " csv_encoding=\"ISO-8859-1\",\n", + " features_column=\"BODY\",\n", + " labels_column=\"REMOVED\",\n", + " raw_text_path='/mnt/text.data',\n", + " labels_path='/mnt/labels.data',\n", + " clean_text_path='/mnt/clean.data',\n", + " spacy_tokens_path='/mnt/tokens.data',\n", + " tfidf_vectors_path='/mnt/tfidf.data',\n", + " lr_prediction_path='/mnt/prediction.data',\n", + " tfidf_model_path='/mnt/tfidf.model',\n", + " lr_model_path='/mnt/lr.model',\n", + " lr_c_param=0.1,\n", + " tfidf_max_features=10000,\n", + " tfidf_ngram_range=3,\n", + " batch_size='100'):\n", + " \"\"\"\n", + " Pipeline \n", + " \"\"\"\n", + " vop = dsl.VolumeOp(\n", + " name='my-pvc',\n", + " resource_name=\"my-pvc\",\n", + " modes=[\"ReadWriteMany\"],\n", + " size=\"1Gi\"\n", + " )\n", + "\n", + " download_step = dsl.ContainerOp(\n", + " name='data_downloader',\n", + " image='data_downloader:0.1',\n", + " command=\"python\",\n", + " arguments=[\n", + " \"/microservice/pipeline_step.py\",\n", + " \"--labels-path\", labels_path,\n", + " \"--features-path\", raw_text_path,\n", + " \"--csv-url\", csv_url,\n", + " \"--csv-encoding\", csv_encoding,\n", + " \"--features-column\", features_column,\n", + " \"--labels-column\", labels_column\n", + " ],\n", + " pvolumes={\"/mnt\": vop.volume}\n", + " )\n", + "\n", + " clean_step = dsl.ContainerOp(\n", + " name='clean_text',\n", + " image='clean_text_transformer:0.1',\n", + " command=\"python\",\n", + " arguments=[\n", + " \"/microservice/pipeline_step.py\",\n", + " \"--in-path\", raw_text_path,\n", + " \"--out-path\", clean_text_path,\n", + " ],\n", + " pvolumes={\"/mnt\": download_step.pvolume}\n", + " )\n", + "\n", + " tokenize_step = dsl.ContainerOp(\n", + " name='tokenize',\n", + " image='spacy_tokenizer:0.1',\n", + " command=\"python\",\n", + " arguments=[\n", + " \"/microservice/pipeline_step.py\",\n", + " \"--in-path\", clean_text_path,\n", + " \"--out-path\", spacy_tokens_path,\n", + " ],\n", + " pvolumes={\"/mnt\": clean_step.pvolume}\n", + " )\n", + "\n", + " vectorize_step = dsl.ContainerOp(\n", + " name='vectorize',\n", + " image='tfidf_vectorizer:0.1',\n", + " command=\"python\",\n", + " arguments=[\n", + " \"/microservice/pipeline_step.py\",\n", + " \"--in-path\", spacy_tokens_path,\n", + " \"--out-path\", tfidf_vectors_path,\n", + " \"--max-features\", tfidf_max_features,\n", + " \"--ngram-range\", tfidf_ngram_range,\n", + " \"--action\", \"train\",\n", + " \"--model-path\", tfidf_model_path,\n", + " ],\n", + " pvolumes={\"/mnt\": tokenize_step.pvolume}\n", + " )\n", + "\n", + " predict_step = dsl.ContainerOp(\n", + " name='predictor',\n", + " image='lr_text_classifier:0.1',\n", + " command=\"python\",\n", + " arguments=[\n", + " \"/microservice/pipeline_step.py\",\n", + " \"--in-path\", tfidf_vectors_path,\n", + " \"--labels-path\", labels_path,\n", + " \"--out-path\", lr_prediction_path,\n", + " \"--c-param\", lr_c_param,\n", + " \"--action\", \"train\",\n", + " \"--model-path\", lr_model_path,\n", + " ],\n", + " pvolumes={\"/mnt\": vectorize_step.pvolume}\n", + " )\n", + "\n", + " try:\n", + " seldon_config = yaml.load(open(\"../deploy_pipeline/seldon_production_pipeline.yaml\"))\n", + " except:\n", + " # If this file is run from the project core directory \n", + " seldon_config = yaml.load(open(\"deploy_pipeline/seldon_production_pipeline.yaml\"))\n", + "\n", + " deploy_step = dsl.ResourceOp(\n", + " name=\"seldondeploy\",\n", + " k8s_resource=seldon_config,\n", + " attribute_outputs={\"name\": \"{.metadata.name}\"})\n", + "\n", + " deploy_step.after(predict_step)\n", + "\n", + "if __name__ == '__main__':\n", + " import kfp.compiler as compiler\n", + " compiler.Compiler().compile(nlp_pipeline, __file__ + '.tar.gz')\n" + ] + } + ], + "source": [ + "!cat train_pipeline/nlp_pipeline.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Breaking down the code\n", + "As you can see in the DSL, we have the ContainerOp - each of those is a step in the Kubeflow pipeline.\n", + "\n", + "At the end we can see the `seldondeploy` step which basically deploys the trained pipeline\n", + "\n", + "The definition of the SeldonDeployment graph is provided in the `deploy_pipeline/seldon_production_pipeline.yaml` file.\n", + "\n", + "The seldondeployment file defines our production execution graph using the same reusable components." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "scrolled": true + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "NAME AGE\n", - "seldon-deployment-nlp-b7qt8 57m\n" - ] - } - ], - "source": ["!kubectl -n kubeflow get seldondeployment "] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "---\n", + "apiVersion: machinelearning.seldon.io/v1alpha2\n", + "kind: SeldonDeployment\n", + "metadata:\n", + " labels:\n", + " app: seldon\n", + " name: \"seldon-deployment-{{workflow.name}}\"\n", + " namespace: kubeflow\n", + "spec:\n", + " annotations:\n", + " project_name: NLP Pipeline\n", + " deployment_version: v1\n", + " name: \"seldon-deployment-{{workflow.name}}\"\n", + " predictors:\n", + " - componentSpecs:\n", + " - spec:\n", + " containers:\n", + " - image: clean_text_transformer:0.1\n", + " imagePullPolicy: IfNotPresent\n", + " name: cleantext\n", + " resources:\n", + " requests:\n", + " memory: 1Mi\n", + " - image: spacy_tokenizer:0.1\n", + " imagePullPolicy: IfNotPresent\n", + " name: spacytokenizer\n", + " - image: tfidf_vectorizer:0.1\n", + " imagePullPolicy: IfNotPresent\n", + " name: tfidfvectorizer\n", + " volumeMounts:\n", + " - name: mypvc\n", + " mountPath: /mnt\n", + " - image: lr_text_classifier:0.1\n", + " imagePullPolicy: IfNotPresent\n", + " name: lrclassifier\n", + " volumeMounts:\n", + " - name: mypvc\n", + " mountPath: /mnt\n", + " terminationGracePeriodSeconds: 20\n", + " volumes:\n", + " - name: mypvc\n", + " persistentVolumeClaim:\n", + " claimName: \"{{workflow.name}}-my-pvc\"\n", + " graph:\n", + " children:\n", + " - name: spacytokenizer\n", + " endpoint:\n", + " type: REST\n", + " type: MODEL\n", + " children:\n", + " - name: tfidfvectorizer\n", + " endpoint:\n", + " type: REST\n", + " type: MODEL\n", + " children:\n", + " - name: lrclassifier\n", + " endpoint:\n", + " type: REST\n", + " type: MODEL\n", + " children: []\n", + " name: cleantext\n", + " endpoint:\n", + " type: REST\n", + " type: MODEL\n", + " name: single-model\n", + " replicas: 1\n", + " annotations:\n", + " predictor_version: v1\n", + "\n" + ] + } + ], + "source": [ + "!cat deploy_pipeline/seldon_production_pipeline.yaml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Seldon Production pipeline contents\n", + "If we look at the file we'll be using to deploy our pipeline, we can see that it has the following key points:\n", + "\n", + "1) Reusable components definitions as containerSpecs: cleantext, spacytokenizer, tfidfvectorizer & lrclassifier\n", + "\n", + "2) DAG (directed acyclic graph) definition for REST pipeline: cleantext -> spacytokenizer -> tfidfvectorizer -> lrclassifier\n", + "\n", + "This graph in our production deployment looks as follows:\n", + "\n", + "![kf-seldon-npl-pipelines-deploy](img/kubeflow-seldon-nlp-ml-pipelines-deploy.jpg)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Generate the pipeline files to upload to Kubeflow\n", + "To generate the pipeline we just have to run the pipeline file, which will output the `tar.gz` file that will be uploaded." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will need the Seldon Pipeline Deployment name to reach the API, so we can get it using:" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "nlp_pipeline.py\n", + "nlp_pipeline.py.tar.gz\n" + ] }, { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": ["seldon-deployment-nlp-b7qt8"] - } - ], - "source": [ - "!kubectl -n kubeflow get seldondeployment -o jsonpath='{.items[0].metadata.name}'" - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/alejandro/miniconda3/lib/python3.7/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Float\" based on the value \"0.1\".\n", + " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", + "/home/alejandro/miniconda3/lib/python3.7/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Integer\" based on the value \"10000\".\n", + " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", + "/home/alejandro/miniconda3/lib/python3.7/site-packages/kfp/components/_data_passing.py:168: UserWarning: Missing type name was inferred as \"Integer\" based on the value \"3\".\n", + " warnings.warn('Missing type name was inferred as \"{}\" based on the value \"{}\".'.format(type_name, str(value)))\n", + "train_pipeline/nlp_pipeline.py:114: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.\n", + " seldon_config = yaml.load(open(\"deploy_pipeline/seldon_production_pipeline.yaml\"))\n" + ] + } + ], + "source": [ + "%%bash\n", + "# Generating graph definition\n", + "python train_pipeline/nlp_pipeline.py\n", + "ls train_pipeline/" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### Run the pipeline\n", + "\n", + "You can access the Kubeflow Pipelines UI by forwarding the port with the following command:\n", + "\n", + "```\n", + " kubectl port-forward -n kubeflow svc/ml-pipeline-ui 8000:80\n", + "```\n", + "\n", + "The UI should now be accessible via [http://localhost:8000](http://localhost:8000).\n", + "\n", + "We now need to upload the resulting `nlp_pipeline.py.tar.gz` file generated.\n", + "\n", + "This can be done through the \"Upload PIpeline\" button in the UI.\n", + "\n", + "Once it's uploaded, we want to create and trigger a run! You should now be able to see how each step is executed:\n", + "\n", + "![running-pipeline](img/running-pipeline.jpg)\n", + "\n", + "### Inspecting the data created in the Persistent Volume\n", + "The pipeline saves the output of the pipeline together with the trained model in the persistent volume claim.\n", + "\n", + "The persistent volume claim is the same name as the argo workflow:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can interact with our API in two ways: \n", - "\n", - "1) Using CURL or any client like PostMan\n", - "\n", - "2) Using the Python SeldonClient\n", - "\n", - "### Using CURL from the terminal\n", - "When using CURL, the only thing we need to provide is the data in JSON format, as well as the url, which is of the format:\n", - "\n", - "```\n", - "http:///seldon/kubeflow//api/v0.1/predictions\n", - "```" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "NAME AGE\n", + "nlp-bddff 2m\n" + ] + } + ], + "source": [ + "!kubectl get workflow -n kubeflow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our workflow is there! So we can actually access it by running" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"meta\": {\n", - " \"puid\": \"k89krp6t7tfgb386nt6vc3iftk\",\n", - " \"tags\": {\n", - " },\n", - " \"routing\": {\n", - " \"cleantext\": -1,\n", - " \"tfidfvectorizer\": -1,\n", - " \"spacytokenizer\": -1\n", - " },\n", - " \"requestPath\": {\n", - " \"cleantext\": \"clean_text_transformer:0.1\",\n", - " \"tfidfvectorizer\": \"tfidf_vectorizer:0.1\",\n", - " \"lrclassifier\": \"lr_text_classifier:0.1\",\n", - " \"spacytokenizer\": \"spacy_tokenizer:0.1\"\n", - " },\n", - " \"metrics\": []\n", - " },\n", - " \"data\": {\n", - " \"names\": [\"t:0\", \"t:1\"],\n", - " \"ndarray\": [[0.6729318752883149, 0.3270681247116851]]\n", - " }\n", - "}" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " % Total % Received % Xferd Average Speed Time Time Time Current\n", - " Dload Upload Total Spent Left Speed\n", - "100 599 100 527 100 72 516 70 0:00:01 0:00:01 --:--:-- 588\n" - ] - } - ], - "source": [ - "%%bash\n", - "curl -X POST -H 'Content-Type: application/json' \\\n", - " -d \"{'data': {'names': ['text'], 'ndarray': ['Hello world this is a test']}}\" \\\n", - " http://127.0.0.1/seldon/kubeflow/$(kubectl -n kubeflow get seldondeployment -o jsonpath='{.items[0].metadata.name}')/api/v0.1/predictions" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "nlp-bddff" + ] + } + ], + "source": [ + "!kubectl get workflow -n kubeflow -o jsonpath='{.items[0].metadata.name}'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we can use good old `sed` to insert this workflow name in our PVC-Access controler which we can use to inspect the contents of the volume:" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Using the SeldonClient\n", - "We can also use the Python SeldonClient to interact with the pipeline we just deployed " - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "apiVersion: v1\n", + "kind: Pod\n", + "metadata:\n", + " name: pvc-access-container\n", + "spec:\n", + " containers:\n", + " - name: pvc-access-container\n", + " image: busybox\n", + " command: [\"/bin/sh\", \"-ec\", \"sleep 1000\"]\n", + " volumeMounts:\n", + " - name: mypvc\n", + " mountPath: /mnt\n", + " volumes:\n", + " - name: mypvc\n", + " persistentVolumeClaim:\n", + " claimName: nlp-b7qt8-my-pvc\n" + ] + } + ], + "source": [ + "!sed \"s/PVC_NAME/\"$(kubectl get workflow -n kubeflow -o jsonpath='{.items[0].metadata.name}')\"-my-pvc/g\" deploy_pipeline/pvc-access.yaml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We just need to apply this container with our kubectl command, and we can use it to inspect the mounted folder:" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Success:True message:\n", - "Request:\n", - "data {\n", - " names: \"text\"\n", - " ndarray {\n", - " values {\n", - " string_value: \"Hello world this is a test\"\n", - " }\n", - " }\n", - "}\n", - "\n", - "Response:\n", - "meta {\n", - " puid: \"qtdca40d3s0463nn4ginhkvc6t\"\n", - " routing {\n", - " key: \"cleantext\"\n", - " value: -1\n", - " }\n", - " routing {\n", - " key: \"spacytokenizer\"\n", - " value: -1\n", - " }\n", - " routing {\n", - " key: \"tfidfvectorizer\"\n", - " value: -1\n", - " }\n", - " requestPath {\n", - " key: \"cleantext\"\n", - " value: \"clean_text_transformer:0.1\"\n", - " }\n", - " requestPath {\n", - " key: \"lrclassifier\"\n", - " value: \"lr_text_classifier:0.1\"\n", - " }\n", - " requestPath {\n", - " key: \"spacytokenizer\"\n", - " value: \"spacy_tokenizer:0.1\"\n", - " }\n", - " requestPath {\n", - " key: \"tfidfvectorizer\"\n", - " value: \"tfidf_vectorizer:0.1\"\n", - " }\n", - "}\n", - "data {\n", - " names: \"t:0\"\n", - " names: \"t:1\"\n", - " ndarray {\n", - " values {\n", - " list_value {\n", - " values {\n", - " number_value: 0.6729318752883149\n", - " }\n", - " values {\n", - " number_value: 0.3270681247116851\n", - " }\n", - " }\n", - " }\n", - " }\n", - "}\n", - "\n" - ] - } - ], - "source": [ - "from seldon_core.seldon_client import SeldonClient\n", - "import numpy as np\n", - "import subprocess\n", - "\n", - "host = \"localhost\"\n", - "port = \"80\" # Make sure you use the port above\n", - "batch = np.array([\"Hello world this is a test\"])\n", - "payload_type = \"ndarray\"\n", - "# Get the deployment name\n", - "deployment_name = subprocess.getoutput(\"kubectl -n kubeflow get seldondeployment -o jsonpath='{.items[0].metadata.name}'\")\n", - "transport=\"rest\"\n", - "namespace=\"kubeflow\"\n", - "\n", - "sc = SeldonClient(\n", - " gateway=\"ambassador\", \n", - " ambassador_endpoint=host + \":\" + port,\n", - " namespace=namespace)\n", - "\n", - "client_prediction = sc.predict(\n", - " data=batch, \n", - " deployment_name=deployment_name,\n", - " names=[\"text\"],\n", - " payload_type=payload_type,\n", - " transport=\"rest\")\n", - "\n", - "print(client_prediction)" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "pod/pvc-access-container created\n" + ] + } + ], + "source": [ + "!sed \"s/PVC_NAME/\"$(kubectl get workflow -n kubeflow -o jsonpath='{.items[0].metadata.name}')\"-my-pvc/g\" deploy_pipeline/pvc-access.yaml | kubectl -n kubeflow apply -f -" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 6) Visualise Seldon's Production ML Pipelines\n", - "We can visualise the performance using the SeldonAnalytics package, which we can deploy using:" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "NAME READY STATUS RESTARTS AGE\n", + "pvc-access-container 1/1 Running 0 6s\n" + ] + } + ], + "source": [ + "!kubectl get pods -n kubeflow pvc-access-container" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can run an `ls` command to see what's inside:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!helm install seldon-core-analytics --repo https://storage.googleapis.com/seldon-charts --namespace kubeflow" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[1;32mclean.data\u001b[m \u001b[1;32mlr.model\u001b[m \u001b[1;32mtext.data\u001b[m \u001b[1;32mtfidf.model\u001b[m\n", + "\u001b[1;32mlabels.data\u001b[m \u001b[1;32mprediction.data\u001b[m \u001b[1;32mtfidf.data\u001b[m \u001b[1;32mtokens.data\u001b[m\n" + ] + } + ], + "source": [ + "!kubectl -n kubeflow exec -it pvc-access-container ls /mnt" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In my case, similar to what I did with Ambassador, I need to make sure the the service is a LoadBalancer instead of a NodePort" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "pod \"pvc-access-container\" deleted\n" + ] + } + ], + "source": [ + "!kubectl delete -f deploy_pipeline/pvc-access.yaml -n kubeflow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5) Test Deployed ML REST Endpoints\n", + "Now that it's running we have a production ML text pipeline that we can Query using REST and GRPC\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First we can check if our Seldon deployment is running with" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": ["service/grafana-prom patched\n"] - } - ], - "source": [ - "!kubectl patch svc grafana-prom --type='json' -p '[{\"op\":\"replace\",\"path\":\"/spec/type\",\"value\":\"LoadBalancer\"}]' -n kubeflow" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "NAME AGE\n", + "seldon-deployment-nlp-b7qt8 57m\n" + ] + } + ], + "source": [ + "!kubectl -n kubeflow get seldondeployment" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will need the Seldon Pipeline Deployment name to reach the API, so we can get it using:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n", - "grafana-prom LoadBalancer 10.98.248.223 localhost 80:32445/TCP 64m\n" - ] - } - ], - "source": ["!kubectl get svc grafana-prom -n kubeflow"] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "seldon-deployment-nlp-b7qt8" + ] + } + ], + "source": [ + "!kubectl -n kubeflow get seldondeployment -o jsonpath='{.items[0].metadata.name}'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can interact with our API in two ways: \n", + "\n", + "1) Using CURL or any client like PostMan\n", + "\n", + "2) Using the Python SeldonClient\n", + "\n", + "### Using CURL from the terminal\n", + "When using CURL, the only thing we need to provide is the data in JSON format, as well as the url, which is of the format:\n", + "\n", + "```\n", + "http:///seldon/kubeflow//api/v0.1/predictions\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can access it at the port provided, in my case it is http://localhost:32445/d/3swM2iGWz/prediction-analytics?refresh=5s&orgId=1\n", - "\n", - "(initial username is admin and password is password, which will be requested to be changed on the first login)\n", - "\n", - "Generate a bunch of requests and visualise:" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"meta\": {\n", + " \"puid\": \"k89krp6t7tfgb386nt6vc3iftk\",\n", + " \"tags\": {\n", + " },\n", + " \"routing\": {\n", + " \"cleantext\": -1,\n", + " \"tfidfvectorizer\": -1,\n", + " \"spacytokenizer\": -1\n", + " },\n", + " \"requestPath\": {\n", + " \"cleantext\": \"clean_text_transformer:0.1\",\n", + " \"tfidfvectorizer\": \"tfidf_vectorizer:0.1\",\n", + " \"lrclassifier\": \"lr_text_classifier:0.1\",\n", + " \"spacytokenizer\": \"spacy_tokenizer:0.1\"\n", + " },\n", + " \"metrics\": []\n", + " },\n", + " \"data\": {\n", + " \"names\": [\"t:0\", \"t:1\"],\n", + " \"ndarray\": [[0.6729318752883149, 0.3270681247116851]]\n", + " }\n", + "}" + ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "while True:\n", - " client_prediction = sc.predict(\n", - " data=batch, \n", - " deployment_name=deployment_name,\n", - " names=[\"text\"],\n", - " payload_type=payload_type,\n", - " transport=\"rest\")" - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + " % Total % Received % Xferd Average Speed Time Time Time Current\n", + " Dload Upload Total Spent Left Speed\n", + "100 599 100 527 100 72 516 70 0:00:01 0:00:01 --:--:-- 588\n" + ] + } + ], + "source": [ + "%%bash\n", + "curl -X POST -H 'Content-Type: application/json' \\\n", + " -d \"{'data': {'names': ['text'], 'ndarray': ['Hello world this is a test']}}\" \\\n", + " http://127.0.0.1/seldon/kubeflow/$(kubectl -n kubeflow get seldondeployment -o jsonpath='{.items[0].metadata.name}')/api/v0.1/predictions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using the SeldonClient\n", + "We can also use the Python SeldonClient to interact with the pipeline we just deployed " + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## You now have a full end-to-end training and production NLP pipeline\n", - "![seldon-analytics](img/seldon-analytics.jpg)" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Success:True message:\n", + "Request:\n", + "data {\n", + " names: \"text\"\n", + " ndarray {\n", + " values {\n", + " string_value: \"Hello world this is a test\"\n", + " }\n", + " }\n", + "}\n", + "\n", + "Response:\n", + "meta {\n", + " puid: \"qtdca40d3s0463nn4ginhkvc6t\"\n", + " routing {\n", + " key: \"cleantext\"\n", + " value: -1\n", + " }\n", + " routing {\n", + " key: \"spacytokenizer\"\n", + " value: -1\n", + " }\n", + " routing {\n", + " key: \"tfidfvectorizer\"\n", + " value: -1\n", + " }\n", + " requestPath {\n", + " key: \"cleantext\"\n", + " value: \"clean_text_transformer:0.1\"\n", + " }\n", + " requestPath {\n", + " key: \"lrclassifier\"\n", + " value: \"lr_text_classifier:0.1\"\n", + " }\n", + " requestPath {\n", + " key: \"spacytokenizer\"\n", + " value: \"spacy_tokenizer:0.1\"\n", + " }\n", + " requestPath {\n", + " key: \"tfidfvectorizer\"\n", + " value: \"tfidf_vectorizer:0.1\"\n", + " }\n", + "}\n", + "data {\n", + " names: \"t:0\"\n", + " names: \"t:1\"\n", + " ndarray {\n", + " values {\n", + " list_value {\n", + " values {\n", + " number_value: 0.6729318752883149\n", + " }\n", + " values {\n", + " number_value: 0.3270681247116851\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n" + ] + } + ], + "source": [ + "import subprocess\n", + "\n", + "import numpy as np\n", + "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", + "host = \"localhost\"\n", + "port = \"80\" # Make sure you use the port above\n", + "batch = np.array([\"Hello world this is a test\"])\n", + "payload_type = \"ndarray\"\n", + "# Get the deployment name\n", + "deployment_name = subprocess.getoutput(\n", + " \"kubectl -n kubeflow get seldondeployment -o jsonpath='{.items[0].metadata.name}'\"\n", + ")\n", + "transport = \"rest\"\n", + "namespace = \"kubeflow\"\n", + "\n", + "sc = SeldonClient(\n", + " gateway=\"ambassador\", ambassador_endpoint=host + \":\" + port, namespace=namespace\n", + ")\n", + "\n", + "client_prediction = sc.predict(\n", + " data=batch,\n", + " deployment_name=deployment_name,\n", + " names=[\"text\"],\n", + " payload_type=payload_type,\n", + " transport=\"rest\",\n", + ")\n", + "\n", + "print(client_prediction)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6) Visualise Seldon's Production ML Pipelines\n", + "We can visualise the performance using the SeldonAnalytics package, which we can deploy using:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!helm install seldon-core-analytics --repo https://storage.googleapis.com/seldon-charts --namespace kubeflow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In my case, similar to what I did with Ambassador, I need to make sure the the service is a LoadBalancer instead of a NodePort" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "name": "stdout", + "output_type": "stream", + "text": [ + "service/grafana-prom patched\n" + ] } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.8" + ], + "source": [ + "!kubectl patch svc grafana-prom --type='json' -p '[{\"op\":\"replace\",\"path\":\"/spec/type\",\"value\":\"LoadBalancer\"}]' -n kubeflow" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE\n", + "grafana-prom LoadBalancer 10.98.248.223 localhost 80:32445/TCP 64m\n" + ] } + ], + "source": [ + "!kubectl get svc grafana-prom -n kubeflow" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can access it at the port provided, in my case it is http://localhost:32445/d/3swM2iGWz/prediction-analytics?refresh=5s&orgId=1\n", + "\n", + "(initial username is admin and password is password, which will be requested to be changed on the first login)\n", + "\n", + "Generate a bunch of requests and visualise:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "while True:\n", + " client_prediction = sc.predict(\n", + " data=batch,\n", + " deployment_name=deployment_name,\n", + " names=[\"text\"],\n", + " payload_type=payload_type,\n", + " transport=\"rest\",\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## You now have a full end-to-end training and production NLP pipeline\n", + "![seldon-analytics](img/seldon-analytics.jpg)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 4 + "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.8" + } + }, + "nbformat": 4, + "nbformat_minor": 4 } diff --git a/examples/models/alibaba_ack_deep_mnist/alibaba_cloud_ack_deep_mnist.ipynb b/examples/models/alibaba_ack_deep_mnist/alibaba_cloud_ack_deep_mnist.ipynb index 6929323778..0b0cf2db62 100644 --- a/examples/models/alibaba_ack_deep_mnist/alibaba_cloud_ack_deep_mnist.ipynb +++ b/examples/models/alibaba_ack_deep_mnist/alibaba_cloud_ack_deep_mnist.ipynb @@ -83,21 +83,24 @@ ], "source": [ "from tensorflow.examples.tutorials.mnist import input_data\n", - "mnist = input_data.read_data_sets(\"MNIST_data/\", one_hot = True)\n", + "\n", + "mnist = input_data.read_data_sets(\"MNIST_data/\", one_hot=True)\n", "import tensorflow as tf\n", "\n", - "if __name__ == '__main__':\n", - " \n", - " x = tf.placeholder(tf.float32, [None,784], name=\"x\")\n", + "if __name__ == \"__main__\":\n", + "\n", + " x = tf.placeholder(tf.float32, [None, 784], name=\"x\")\n", "\n", - " W = tf.Variable(tf.zeros([784,10]))\n", + " W = tf.Variable(tf.zeros([784, 10]))\n", " b = tf.Variable(tf.zeros([10]))\n", "\n", - " y = tf.nn.softmax(tf.matmul(x,W) + b, name=\"y\")\n", + " y = tf.nn.softmax(tf.matmul(x, W) + b, name=\"y\")\n", "\n", " y_ = tf.placeholder(tf.float32, [None, 10])\n", "\n", - " cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))\n", + " cross_entropy = tf.reduce_mean(\n", + " -tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])\n", + " )\n", "\n", " train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)\n", "\n", @@ -110,9 +113,9 @@ " batch_xs, batch_ys = mnist.train.next_batch(100)\n", " sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})\n", "\n", - " correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))\n", + " correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))\n", " accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))\n", - " print(sess.run(accuracy, feed_dict = {x: mnist.test.images, y_:mnist.test.labels}))\n", + " print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))\n", "\n", " saver = tf.train.Saver()\n", "\n", @@ -348,13 +351,14 @@ "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "\n", "# This is the variable that was initialised at the beginning of the file\n", "i = [0]\n", "x = mnist.test.images[i]\n", "y = mnist.test.labels[i]\n", - "plt.imshow(x.reshape((28, 28)), cmap='gray')\n", + "plt.imshow(x.reshape((28, 28)), cmap=\"gray\")\n", "plt.show()\n", - "print(\"Expected label: \", np.sum(range(0,10) * y), \". One hot encoding: \", y)" + "print(\"Expected label: \", np.sum(range(0, 10) * y), \". One hot encoding: \", y)" ] }, { @@ -380,10 +384,12 @@ } ], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import math\n", + "\n", "import numpy as np\n", "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", "# We now test the REST endpoint expecting the same result\n", "endpoint = \"0.0.0.0:5000\"\n", "batch = x\n", @@ -393,12 +399,13 @@ "\n", "# We use the microservice, instead of the \"predict\" function\n", "client_prediction = sc.microservice(\n", - " data=batch,\n", - " method=\"predict\",\n", - " payload_type=payload_type,\n", - " names=[\"tfidf\"])\n", + " data=batch, method=\"predict\", payload_type=payload_type, names=[\"tfidf\"]\n", + ")\n", "\n", - "for proba, label in zip(client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1], range(0,10)):\n", + "for proba, label in zip(\n", + " client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1],\n", + " range(0, 10),\n", + "):\n", " print(f\"LABEL {label}:\\t {proba.number_value*100:6.4f} %\")" ] }, @@ -707,13 +714,14 @@ "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "\n", "# This is the variable that was initialised at the beginning of the file\n", "i = [0]\n", "x = mnist.test.images[i]\n", "y = mnist.test.labels[i]\n", - "plt.imshow(x.reshape((28, 28)), cmap='gray')\n", + "plt.imshow(x.reshape((28, 28)), cmap=\"gray\")\n", "plt.show()\n", - "print(\"Expected label: \", np.sum(range(0,10) * y), \". One hot encoding: \", y)" + "print(\"Expected label: \", np.sum(range(0, 10) * y), \". One hot encoding: \", y)" ] }, { @@ -738,7 +746,7 @@ } ], "source": [ - "!kubectl get svc ambassador -o jsonpath='{.status.loadBalancer.ingress[0].ip}' " + "!kubectl get svc ambassador -o jsonpath='{.status.loadBalancer.ingress[0].ip}'" ] }, { @@ -817,29 +825,28 @@ } ], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import math\n", - "import numpy as np\n", "import subprocess\n", "\n", + "import numpy as np\n", + "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", "# Add the URL you found above, here:\n", "HOST = \"8.208.23.117\"\n", "\n", "\n", - "port = \"80\" # Make sure you use the port above\n", + "port = \"80\" # Make sure you use the port above\n", "batch = x\n", "payload_type = \"ndarray\"\n", "\n", "sc = SeldonClient(\n", - " gateway=\"ambassador\", \n", - " gateway_endpoint=HOST + \":\" + port,\n", - " namespace=\"default\")\n", + " gateway=\"ambassador\", gateway_endpoint=HOST + \":\" + port, namespace=\"default\"\n", + ")\n", "\n", "client_prediction = sc.predict(\n", - " data=batch, \n", - " deployment_name=\"deep-mnist\",\n", - " names=[\"text\"],\n", - " payload_type=payload_type)\n", + " data=batch, deployment_name=\"deep-mnist\", names=[\"text\"], payload_type=payload_type\n", + ")\n", "\n", "print(client_prediction.response)" ] @@ -875,7 +882,10 @@ } ], "source": [ - "for proba, label in zip(client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1], range(0,10)):\n", + "for proba, label in zip(\n", + " client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1],\n", + " range(0, 10),\n", + "):\n", " print(f\"LABEL {label}:\\t {proba.number_value*100:6.4f} %\")" ] }, @@ -905,7 +915,7 @@ } ], "source": [ - "!kubectl get svc grafana-prom -o jsonpath='{.status.loadBalancer.ingress[0].ip}' " + "!kubectl get svc grafana-prom -o jsonpath='{.status.loadBalancer.ingress[0].ip}'" ] }, { diff --git a/examples/models/aws_eks_deep_mnist/aws_eks_deep_mnist.ipynb b/examples/models/aws_eks_deep_mnist/aws_eks_deep_mnist.ipynb index 7578dd2f98..c6fd7bf754 100644 --- a/examples/models/aws_eks_deep_mnist/aws_eks_deep_mnist.ipynb +++ b/examples/models/aws_eks_deep_mnist/aws_eks_deep_mnist.ipynb @@ -63,21 +63,24 @@ ], "source": [ "from tensorflow.examples.tutorials.mnist import input_data\n", - "mnist = input_data.read_data_sets(\"MNIST_data/\", one_hot = True)\n", + "\n", + "mnist = input_data.read_data_sets(\"MNIST_data/\", one_hot=True)\n", "import tensorflow as tf\n", "\n", - "if __name__ == '__main__':\n", - " \n", - " x = tf.placeholder(tf.float32, [None,784], name=\"x\")\n", + "if __name__ == \"__main__\":\n", + "\n", + " x = tf.placeholder(tf.float32, [None, 784], name=\"x\")\n", "\n", - " W = tf.Variable(tf.zeros([784,10]))\n", + " W = tf.Variable(tf.zeros([784, 10]))\n", " b = tf.Variable(tf.zeros([10]))\n", "\n", - " y = tf.nn.softmax(tf.matmul(x,W) + b, name=\"y\")\n", + " y = tf.nn.softmax(tf.matmul(x, W) + b, name=\"y\")\n", "\n", " y_ = tf.placeholder(tf.float32, [None, 10])\n", "\n", - " cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))\n", + " cross_entropy = tf.reduce_mean(\n", + " -tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])\n", + " )\n", "\n", " train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)\n", "\n", @@ -90,9 +93,9 @@ " batch_xs, batch_ys = mnist.train.next_batch(100)\n", " sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})\n", "\n", - " correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))\n", + " correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))\n", " accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))\n", - " print(sess.run(accuracy, feed_dict = {x: mnist.test.images, y_:mnist.test.labels}))\n", + " print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))\n", "\n", " saver = tf.train.Saver()\n", "\n", @@ -244,13 +247,14 @@ ], "source": [ "import matplotlib.pyplot as plt\n", + "\n", "# This is the variable that was initialised at the beginning of the file\n", "i = [0]\n", "x = mnist.test.images[i]\n", "y = mnist.test.labels[i]\n", - "plt.imshow(x.reshape((28, 28)), cmap='gray')\n", + "plt.imshow(x.reshape((28, 28)), cmap=\"gray\")\n", "plt.show()\n", - "print(\"Expected label: \", np.sum(range(0,10) * y), \". One hot encoding: \", y)" + "print(\"Expected label: \", np.sum(range(0, 10) * y), \". One hot encoding: \", y)" ] }, { @@ -276,10 +280,12 @@ } ], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import math\n", + "\n", "import numpy as np\n", "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", "# We now test the REST endpoint expecting the same result\n", "endpoint = \"0.0.0.0:5000\"\n", "batch = x\n", @@ -289,12 +295,13 @@ "\n", "# We use the microservice, instead of the \"predict\" function\n", "client_prediction = sc.microservice(\n", - " data=batch,\n", - " method=\"predict\",\n", - " payload_type=payload_type,\n", - " names=[\"tfidf\"])\n", + " data=batch, method=\"predict\", payload_type=payload_type, names=[\"tfidf\"]\n", + ")\n", "\n", - "for proba, label in zip(client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1], range(0,10)):\n", + "for proba, label in zip(\n", + " client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1],\n", + " range(0, 10),\n", + "):\n", " print(f\"LABEL {label}:\\t {proba.number_value*100:6.4f} %\")" ] }, @@ -413,7 +420,7 @@ "metadata": {}, "outputs": [], "source": [ - "!curl --silent --location \"https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz\" | tar xz " + "!curl --silent --location \"https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz\" | tar xz" ] }, { @@ -903,7 +910,7 @@ } ], "source": [ - "!kubectl get svc ambassador -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' " + "!kubectl get svc ambassador -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'" ] }, { @@ -940,13 +947,14 @@ ], "source": [ "import matplotlib.pyplot as plt\n", + "\n", "# This is the variable that was initialised at the beginning of the file\n", "i = [0]\n", "x = mnist.test.images[i]\n", "y = mnist.test.labels[i]\n", - "plt.imshow(x.reshape((28, 28)), cmap='gray')\n", + "plt.imshow(x.reshape((28, 28)), cmap=\"gray\")\n", "plt.show()\n", - "print(\"Expected label: \", np.sum(range(0,10) * y), \". One hot encoding: \", y)" + "print(\"Expected label: \", np.sum(range(0, 10) * y), \". One hot encoding: \", y)" ] }, { @@ -3390,25 +3398,24 @@ } ], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import math\n", + "\n", "import numpy as np\n", "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", "host = \"a68bbac487ca611e988060247f81f4c1-707754258.us-west-2.elb.amazonaws.com\"\n", - "port = \"80\" # Make sure you use the port above\n", + "port = \"80\" # Make sure you use the port above\n", "batch = x\n", "payload_type = \"ndarray\"\n", "\n", "sc = SeldonClient(\n", - " gateway=\"ambassador\", \n", - " ambassador_endpoint=host + \":\" + port,\n", - " namespace=\"default\")\n", + " gateway=\"ambassador\", ambassador_endpoint=host + \":\" + port, namespace=\"default\"\n", + ")\n", "\n", "client_prediction = sc.predict(\n", - " data=batch, \n", - " deployment_name=\"deep-mnist\",\n", - " names=[\"text\"],\n", - " payload_type=payload_type)\n", + " data=batch, deployment_name=\"deep-mnist\", names=[\"text\"], payload_type=payload_type\n", + ")\n", "\n", "print(client_prediction)" ] @@ -3444,7 +3451,10 @@ } ], "source": [ - "for proba, label in zip(client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1], range(0,10)):\n", + "for proba, label in zip(\n", + " client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1],\n", + " range(0, 10),\n", + "):\n", " print(f\"LABEL {label}:\\t {proba.number_value*100:6.4f} %\")" ] }, diff --git a/examples/models/azure_aks_deep_mnist/azure_aks_deep_mnist.ipynb b/examples/models/azure_aks_deep_mnist/azure_aks_deep_mnist.ipynb index 01039bab74..826fdbe53d 100644 --- a/examples/models/azure_aks_deep_mnist/azure_aks_deep_mnist.ipynb +++ b/examples/models/azure_aks_deep_mnist/azure_aks_deep_mnist.ipynb @@ -96,21 +96,24 @@ ], "source": [ "from tensorflow.examples.tutorials.mnist import input_data\n", - "mnist = input_data.read_data_sets(\"MNIST_data/\", one_hot = True)\n", + "\n", + "mnist = input_data.read_data_sets(\"MNIST_data/\", one_hot=True)\n", "import tensorflow as tf\n", "\n", - "if __name__ == '__main__':\n", - " \n", - " x = tf.placeholder(tf.float32, [None,784], name=\"x\")\n", + "if __name__ == \"__main__\":\n", + "\n", + " x = tf.placeholder(tf.float32, [None, 784], name=\"x\")\n", "\n", - " W = tf.Variable(tf.zeros([784,10]))\n", + " W = tf.Variable(tf.zeros([784, 10]))\n", " b = tf.Variable(tf.zeros([10]))\n", "\n", - " y = tf.nn.softmax(tf.matmul(x,W) + b, name=\"y\")\n", + " y = tf.nn.softmax(tf.matmul(x, W) + b, name=\"y\")\n", "\n", " y_ = tf.placeholder(tf.float32, [None, 10])\n", "\n", - " cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))\n", + " cross_entropy = tf.reduce_mean(\n", + " -tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])\n", + " )\n", "\n", " train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)\n", "\n", @@ -123,9 +126,9 @@ " batch_xs, batch_ys = mnist.train.next_batch(100)\n", " sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})\n", "\n", - " correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))\n", + " correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))\n", " accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))\n", - " print(sess.run(accuracy, feed_dict = {x: mnist.test.images, y_:mnist.test.labels}))\n", + " print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))\n", "\n", " saver = tf.train.Saver()\n", "\n", @@ -278,13 +281,14 @@ "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "\n", "# This is the variable that was initialised at the beginning of the file\n", "i = [0]\n", "x = mnist.test.images[i]\n", "y = mnist.test.labels[i]\n", - "plt.imshow(x.reshape((28, 28)), cmap='gray')\n", + "plt.imshow(x.reshape((28, 28)), cmap=\"gray\")\n", "plt.show()\n", - "print(\"Expected label: \", np.sum(range(0,10) * y), \". One hot encoding: \", y)" + "print(\"Expected label: \", np.sum(range(0, 10) * y), \". One hot encoding: \", y)" ] }, { @@ -310,10 +314,12 @@ } ], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import math\n", + "\n", "import numpy as np\n", "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", "# We now test the REST endpoint expecting the same result\n", "endpoint = \"0.0.0.0:5000\"\n", "batch = x\n", @@ -323,12 +329,13 @@ "\n", "# We use the microservice, instead of the \"predict\" function\n", "client_prediction = sc.microservice(\n", - " data=batch,\n", - " method=\"predict\",\n", - " payload_type=payload_type,\n", - " names=[\"tfidf\"])\n", + " data=batch, method=\"predict\", payload_type=payload_type, names=[\"tfidf\"]\n", + ")\n", "\n", - "for proba, label in zip(client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1], range(0,10)):\n", + "for proba, label in zip(\n", + " client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1],\n", + " range(0, 10),\n", + "):\n", " print(f\"LABEL {label}:\\t {proba.number_value*100:6.4f} %\")" ] }, @@ -761,7 +768,7 @@ } ], "source": [ - "!kubectl get svc ambassador -o jsonpath='{.status.loadBalancer.ingress[0].ip}' " + "!kubectl get svc ambassador -o jsonpath='{.status.loadBalancer.ingress[0].ip}'" ] }, { @@ -798,13 +805,14 @@ ], "source": [ "import matplotlib.pyplot as plt\n", + "\n", "# This is the variable that was initialised at the beginning of the file\n", "i = [0]\n", "x = mnist.test.images[i]\n", "y = mnist.test.labels[i]\n", - "plt.imshow(x.reshape((28, 28)), cmap='gray')\n", + "plt.imshow(x.reshape((28, 28)), cmap=\"gray\")\n", "plt.show()\n", - "print(\"Expected label: \", np.sum(range(0,10) * y), \". One hot encoding: \", y)" + "print(\"Expected label: \", np.sum(range(0, 10) * y), \". One hot encoding: \", y)" ] }, { @@ -3248,25 +3256,24 @@ } ], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import math\n", + "\n", "import numpy as np\n", "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", "host = \"52.160.64.65\"\n", - "port = \"80\" # Make sure you use the port above\n", + "port = \"80\" # Make sure you use the port above\n", "batch = x\n", "payload_type = \"ndarray\"\n", "\n", "sc = SeldonClient(\n", - " gateway=\"ambassador\", \n", - " ambassador_endpoint=host + \":\" + port,\n", - " namespace=\"default\")\n", + " gateway=\"ambassador\", ambassador_endpoint=host + \":\" + port, namespace=\"default\"\n", + ")\n", "\n", "client_prediction = sc.predict(\n", - " data=batch, \n", - " deployment_name=\"deep-mnist\",\n", - " names=[\"text\"],\n", - " payload_type=payload_type)\n", + " data=batch, deployment_name=\"deep-mnist\", names=[\"text\"], payload_type=payload_type\n", + ")\n", "\n", "print(client_prediction)" ] @@ -3302,7 +3309,10 @@ } ], "source": [ - "for proba, label in zip(client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1], range(0,10)):\n", + "for proba, label in zip(\n", + " client_prediction.response.data.ndarray.values[0].list_value.ListFields()[0][1],\n", + " range(0, 10),\n", + "):\n", " print(f\"LABEL {label}:\\t {proba.number_value*100:6.4f} %\")" ] }, diff --git a/examples/models/chainer_mnist/chainer_mnist.ipynb b/examples/models/chainer_mnist/chainer_mnist.ipynb index 367a8589af..6657ad0856 100644 --- a/examples/models/chainer_mnist/chainer_mnist.ipynb +++ b/examples/models/chainer_mnist/chainer_mnist.ipynb @@ -601,14 +601,13 @@ "import chainer\n", "import chainer.functions as F\n", "import chainer.links as L\n", + "import chainerx\n", "from chainer import training\n", "from chainer.training import extensions\n", - "import chainerx\n", "\n", "\n", "# Network definition\n", "class MLP(chainer.Chain):\n", - "\n", " def __init__(self, n_units, n_out):\n", " super(MLP, self).__init__()\n", " with self.init_scope():\n", @@ -624,39 +623,66 @@ "\n", "\n", "def main():\n", - " parser = argparse.ArgumentParser(description='Chainer example: MNIST')\n", - " parser.add_argument('--batchsize', '-b', type=int, default=100,\n", - " help='Number of images in each mini-batch')\n", - " parser.add_argument('--epoch', '-e', type=int, default=20,\n", - " help='Number of sweeps over the dataset to train')\n", - " parser.add_argument('--frequency', '-f', type=int, default=-1,\n", - " help='Frequency of taking a snapshot')\n", - " parser.add_argument('--device', '-d', type=str, default='-1',\n", - " help='Device specifier. Either ChainerX device '\n", - " 'specifier or an integer. If non-negative integer, '\n", - " 'CuPy arrays with specified device id are used. If '\n", - " 'negative integer, NumPy arrays are used')\n", - " parser.add_argument('--out', '-o', default='result',\n", - " help='Directory to output the result')\n", - " parser.add_argument('--resume', '-r', type=str,\n", - " help='Resume the training from snapshot')\n", - " parser.add_argument('--unit', '-u', type=int, default=1000,\n", - " help='Number of units')\n", - " parser.add_argument('--noplot', dest='plot', action='store_false',\n", - " help='Disable PlotReport extension')\n", - " group = parser.add_argument_group('deprecated arguments')\n", - " group.add_argument('--gpu', '-g', dest='device',\n", - " type=int, nargs='?', const=0,\n", - " help='GPU ID (negative value indicates CPU)')\n", + " parser = argparse.ArgumentParser(description=\"Chainer example: MNIST\")\n", + " parser.add_argument(\n", + " \"--batchsize\",\n", + " \"-b\",\n", + " type=int,\n", + " default=100,\n", + " help=\"Number of images in each mini-batch\",\n", + " )\n", + " parser.add_argument(\n", + " \"--epoch\",\n", + " \"-e\",\n", + " type=int,\n", + " default=20,\n", + " help=\"Number of sweeps over the dataset to train\",\n", + " )\n", + " parser.add_argument(\n", + " \"--frequency\", \"-f\", type=int, default=-1, help=\"Frequency of taking a snapshot\"\n", + " )\n", + " parser.add_argument(\n", + " \"--device\",\n", + " \"-d\",\n", + " type=str,\n", + " default=\"-1\",\n", + " help=\"Device specifier. Either ChainerX device \"\n", + " \"specifier or an integer. If non-negative integer, \"\n", + " \"CuPy arrays with specified device id are used. If \"\n", + " \"negative integer, NumPy arrays are used\",\n", + " )\n", + " parser.add_argument(\n", + " \"--out\", \"-o\", default=\"result\", help=\"Directory to output the result\"\n", + " )\n", + " parser.add_argument(\n", + " \"--resume\", \"-r\", type=str, help=\"Resume the training from snapshot\"\n", + " )\n", + " parser.add_argument(\"--unit\", \"-u\", type=int, default=1000, help=\"Number of units\")\n", + " parser.add_argument(\n", + " \"--noplot\",\n", + " dest=\"plot\",\n", + " action=\"store_false\",\n", + " help=\"Disable PlotReport extension\",\n", + " )\n", + " group = parser.add_argument_group(\"deprecated arguments\")\n", + " group.add_argument(\n", + " \"--gpu\",\n", + " \"-g\",\n", + " dest=\"device\",\n", + " type=int,\n", + " nargs=\"?\",\n", + " const=0,\n", + " help=\"GPU ID (negative value indicates CPU)\",\n", + " )\n", " args = parser.parse_args(args=[])\n", "\n", " device = chainer.get_device(args.device)\n", "\n", - " print('Device: {}'.format(device))\n", - " print('# unit: {}'.format(args.unit))\n", - " print('# Minibatch-size: {}'.format(args.batchsize))\n", - " print('# epoch: {}'.format(args.epoch))\n", - " print('')\n", + " print(\"Device: {}\".format(device))\n", + " print(\"# unit: {}\".format(args.unit))\n", + " print(\"# Minibatch-size: {}\".format(args.batchsize))\n", + " print(\"# epoch: {}\".format(args.epoch))\n", + " print(\"\")\n", "\n", " # Set up a neural network to train\n", " # Classifier reports softmax cross entropy loss and accuracy at every\n", @@ -673,13 +699,13 @@ " train, test = chainer.datasets.get_mnist()\n", "\n", " train_iter = chainer.iterators.SerialIterator(train, args.batchsize)\n", - " test_iter = chainer.iterators.SerialIterator(test, args.batchsize,\n", - " repeat=False, shuffle=False)\n", + " test_iter = chainer.iterators.SerialIterator(\n", + " test, args.batchsize, repeat=False, shuffle=False\n", + " )\n", "\n", " # Set up a trainer\n", - " updater = training.updaters.StandardUpdater(\n", - " train_iter, optimizer, device=device)\n", - " trainer = training.Trainer(updater, (args.epoch, 'epoch'), out=args.out)\n", + " updater = training.updaters.StandardUpdater(train_iter, optimizer, device=device)\n", + " trainer = training.Trainer(updater, (args.epoch, \"epoch\"), out=args.out)\n", "\n", " # Evaluate the model with the test dataset for each epoch\n", " trainer.extend(extensions.Evaluator(test_iter, model, device=device))\n", @@ -688,11 +714,11 @@ " # The \"main\" refers to the target link of the \"main\" optimizer.\n", " # TODO(niboshi): Temporarily disabled for chainerx. Fix it.\n", " if device.xp is not chainerx:\n", - " trainer.extend(extensions.DumpGraph('main/loss'))\n", + " trainer.extend(extensions.DumpGraph(\"main/loss\"))\n", "\n", " # Take a snapshot for each specified epoch\n", " frequency = args.epoch if args.frequency == -1 else max(1, args.frequency)\n", - " trainer.extend(extensions.snapshot(), trigger=(frequency, 'epoch'))\n", + " trainer.extend(extensions.snapshot(), trigger=(frequency, \"epoch\"))\n", "\n", " # Write a log of evaluation statistics for each epoch\n", " trainer.extend(extensions.LogReport())\n", @@ -700,21 +726,35 @@ " # Save two plot images to the result dir\n", " if args.plot and extensions.PlotReport.available():\n", " trainer.extend(\n", - " extensions.PlotReport(['main/loss', 'validation/main/loss'],\n", - " 'epoch', file_name='loss.png'))\n", + " extensions.PlotReport(\n", + " [\"main/loss\", \"validation/main/loss\"], \"epoch\", file_name=\"loss.png\"\n", + " )\n", + " )\n", " trainer.extend(\n", " extensions.PlotReport(\n", - " ['main/accuracy', 'validation/main/accuracy'],\n", - " 'epoch', file_name='accuracy.png'))\n", + " [\"main/accuracy\", \"validation/main/accuracy\"],\n", + " \"epoch\",\n", + " file_name=\"accuracy.png\",\n", + " )\n", + " )\n", "\n", " # Print selected entries of the log to stdout\n", " # Here \"main\" refers to the target link of the \"main\" optimizer again, and\n", " # \"validation\" refers to the default name of the Evaluator extension.\n", " # Entries other than 'epoch' are reported by the Classifier link, called by\n", " # either the updater or the evaluator.\n", - " trainer.extend(extensions.PrintReport(\n", - " ['epoch', 'main/loss', 'validation/main/loss',\n", - " 'main/accuracy', 'validation/main/accuracy', 'elapsed_time']))\n", + " trainer.extend(\n", + " extensions.PrintReport(\n", + " [\n", + " \"epoch\",\n", + " \"main/loss\",\n", + " \"validation/main/loss\",\n", + " \"main/accuracy\",\n", + " \"validation/main/accuracy\",\n", + " \"elapsed_time\",\n", + " ]\n", + " )\n", + " )\n", "\n", " # Print a progress bar to stdout\n", " trainer.extend(extensions.ProgressBar())\n", @@ -727,7 +767,7 @@ " trainer.run()\n", "\n", "\n", - "if __name__ == '__main__':\n", + "if __name__ == \"__main__\":\n", " main()" ] }, @@ -1035,7 +1075,7 @@ } ], "source": [ - "!minikube start --memory 4096 " + "!minikube start --memory 4096" ] }, { diff --git a/examples/models/cpp/buildsystem-override/README.ipynb b/examples/models/cpp/buildsystem-override/README.ipynb index 25a4bac44b..19860b0418 100644 --- a/examples/models/cpp/buildsystem-override/README.ipynb +++ b/examples/models/cpp/buildsystem-override/README.ipynb @@ -166,7 +166,7 @@ ], "source": [ "%writefile .s2i/environment\n", - "MODEL_NAME=CustomSeldonPackage.MyModelClass" + "MODEL_NAME = CustomSeldonPackage.MyModelClass" ] }, { diff --git a/examples/models/custom_metrics/customMetrics.ipynb b/examples/models/custom_metrics/customMetrics.ipynb index 21f65817d5..49e5f0d9f2 100644 --- a/examples/models/custom_metrics/customMetrics.ipynb +++ b/examples/models/custom_metrics/customMetrics.ipynb @@ -196,9 +196,9 @@ } ], "source": [ - "response=json.loads(responseRaw[0])\n", + "response = json.loads(responseRaw[0])\n", "print(response)\n", - "assert(len(response[\"meta\"][\"metrics\"]) == 3)" + "assert len(response[\"meta\"][\"metrics\"]) == 3" ] }, { @@ -282,9 +282,9 @@ } ], "source": [ - "response=json.loads(responseRaw[0])\n", + "response = json.loads(responseRaw[0])\n", "print(response)\n", - "assert(response['data'][\"result\"][0][\"metric\"][\"__name__\"]=='mycounter_total')" + "assert response[\"data\"][\"result\"][0][\"metric\"][\"__name__\"] == \"mycounter_total\"" ] }, { @@ -313,9 +313,9 @@ } ], "source": [ - "response=json.loads(\"\".join(responseRaw))\n", + "response = json.loads(\"\".join(responseRaw))\n", "print(response)\n", - "assert(len(response[\"meta\"][\"metrics\"]) == 3)" + "assert len(response[\"meta\"][\"metrics\"]) == 3" ] }, { @@ -359,10 +359,13 @@ } ], "source": [ - "response=json.loads(responseRaw[0])\n", + "response = json.loads(responseRaw[0])\n", "print(response)\n", - "assert(response['data'][\"result\"][0][\"metric\"][\"__name__\"]=='mycounter_total')\n", - "assert(response['data'][\"result\"][0][\"metric\"][\"image_name\"]=='seldonio/model-with-metrics')" + "assert response[\"data\"][\"result\"][0][\"metric\"][\"__name__\"] == \"mycounter_total\"\n", + "assert (\n", + " response[\"data\"][\"result\"][0][\"metric\"][\"image_name\"]\n", + " == \"seldonio/model-with-metrics\"\n", + ")" ] }, { diff --git a/examples/models/custom_metrics/tfservingMetrics.ipynb b/examples/models/custom_metrics/tfservingMetrics.ipynb index a12bed2043..ffd570de7a 100644 --- a/examples/models/custom_metrics/tfservingMetrics.ipynb +++ b/examples/models/custom_metrics/tfservingMetrics.ipynb @@ -179,9 +179,11 @@ "metadata": {}, "outputs": [], "source": [ - "response=json.loads(responseRaw[0])\n", + "response = json.loads(responseRaw[0])\n", "print(response)\n", - "assert(response['data'][\"result\"][0][\"metric\"][\"__name__\"]==':tensorflow:core:graph_runs')" + "assert (\n", + " response[\"data\"][\"result\"][0][\"metric\"][\"__name__\"] == \":tensorflow:core:graph_runs\"\n", + ")" ] }, { diff --git a/examples/models/gpu_tensorflow_deep_mnist/gpu_tensorflow_deep_mnist.ipynb b/examples/models/gpu_tensorflow_deep_mnist/gpu_tensorflow_deep_mnist.ipynb index 6fc9a85ebb..46dc54fe52 100644 --- a/examples/models/gpu_tensorflow_deep_mnist/gpu_tensorflow_deep_mnist.ipynb +++ b/examples/models/gpu_tensorflow_deep_mnist/gpu_tensorflow_deep_mnist.ipynb @@ -365,6 +365,7 @@ "outputs": [], "source": [ "import tensorflow as tf\n", + "\n", "sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))" ] }, @@ -400,22 +401,24 @@ "outputs": [], "source": [ "from tensorflow.examples.tutorials.mnist import input_data\n", - "mnist = input_data.read_data_sets(\"MNIST_data/\", one_hot = True)\n", + "\n", + "mnist = input_data.read_data_sets(\"MNIST_data/\", one_hot=True)\n", "import tensorflow as tf\n", "\n", - "if __name__ == '__main__':\n", - " \n", - " x = tf.placeholder(tf.float32, [None,784], name=\"x\")\n", + "if __name__ == \"__main__\":\n", "\n", - " W = tf.Variable(tf.zeros([784,10]))\n", + " x = tf.placeholder(tf.float32, [None, 784], name=\"x\")\n", + "\n", + " W = tf.Variable(tf.zeros([784, 10]))\n", " b = tf.Variable(tf.zeros([10]))\n", "\n", - " y = tf.nn.softmax(tf.matmul(x,W) + b, name=\"y\")\n", + " y = tf.nn.softmax(tf.matmul(x, W) + b, name=\"y\")\n", "\n", " y_ = tf.placeholder(tf.float32, [None, 10])\n", "\n", - "\n", - " cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))\n", + " cross_entropy = tf.reduce_mean(\n", + " -tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1])\n", + " )\n", "\n", " train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)\n", "\n", @@ -428,14 +431,13 @@ " batch_xs, batch_ys = mnist.train.next_batch(100)\n", " sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})\n", "\n", - " correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))\n", + " correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))\n", " accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))\n", - " print(sess.run(accuracy, feed_dict = {x: mnist.test.images, y_:mnist.test.labels}))\n", + " print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))\n", "\n", " saver = tf.train.Saver()\n", "\n", - " saver.save(sess, \"model/deep_mnist_model\")\n", - "\n" + " saver.save(sess, \"model/deep_mnist_model\")" ] }, { diff --git a/examples/models/h2o_mojo/h2o_model.ipynb b/examples/models/h2o_mojo/h2o_model.ipynb index 7a75ed636c..410649ddfe 100644 --- a/examples/models/h2o_mojo/h2o_model.ipynb +++ b/examples/models/h2o_mojo/h2o_model.ipynb @@ -127,17 +127,19 @@ ], "source": [ "import h2o\n", + "\n", "h2o.init()\n", "from h2o.estimators.glm import H2OGeneralizedLinearEstimator\n", - "path = \"https://s3.amazonaws.com/h2o-public-test-data/smalldata/prostate/prostate.csv.zip\"\n", + "\n", + "path = (\n", + " \"https://s3.amazonaws.com/h2o-public-test-data/smalldata/prostate/prostate.csv.zip\"\n", + ")\n", "h2o_df = h2o.import_file(path)\n", - "h2o_df['CAPSULE'] = h2o_df['CAPSULE'].asfactor()\n", - "model = H2OGeneralizedLinearEstimator(family = \"binomial\")\n", - "model.train(y = \"CAPSULE\",\n", - " x = [\"AGE\", \"RACE\", \"PSA\", \"GLEASON\"],\n", - " training_frame = h2o_df)\n", + "h2o_df[\"CAPSULE\"] = h2o_df[\"CAPSULE\"].asfactor()\n", + "model = H2OGeneralizedLinearEstimator(family=\"binomial\")\n", + "model.train(y=\"CAPSULE\", x=[\"AGE\", \"RACE\", \"PSA\", \"GLEASON\"], training_frame=h2o_df)\n", "modelfile = model.download_mojo(path=\"./experiment/\", get_genmodel_jar=False)\n", - "print(\"Model saved to \" + modelfile)\n" + "print(\"Model saved to \" + modelfile)" ] }, { @@ -2073,7 +2075,7 @@ } ], "source": [ - "!minikube start --memory 4096 " + "!minikube start --memory 4096" ] }, { diff --git a/examples/models/metadata/graph_metadata.ipynb b/examples/models/metadata/graph_metadata.ipynb index c5e679daa8..6dbe5e37b9 100644 --- a/examples/models/metadata/graph_metadata.ipynb +++ b/examples/models/metadata/graph_metadata.ipynb @@ -249,8 +249,11 @@ "metadata": {}, "outputs": [], "source": [ - "import requests\n", "import time\n", + "\n", + "import requests\n", + "\n", + "\n", "def getWithRetry(url):\n", " for i in range(3):\n", " r = requests.get(url)\n", @@ -258,7 +261,7 @@ " meta = r.json()\n", " return meta\n", " else:\n", - " print(\"Failed request with status code \",r.status_code)\n", + " print(\"Failed request with status code \", r.status_code)\n", " time.sleep(3)" ] }, @@ -290,7 +293,9 @@ } ], "source": [ - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/graph-metadata-single/api/v1.0/metadata\")\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/graph-metadata-single/api/v1.0/metadata\"\n", + ")\n", "\n", "assert meta == {\n", " \"name\": \"example\",\n", @@ -300,10 +305,16 @@ " \"platform\": \"seldon\",\n", " \"versions\": [\"generic-node/v0.4\"],\n", " \"inputs\": [\n", - " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-input\"], \"shape\": [1]}}\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"node-input\"], \"shape\": [1]},\n", + " }\n", " ],\n", " \"outputs\": [\n", - " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]}}\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]},\n", + " }\n", " ],\n", " }\n", " },\n", @@ -352,19 +363,28 @@ ], "source": [ "import requests\n", - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/graph-metadata-single/api/v1.0/metadata/model\")\n", + "\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/graph-metadata-single/api/v1.0/metadata/model\"\n", + ")\n", "\n", "assert meta == {\n", " \"custom\": {},\n", " \"name\": \"single-node\",\n", " \"platform\": \"seldon\",\n", " \"versions\": [\"generic-node/v0.4\"],\n", - " \"inputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-input\"], \"shape\": [1]},\n", - " }],\n", - " \"outputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]},\n", - " }],\n", + " \"inputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"node-input\"], \"shape\": [1]},\n", + " }\n", + " ],\n", + " \"outputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]},\n", + " }\n", + " ],\n", "}\n", "\n", "meta" @@ -548,7 +568,10 @@ ], "source": [ "import requests\n", - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/graph-metadata-two-levels/api/v1.0/metadata\")\n", + "\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/graph-metadata-two-levels/api/v1.0/metadata\"\n", + ")\n", "\n", "assert meta == {\n", " \"name\": \"example\",\n", @@ -558,7 +581,10 @@ " \"platform\": \"seldon\",\n", " \"versions\": [\"generic-node/v0.4\"],\n", " \"inputs\": [\n", - " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"a1\", \"a2\"], \"shape\": [2]}}\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"a1\", \"a2\"], \"shape\": [2]},\n", + " }\n", " ],\n", " \"outputs\": [\n", " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"a3\"], \"shape\": [1]}}\n", @@ -572,9 +598,12 @@ " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"a3\"], \"shape\": [1]}}\n", " ],\n", " \"outputs\": [\n", - " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"b1\", \"b2\"], \"shape\": [2]}}\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"b1\", \"b2\"], \"shape\": [2]},\n", + " }\n", " ],\n", - " } \n", + " },\n", " },\n", " \"graphinputs\": [\n", " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"a1\", \"a2\"], \"shape\": [2]}}\n", @@ -799,7 +828,10 @@ ], "source": [ "import requests\n", - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/graph-metadata-combiner/api/v1.0/metadata\")\n", + "\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/graph-metadata-combiner/api/v1.0/metadata\"\n", + ")\n", "\n", "assert meta == {\n", " \"name\": \"example\",\n", @@ -813,7 +845,10 @@ " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"c2\"], \"shape\": [1]}},\n", " ],\n", " \"outputs\": [\n", - " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"combiner-output\"], \"shape\": [1]}}\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"combiner-output\"], \"shape\": [1]},\n", + " }\n", " ],\n", " },\n", " \"node-one\": {\n", @@ -821,7 +856,10 @@ " \"platform\": \"seldon\",\n", " \"versions\": [\"generic-node/v0.4\"],\n", " \"inputs\": [\n", - " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"a\", \"b\"], \"shape\": [2]}},\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"a\", \"b\"], \"shape\": [2]},\n", + " },\n", " ],\n", " \"outputs\": [\n", " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"c1\"], \"shape\": [1]}}\n", @@ -832,18 +870,24 @@ " \"platform\": \"seldon\",\n", " \"versions\": [\"generic-node/v0.4\"],\n", " \"inputs\": [\n", - " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"a\", \"b\"], \"shape\": [2]}},\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"a\", \"b\"], \"shape\": [2]},\n", + " },\n", " ],\n", " \"outputs\": [\n", " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"c2\"], \"shape\": [1]}}\n", " ],\n", - " } \n", + " },\n", " },\n", " \"graphinputs\": [\n", " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"a\", \"b\"], \"shape\": [2]}},\n", " ],\n", " \"graphoutputs\": [\n", - " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"combiner-output\"], \"shape\": [1]}}\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"combiner-output\"], \"shape\": [1]},\n", + " }\n", " ],\n", "}\n", "\n", @@ -1037,16 +1081,19 @@ ], "source": [ "import requests\n", - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/graph-metadata-router/api/v1.0/metadata\")\n", + "\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/graph-metadata-router/api/v1.0/metadata\"\n", + ")\n", "\n", "assert meta == {\n", " \"name\": \"example\",\n", " \"models\": {\n", - " 'node-router': {\n", - " 'name': 'seldonio/metadata-generic-node',\n", - " 'versions': ['0.4'],\n", - " 'inputs': [],\n", - " 'outputs': [],\n", + " \"node-router\": {\n", + " \"name\": \"seldonio/metadata-generic-node\",\n", + " \"versions\": [\"0.4\"],\n", + " \"inputs\": [],\n", + " \"outputs\": [],\n", " },\n", " \"node-one\": {\n", " \"name\": \"node-one\",\n", @@ -1056,7 +1103,10 @@ " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"a\", \"b\"], \"shape\": [2]}}\n", " ],\n", " \"outputs\": [\n", - " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]}}\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]},\n", + " }\n", " ],\n", " },\n", " \"node-two\": {\n", @@ -1067,9 +1117,12 @@ " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"a\", \"b\"], \"shape\": [2]}}\n", " ],\n", " \"outputs\": [\n", - " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]}}\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]},\n", + " }\n", " ],\n", - " } \n", + " },\n", " },\n", " \"graphinputs\": [\n", " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"a\", \"b\"], \"shape\": [2]}}\n", @@ -1258,7 +1311,10 @@ ], "source": [ "import requests\n", - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/graph-metadata-input/api/v1.0/metadata\")\n", + "\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/graph-metadata-input/api/v1.0/metadata\"\n", + ")\n", "\n", "assert meta == {\n", " \"name\": \"example\",\n", @@ -1267,31 +1323,46 @@ " \"name\": \"node-input-transformer\",\n", " \"platform\": \"seldon\",\n", " \"versions\": [\"generic-node/v0.4\"],\n", - " \"inputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"transformer-input\"], \"shape\": [1]},\n", - " }],\n", - " \"outputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"transformer-output\"], \"shape\": [1]},\n", - " }],\n", + " \"inputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"transformer-input\"], \"shape\": [1]},\n", + " }\n", + " ],\n", + " \"outputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"transformer-output\"], \"shape\": [1]},\n", + " }\n", + " ],\n", " },\n", " \"node\": {\n", " \"name\": \"node\",\n", " \"platform\": \"seldon\",\n", " \"versions\": [\"generic-node/v0.4\"],\n", - " \"inputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"transformer-output\"], \"shape\": [1]},\n", - " }],\n", - " \"outputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]},\n", - " }],\n", - " } \n", + " \"inputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"transformer-output\"], \"shape\": [1]},\n", + " }\n", + " ],\n", + " \"outputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]},\n", + " }\n", + " ],\n", + " },\n", " },\n", - " \"graphinputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"transformer-input\"], \"shape\": [1]}\n", - " }],\n", - " \"graphoutputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]}\n", - " }],\n", + " \"graphinputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"transformer-input\"], \"shape\": [1]},\n", + " }\n", + " ],\n", + " \"graphoutputs\": [\n", + " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-output\"], \"shape\": [1]}}\n", + " ],\n", "}\n", "\n", "meta" @@ -1472,7 +1543,10 @@ ], "source": [ "import requests\n", - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/graph-metadata-output/api/v1.0/metadata\")\n", + "\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/graph-metadata-output/api/v1.0/metadata\"\n", + ")\n", "\n", "assert meta == {\n", " \"name\": \"example\",\n", @@ -1481,31 +1555,46 @@ " \"name\": \"node-output-transformer\",\n", " \"platform\": \"seldon\",\n", " \"versions\": [\"generic-node/v0.4\"],\n", - " \"inputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"transformer-input\"], \"shape\": [1]},\n", - " }],\n", - " \"outputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"transformer-output\"], \"shape\": [1]},\n", - " }],\n", + " \"inputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"transformer-input\"], \"shape\": [1]},\n", + " }\n", + " ],\n", + " \"outputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"transformer-output\"], \"shape\": [1]},\n", + " }\n", + " ],\n", " },\n", " \"node\": {\n", " \"name\": \"node\",\n", " \"platform\": \"seldon\",\n", " \"versions\": [\"generic-node/v0.4\"],\n", - " \"inputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-input\"], \"shape\": [1]},\n", - " }],\n", - " \"outputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"transformer-input\"], \"shape\": [1]},\n", - " }],\n", - " } \n", + " \"inputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"node-input\"], \"shape\": [1]},\n", + " }\n", + " ],\n", + " \"outputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"transformer-input\"], \"shape\": [1]},\n", + " }\n", + " ],\n", + " },\n", " },\n", - " \"graphinputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-input\"], \"shape\": [1]}\n", - " }],\n", - " \"graphoutputs\": [{\n", - " \"messagetype\": \"tensor\", \"schema\": {\"names\": [\"transformer-output\"], \"shape\": [1]}\n", - " }],\n", + " \"graphinputs\": [\n", + " {\"messagetype\": \"tensor\", \"schema\": {\"names\": [\"node-input\"], \"shape\": [1]}}\n", + " ],\n", + " \"graphoutputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"transformer-output\"], \"shape\": [1]},\n", + " }\n", + " ],\n", "}\n", "\n", "meta" diff --git a/examples/models/metadata/metadata.ipynb b/examples/models/metadata/metadata.ipynb index ba6122839c..fdbd935776 100644 --- a/examples/models/metadata/metadata.ipynb +++ b/examples/models/metadata/metadata.ipynb @@ -91,8 +91,11 @@ "metadata": {}, "outputs": [], "source": [ - "import requests\n", "import time\n", + "\n", + "import requests\n", + "\n", + "\n", "def getWithRetry(url, expected_code=requests.codes.ok):\n", " for i in range(3):\n", " r = requests.get(url)\n", @@ -100,7 +103,7 @@ " meta = r.json()\n", " return meta\n", " else:\n", - " print(\"Failed request with status code \",r.status_code)\n", + " print(\"Failed request with status code \", r.status_code)\n", " time.sleep(3)" ] }, @@ -300,16 +303,20 @@ } ], "source": [ - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/seldon-model-init-metadata/api/v1.0/metadata/my-model\")\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/seldon-model-init-metadata/api/v1.0/metadata/my-model\"\n", + ")\n", "\n", "assert meta == {\n", " \"name\": \"my-model-name\",\n", " \"versions\": [\"my-model-version-01\"],\n", " \"platform\": \"seldon\",\n", - " \"inputs\": [{\n", - " \"messagetype\": \"tensor\",\n", - " \"schema\": {\"names\": [\"a\", \"b\", \"c\", \"d\"], \"shape\": [4]},\n", - " }],\n", + " \"inputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"a\", \"b\", \"c\", \"d\"], \"shape\": [4]},\n", + " }\n", + " ],\n", " \"outputs\": [{\"messagetype\": \"tensor\", \"schema\": {\"shape\": [1]}}],\n", " \"custom\": {\"author\": \"seldon-dev\"},\n", "}\n", @@ -351,7 +358,9 @@ } ], "source": [ - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/seldon-model-init-metadata/api/v1.0/metadata\")\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/seldon-model-init-metadata/api/v1.0/metadata\"\n", + ")\n", "\n", "assert meta == {\n", " \"name\": \"example\",\n", @@ -360,18 +369,22 @@ " \"name\": \"my-model-name\",\n", " \"platform\": \"seldon\",\n", " \"versions\": [\"my-model-version-01\"],\n", - " \"inputs\": [{\n", - " \"messagetype\": \"tensor\",\n", - " \"schema\": {\"names\": [\"a\", \"b\", \"c\", \"d\"], \"shape\": [4]},\n", - " }],\n", + " \"inputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"a\", \"b\", \"c\", \"d\"], \"shape\": [4]},\n", + " }\n", + " ],\n", " \"outputs\": [{\"messagetype\": \"tensor\", \"schema\": {\"shape\": [1]}}],\n", " \"custom\": {\"author\": \"seldon-dev\"},\n", " }\n", " },\n", - " \"graphinputs\": [{\n", - " \"messagetype\": \"tensor\",\n", - " \"schema\": {\"names\": [\"a\", \"b\", \"c\", \"d\"], \"shape\": [4]},\n", - " }],\n", + " \"graphinputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"a\", \"b\", \"c\", \"d\"], \"shape\": [4]},\n", + " }\n", + " ],\n", " \"graphoutputs\": [{\"messagetype\": \"tensor\", \"schema\": {\"shape\": [1]}}],\n", "}\n", "\n", @@ -508,17 +521,21 @@ } ], "source": [ - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/seldon-model-environ-metadata/api/v1.0/metadata/my-model\")\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/seldon-model-environ-metadata/api/v1.0/metadata/my-model\"\n", + ")\n", "\n", "\n", "assert meta == {\n", " \"name\": \"second-example-model-name\",\n", " \"versions\": [\"my-model-version-01\"],\n", " \"platform\": \"seldon\",\n", - " \"inputs\": [{\n", - " \"messagetype\": \"tensor\",\n", - " \"schema\": {\"names\": [\"alpha\", \"beta\", \"gamma\", \"delta\"], \"shape\": [4]},\n", - " }],\n", + " \"inputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"alpha\", \"beta\", \"gamma\", \"delta\"], \"shape\": [4]},\n", + " }\n", + " ],\n", " \"outputs\": [{\"messagetype\": \"tensor\", \"schema\": {\"shape\": [1]}}],\n", " \"custom\": {\"author\": \"seldon-dev\", \"purpose\": \"tutorial\"},\n", "}\n", @@ -560,7 +577,9 @@ } ], "source": [ - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/seldon-model-environ-metadata/api/v1.0/metadata\")\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/seldon-model-environ-metadata/api/v1.0/metadata\"\n", + ")\n", "\n", "assert meta == {\n", " \"name\": \"example\",\n", @@ -569,18 +588,25 @@ " \"name\": \"second-example-model-name\",\n", " \"platform\": \"seldon\",\n", " \"versions\": [\"my-model-version-01\"],\n", - " \"inputs\": [{\n", - " \"messagetype\": \"tensor\",\n", - " \"schema\": {\"names\": [\"alpha\", \"beta\", \"gamma\", \"delta\"], \"shape\": [4]},\n", - " }],\n", + " \"inputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\n", + " \"names\": [\"alpha\", \"beta\", \"gamma\", \"delta\"],\n", + " \"shape\": [4],\n", + " },\n", + " }\n", + " ],\n", " \"outputs\": [{\"messagetype\": \"tensor\", \"schema\": {\"shape\": [1]}}],\n", " \"custom\": {\"author\": \"seldon-dev\", \"purpose\": \"tutorial\"},\n", " }\n", " },\n", - " \"graphinputs\": [{\n", - " \"messagetype\": \"tensor\",\n", - " \"schema\": {\"names\": [\"alpha\", \"beta\", \"gamma\", \"delta\"], \"shape\": [4]},\n", - " }],\n", + " \"graphinputs\": [\n", + " {\n", + " \"messagetype\": \"tensor\",\n", + " \"schema\": {\"names\": [\"alpha\", \"beta\", \"gamma\", \"delta\"], \"shape\": [4]},\n", + " }\n", + " ],\n", " \"graphoutputs\": [{\"messagetype\": \"tensor\", \"schema\": {\"shape\": [1]}}],\n", "}\n", "\n", @@ -702,14 +728,17 @@ } ], "source": [ - "meta = getWithRetry(\"http://localhost:8003/seldon/seldon/seldon-model-invalid-environ-metadata/api/v1.0/metadata/my-model\", 500)\n", + "meta = getWithRetry(\n", + " \"http://localhost:8003/seldon/seldon/seldon-model-invalid-environ-metadata/api/v1.0/metadata/my-model\",\n", + " 500,\n", + ")\n", "\n", "assert meta == {\n", - " 'status': {\n", - " 'code': -1,\n", - " 'info': 'Model metadata unavailable',\n", - " 'reason': 'MICROSERVICE_BAD_METADATA',\n", - " 'status': 1\n", + " \"status\": {\n", + " \"code\": -1,\n", + " \"info\": \"Model metadata unavailable\",\n", + " \"reason\": \"MICROSERVICE_BAD_METADATA\",\n", + " \"status\": 1,\n", " }\n", "}\n", "\n", diff --git a/examples/models/metadata/metadata_schema_examples.ipynb b/examples/models/metadata/metadata_schema_examples.ipynb index 65395759a0..91ca80c6ad 100644 --- a/examples/models/metadata/metadata_schema_examples.ipynb +++ b/examples/models/metadata/metadata_schema_examples.ipynb @@ -13,8 +13,9 @@ "metadata": {}, "outputs": [], "source": [ - "from seldon_core.metadata import validate_model_metadata\n", - "import yaml" + "import yaml\n", + "\n", + "from seldon_core.metadata import validate_model_metadata" ] }, { diff --git a/examples/models/mlflow_server_ab_test_ambassador/mlflow_server_ab_test_ambassador.ipynb b/examples/models/mlflow_server_ab_test_ambassador/mlflow_server_ab_test_ambassador.ipynb index 1ddb861480..850a0da946 100644 --- a/examples/models/mlflow_server_ab_test_ambassador/mlflow_server_ab_test_ambassador.ipynb +++ b/examples/models/mlflow_server_ab_test_ambassador/mlflow_server_ab_test_ambassador.ipynb @@ -55,8 +55,9 @@ "metadata": {}, "outputs": [], "source": [ - "import pandas as pd\n", "import numpy as np\n", + "import pandas as pd\n", + "\n", "from seldon_core.seldon_client import SeldonClient" ] }, @@ -391,26 +392,25 @@ "metadata": {}, "outputs": [], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import math\n", - "import numpy as np\n", "import subprocess\n", "\n", - "HOST = \"localhost\" # Add the URL you found above\n", - "port = \"80\" # Make sure you use the port above\n", + "import numpy as np\n", + "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", + "HOST = \"localhost\" # Add the URL you found above\n", + "port = \"80\" # Make sure you use the port above\n", "batch = x_0\n", "payload_type = \"ndarray\"\n", "\n", "sc = SeldonClient(\n", - " gateway=\"ambassador\", \n", - " namespace=\"seldon\",\n", - " gateway_endpoint=HOST + \":\" + port)\n", + " gateway=\"ambassador\", namespace=\"seldon\", gateway_endpoint=HOST + \":\" + port\n", + ")\n", "\n", "client_prediction = sc.predict(\n", - " data=batch, \n", - " deployment_name=\"mlflow-deployment\",\n", - " names=[],\n", - " payload_type=payload_type)\n", + " data=batch, deployment_name=\"mlflow-deployment\", names=[], payload_type=payload_type\n", + ")\n", "\n", "print(client_prediction.response)" ] @@ -521,7 +521,7 @@ "metadata": {}, "outputs": [], "source": [ - "!kubectl get svc grafana-prom -o jsonpath='{.spec.ports[0].nodePort}' " + "!kubectl get svc grafana-prom -o jsonpath='{.spec.ports[0].nodePort}'" ] }, { @@ -551,39 +551,38 @@ "outputs": [], "source": [ "sc = SeldonClient(\n", - " gateway=\"ambassador\", \n", - " namespace=\"seldon\",\n", - " deployment_name='wines-classifier'\n", + " gateway=\"ambassador\", namespace=\"seldon\", deployment_name=\"wines-classifier\"\n", ")\n", "\n", + "\n", "def _get_reward(y, y_pred):\n", " if y == y_pred:\n", - " return 500 \n", - " \n", + " return 500\n", + "\n", " return 1 / np.square(y - y_pred)\n", "\n", + "\n", "def _test_row(row):\n", " input_features = row[:-1]\n", " feature_names = input_features.index.to_list()\n", " X = input_features.values.reshape(1, -1)\n", " y = row[-1].reshape(1, -1)\n", - " \n", + "\n", " # Note that we are re-using the SeldonClient defined previously\n", - " r = sc.predict(\n", - " deployment_name=\"mlflow-deployment\",\n", - " data=X,\n", - " names=feature_names)\n", - " \n", - " y_pred = r.response['data']['tensor']['values']\n", + " r = sc.predict(deployment_name=\"mlflow-deployment\", data=X, names=feature_names)\n", + "\n", + " y_pred = r.response[\"data\"][\"tensor\"][\"values\"]\n", " reward = _get_reward(y, y_pred)\n", " sc.feedback(\n", " deployment_name=\"mlflow-deployment\",\n", " prediction_request=r.request,\n", " prediction_response=r.response,\n", - " reward=reward)\n", - " \n", + " reward=reward,\n", + " )\n", + "\n", " return reward[0]\n", "\n", + "\n", "data.apply(_test_row, axis=1)" ] }, diff --git a/examples/models/openvino/openvino-squeezenet.ipynb b/examples/models/openvino/openvino-squeezenet.ipynb index 91472af7b7..3e6a11b79e 100644 --- a/examples/models/openvino/openvino-squeezenet.ipynb +++ b/examples/models/openvino/openvino-squeezenet.ipynb @@ -104,43 +104,49 @@ "outputs": [], "source": [ "%matplotlib inline\n", - "import numpy as np\n", - "from keras.applications.imagenet_utils import preprocess_input, decode_predictions\n", - "from keras.preprocessing import image\n", - "import sys\n", "import json\n", + "import sys\n", + "\n", "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from keras.applications.imagenet_utils import decode_predictions, preprocess_input\n", + "from keras.preprocessing import image\n", + "\n", "from seldon_core.seldon_client import SeldonClient\n", "\n", + "\n", "def getImage(path):\n", " img = image.load_img(path, target_size=(227, 227))\n", " x = image.img_to_array(img)\n", - " plt.imshow(x/255.)\n", + " plt.imshow(x / 255.0)\n", " x = np.expand_dims(x, axis=0)\n", " x = preprocess_input(x)\n", " return x\n", "\n", + "\n", "X = getImage(\"car.png\")\n", - "X = X.transpose((0,3,1,2))\n", + "X = X.transpose((0, 3, 1, 2))\n", "print(X.shape)\n", "\n", - "sc = SeldonClient(deployment_name=\"openvino-model\",namespace=\"seldon\")\n", + "sc = SeldonClient(deployment_name=\"openvino-model\", namespace=\"seldon\")\n", "\n", - "response = sc.predict(gateway=\"ambassador\",transport=\"grpc\",data=X, client_return_type=\"proto\")\n", + "response = sc.predict(\n", + " gateway=\"ambassador\", transport=\"grpc\", data=X, client_return_type=\"proto\"\n", + ")\n", "\n", "result = response.response.data.tensor.values\n", - " \n", + "\n", "result = np.array(result)\n", - "result = result.reshape(1,1000)\n", + "result = result.reshape(1, 1000)\n", "\n", - "with open('imagenet_classes.json') as f:\n", + "with open(\"imagenet_classes.json\") as f:\n", " cnames = eval(f.read())\n", "\n", " for i in range(result.shape[0]):\n", - " single_result = result[[i],...]\n", + " single_result = result[[i], ...]\n", " ma = np.argmax(single_result)\n", - " print(\"\\t\",i, cnames[ma])\n", - " assert(cnames[ma]==\"sports car, sport car\")\n" + " print(\"\\t\", i, cnames[ma])\n", + " assert cnames[ma] == \"sports car, sport car\"" ] }, { diff --git a/examples/models/payload_logging/payload_logging.ipynb b/examples/models/payload_logging/payload_logging.ipynb index b8ec641fbb..ac50864cae 100644 --- a/examples/models/payload_logging/payload_logging.ipynb +++ b/examples/models/payload_logging/payload_logging.ipynb @@ -76,9 +76,10 @@ "source": [ "from IPython.core.magic import register_line_cell_magic\n", "\n", + "\n", "@register_line_cell_magic\n", "def writetemplate(line, cell):\n", - " with open(line, 'w') as f:\n", + " with open(line, \"w\") as f:\n", " f.write(cell.format(**globals()))" ] }, diff --git a/examples/models/resnet/reset.ipynb b/examples/models/resnet/reset.ipynb index 8416ccf195..71998b5ba0 100644 --- a/examples/models/resnet/reset.ipynb +++ b/examples/models/resnet/reset.ipynb @@ -143,18 +143,17 @@ "metadata": {}, "outputs": [], "source": [ - "import json\n", - "import requests\n", "import base64\n", - "from proto import prediction_pb2\n", - "from proto import prediction_pb2_grpc\n", + "import datetime\n", + "import json\n", + "import pickle\n", + "\n", + "import cv2\n", "import grpc\n", "import numpy as np\n", - "import pickle\n", + "import requests\n", "import tensorflow as tf\n", - "import cv2\n", - "import datetime\n", - "import tensorflow as tf\n" + "from proto import prediction_pb2, prediction_pb2_grpc" ] }, { @@ -165,88 +164,122 @@ "source": [ "def image_2_vector(input_file):\n", " nparr = np.fromfile(input_file, dtype=np.float32)\n", - " print(\"nparr\",nparr.dtype,nparr.shape)\n", + " print(\"nparr\", nparr.dtype, nparr.shape)\n", " img = cv2.imdecode(nparr, cv2.IMREAD_ANYCOLOR)\n", - " print(\"img\",img.dtype,img.shape)\n", - " print(\"Initial size\",img.shape)\n", + " print(\"img\", img.dtype, img.shape)\n", + " print(\"Initial size\", img.shape)\n", " image = cv2.resize(img, (w, h))\n", - " print(\"image\",image.dtype)\n", - " print(\"Converted size\",image.shape)\n", + " print(\"image\", image.dtype)\n", + " print(\"Converted size\", image.shape)\n", "\n", " vector = image.reshape((w * h * 3))\n", - " print(\"vector shape\",vector.shape, \"vector type\", vector.dtype )\n", + " print(\"vector shape\", vector.shape, \"vector type\", vector.dtype)\n", " return vector\n", "\n", + "\n", "def image_2_bytes(input_file):\n", " with open(input_file, \"rb\") as binary_file:\n", " # Read the whole file at once\n", " data = binary_file.read()\n", "\n", - " #data = data.tobytes()\n", - " #print(data)\n", + " # data = data.tobytes()\n", + " # print(data)\n", " print(\"binary data size:\", len(data), type(data))\n", " return data\n", "\n", - "def run(function,image_path,iterations=1):\n", + "\n", + "def run(function, image_path, iterations=1):\n", " w = 224\n", " h = 224\n", "\n", " # NOTE(gRPC Python Team): .close() is possible on a channel and should be\n", " # used in circumstances in which the with statement does not fit the needs\n", " # of the code.\n", - " with grpc.insecure_channel('localhost:5000') as channel:\n", + " with grpc.insecure_channel(\"localhost:5000\") as channel:\n", " stub = prediction_pb2_grpc.ModelStub(channel)\n", " print(\"seldon stub\", stub)\n", " start_time = datetime.datetime.now()\n", - " processing_times = np.zeros((0),int)\n", + " processing_times = np.zeros((0), int)\n", "\n", " img = cv2.imread(image_path)\n", " print(\"img type\", type(img))\n", - " print(\"img\",img.shape)\n", - " print(\"Initial size\",img.shape)\n", + " print(\"img\", img.shape)\n", + " print(\"Initial size\", img.shape)\n", " image = cv2.resize(img, (w, h))\n", " image = image.reshape(1, w, h, 3)\n", - " print(\"image\",image.dtype)\n", - " print(\"Converted size\",image.shape)\n", - " \n", + " print(\"image\", image.dtype)\n", + " print(\"Converted size\", image.shape)\n", + "\n", " if function == \"tensor\":\n", " datadef = prediction_pb2.DefaultData(\n", - " names = 'x',\n", - " tensor = prediction_pb2.Tensor(\n", - " shape = image.shape,\n", - " values = image.ravel().tolist()\n", - " )\n", + " names=\"x\",\n", + " tensor=prediction_pb2.Tensor(\n", + " shape=image.shape, values=image.ravel().tolist()\n", + " ),\n", " )\n", " elif function == \"tftensor\":\n", " print(\"Create tftensor\")\n", " datadef = prediction_pb2.DefaultData(\n", - " names = 'x',\n", - " tftensor = tf.make_tensor_proto(image)\n", + " names=\"x\", tftensor=tf.make_tensor_proto(image)\n", " )\n", - " \n", - " GRPC_request = prediction_pb2.SeldonMessage(\n", - " data = datadef\n", - " )\n", - " \n", + "\n", + " GRPC_request = prediction_pb2.SeldonMessage(data=datadef)\n", + "\n", " for I in range(iterations):\n", " start_time = datetime.datetime.now()\n", " response = stub.Predict(request=GRPC_request)\n", " end_time = datetime.datetime.now()\n", " duration = (end_time - start_time).total_seconds() * 1000\n", - " processing_times = np.append(processing_times,np.array([int(duration)]))\n", - " \n", - " print('processing time for all iterations')\n", + " processing_times = np.append(processing_times, np.array([int(duration)]))\n", + "\n", + " print(\"processing time for all iterations\")\n", " for x in processing_times:\n", - " print(x,\"ms\")\n", - " print('processing_statistics')\n", - " print('average time:',round(np.average(processing_times),1), 'ms; average speed:', round(1000/np.average(processing_times),1),'fps')\n", - " print('median time:',round(np.median(processing_times),1), 'ms; median speed:',round(1000/np.median(processing_times),1),'fps')\n", - " print('max time:',round(np.max(processing_times),1), 'ms; max speed:',round(1000/np.max(processing_times),1),'fps')\n", - " print('min time:',round(np.min(processing_times),1),'ms; min speed:',round(1000/np.min(processing_times),1),'fps')\n", - " print('time percentile 90:',round(np.percentile(processing_times,90),1),'ms; speed percentile 90:',round(1000/np.percentile(processing_times,90),1),'fps')\n", - " print('time percentile 50:',round(np.percentile(processing_times,50),1),'ms; speed percentile 50:',round(1000/np.percentile(processing_times,50),1),'fps')\n", - " print('time standard deviation:',round(np.std(processing_times)))\n", - " print('time variance:',round(np.var(processing_times)))\n" + " print(x, \"ms\")\n", + " print(\"processing_statistics\")\n", + " print(\n", + " \"average time:\",\n", + " round(np.average(processing_times), 1),\n", + " \"ms; average speed:\",\n", + " round(1000 / np.average(processing_times), 1),\n", + " \"fps\",\n", + " )\n", + " print(\n", + " \"median time:\",\n", + " round(np.median(processing_times), 1),\n", + " \"ms; median speed:\",\n", + " round(1000 / np.median(processing_times), 1),\n", + " \"fps\",\n", + " )\n", + " print(\n", + " \"max time:\",\n", + " round(np.max(processing_times), 1),\n", + " \"ms; max speed:\",\n", + " round(1000 / np.max(processing_times), 1),\n", + " \"fps\",\n", + " )\n", + " print(\n", + " \"min time:\",\n", + " round(np.min(processing_times), 1),\n", + " \"ms; min speed:\",\n", + " round(1000 / np.min(processing_times), 1),\n", + " \"fps\",\n", + " )\n", + " print(\n", + " \"time percentile 90:\",\n", + " round(np.percentile(processing_times, 90), 1),\n", + " \"ms; speed percentile 90:\",\n", + " round(1000 / np.percentile(processing_times, 90), 1),\n", + " \"fps\",\n", + " )\n", + " print(\n", + " \"time percentile 50:\",\n", + " round(np.percentile(processing_times, 50), 1),\n", + " \"ms; speed percentile 50:\",\n", + " round(1000 / np.percentile(processing_times, 50), 1),\n", + " \"fps\",\n", + " )\n", + " print(\"time standard deviation:\", round(np.std(processing_times)))\n", + " print(\"time variance:\", round(np.var(processing_times)))" ] }, { @@ -378,7 +411,7 @@ } ], "source": [ - "run(\"tensor\",\"./dog.jpeg\",iterations=100)" + "run(\"tensor\", \"./dog.jpeg\", iterations=100)" ] }, { @@ -511,7 +544,7 @@ } ], "source": [ - "run(\"tftensor\",\"./dog.jpeg\",iterations=100)" + "run(\"tftensor\", \"./dog.jpeg\", iterations=100)" ] }, { diff --git a/examples/models/sklearn_iris/sklearn_iris.ipynb b/examples/models/sklearn_iris/sklearn_iris.ipynb index a1758ca0cf..848e702cff 100644 --- a/examples/models/sklearn_iris/sklearn_iris.ipynb +++ b/examples/models/sklearn_iris/sklearn_iris.ipynb @@ -220,8 +220,9 @@ "source": [ "print(res)\n", "import json\n", - "j=json.loads(res[0])\n", - "assert(j[\"data\"][\"ndarray\"][0][0]>0.0)" + "\n", + "j = json.loads(res[0])\n", + "assert j[\"data\"][\"ndarray\"][0][0] > 0.0" ] }, { @@ -246,10 +247,16 @@ ], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"seldon-deployment-example\",namespace=\"seldon\")\n", - "res = sc.predict(gateway=\"istio\",gateway_endpoint=\"localhost:8003\", transport=\"rest\",raw_data = {\"data\":{\"ndarray\":[[5.964,4.006,2.081,1.031]]}})\n", + "\n", + "sc = SeldonClient(deployment_name=\"seldon-deployment-example\", namespace=\"seldon\")\n", + "res = sc.predict(\n", + " gateway=\"istio\",\n", + " gateway_endpoint=\"localhost:8003\",\n", + " transport=\"rest\",\n", + " raw_data={\"data\": {\"ndarray\": [[5.964, 4.006, 2.081, 1.031]]}},\n", + ")\n", "print(res.response)\n", - "assert(res.success==True)" + "assert res.success == True" ] }, { @@ -278,10 +285,18 @@ ], "source": [ "from seldon_core.utils import json_to_seldon_message\n", - "proto_raw_data = json_to_seldon_message({\"data\":{\"ndarray\":[[5.964,4.006,2.081,1.031]]}})\n", - "res = sc.predict(gateway=\"istio\",gateway_endpoint=\"localhost:8003\", transport=\"grpc\",raw_data = proto_raw_data)\n", + "\n", + "proto_raw_data = json_to_seldon_message(\n", + " {\"data\": {\"ndarray\": [[5.964, 4.006, 2.081, 1.031]]}}\n", + ")\n", + "res = sc.predict(\n", + " gateway=\"istio\",\n", + " gateway_endpoint=\"localhost:8003\",\n", + " transport=\"grpc\",\n", + " raw_data=proto_raw_data,\n", + ")\n", "print(res)\n", - "assert(res.success==True)" + "assert res.success == True" ] }, { diff --git a/examples/models/sklearn_iris_customdata/sklearn_iris_customdata.ipynb b/examples/models/sklearn_iris_customdata/sklearn_iris_customdata.ipynb index b83df2ea3e..0987f98ff1 100644 --- a/examples/models/sklearn_iris_customdata/sklearn_iris_customdata.ipynb +++ b/examples/models/sklearn_iris_customdata/sklearn_iris_customdata.ipynb @@ -35,30 +35,33 @@ "metadata": {}, "outputs": [], "source": [ - "import numpy as np\n", "import os\n", + "\n", + "import numpy as np\n", + "from sklearn import datasets\n", + "from sklearn.externals import joblib\n", "from sklearn.linear_model import LogisticRegression\n", "from sklearn.pipeline import Pipeline\n", - "from sklearn.externals import joblib\n", - "from sklearn import datasets\n", + "\n", "\n", "def main():\n", " clf = LogisticRegression()\n", - " p = Pipeline([('clf', clf)])\n", - " print('Training model...')\n", + " p = Pipeline([(\"clf\", clf)])\n", + " print(\"Training model...\")\n", " p.fit(X, y)\n", - " print('Model trained!')\n", + " print(\"Model trained!\")\n", "\n", - " filename_p = 'IrisClassifier.sav'\n", - " print('Saving model in %s' % filename_p)\n", + " filename_p = \"IrisClassifier.sav\"\n", + " print(\"Saving model in %s\" % filename_p)\n", " joblib.dump(p, filename_p)\n", - " print('Model saved!')\n", - " \n", + " print(\"Model saved!\")\n", + "\n", + "\n", "if __name__ == \"__main__\":\n", - " print('Loading iris data set...')\n", + " print(\"Loading iris data set...\")\n", " iris = datasets.load_iris()\n", " X, y = iris.data, iris.target\n", - " print('Dataset loaded!')\n", + " print(\"Dataset loaded!\")\n", " main()" ] }, @@ -164,14 +167,17 @@ "metadata": {}, "outputs": [], "source": [ + "import grpc\n", "from iris_pb2 import IrisPredictRequest, IrisPredictResponse\n", + "\n", "from seldon_core.proto import prediction_pb2, prediction_pb2_grpc\n", - "import grpc\n", "\n", "channel = grpc.insecure_channel(\"localhost:5000\")\n", "stub = prediction_pb2_grpc.ModelStub(channel)\n", "\n", - "iris_request = IrisPredictRequest(sepal_length=7.233, sepal_width=4.652, petal_length=7.39, petal_width=0.324)\n", + "iris_request = IrisPredictRequest(\n", + " sepal_length=7.233, sepal_width=4.652, petal_length=7.39, petal_width=0.324\n", + ")\n", "\n", "seldon_request = prediction_pb2.SeldonMessage()\n", "seldon_request.customData.Pack(iris_request)\n", @@ -321,7 +327,9 @@ "metadata": {}, "outputs": [], "source": [ - "iris_request = IrisPredictRequest(sepal_length=7.233, sepal_width=4.652, petal_length=7.39, petal_width=0.324)\n", + "iris_request = IrisPredictRequest(\n", + " sepal_length=7.233, sepal_width=4.652, petal_length=7.39, petal_width=0.324\n", + ")\n", "\n", "seldon_request = prediction_pb2.SeldonMessage()\n", "seldon_request.customData.Pack(iris_request)\n", diff --git a/examples/models/sklearn_spacy_text/sklearn_spacy_text_classifier_example.ipynb b/examples/models/sklearn_spacy_text/sklearn_spacy_text_classifier_example.ipynb index 3bd11953bd..21889468fe 100644 --- a/examples/models/sklearn_spacy_text/sklearn_spacy_text_classifier_example.ipynb +++ b/examples/models/sklearn_spacy_text/sklearn_spacy_text_classifier_example.ipynb @@ -92,17 +92,20 @@ "metadata": {}, "outputs": [], "source": [ - "import pandas as pd \n", - "from sklearn.model_selection import train_test_split\n", + "import os\n", + "import sys\n", + "\n", + "import dill\n", "import numpy as np\n", + "import pandas as pd\n", + "\n", + "# This import may take a while as it will download the Spacy ENGLISH model\n", + "from ml_utils import CleanTextTransformer, SpacyTokenTransformer\n", "from sklearn.feature_extraction.text import TfidfVectorizer\n", "from sklearn.linear_model import LogisticRegression\n", - "from seldon_core.seldon_client import SeldonClient\n", - "import dill\n", - "import sys, os\n", + "from sklearn.model_selection import train_test_split\n", "\n", - "# This import may take a while as it will download the Spacy ENGLISH model\n", - "from ml_utils import CleanTextTransformer, SpacyTokenTransformer" + "from seldon_core.seldon_client import SeldonClient" ] }, { @@ -201,13 +204,17 @@ "source": [ "df_cols = [\"prev_idx\", \"parent_idx\", \"body\", \"removed\"]\n", "\n", - "TEXT_COLUMN = \"body\" \n", + "TEXT_COLUMN = \"body\"\n", "CLEAN_COLUMN = \"clean_body\"\n", "TOKEN_COLUMN = \"token_body\"\n", "\n", "# Downloading the 50k reddit dataset of moderated comments\n", - "df = pd.read_csv(\"https://raw.githubusercontent.com/axsauze/reddit-classification-exploration/master/data/reddit_train.csv\", \n", - " names=df_cols, skiprows=1, encoding=\"ISO-8859-1\")\n", + "df = pd.read_csv(\n", + " \"https://raw.githubusercontent.com/axsauze/reddit-classification-exploration/master/data/reddit_train.csv\",\n", + " names=df_cols,\n", + " skiprows=1,\n", + " encoding=\"ISO-8859-1\",\n", + ")\n", "\n", "df.head()" ] @@ -263,10 +270,8 @@ "x = df[\"body\"].values\n", "y = df[\"removed\"].values\n", "x_train, x_test, y_train, y_test = train_test_split(\n", - " x, y, \n", - " stratify=y, \n", - " random_state=42, \n", - " test_size=0.1, shuffle=True)" + " x, y, stratify=y, random_state=42, test_size=0.1, shuffle=True\n", + ")" ] }, { @@ -314,10 +319,11 @@ "# Build tfidf vectorizer\n", "tfidf_vectorizer = TfidfVectorizer(\n", " max_features=10000,\n", - " preprocessor=lambda x: x, \n", - " tokenizer=lambda x: x, \n", + " preprocessor=lambda x: x,\n", + " tokenizer=lambda x: x,\n", " token_pattern=None,\n", - " ngram_range=(1, 3))\n", + " ngram_range=(1, 3),\n", + ")\n", "\n", "tfidf_vectorizer.fit(x_train_tokenized)" ] @@ -350,7 +356,7 @@ ], "source": [ "# Train logistic regression classifier\n", - "lr = LogisticRegression(C=0.1, solver='sag')\n", + "lr = LogisticRegression(C=0.1, solver=\"sag\")\n", "lr.fit(x_train_tfidf, y_train)" ] }, @@ -361,9 +367,9 @@ "outputs": [], "source": [ "# These are the models we'll deploy\n", - "with open('tfidf_vectorizer.model', 'wb') as model_file:\n", + "with open(\"tfidf_vectorizer.model\", \"wb\") as model_file:\n", " dill.dump(tfidf_vectorizer, model_file)\n", - "with open('lr.model', 'wb') as model_file:\n", + "with open(\"lr.model\", \"wb\") as model_file:\n", " dill.dump(lr, model_file)" ] }, @@ -431,6 +437,7 @@ "source": [ "# test that our model works\n", "from RedditClassifier import RedditClassifier\n", + "\n", "# With one sample\n", "sample = x_test[0:1]\n", "print(sample)\n", @@ -597,17 +604,15 @@ "metadata": {}, "outputs": [], "source": [ - "#We now test the REST endpoint expecting the same result\n", + "# We now test the REST endpoint expecting the same result\n", "endpoint = \"0.0.0.0:9001\"\n", "batch = sample\n", "payload_type = \"ndarray\"\n", "\n", "sc = SeldonClient(microservice_endpoint=endpoint)\n", "response = sc.microservice(\n", - " data=batch,\n", - " method=\"predict\",\n", - " payload_type=payload_type,\n", - " names=[\"tfidf\"])\n", + " data=batch, method=\"predict\", payload_type=payload_type, names=[\"tfidf\"]\n", + ")\n", "\n", "print(response)" ] @@ -767,7 +772,7 @@ } ], "source": [ - "!kubectl get pods " + "!kubectl get pods" ] }, { @@ -813,18 +818,19 @@ "metadata": {}, "outputs": [], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import numpy as np\n", "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", "sc = SeldonClient(\n", - " gateway=\"ambassador\", \n", + " gateway=\"ambassador\",\n", " transport=\"rest\",\n", - " gateway_endpoint=\"localhost:80\", # Make sure you use the port above\n", - " namespace=\"default\"\n", + " gateway_endpoint=\"localhost:80\", # Make sure you use the port above\n", + " namespace=\"default\",\n", ")\n", "\n", "client_prediction = sc.predict(\n", - " data=np.array([\"Hello world this is a test\"]), \n", + " data=np.array([\"Hello world this is a test\"]),\n", " deployment_name=\"reddit-classifier\",\n", " names=[\"text\"],\n", " payload_type=\"ndarray\",\n", diff --git a/examples/models/statsmodels/statsmodels.ipynb b/examples/models/statsmodels/statsmodels.ipynb index 7b4dbd29b3..552ada34c5 100644 --- a/examples/models/statsmodels/statsmodels.ipynb +++ b/examples/models/statsmodels/statsmodels.ipynb @@ -5,7 +5,6 @@ "metadata": {}, "source": [ "# Deploying Time-Series Models on Seldon " - ] }, { @@ -54,26 +53,33 @@ "metadata": {}, "outputs": [], "source": [ + "import joblib\n", + "import numpy as np\n", "import pandas as pd\n", "from statsmodels.tsa.holtwinters import ExponentialSmoothing\n", - "import numpy as np\n", - "import joblib\n", - "\n", - "df=pd.read_csv('https://raw.githubusercontent.com/jbrownlee/Datasets/master/shampoo.csv')\n", - "\n", - "#Taking a test-train split of 80 %\n", - "train=df[0:int(len(df)*0.8)] \n", - "test=df[int(len(df)*0.8):]\n", - "\n", - "#Pre-processing the Month field\n", - "train.Timestamp = pd.to_datetime(train.Month,format='%m-%d') \n", - "train.index = train.Timestamp \n", - "test.Timestamp = pd.to_datetime(test.Month,format='%m-%d') \n", - "test.index = test.Timestamp \n", "\n", - "#fitting the model based on optimal parameters\n", - "model = ExponentialSmoothing(np.asarray(train['Sales']) ,seasonal_periods=7 ,trend='add', seasonal='add',).fit()\n", - "joblib.dump(model,'model.sav')" + "df = pd.read_csv(\n", + " \"https://raw.githubusercontent.com/jbrownlee/Datasets/master/shampoo.csv\"\n", + ")\n", + "\n", + "# Taking a test-train split of 80 %\n", + "train = df[0 : int(len(df) * 0.8)]\n", + "test = df[int(len(df) * 0.8) :]\n", + "\n", + "# Pre-processing the Month field\n", + "train.Timestamp = pd.to_datetime(train.Month, format=\"%m-%d\")\n", + "train.index = train.Timestamp\n", + "test.Timestamp = pd.to_datetime(test.Month, format=\"%m-%d\")\n", + "test.index = test.Timestamp\n", + "\n", + "# fitting the model based on optimal parameters\n", + "model = ExponentialSmoothing(\n", + " np.asarray(train[\"Sales\"]),\n", + " seasonal_periods=7,\n", + " trend=\"add\",\n", + " seasonal=\"add\",\n", + ").fit()\n", + "joblib.dump(model, \"model.sav\")" ] }, { @@ -200,7 +206,7 @@ "metadata": {}, "outputs": [], "source": [ - "!s2i build -E environment_rest . seldonio/seldon-core-s2i-python37-ubi8:1.7.0-dev seldonio/statsmodel-holts:0.1\n" + "!s2i build -E environment_rest . seldonio/seldon-core-s2i-python37-ubi8:1.7.0-dev seldonio/statsmodel-holts:0.1" ] }, { @@ -216,7 +222,7 @@ "metadata": {}, "outputs": [], "source": [ - "!docker run --name \"holt_predictor\" -d --rm -p 5000:5000 seldonio/statsmodel-holts:0.1\n" + "!docker run --name \"holt_predictor\" -d --rm -p 5000:5000 seldonio/statsmodel-holts:0.1" ] }, { @@ -232,7 +238,7 @@ "metadata": {}, "outputs": [], "source": [ - "!curl -s http://localhost:5000/predict -H \"Content-Type: application/json\" -d '{\"data\":{\"ndarray\":3}}'\n" + "!curl -s http://localhost:5000/predict -H \"Content-Type: application/json\" -d '{\"data\":{\"ndarray\":3}}'" ] }, { @@ -295,7 +301,7 @@ "metadata": {}, "outputs": [], "source": [ - "!kubectl apply -f model.yaml\n" + "!kubectl apply -f model.yaml" ] }, { diff --git a/examples/models/tensorrt/triton_tensorrt.ipynb b/examples/models/tensorrt/triton_tensorrt.ipynb index 14e3404614..406f622935 100644 --- a/examples/models/tensorrt/triton_tensorrt.ipynb +++ b/examples/models/tensorrt/triton_tensorrt.ipynb @@ -31,15 +31,16 @@ "source": [ "%matplotlib inline\n", "import json\n", - "from matplotlib import pyplot as plt\n", + "\n", "import numpy as np\n", "import tensorflow as tf\n", "import tensorflow_datasets as tfds\n", - "import numpy as np\n", + "from matplotlib import pyplot as plt\n", + "\n", "\n", "def gen_image(arr):\n", " two_d = (np.reshape(arr, (28, 28)) * 255).astype(np.uint8)\n", - " plt.imshow(two_d,cmap=plt.cm.gray_r, interpolation='nearest')\n", + " plt.imshow(two_d, cmap=plt.cm.gray_r, interpolation=\"nearest\")\n", " return plt" ] }, @@ -50,13 +51,12 @@ "outputs": [], "source": [ "(ds_train, ds_test), ds_info = tfds.load(\n", - " 'mnist',\n", - " split=['train', 'test'],\n", + " \"mnist\",\n", + " split=[\"train\", \"test\"],\n", " shuffle_files=True,\n", " as_supervised=True,\n", " with_info=True,\n", - ")\n", - "\n" + ")" ] }, { @@ -66,15 +66,13 @@ "outputs": [], "source": [ "def normalize_img(image, label):\n", - " \"\"\"Normalizes images: `uint8` -> `float32`.\"\"\"\n", - " return tf.cast(image, tf.float32) * 255, label\n", + " \"\"\"Normalizes images: `uint8` -> `float32`.\"\"\"\n", + " return tf.cast(image, tf.float32) * 255, label\n", "\n", - "ds_train = ds_train.map(\n", - " normalize_img, num_parallel_calls=tf.data.experimental.AUTOTUNE)\n", "\n", - "npX = tfds.as_numpy(\n", - " ds_train, graph=None\n", - ")" + "ds_train = ds_train.map(normalize_img, num_parallel_calls=tf.data.experimental.AUTOTUNE)\n", + "\n", + "npX = tfds.as_numpy(ds_train, graph=None)" ] }, { @@ -83,7 +81,794 @@ "metadata": {}, "outputs": [], "source": [ - "MEANS=np.array([255.0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,254,254,253,252,252,251,251,252,252,253,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,254,254,253,251,249,248,245,243,242,242,243,246,248,251,253,254,255,255,255,255,255,255,255,255,255,255,255,254,253,250,247,242,235,228,220,213,210,211,216,224,232,240,246,251,253,254,255,255,255,255,255,255,255,255,254,251,248,242,234,223,211,196,181,170,164,166,175,189,205,221,233,243,248,252,254,255,255,255,255,255,255,254,252,248,241,231,217,202,184,166,149,136,131,134,143,159,180,201,220,234,243,249,253,255,255,255,255,255,254,253,249,243,233,219,201,181,161,143,130,122,120,122,129,141,161,185,208,227,240,248,252,254,255,255,255,255,254,251,246,238,226,208,187,164,146,135,131,132,133,132,133,139,154,178,202,223,239,248,252,255,255,255,255,254,253,251,245,236,221,200,177,156,144,144,150,156,156,151,144,144,156,178,202,224,240,249,253,255,255,255,255,254,253,251,245,235,218,195,172,155,152,161,172,176,170,161,150,149,161,183,207,227,242,250,254,255,255,255,255,255,254,251,246,234,215,191,168,156,160,173,182,179,169,157,147,149,166,190,213,230,243,251,254,255,255,255,255,255,254,252,246,233,212,186,165,157,164,175,176,165,153,142,137,147,170,196,217,231,242,251,255,255,255,255,255,255,254,252,245,230,207,182,163,158,164,168,158,143,131,125,128,146,174,200,218,231,241,250,254,255,255,255,255,255,255,252,243,227,205,181,164,159,161,157,139,124,115,118,127,148,176,199,216,230,240,249,254,255,255,255,255,255,254,251,241,224,204,184,169,163,160,150,132,119,116,123,133,153,177,197,214,228,240,249,254,255,255,255,255,255,254,251,239,222,205,189,177,171,166,154,139,129,128,134,144,159,177,195,213,228,241,249,254,255,255,255,255,255,254,249,237,222,207,195,186,180,175,166,153,143,140,142,150,162,178,195,214,230,242,250,254,255,255,255,255,255,253,247,235,220,207,197,189,183,179,172,160,148,142,143,150,161,178,198,217,233,244,250,254,255,255,255,255,255,253,246,233,218,204,192,184,177,172,165,153,142,137,139,148,163,183,204,222,236,246,251,254,255,255,255,255,255,253,247,234,218,201,186,174,165,157,148,137,130,129,137,151,171,194,214,230,242,248,252,254,255,255,255,255,255,253,249,238,222,203,184,168,154,143,132,124,123,130,145,165,188,209,227,239,247,251,253,255,255,255,255,255,255,254,251,244,232,214,194,174,156,142,132,130,134,148,167,189,210,226,238,246,250,253,254,255,255,255,255,255,255,255,253,250,243,231,215,196,178,163,155,156,164,179,197,215,230,240,247,251,253,254,255,255,255,255,255,255,255,255,254,253,251,246,238,228,217,208,203,204,210,218,228,236,243,248,251,253,254,255,255,255,255,255,255,255,255,255,255,255,254,252,249,245,241,238,237,237,239,242,245,247,250,252,253,254,255,255,255,255,255,255,255,255,255,255,255,255,254,254,253,252,250,249,248,249,249,250,252,253,253,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,254,254,254,255,255,255,255,255,255,255,255,255,255,255,255])" + "MEANS = np.array(\n", + " [\n", + " 255.0,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 254,\n", + " 254,\n", + " 253,\n", + " 252,\n", + " 252,\n", + " 251,\n", + " 251,\n", + " 252,\n", + " 252,\n", + " 253,\n", + " 254,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 254,\n", + " 253,\n", + " 251,\n", + " 249,\n", + " 248,\n", + " 245,\n", + " 243,\n", + " 242,\n", + " 242,\n", + " 243,\n", + " 246,\n", + " 248,\n", + " 251,\n", + " 253,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 253,\n", + " 250,\n", + " 247,\n", + " 242,\n", + " 235,\n", + " 228,\n", + " 220,\n", + " 213,\n", + " 210,\n", + " 211,\n", + " 216,\n", + " 224,\n", + " 232,\n", + " 240,\n", + " 246,\n", + " 251,\n", + " 253,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 251,\n", + " 248,\n", + " 242,\n", + " 234,\n", + " 223,\n", + " 211,\n", + " 196,\n", + " 181,\n", + " 170,\n", + " 164,\n", + " 166,\n", + " 175,\n", + " 189,\n", + " 205,\n", + " 221,\n", + " 233,\n", + " 243,\n", + " 248,\n", + " 252,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 252,\n", + " 248,\n", + " 241,\n", + " 231,\n", + " 217,\n", + " 202,\n", + " 184,\n", + " 166,\n", + " 149,\n", + " 136,\n", + " 131,\n", + " 134,\n", + " 143,\n", + " 159,\n", + " 180,\n", + " 201,\n", + " 220,\n", + " 234,\n", + " 243,\n", + " 249,\n", + " 253,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 253,\n", + " 249,\n", + " 243,\n", + " 233,\n", + " 219,\n", + " 201,\n", + " 181,\n", + " 161,\n", + " 143,\n", + " 130,\n", + " 122,\n", + " 120,\n", + " 122,\n", + " 129,\n", + " 141,\n", + " 161,\n", + " 185,\n", + " 208,\n", + " 227,\n", + " 240,\n", + " 248,\n", + " 252,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 251,\n", + " 246,\n", + " 238,\n", + " 226,\n", + " 208,\n", + " 187,\n", + " 164,\n", + " 146,\n", + " 135,\n", + " 131,\n", + " 132,\n", + " 133,\n", + " 132,\n", + " 133,\n", + " 139,\n", + " 154,\n", + " 178,\n", + " 202,\n", + " 223,\n", + " 239,\n", + " 248,\n", + " 252,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 253,\n", + " 251,\n", + " 245,\n", + " 236,\n", + " 221,\n", + " 200,\n", + " 177,\n", + " 156,\n", + " 144,\n", + " 144,\n", + " 150,\n", + " 156,\n", + " 156,\n", + " 151,\n", + " 144,\n", + " 144,\n", + " 156,\n", + " 178,\n", + " 202,\n", + " 224,\n", + " 240,\n", + " 249,\n", + " 253,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 253,\n", + " 251,\n", + " 245,\n", + " 235,\n", + " 218,\n", + " 195,\n", + " 172,\n", + " 155,\n", + " 152,\n", + " 161,\n", + " 172,\n", + " 176,\n", + " 170,\n", + " 161,\n", + " 150,\n", + " 149,\n", + " 161,\n", + " 183,\n", + " 207,\n", + " 227,\n", + " 242,\n", + " 250,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 251,\n", + " 246,\n", + " 234,\n", + " 215,\n", + " 191,\n", + " 168,\n", + " 156,\n", + " 160,\n", + " 173,\n", + " 182,\n", + " 179,\n", + " 169,\n", + " 157,\n", + " 147,\n", + " 149,\n", + " 166,\n", + " 190,\n", + " 213,\n", + " 230,\n", + " 243,\n", + " 251,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 252,\n", + " 246,\n", + " 233,\n", + " 212,\n", + " 186,\n", + " 165,\n", + " 157,\n", + " 164,\n", + " 175,\n", + " 176,\n", + " 165,\n", + " 153,\n", + " 142,\n", + " 137,\n", + " 147,\n", + " 170,\n", + " 196,\n", + " 217,\n", + " 231,\n", + " 242,\n", + " 251,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 252,\n", + " 245,\n", + " 230,\n", + " 207,\n", + " 182,\n", + " 163,\n", + " 158,\n", + " 164,\n", + " 168,\n", + " 158,\n", + " 143,\n", + " 131,\n", + " 125,\n", + " 128,\n", + " 146,\n", + " 174,\n", + " 200,\n", + " 218,\n", + " 231,\n", + " 241,\n", + " 250,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 252,\n", + " 243,\n", + " 227,\n", + " 205,\n", + " 181,\n", + " 164,\n", + " 159,\n", + " 161,\n", + " 157,\n", + " 139,\n", + " 124,\n", + " 115,\n", + " 118,\n", + " 127,\n", + " 148,\n", + " 176,\n", + " 199,\n", + " 216,\n", + " 230,\n", + " 240,\n", + " 249,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 251,\n", + " 241,\n", + " 224,\n", + " 204,\n", + " 184,\n", + " 169,\n", + " 163,\n", + " 160,\n", + " 150,\n", + " 132,\n", + " 119,\n", + " 116,\n", + " 123,\n", + " 133,\n", + " 153,\n", + " 177,\n", + " 197,\n", + " 214,\n", + " 228,\n", + " 240,\n", + " 249,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 251,\n", + " 239,\n", + " 222,\n", + " 205,\n", + " 189,\n", + " 177,\n", + " 171,\n", + " 166,\n", + " 154,\n", + " 139,\n", + " 129,\n", + " 128,\n", + " 134,\n", + " 144,\n", + " 159,\n", + " 177,\n", + " 195,\n", + " 213,\n", + " 228,\n", + " 241,\n", + " 249,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 249,\n", + " 237,\n", + " 222,\n", + " 207,\n", + " 195,\n", + " 186,\n", + " 180,\n", + " 175,\n", + " 166,\n", + " 153,\n", + " 143,\n", + " 140,\n", + " 142,\n", + " 150,\n", + " 162,\n", + " 178,\n", + " 195,\n", + " 214,\n", + " 230,\n", + " 242,\n", + " 250,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 253,\n", + " 247,\n", + " 235,\n", + " 220,\n", + " 207,\n", + " 197,\n", + " 189,\n", + " 183,\n", + " 179,\n", + " 172,\n", + " 160,\n", + " 148,\n", + " 142,\n", + " 143,\n", + " 150,\n", + " 161,\n", + " 178,\n", + " 198,\n", + " 217,\n", + " 233,\n", + " 244,\n", + " 250,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 253,\n", + " 246,\n", + " 233,\n", + " 218,\n", + " 204,\n", + " 192,\n", + " 184,\n", + " 177,\n", + " 172,\n", + " 165,\n", + " 153,\n", + " 142,\n", + " 137,\n", + " 139,\n", + " 148,\n", + " 163,\n", + " 183,\n", + " 204,\n", + " 222,\n", + " 236,\n", + " 246,\n", + " 251,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 253,\n", + " 247,\n", + " 234,\n", + " 218,\n", + " 201,\n", + " 186,\n", + " 174,\n", + " 165,\n", + " 157,\n", + " 148,\n", + " 137,\n", + " 130,\n", + " 129,\n", + " 137,\n", + " 151,\n", + " 171,\n", + " 194,\n", + " 214,\n", + " 230,\n", + " 242,\n", + " 248,\n", + " 252,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 253,\n", + " 249,\n", + " 238,\n", + " 222,\n", + " 203,\n", + " 184,\n", + " 168,\n", + " 154,\n", + " 143,\n", + " 132,\n", + " 124,\n", + " 123,\n", + " 130,\n", + " 145,\n", + " 165,\n", + " 188,\n", + " 209,\n", + " 227,\n", + " 239,\n", + " 247,\n", + " 251,\n", + " 253,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 251,\n", + " 244,\n", + " 232,\n", + " 214,\n", + " 194,\n", + " 174,\n", + " 156,\n", + " 142,\n", + " 132,\n", + " 130,\n", + " 134,\n", + " 148,\n", + " 167,\n", + " 189,\n", + " 210,\n", + " 226,\n", + " 238,\n", + " 246,\n", + " 250,\n", + " 253,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 253,\n", + " 250,\n", + " 243,\n", + " 231,\n", + " 215,\n", + " 196,\n", + " 178,\n", + " 163,\n", + " 155,\n", + " 156,\n", + " 164,\n", + " 179,\n", + " 197,\n", + " 215,\n", + " 230,\n", + " 240,\n", + " 247,\n", + " 251,\n", + " 253,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 253,\n", + " 251,\n", + " 246,\n", + " 238,\n", + " 228,\n", + " 217,\n", + " 208,\n", + " 203,\n", + " 204,\n", + " 210,\n", + " 218,\n", + " 228,\n", + " 236,\n", + " 243,\n", + " 248,\n", + " 251,\n", + " 253,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 252,\n", + " 249,\n", + " 245,\n", + " 241,\n", + " 238,\n", + " 237,\n", + " 237,\n", + " 239,\n", + " 242,\n", + " 245,\n", + " 247,\n", + " 250,\n", + " 252,\n", + " 253,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 254,\n", + " 253,\n", + " 252,\n", + " 250,\n", + " 249,\n", + " 248,\n", + " 249,\n", + " 249,\n", + " 250,\n", + " 252,\n", + " 253,\n", + " 253,\n", + " 254,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 254,\n", + " 254,\n", + " 254,\n", + " 254,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " 255,\n", + " ]\n", + ")" ] }, { diff --git a/examples/models/tfserving-mnist/tfserving-mnist.ipynb b/examples/models/tfserving-mnist/tfserving-mnist.ipynb index e5314e917f..1221f875b4 100644 --- a/examples/models/tfserving-mnist/tfserving-mnist.ipynb +++ b/examples/models/tfserving-mnist/tfserving-mnist.ipynb @@ -34,20 +34,22 @@ "outputs": [], "source": [ "%matplotlib inline\n", - "import requests\n", - "from random import randint,random\n", "import json\n", - "from matplotlib import pyplot as plt\n", + "import sys\n", + "from random import randint, random\n", + "\n", "import numpy as np\n", + "import requests\n", + "from matplotlib import pyplot as plt\n", "from tensorflow.examples.tutorials.mnist import input_data\n", - "import sys\n", + "\n", "sys.path.append(\"../../../notebooks\")\n", - "from visualizer import get_graph\n", - "from seldon_core.proto import prediction_pb2\n", - "from seldon_core.proto import prediction_pb2_grpc\n", "import grpc\n", "import tensorflow as tf\n", - "from tensorflow.core.framework.tensor_pb2 import TensorProto" + "from tensorflow.core.framework.tensor_pb2 import TensorProto\n", + "from visualizer import get_graph\n", + "\n", + "from seldon_core.proto import prediction_pb2, prediction_pb2_grpc" ] }, { @@ -58,47 +60,68 @@ "source": [ "def gen_image(arr):\n", " two_d = (np.reshape(arr, (28, 28)) * 255).astype(np.uint8)\n", - " plt.imshow(two_d,cmap=plt.cm.gray_r, interpolation='nearest')\n", + " plt.imshow(two_d, cmap=plt.cm.gray_r, interpolation=\"nearest\")\n", " return plt\n", "\n", + "\n", "def download_mnist():\n", - " return input_data.read_data_sets(\"MNIST_data/\", one_hot = True)\n", + " return input_data.read_data_sets(\"MNIST_data/\", one_hot=True)\n", + "\n", "\n", - "def rest_predict_request(endpoint,data):\n", - " request = {\"data\":{\"ndarray\":data.tolist()}}\n", + "def rest_predict_request(endpoint, data):\n", + " request = {\"data\": {\"ndarray\": data.tolist()}}\n", " response = requests.post(\n", - " \"http://\"+endpoint+\"/predict\",\n", - " data={\"json\":json.dumps(request),\"isDefault\":True})\n", - " return response.json() \n", + " \"http://\" + endpoint + \"/predict\",\n", + " data={\"json\": json.dumps(request), \"isDefault\": True},\n", + " )\n", + " return response.json()\n", "\n", - "def rest_transform_input_request(endpoint,data):\n", - " request = {\"data\":{\"ndarray\":data.tolist()}}\n", + "\n", + "def rest_transform_input_request(endpoint, data):\n", + " request = {\"data\": {\"ndarray\": data.tolist()}}\n", " response = requests.post(\n", - " \"http://\"+endpoint+\"/transform-input\",\n", - " data={\"json\":json.dumps(request),\"isDefault\":True})\n", - " return response.json() \n", + " \"http://\" + endpoint + \"/transform-input\",\n", + " data={\"json\": json.dumps(request), \"isDefault\": True},\n", + " )\n", + " return response.json()\n", + "\n", "\n", - "def rest_transform_output_request(endpoint,data):\n", - " request = {\"data\":{\"ndarray\":data.tolist()}}\n", + "def rest_transform_output_request(endpoint, data):\n", + " request = {\"data\": {\"ndarray\": data.tolist()}}\n", " response = requests.post(\n", - " \"http://\"+endpoint+\"/transform-output\",\n", - " data={\"json\":json.dumps(request),\"isDefault\":True})\n", - " return response.json() \n", + " \"http://\" + endpoint + \"/transform-output\",\n", + " data={\"json\": json.dumps(request), \"isDefault\": True},\n", + " )\n", + " return response.json()\n", "\n", - "def rest_request_ambassador(deploymentName,namespace,endpoint=\"localhost:8003\",arr=None):\n", - " payload = {\"data\":{\"names\":[\"a\",\"b\"],\"tensor\":{\"shape\":[1,784],\"values\":arr.tolist()}}}\n", + "\n", + "def rest_request_ambassador(\n", + " deploymentName, namespace, endpoint=\"localhost:8003\", arr=None\n", + "):\n", + " payload = {\n", + " \"data\": {\n", + " \"names\": [\"a\", \"b\"],\n", + " \"tensor\": {\"shape\": [1, 784], \"values\": arr.tolist()},\n", + " }\n", + " }\n", " response = requests.post(\n", - " \"http://\"+endpoint+\"/seldon/\"+namespace+\"/\"+deploymentName+\"/api/v0.1/predictions\",\n", - " json=payload)\n", + " \"http://\"\n", + " + endpoint\n", + " + \"/seldon/\"\n", + " + namespace\n", + " + \"/\"\n", + " + deploymentName\n", + " + \"/api/v0.1/predictions\",\n", + " json=payload,\n", + " )\n", " print(response.status_code)\n", " print(response.text)\n", "\n", - "def grpc_request_internal(data,endpoint=\"localhost:5000\"):\n", - " datadef = prediction_pb2.DefaultData(\n", - " tftensor=tf.make_tensor_proto(data)\n", - " )\n", "\n", - " request = prediction_pb2.SeldonMessage(data = datadef)\n", + "def grpc_request_internal(data, endpoint=\"localhost:5000\"):\n", + " datadef = prediction_pb2.DefaultData(tftensor=tf.make_tensor_proto(data))\n", + "\n", + " request = prediction_pb2.SeldonMessage(data=datadef)\n", " channel = grpc.insecure_channel(endpoint)\n", " stub = prediction_pb2_grpc.ModelStub(channel)\n", " response = stub.Predict(request=request)\n", @@ -107,10 +130,10 @@ "\n", "def gen_mnist_data(mnist):\n", " batch_xs, batch_ys = mnist.train.next_batch(1)\n", - " chosen=0\n", + " chosen = 0\n", " gen_image(batch_xs[chosen]).show()\n", - " data = batch_xs[chosen].reshape((1,784))\n", - " return data\n" + " data = batch_xs[chosen].reshape((1, 784))\n", + " return data" ] }, { @@ -337,7 +360,7 @@ } ], "source": [ - "!helm install tfserving-mnist tfserving-mnist --namespace seldon --set tfserving.model_base_path=${MODEL_REPOSITORY_BUCKET}/mnist-model " + "!helm install tfserving-mnist tfserving-mnist --namespace seldon --set tfserving.model_base_path=${MODEL_REPOSITORY_BUCKET}/mnist-model" ] }, { @@ -581,7 +604,9 @@ "source": [ "data = gen_mnist_data(mnist)\n", "data = data.reshape((784))\n", - "rest_request_ambassador(\"tfserving-mnist\",\"seldon\",endpoint=\"localhost:8003\",arr=data)" + "rest_request_ambassador(\n", + " \"tfserving-mnist\", \"seldon\", endpoint=\"localhost:8003\", arr=data\n", + ")" ] }, { @@ -736,7 +761,7 @@ " --set locust.minWait=0 \\\n", " --set locust.maxWait=0 \\\n", " --set replicaCount=1 \\\n", - " --set data.size=784\n" + " --set data.size=784" ] }, { diff --git a/examples/models/xss/xss-example.ipynb b/examples/models/xss/xss-example.ipynb index 94ae7c28e8..afb66672ae 100644 --- a/examples/models/xss/xss-example.ipynb +++ b/examples/models/xss/xss-example.ipynb @@ -10352,7 +10352,7 @@ "source": [ "from seldon_core.seldon_client import SeldonClient\n", "\n", - "sc = SeldonClient(deployment_name='xss-example', namespace=\"default\")" + "sc = SeldonClient(deployment_name=\"xss-example\", namespace=\"default\")" ] }, { @@ -10382,7 +10382,7 @@ } ], "source": [ - "r = sc.predict(gateway='ambassador', str_data=\"
This is a div
\")\n", + "r = sc.predict(gateway=\"ambassador\", str_data='
This is a div
')\n", "print(r)" ] }, diff --git a/examples/outliers/alibi-detect-combiner/notebook.ipynb b/examples/outliers/alibi-detect-combiner/notebook.ipynb index 7be05b6b00..3110aea229 100644 --- a/examples/outliers/alibi-detect-combiner/notebook.ipynb +++ b/examples/outliers/alibi-detect-combiner/notebook.ipynb @@ -288,7 +288,9 @@ "metadata": {}, "outputs": [], "source": [ - "import sys; sys.path.append(\"pipeline/loanclassifier\")\n", + "import sys\n", + "\n", + "sys.path.append(\"pipeline/loanclassifier\")\n", "from Model import Model\n", "\n", "model = Model()" @@ -387,9 +389,8 @@ } ], "source": [ - "import xai\n", "import numpy as np\n", - "\n", + "import xai\n", "from train_classifier import load_data\n", "\n", "data, X_train, y_train, X_test, y_test = load_data()\n", @@ -617,7 +618,9 @@ } ], "source": [ - "import sys; sys.path.append(\"pipeline/outliersdetector\")\n", + "import sys\n", + "\n", + "sys.path.append(\"pipeline/outliersdetector\")\n", "from Detector import Detector\n", "\n", "detector = Detector()" @@ -631,20 +634,21 @@ "source": [ "import json\n", "\n", + "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "import seaborn as sns\n", "\n", - "import matplotlib.pyplot as plt\n", "%matplotlib inline\n", "\n", - "from sklearn.metrics import confusion_matrix, f1_score\n", "from alibi_detect.utils.data import create_outlier_batch\n", - "\n", + "from sklearn.metrics import confusion_matrix, f1_score\n", "\n", "np.random.seed(1)\n", - "outlier_batch = create_outlier_batch(data.data, data.target, n_samples=1000, perc_outlier=10)\n", - "X_outlier, y_outlier = outlier_batch.data.astype('float'), outlier_batch.target" + "outlier_batch = create_outlier_batch(\n", + " data.data, data.target, n_samples=1000, perc_outlier=10\n", + ")\n", + "X_outlier, y_outlier = outlier_batch.data.astype(\"float\"), outlier_batch.target" ] }, { @@ -684,10 +688,10 @@ "source": [ "labels = outlier_batch.target_names\n", "f1 = f1_score(y_outlier, y_pred)\n", - "print('F1 score: {}'.format(f1))\n", + "print(\"F1 score: {}\".format(f1))\n", "cm = confusion_matrix(y_outlier, y_pred)\n", "df_cm = pd.DataFrame(cm, index=labels, columns=labels)\n", - "sns.heatmap(df_cm, annot=True, cbar=True, linewidths=.5)\n", + "sns.heatmap(df_cm, annot=True, cbar=True, linewidths=0.5)\n", "plt.show()" ] }, @@ -1006,12 +1010,12 @@ ], "source": [ "sc = SeldonClient(\n", - " gateway=\"ambassador\", \n", + " gateway=\"ambassador\",\n", " deployment_name=\"loanclassifier\",\n", " gateway_endpoint=\"localhost:8003\",\n", " payload_type=\"ndarray\",\n", " namespace=\"seldon\",\n", - " transport=\"rest\"\n", + " transport=\"rest\",\n", ")\n", "\n", "prediction = sc.predict(data=to_explain)\n", @@ -1036,12 +1040,12 @@ ], "source": [ "sc = SeldonClient(\n", - " gateway=\"ambassador\", \n", + " gateway=\"ambassador\",\n", " deployment_name=\"outliersdetector\",\n", " gateway_endpoint=\"localhost:8003\",\n", " payload_type=\"ndarray\",\n", " namespace=\"seldon\",\n", - " transport=\"rest\"\n", + " transport=\"rest\",\n", ")\n", "\n", "prediction = sc.predict(data=to_explain)\n", @@ -1208,12 +1212,12 @@ "outputs": [], "source": [ "sc = SeldonClient(\n", - " gateway=\"ambassador\", \n", + " gateway=\"ambassador\",\n", " deployment_name=\"loanclassifier-combined\",\n", " gateway_endpoint=\"localhost:8003\",\n", " payload_type=\"ndarray\",\n", " namespace=\"seldon\",\n", - " transport=\"rest\"\n", + " transport=\"rest\",\n", ")\n", "\n", "prediction = sc.predict(data=to_explain)\n", @@ -1332,7 +1336,7 @@ } ], "source": [ - "output['loanclassifier']" + "output[\"loanclassifier\"]" ] }, { @@ -1352,7 +1356,7 @@ } ], "source": [ - "output['outliersdetector']" + "output[\"outliersdetector\"]" ] } ], diff --git a/examples/pachyderm-cd4ml/index.ipynb b/examples/pachyderm-cd4ml/index.ipynb index fa8ce76e98..0d0b830a10 100644 --- a/examples/pachyderm-cd4ml/index.ipynb +++ b/examples/pachyderm-cd4ml/index.ipynb @@ -597,23 +597,30 @@ "metadata": {}, "outputs": [], "source": [ - "from urllib import request, parse\n", "import json\n", "from pprint import pprint\n", + "from urllib import parse, request\n", + "\n", "\n", "def get_predictions(num_periods: int = 6):\n", - " data = json.dumps({\"data\":{\"ndarray\": num_periods}}).encode()\n", - " req = request.Request(\"http://localhost:8003/seldon/seldon/rsi-predictor/api/v1.0/predictions\", data=data)\n", - " req.add_header('Content-Type', 'application/json')\n", + " data = json.dumps({\"data\": {\"ndarray\": num_periods}}).encode()\n", + " req = request.Request(\n", + " \"http://localhost:8003/seldon/seldon/rsi-predictor/api/v1.0/predictions\",\n", + " data=data,\n", + " )\n", + " req.add_header(\"Content-Type\", \"application/json\")\n", " resp = request.urlopen(req)\n", " print(resp.status)\n", " resp_data = json.loads(resp.read())\n", " pprint(resp_data)\n", " return resp_data[\"data\"][\"ndarray\"]\n", "\n", + "\n", "def get_metadata() -> None:\n", - " req = request.Request(\"http://localhost:8003/seldon/seldon/rsi-predictor/api/v1.0/metadata\")\n", - " req.add_header('Content-Type', 'application/json')\n", + " req = request.Request(\n", + " \"http://localhost:8003/seldon/seldon/rsi-predictor/api/v1.0/metadata\"\n", + " )\n", + " req.add_header(\"Content-Type\", \"application/json\")\n", " resp = request.urlopen(req)\n", " print(resp.status)\n", " resp_data = json.loads(resp.read())\n", @@ -711,9 +718,11 @@ "source": [ "import pandas as pd\n", "\n", - "rsi = pd.read_csv(\"./data/rsi_before.csv\", index_col=\"Date\", parse_dates=True) # Load data\n", - "rsi_prediction = pd.DataFrame(predictions).set_index(0) # Move timestamp to index\n", - "rsi_prediction.index = pd.to_datetime(rsi_prediction.index) # Parse timestamp\n", + "rsi = pd.read_csv(\n", + " \"./data/rsi_before.csv\", index_col=\"Date\", parse_dates=True\n", + ") # Load data\n", + "rsi_prediction = pd.DataFrame(predictions).set_index(0) # Move timestamp to index\n", + "rsi_prediction.index = pd.to_datetime(rsi_prediction.index) # Parse timestamp\n", "ax = rsi.plot()\n", "rsi_prediction.plot(ax=ax)" ] @@ -770,7 +779,9 @@ } ], "source": [ - "rsi = pd.read_csv(\"./data/rsi_mid.csv\", index_col=\"Date\", parse_dates=True) # Load more recent data\n", + "rsi = pd.read_csv(\n", + " \"./data/rsi_mid.csv\", index_col=\"Date\", parse_dates=True\n", + ") # Load more recent data\n", "rsi_prediction = pd.DataFrame(predictions).set_index(0)\n", "rsi_prediction.index = pd.to_datetime(rsi_prediction.index)\n", "ax = rsi.plot()\n", diff --git a/examples/ray/batch-split-proxy/ray-proxy.ipynb b/examples/ray/batch-split-proxy/ray-proxy.ipynb index 1f354e7556..78ed228ccc 100644 --- a/examples/ray/batch-split-proxy/ray-proxy.ipynb +++ b/examples/ray/batch-split-proxy/ray-proxy.ipynb @@ -664,8 +664,8 @@ "metadata": {}, "outputs": [], "source": [ - "import requests\n", - "import numpy as np" + "import numpy as np\n", + "import requests" ] }, { @@ -722,7 +722,9 @@ "model_namespace = \"distributed-roberta\"\n", "model_name = \"seldon-model\"\n", "\n", - "endpoint = f\"http://localhost:8003/seldon/{model_namespace}/{model_name}/api/v1.0/predictions\"\n", + "endpoint = (\n", + " f\"http://localhost:8003/seldon/{model_namespace}/{model_name}/api/v1.0/predictions\"\n", + ")\n", "\n", "r = requests.post(url=endpoint, json={\"data\": {\"ndarray\": payload}})" ] @@ -762,7 +764,9 @@ "model_namespace = \"distributed-roberta\"\n", "model_name = \"seldon-model-ray-proxy\"\n", "\n", - "endpoint = f\"http://localhost:8003/seldon/{model_namespace}/{model_name}/api/v1.0/predictions\"\n", + "endpoint = (\n", + " f\"http://localhost:8003/seldon/{model_namespace}/{model_name}/api/v1.0/predictions\"\n", + ")\n", "\n", "r = requests.post(url=endpoint, json={\"data\": {\"ndarray\": payload}})" ] diff --git a/examples/security/ssl_requests/README.ipynb b/examples/security/ssl_requests/README.ipynb index a7687384a6..6ed879cb8c 100644 --- a/examples/security/ssl_requests/README.ipynb +++ b/examples/security/ssl_requests/README.ipynb @@ -200,7 +200,7 @@ } ], "source": [ - "!kubectl get secret sklearn-default-cert " + "!kubectl get secret sklearn-default-cert" ] }, { diff --git a/examples/streaming/knative-eventing/README.ipynb b/examples/streaming/knative-eventing/README.ipynb index 72683572ca..dfbacd02c7 100644 --- a/examples/streaming/knative-eventing/README.ipynb +++ b/examples/streaming/knative-eventing/README.ipynb @@ -235,7 +235,7 @@ } ], "source": [ - "!kubectl get trigger " + "!kubectl get trigger" ] }, { diff --git a/examples/triton_gpt2/README.ipynb b/examples/triton_gpt2/README.ipynb index a143038412..ffd9497194 100644 --- a/examples/triton_gpt2/README.ipynb +++ b/examples/triton_gpt2/README.ipynb @@ -53,7 +53,7 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install --trusted-host=pypi.python.org --trusted-host=pypi.org --trusted-host=files.pythonhosted.org -r requirements.txt\n" + "!pip install --trusted-host=pypi.python.org --trusted-host=pypi.org --trusted-host=files.pythonhosted.org -r requirements.txt" ] }, { @@ -71,9 +71,12 @@ "metadata": {}, "outputs": [], "source": [ - "from transformers import TFGPT2LMHeadModel, GPT2Tokenizer\n", + "from transformers import GPT2Tokenizer, TFGPT2LMHeadModel\n", + "\n", "tokenizer = GPT2Tokenizer.from_pretrained(\"gpt2\")\n", - "model = TFGPT2LMHeadModel.from_pretrained(\"gpt2\", from_pt=True, pad_token_id=tokenizer.eos_token_id)\n", + "model = TFGPT2LMHeadModel.from_pretrained(\n", + " \"gpt2\", from_pt=True, pad_token_id=tokenizer.eos_token_id\n", + ")\n", "model.save_pretrained(\"./tfgpt2model\", saved_model=True)" ] }, @@ -338,40 +341,45 @@ } ], "source": [ - "import requests\n", "import json\n", + "\n", "import numpy as np\n", + "import requests\n", "from transformers import GPT2Tokenizer\n", "\n", "tokenizer = GPT2Tokenizer.from_pretrained(\"gpt2\")\n", - "input_text = 'I enjoy working in Seldon'\n", + "input_text = \"I enjoy working in Seldon\"\n", "count = 0\n", "max_gen_len = 10\n", "gen_sentence = input_text\n", "while count < max_gen_len:\n", - " input_ids = tokenizer.encode(gen_sentence, return_tensors='tf')\n", + " input_ids = tokenizer.encode(gen_sentence, return_tensors=\"tf\")\n", " shape = input_ids.shape.as_list()\n", " payload = {\n", - " \"inputs\": [\n", - " {\"name\": \"input_ids:0\",\n", - " \"datatype\": \"INT32\",\n", - " \"shape\": shape,\n", - " \"data\": input_ids.numpy().tolist()\n", - " },\n", - " {\"name\": \"attention_mask:0\",\n", - " \"datatype\": \"INT32\",\n", - " \"shape\": shape,\n", - " \"data\": np.ones(shape, dtype=np.int32).tolist()\n", - " }\n", - " ]\n", - " }\n", + " \"inputs\": [\n", + " {\n", + " \"name\": \"input_ids:0\",\n", + " \"datatype\": \"INT32\",\n", + " \"shape\": shape,\n", + " \"data\": input_ids.numpy().tolist(),\n", + " },\n", + " {\n", + " \"name\": \"attention_mask:0\",\n", + " \"datatype\": \"INT32\",\n", + " \"shape\": shape,\n", + " \"data\": np.ones(shape, dtype=np.int32).tolist(),\n", + " },\n", + " ]\n", + " }\n", "\n", - " ret = requests.post('http://localhost:80/seldon/default/gpt2/v2/models/gpt2/infer', json=payload)\n", + " ret = requests.post(\n", + " \"http://localhost:80/seldon/default/gpt2/v2/models/gpt2/infer\", json=payload\n", + " )\n", "\n", " try:\n", " res = ret.json()\n", " except:\n", - " continue\n", + " continue\n", "\n", " # extract logits\n", " logits = np.array(res[\"outputs\"][1][\"data\"])\n", @@ -379,12 +387,13 @@ "\n", " # take the best next token probability of the last token of input ( greedy approach)\n", " next_token = logits.argmax(axis=2)[0]\n", - " next_token_str = tokenizer.decode(next_token[-1:], skip_special_tokens=True,\n", - " clean_up_tokenization_spaces=True).strip()\n", - " gen_sentence += ' ' + next_token_str\n", + " next_token_str = tokenizer.decode(\n", + " next_token[-1:], skip_special_tokens=True, clean_up_tokenization_spaces=True\n", + " ).strip()\n", + " gen_sentence += \" \" + next_token_str\n", " count += 1\n", "\n", - "print(f'Input: {input_text}\\nOutput: {gen_sentence}')" + "print(f\"Input: {input_text}\\nOutput: {gen_sentence}\")" ] }, { @@ -430,39 +439,44 @@ "metadata": {}, "outputs": [], "source": [ - "from subprocess import run, Popen, PIPE\n", + "import base64\n", "import json\n", + "from subprocess import PIPE, Popen, run\n", + "\n", "import numpy as np\n", - "from transformers import TFGPT2LMHeadModel, GPT2Tokenizer\n", - "import base64\n", + "from transformers import GPT2Tokenizer, TFGPT2LMHeadModel\n", "\n", "tokenizer = GPT2Tokenizer.from_pretrained(\"gpt2\")\n", - "input_text = 'I enjoy working in Seldon'\n", - "input_ids = tokenizer.encode(input_text, return_tensors='tf')\n", + "input_text = \"I enjoy working in Seldon\"\n", + "input_ids = tokenizer.encode(input_text, return_tensors=\"tf\")\n", "shape = input_ids.shape.as_list()\n", "payload = {\n", - "\t\t\"inputs\": [\n", - "\t\t\t{\"name\": \"input_ids:0\",\n", - "\t\t\t \"datatype\": \"INT32\",\n", - "\t\t\t \"shape\": shape,\n", - "\t\t\t \"data\": input_ids.numpy().tolist()\n", - "\t\t\t },\n", - "\t\t\t{\"name\": \"attention_mask:0\",\n", - "\t\t\t \"datatype\": \"INT32\",\n", - "\t\t\t \"shape\": shape,\n", - "\t\t\t \"data\": np.ones(shape, dtype=np.int32).tolist()\n", - "\t\t\t }\n", - "\t\t\t]\n", - "\t\t}\n", + " \"inputs\": [\n", + " {\n", + " \"name\": \"input_ids:0\",\n", + " \"datatype\": \"INT32\",\n", + " \"shape\": shape,\n", + " \"data\": input_ids.numpy().tolist(),\n", + " },\n", + " {\n", + " \"name\": \"attention_mask:0\",\n", + " \"datatype\": \"INT32\",\n", + " \"shape\": shape,\n", + " \"data\": np.ones(shape, dtype=np.int32).tolist(),\n", + " },\n", + " ]\n", + "}\n", "\n", - "cmd= {\"method\": \"POST\",\n", - "\t\t\"header\": {\"Content-Type\": [\"application/json\"] },\n", - "\t\t\"url\": \"http://localhost:80/seldon/default/gpt2/v2/models/gpt2/infer\",\n", - "\t\t\"body\": base64.b64encode(bytes(json.dumps(payload), \"utf-8\")).decode(\"utf-8\")}\n", + "cmd = {\n", + " \"method\": \"POST\",\n", + " \"header\": {\"Content-Type\": [\"application/json\"]},\n", + " \"url\": \"http://localhost:80/seldon/default/gpt2/v2/models/gpt2/infer\",\n", + " \"body\": base64.b64encode(bytes(json.dumps(payload), \"utf-8\")).decode(\"utf-8\"),\n", + "}\n", "\n", "with open(\"vegeta_target.json\", mode=\"w\") as file:\n", - "\tjson.dump(cmd, file)\n", - "\tfile.write('\\n\\n')" + " json.dump(cmd, file)\n", + " file.write(\"\\n\\n\")" ] }, { diff --git a/incubating/examples/nodejs_tensorflow/nodejs_tensorflow.ipynb b/incubating/examples/nodejs_tensorflow/nodejs_tensorflow.ipynb index 1901992f41..c8588dc7e7 100644 --- a/incubating/examples/nodejs_tensorflow/nodejs_tensorflow.ipynb +++ b/incubating/examples/nodejs_tensorflow/nodejs_tensorflow.ipynb @@ -437,7 +437,7 @@ "metadata": {}, "outputs": [], "source": [ - "!minikube start --memory 4096 " + "!minikube start --memory 4096" ] }, { diff --git a/notebooks/backwards_compatability.ipynb b/notebooks/backwards_compatability.ipynb index 1377a447fd..0290ad3030 100644 --- a/notebooks/backwards_compatability.ipynb +++ b/notebooks/backwards_compatability.ipynb @@ -76,9 +76,10 @@ "source": [ "from IPython.core.magic import register_line_cell_magic\n", "\n", + "\n", "@register_line_cell_magic\n", "def writetemplate(line, cell):\n", - " with open(line, 'w') as f:\n", + " with open(line, \"w\") as f:\n", " f.write(cell.format(**globals()))" ] }, diff --git a/notebooks/explainer_examples.ipynb b/notebooks/explainer_examples.ipynb index 420cf6e9ca..120d4f0839 100644 --- a/notebooks/explainer_examples.ipynb +++ b/notebooks/explainer_examples.ipynb @@ -191,9 +191,16 @@ }, "outputs": [], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import numpy as np\n", - "sc = SeldonClient(deployment_name=\"income\",namespace=\"seldon\", gateway=\"ambassador\", gateway_endpoint=\"localhost:8003\")" + "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"income\",\n", + " namespace=\"seldon\",\n", + " gateway=\"ambassador\",\n", + " gateway_endpoint=\"localhost:8003\",\n", + ")" ] }, { @@ -358,9 +365,16 @@ }, "outputs": [], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import numpy as np\n", - "sc = SeldonClient(deployment_name=\"movie\", namespace=\"seldon\", gateway_endpoint=\"localhost:8003\", payload_type='ndarray')" + "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"movie\",\n", + " namespace=\"seldon\",\n", + " gateway_endpoint=\"localhost:8003\",\n", + " payload_type=\"ndarray\",\n", + ")" ] }, { @@ -382,10 +396,10 @@ }, "outputs": [], "source": [ - "data = np.array(['this film has great actors'])\n", + "data = np.array([\"this film has great actors\"])\n", "r = sc.predict(data=data)\n", "print(r)\n", - "assert(r.success==True)" + "assert r.success == True" ] }, { @@ -407,7 +421,11 @@ }, "outputs": [], "source": [ - "data = np.array(['a visually exquisite but narratively opaque and emotionally vapid experience of style and mystification'])\n", + "data = np.array(\n", + " [\n", + " \"a visually exquisite but narratively opaque and emotionally vapid experience of style and mystification\"\n", + " ]\n", + ")\n", "explanation = sc.explain(predictor=\"default\", data=data)\n", "print(explanation.response[\"data\"][\"anchor\"])" ] @@ -494,12 +512,13 @@ "metadata": {}, "outputs": [], "source": [ - "import tensorflow as tf\n", - "import matplotlib.pyplot as plt\n", "import os\n", "\n", - "url = 'https://storage.googleapis.com/seldon-models/alibi-detect/classifier/'\n", - "path_model = os.path.join(url, \"cifar10\", \"resnet32\", 'model.h5')\n", + "import matplotlib.pyplot as plt\n", + "import tensorflow as tf\n", + "\n", + "url = \"https://storage.googleapis.com/seldon-models/alibi-detect/classifier/\"\n", + "path_model = os.path.join(url, \"cifar10\", \"resnet32\", \"model.h5\")\n", "save_path = tf.keras.utils.get_file(\"resnet32\", path_model)\n", "model = tf.keras.models.load_model(save_path)\n", "\n", @@ -507,11 +526,21 @@ "X_train, y_train = train\n", "X_test, y_test = test\n", "\n", - "X_train = X_train.astype('float32') / 255\n", - "X_test = X_test.astype('float32') / 255\n", + "X_train = X_train.astype(\"float32\") / 255\n", + "X_test = X_test.astype(\"float32\") / 255\n", "print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)\n", - "class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',\n", - " 'dog', 'frog', 'horse', 'ship', 'truck']" + "class_names = [\n", + " \"airplane\",\n", + " \"automobile\",\n", + " \"bird\",\n", + " \"cat\",\n", + " \"deer\",\n", + " \"dog\",\n", + " \"frog\",\n", + " \"horse\",\n", + " \"ship\",\n", + " \"truck\",\n", + "]" ] }, { @@ -520,27 +549,29 @@ "metadata": {}, "outputs": [], "source": [ - "from subprocess import run, Popen, PIPE\n", "import json\n", + "from subprocess import PIPE, Popen, run\n", + "\n", "import numpy as np\n", - "idx=12\n", - "test_example=X_test[idx:idx+1].tolist()\n", - "payload='{\"instances\":'+f\"{test_example}\"+' }'\n", - "cmd=f\"\"\"curl -d '{payload}' \\\n", + "\n", + "idx = 12\n", + "test_example = X_test[idx : idx + 1].tolist()\n", + "payload = '{\"instances\":' + f\"{test_example}\" + \" }\"\n", + "cmd = f\"\"\"curl -d '{payload}' \\\n", " http://localhost:8003/seldon/seldon/cifar10-classifier/v1/models/cifar10-classifier/:predict \\\n", " -H \"Content-Type: application/json\"\n", "\"\"\"\n", - "ret = Popen(cmd, shell=True,stdout=PIPE)\n", + "ret = Popen(cmd, shell=True, stdout=PIPE)\n", "raw = ret.stdout.read().decode(\"utf-8\")\n", "print(raw)\n", - "res=json.loads(raw)\n", - "arr=np.array(res[\"predictions\"])\n", + "res = json.loads(raw)\n", + "arr = np.array(res[\"predictions\"])\n", "X = X_test[idx].reshape(1, 32, 32, 3)\n", "plt.imshow(X.reshape(32, 32, 3))\n", - "plt.axis('off')\n", + "plt.axis(\"off\")\n", "plt.show()\n", - "print(\"class:\",class_names[y_test[idx][0]])\n", - "print(\"prediction:\",class_names[arr[0].argmax()])" + "print(\"class:\", class_names[y_test[idx][0]])\n", + "print(\"prediction:\", class_names[arr[0].argmax()])" ] }, { @@ -549,13 +580,13 @@ "metadata": {}, "outputs": [], "source": [ - "test_example=X_test[idx:idx+1].tolist()\n", - "payload='{\"instances\":'+f\"{test_example}\"+' }'\n", - "cmd=f\"\"\"curl -d '{payload}' \\\n", + "test_example = X_test[idx : idx + 1].tolist()\n", + "payload = '{\"instances\":' + f\"{test_example}\" + \" }\"\n", + "cmd = f\"\"\"curl -d '{payload}' \\\n", " http://localhost:8003/seldon/seldon/cifar10-classifier-explainer/default/v1/models/cifar10-classifier:explain \\\n", " -H \"Content-Type: application/json\"\n", "\"\"\"\n", - "ret = Popen(cmd, shell=True,stdout=PIPE)\n", + "ret = Popen(cmd, shell=True, stdout=PIPE)\n", "raw = ret.stdout.read().decode(\"utf-8\")\n", "explanation = json.loads(raw)\n", "arr = np.array(explanation[\"data\"][\"anchor\"])\n", @@ -589,6 +620,7 @@ "outputs": [], "source": [ "import shap\n", + "\n", "shap.initjs()" ] }, @@ -600,16 +632,18 @@ "source": [ "from sklearn.datasets import load_wine\n", "from sklearn.model_selection import train_test_split\n", + "\n", "wine = load_wine()\n", "data = wine.data\n", "target = wine.target\n", "target_names = wine.target_names\n", - "feature_names = wine.feature_names\n", - "X_train, X_test, y_train, y_test = train_test_split(data, \n", - " target, \n", - " test_size=0.2, \n", - " random_state=0,\n", - " )\n", + "feature_names = wine.feature_names\n", + "X_train, X_test, y_train, y_test = train_test_split(\n", + " data,\n", + " target,\n", + " test_size=0.2,\n", + " random_state=0,\n", + ")\n", "print(\"Training records: {}\".format(X_train.shape[0]))\n", "print(\"Testing records: {}\".format(X_test.shape[0]))" ] @@ -621,6 +655,7 @@ "outputs": [], "source": [ "from sklearn.preprocessing import StandardScaler\n", + "\n", "scaler = StandardScaler().fit(X_train)\n", "X_train_norm = scaler.transform(X_train)\n", "X_test_norm = scaler.transform(X_test)" @@ -696,9 +731,16 @@ }, "outputs": [], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import numpy as np\n", - "sc = SeldonClient(deployment_name=\"wine\",namespace=\"seldon\", gateway=\"ambassador\", gateway_endpoint=\"localhost:8003\")" + "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"wine\",\n", + " namespace=\"seldon\",\n", + " gateway=\"ambassador\",\n", + " gateway_endpoint=\"localhost:8003\",\n", + ")" ] }, { @@ -716,9 +758,25 @@ }, "outputs": [], "source": [ - "data = np.array([[-0.24226334, 0.26757916, 0.42085937, 0.7127641 , 0.84067236,\n", - " -1.27747161, -0.60582812, -0.9706341 , -0.5873972 , 2.42611713,\n", - " -2.06608025, -1.55017035, -0.86659858]])\n", + "data = np.array(\n", + " [\n", + " [\n", + " -0.24226334,\n", + " 0.26757916,\n", + " 0.42085937,\n", + " 0.7127641,\n", + " 0.84067236,\n", + " -1.27747161,\n", + " -0.60582812,\n", + " -0.9706341,\n", + " -0.5873972,\n", + " 2.42611713,\n", + " -2.06608025,\n", + " -1.55017035,\n", + " -0.86659858,\n", + " ]\n", + " ]\n", + ")\n", "r = sc.predict(data=data)\n", "print(r.response)\n", "class_idx = np.argmax(np.array(r.response[\"data\"][\"tensor\"][\"values\"]))" @@ -758,9 +816,26 @@ "outputs": [], "source": [ "import json\n", - "data = np.array([[-0.24226334, 0.26757916, 0.42085937, 0.7127641 , 0.84067236,\n", - " -1.27747161, -0.60582812, -0.9706341 , -0.5873972 , 2.42611713,\n", - " -2.06608025, -1.55017035, -0.86659858]])\n", + "\n", + "data = np.array(\n", + " [\n", + " [\n", + " -0.24226334,\n", + " 0.26757916,\n", + " 0.42085937,\n", + " 0.7127641,\n", + " 0.84067236,\n", + " -1.27747161,\n", + " -0.60582812,\n", + " -0.9706341,\n", + " -0.5873972,\n", + " 2.42611713,\n", + " -2.06608025,\n", + " -1.55017035,\n", + " -0.86659858,\n", + " ]\n", + " ]\n", + ")\n", "explanation = sc.explain(deployment_name=\"wine\", predictor=\"default\", data=data)\n", "explanation = explanation.response\n", "expStr = json.dumps(explanation)" @@ -773,6 +848,7 @@ "outputs": [], "source": [ "from alibi.api.interfaces import Explanation\n", + "\n", "explanation = Explanation.from_json(expStr)" ] }, @@ -792,11 +868,11 @@ "metadata": {}, "outputs": [], "source": [ - "idx=0\n", + "idx = 0\n", "shap.force_plot(\n", - " explanation.expected_value[class_idx], \n", - " explanation.shap_values[class_idx][idx, :], \n", - " explanation.raw['instances'][idx][None, :], \n", + " explanation.expected_value[class_idx],\n", + " explanation.shap_values[class_idx][idx, :],\n", + " explanation.raw[\"instances\"][idx][None, :],\n", " explanation.feature_names,\n", ")" ] @@ -898,17 +974,18 @@ "metadata": {}, "outputs": [], "source": [ + "import numpy as np\n", "import tensorflow as tf\n", "from tensorflow.keras.utils import to_categorical\n", - "import numpy as np\n", + "\n", "train, test = tf.keras.datasets.mnist.load_data()\n", "X_train, y_train = train\n", "X_test, y_test = test\n", "test_labels = y_test.copy()\n", "train_labels = y_train.copy()\n", - " \n", - "X_train = X_train.reshape(-1, 28, 28, 1).astype('float64') / 255\n", - "X_test = X_test.reshape(-1, 28, 28, 1).astype('float64') / 255\n", + "\n", + "X_train = X_train.reshape(-1, 28, 28, 1).astype(\"float64\") / 255\n", + "X_test = X_test.reshape(-1, 28, 28, 1).astype(\"float64\") / 255\n", "y_train = to_categorical(y_train, 10)\n", "y_test = to_categorical(y_test, 10)\n", "print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)" @@ -931,8 +1008,11 @@ "outputs": [], "source": [ "import json\n", - "d = {\"data\": {\"tensor\":{\"shape\":[10,784],\"values\":X_test_sample.flatten().tolist()}}}\n", - "with open(\"input.json\",\"w\") as f:\n", + "\n", + "d = {\n", + " \"data\": {\"tensor\": {\"shape\": [10, 784], \"values\": X_test_sample.flatten().tolist()}}\n", + "}\n", + "with open(\"input.json\", \"w\") as f:\n", " f.write(json.dumps(d))" ] }, @@ -954,7 +1034,9 @@ "metadata": {}, "outputs": [], "source": [ - "predictions = np.array(res[\"data\"][\"tensor\"][\"values\"]).reshape(res[\"data\"][\"tensor\"][\"shape\"])\n", + "predictions = np.array(res[\"data\"][\"tensor\"][\"values\"]).reshape(\n", + " res[\"data\"][\"tensor\"][\"shape\"]\n", + ")\n", "predictions = predictions.argmax(axis=1)" ] }, @@ -974,8 +1056,16 @@ "outputs": [], "source": [ "import json\n", - "d = {\"data\": {\"tensor\":{\"shape\":X_test_sample.shape,\"values\":X_test_sample.flatten().tolist()}}}\n", - "with open(\"input.json\",\"w\") as f:\n", + "\n", + "d = {\n", + " \"data\": {\n", + " \"tensor\": {\n", + " \"shape\": X_test_sample.shape,\n", + " \"values\": X_test_sample.flatten().tolist(),\n", + " }\n", + " }\n", + "}\n", + "with open(\"input.json\", \"w\") as f:\n", " f.write(json.dumps(d))" ] }, @@ -1008,33 +1098,40 @@ "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "\n", "fig, ax = plt.subplots(nrows=3, ncols=4, figsize=(10, 7))\n", "image_ids = [0, 1, 9]\n", "cmap_bound = np.abs(attrs[[0, 1, 9]]).max()\n", "\n", "for row, image_id in enumerate(image_ids):\n", " # original images\n", - " ax[row, 0].imshow(X_test[image_id].squeeze(), cmap='gray')\n", - " ax[row, 0].set_title(f'Prediction: {predictions[image_id]}')\n", - " \n", + " ax[row, 0].imshow(X_test[image_id].squeeze(), cmap=\"gray\")\n", + " ax[row, 0].set_title(f\"Prediction: {predictions[image_id]}\")\n", + "\n", " # attributions\n", " attr = attrs[image_id]\n", - " im = ax[row, 1].imshow(attr.squeeze(), vmin=-cmap_bound, vmax=cmap_bound, cmap='PiYG')\n", - " \n", + " im = ax[row, 1].imshow(\n", + " attr.squeeze(), vmin=-cmap_bound, vmax=cmap_bound, cmap=\"PiYG\"\n", + " )\n", + "\n", " # positive attributions\n", " attr_pos = attr.clip(0, 1)\n", - " im_pos = ax[row, 2].imshow(attr_pos.squeeze(), vmin=-cmap_bound, vmax=cmap_bound, cmap='PiYG')\n", - " \n", + " im_pos = ax[row, 2].imshow(\n", + " attr_pos.squeeze(), vmin=-cmap_bound, vmax=cmap_bound, cmap=\"PiYG\"\n", + " )\n", + "\n", " # negative attributions\n", " attr_neg = attr.clip(-1, 0)\n", - " im_neg = ax[row, 3].imshow(attr_neg.squeeze(), vmin=-cmap_bound, vmax=cmap_bound, cmap='PiYG')\n", - " \n", - "ax[0, 1].set_title('Attributions');\n", - "ax[0, 2].set_title('Positive attributions');\n", - "ax[0, 3].set_title('Negative attributions');\n", + " im_neg = ax[row, 3].imshow(\n", + " attr_neg.squeeze(), vmin=-cmap_bound, vmax=cmap_bound, cmap=\"PiYG\"\n", + " )\n", + "\n", + "ax[0, 1].set_title(\"Attributions\")\n", + "ax[0, 2].set_title(\"Positive attributions\")\n", + "ax[0, 3].set_title(\"Negative attributions\")\n", "\n", "for ax in fig.axes:\n", - " ax.axis('off')\n", + " ax.axis(\"off\")\n", "\n", "fig.colorbar(im, cax=fig.add_axes([0.95, 0.25, 0.03, 0.5]));" ] @@ -1112,9 +1209,16 @@ }, "outputs": [], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import numpy as np\n", - "sc = SeldonClient(deployment_name=\"income\",namespace=\"seldon\", gateway=\"istio\", gateway_endpoint=\"localhost:8003\")" + "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"income\",\n", + " namespace=\"seldon\",\n", + " gateway=\"istio\",\n", + " gateway_endpoint=\"localhost:8003\",\n", + ")" ] }, { @@ -1140,7 +1244,7 @@ } ], "source": [ - "data = np.array([[52, 4, 0, 2, 8, 4, 2, 0, 0, 0, 60, 9]])\n", + "data = np.array([[52, 4, 0, 2, 8, 4, 2, 0, 0, 0, 60, 9]])\n", "r = sc.predict(data=data)\n", "print(r.response)" ] @@ -1159,6 +1263,7 @@ "outputs": [], "source": [ "from alibi.datasets import fetch_adult\n", + "\n", "adult = fetch_adult()\n", "data = adult.data" ] @@ -1181,11 +1286,12 @@ "source": [ "import json\n", "import time\n", - "#data = np.array([[52, 4, 0, 2, 8, 4, 2, 0, 0, 0, 60, 9]])\n", + "\n", + "# data = np.array([[52, 4, 0, 2, 8, 4, 2, 0, 0, 0, 60, 9]])\n", "start = time.time()\n", "res = sc.explain(deployment_name=\"income\", predictor=\"default\", data=data[0:1000])\n", "end = time.time()\n", - "print(\"Elapsed time:\",end-start)\n", + "print(\"Elapsed time:\", end - start)\n", "explanation = res.response\n", "explanationStr = json.dumps(explanation)" ] @@ -1197,6 +1303,7 @@ "outputs": [], "source": [ "from alibi.api.interfaces import Explanation\n", + "\n", "explanation = Explanation.from_json(explanationStr)" ] }, @@ -1218,14 +1325,14 @@ "source": [ "def decode_data(X, feature_names, category_map):\n", " \"\"\"\n", - " Given an encoded data matrix `X` returns a matrix where the \n", + " Given an encoded data matrix `X` returns a matrix where the\n", " categorical levels have been replaced by human readable categories.\n", " \"\"\"\n", - " \n", + "\n", " # expect 2D array\n", " if len(X.shape) == 1:\n", " X = X.reshape(1, -1)\n", - " \n", + "\n", " X_new = np.zeros(X.shape, dtype=object)\n", " # Check if a column is categorical and replace it with values from category map\n", " for idx, name in enumerate(feature_names):\n", @@ -1236,7 +1343,7 @@ " X_new[encoded_vals, idx] = category\n", " else:\n", " X_new[:, idx] = X[:, idx]\n", - " \n", + "\n", " return X_new" ] }, @@ -1246,7 +1353,9 @@ "metadata": {}, "outputs": [], "source": [ - "decoded_features = decode_data(data,explanation.feature_names,explanation.categorical_names)" + "decoded_features = decode_data(\n", + " data, explanation.feature_names, explanation.categorical_names\n", + ")" ] }, { @@ -1256,6 +1365,7 @@ "outputs": [], "source": [ "import shap\n", + "\n", "shap.initjs()" ] }, @@ -1266,9 +1376,9 @@ "outputs": [], "source": [ "shap.force_plot(\n", - " explanation.expected_value[0], # 0 is a class index but we have single-output model\n", - " explanation.shap_values[0], \n", - " decoded_features, \n", + " explanation.expected_value[0], # 0 is a class index but we have single-output model\n", + " explanation.shap_values[0],\n", + " decoded_features,\n", " explanation.feature_names,\n", ")" ] @@ -1354,9 +1464,16 @@ }, "outputs": [], "source": [ - "from seldon_core.seldon_client import SeldonClient\n", "import numpy as np\n", - "sc = SeldonClient(deployment_name=\"incomegpu\",namespace=\"seldon\", gateway=\"istio\", gateway_endpoint=\"localhost:8003\")" + "\n", + "from seldon_core.seldon_client import SeldonClient\n", + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"incomegpu\",\n", + " namespace=\"seldon\",\n", + " gateway=\"istio\",\n", + " gateway_endpoint=\"localhost:8003\",\n", + ")" ] }, { @@ -1382,7 +1499,7 @@ } ], "source": [ - "data = np.array([[52, 4, 0, 2, 8, 4, 2, 0, 0, 0, 60, 9]])\n", + "data = np.array([[52, 4, 0, 2, 8, 4, 2, 0, 0, 0, 60, 9]])\n", "r = sc.predict(data=data)\n", "print(r.response)" ] @@ -1401,6 +1518,7 @@ "outputs": [], "source": [ "from alibi.datasets import fetch_adult\n", + "\n", "adult = fetch_adult()\n", "data = adult.data" ] @@ -1420,10 +1538,11 @@ ], "source": [ "import time\n", + "\n", "start = time.time()\n", "res = sc.explain(deployment_name=\"incomegpu\", predictor=\"default\", data=data[0:1000])\n", "end = time.time()\n", - "print(\"Elapsed time:\",end-start)" + "print(\"Elapsed time:\", end - start)" ] }, { @@ -1454,7 +1573,7 @@ " explanation = res.response\n", " explanationStr = json.dumps(explanation)\n", " explanation = Explanation.from_json(explanationStr)\n", - " \n", + "\n", " explanation.shap_values = np.array(explanation.shap_values)\n", " explanation.raw[\"instances\"] = np.array(explanation.raw[\"instances\"])\n", "else:\n", @@ -1470,14 +1589,14 @@ "source": [ "def decode_data(X, feature_names, category_map):\n", " \"\"\"\n", - " Given an encoded data matrix `X` returns a matrix where the \n", + " Given an encoded data matrix `X` returns a matrix where the\n", " categorical levels have been replaced by human readable categories.\n", " \"\"\"\n", - " \n", + "\n", " # expect 2D array\n", " if len(X.shape) == 1:\n", " X = X.reshape(1, -1)\n", - " \n", + "\n", " X_new = np.zeros(X.shape, dtype=object)\n", " # Check if a column is categorical and replace it with values from category map\n", " for idx, name in enumerate(feature_names):\n", @@ -1488,7 +1607,7 @@ " X_new[encoded_vals, idx] = category\n", " else:\n", " X_new[:, idx] = X[:, idx]\n", - " \n", + "\n", " return X_new" ] }, @@ -1542,6 +1661,7 @@ ], "source": [ "import shap\n", + "\n", "shap.initjs()" ] }, @@ -1580,12 +1700,16 @@ ], "source": [ "if explanation is not None:\n", - " decoded_features = decode_data(data, explanation.feature_names, explanation.categorical_names)\n", + " decoded_features = decode_data(\n", + " data, explanation.feature_names, explanation.categorical_names\n", + " )\n", " shap.force_plot(\n", - " explanation.expected_value[0], # 0 is a class index but we have single-output model\n", - " explanation.shap_values[0],\n", - " decoded_features,\n", - " explanation.feature_names,\n", + " explanation.expected_value[\n", + " 0\n", + " ], # 0 is a class index but we have single-output model\n", + " explanation.shap_values[0],\n", + " decoded_features,\n", + " explanation.feature_names,\n", " )" ] }, diff --git a/notebooks/helm_examples.ipynb b/notebooks/helm_examples.ipynb index 646c62efc9..aa2d3255de 100644 --- a/notebooks/helm_examples.ipynb +++ b/notebooks/helm_examples.ipynb @@ -180,7 +180,13 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"mymodel\",namespace=\"seldon\",gateway_endpoint=\"localhost:8003\",gateway=\"ambassador\")" + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"mymodel\",\n", + " namespace=\"seldon\",\n", + " gateway_endpoint=\"localhost:8003\",\n", + " gateway=\"ambassador\",\n", + ")" ] }, { @@ -220,7 +226,7 @@ ], "source": [ "r = sc.predict(transport=\"rest\")\n", - "assert(r.success==True)\n", + "assert r.success == True\n", "print(r)" ] }, @@ -440,7 +446,13 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"myabtest\",namespace=\"seldon\",gateway_endpoint=\"localhost:8003\",gateway=\"ambassador\")" + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"myabtest\",\n", + " namespace=\"seldon\",\n", + " gateway_endpoint=\"localhost:8003\",\n", + " gateway=\"ambassador\",\n", + ")" ] }, { @@ -480,7 +492,7 @@ ], "source": [ "r = sc.predict(transport=\"rest\")\n", - "assert(r.success==True)\n", + "assert r.success == True\n", "print(r)" ] }, @@ -736,7 +748,13 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"mymab\",namespace=\"seldon\",gateway_endpoint=\"localhost:8003\",gateway=\"ambassador\")" + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"mymab\",\n", + " namespace=\"seldon\",\n", + " gateway_endpoint=\"localhost:8003\",\n", + " gateway=\"ambassador\",\n", + ")" ] }, { @@ -776,7 +794,7 @@ ], "source": [ "r = sc.predict(transport=\"rest\")\n", - "assert(r.success==True)\n", + "assert r.success == True\n", "print(r)" ] }, diff --git a/notebooks/istio_example.ipynb b/notebooks/istio_example.ipynb index 5e976a8199..113ab5c2ad 100644 --- a/notebooks/istio_example.ipynb +++ b/notebooks/istio_example.ipynb @@ -302,7 +302,10 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"mymodel\",namespace=\"seldon\",gateway_endpoint=ISTIO_GATEWAY)" + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"mymodel\", namespace=\"seldon\", gateway_endpoint=ISTIO_GATEWAY\n", + ")" ] }, { @@ -341,8 +344,8 @@ } ], "source": [ - "r = sc.predict(gateway=\"istio\",transport=\"rest\")\n", - "assert(r.success==True)\n", + "r = sc.predict(gateway=\"istio\", transport=\"rest\")\n", + "assert r.success == True\n", "print(r)" ] }, @@ -371,8 +374,8 @@ } ], "source": [ - "r = sc.predict(gateway=\"istio\",transport=\"grpc\")\n", - "assert(r.success==True)\n", + "r = sc.predict(gateway=\"istio\", transport=\"grpc\")\n", + "assert r.success == True\n", "print(r)" ] }, diff --git a/notebooks/max_grpc_msg_size.ipynb b/notebooks/max_grpc_msg_size.ipynb index 193bdc5461..d6f834659c 100644 --- a/notebooks/max_grpc_msg_size.ipynb +++ b/notebooks/max_grpc_msg_size.ipynb @@ -28,9 +28,10 @@ "source": [ "from IPython.core.magic import register_line_cell_magic\n", "\n", + "\n", "@register_line_cell_magic\n", "def writetemplate(line, cell):\n", - " with open(line, 'w') as f:\n", + " with open(line, \"w\") as f:\n", " f.write(cell.format(**globals()))" ] }, @@ -216,8 +217,13 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"model-long-timeout\",namespace=\"seldon\", \n", - " grpc_max_send_message_length=50 * 1024 * 1024, grpc_max_receive_message_length=50 * 1024 * 1024)" + "\n", + "sc = SeldonClient(\n", + " deployment_name=\"model-long-timeout\",\n", + " namespace=\"seldon\",\n", + " grpc_max_send_message_length=50 * 1024 * 1024,\n", + " grpc_max_receive_message_length=50 * 1024 * 1024,\n", + ")" ] }, { @@ -247,8 +253,8 @@ } ], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"grpc\")\n", - "assert(r.success==True)\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"grpc\")\n", + "assert r.success == True\n", "print(r)" ] }, @@ -279,8 +285,8 @@ } ], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"grpc\",shape=(1000000,1))\n", - "print(r.success,r.msg)" + "r = sc.predict(gateway=\"ambassador\", transport=\"grpc\", shape=(1000000, 1))\n", + "print(r.success, r.msg)" ] }, { @@ -420,10 +426,14 @@ } ], "source": [ - "sc = SeldonClient(deployment_name=\"seldon-model\",namespace=\"seldon\",\n", - " grpc_max_send_message_length=50 * 1024 * 1024, grpc_max_receive_message_length=50 * 1024 * 1024)\n", - "r = sc.predict(gateway=\"ambassador\",transport=\"grpc\",shape=(1000000,1))\n", - "assert(r.success==True)\n", + "sc = SeldonClient(\n", + " deployment_name=\"seldon-model\",\n", + " namespace=\"seldon\",\n", + " grpc_max_send_message_length=50 * 1024 * 1024,\n", + " grpc_max_receive_message_length=50 * 1024 * 1024,\n", + ")\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"grpc\", shape=(1000000, 1))\n", + "assert r.success == True\n", "print(r.success)" ] }, diff --git a/notebooks/minio_setup.ipynb b/notebooks/minio_setup.ipynb index ec58710b0e..a561ef922e 100644 --- a/notebooks/minio_setup.ipynb +++ b/notebooks/minio_setup.ipynb @@ -35,7 +35,7 @@ "metadata": {}, "outputs": [], "source": [ - "!kubectl rollout status deployment -n minio-system minio " + "!kubectl rollout status deployment -n minio-system minio" ] }, { diff --git a/notebooks/operator_upgrade.ipynb b/notebooks/operator_upgrade.ipynb index 6de3694ffd..2b80403483 100644 --- a/notebooks/operator_upgrade.ipynb +++ b/notebooks/operator_upgrade.ipynb @@ -40,8 +40,8 @@ "metadata": {}, "outputs": [], "source": [ - "import time\n", - "import json" + "import json\n", + "import time" ] }, { @@ -376,7 +376,7 @@ "outputs": [], "source": [ "actual = waitStatus(False)\n", - "assert(actual==False)" + "assert actual == False" ] }, { @@ -386,7 +386,7 @@ "outputs": [], "source": [ "actual = waitStatus(True)\n", - "assert(actual==True)" + "assert actual == True" ] }, { @@ -395,16 +395,16 @@ "metadata": {}, "outputs": [], "source": [ - "#Give time for resources to terminate\n", + "# Give time for resources to terminate\n", "for i in range(120):\n", - " (dp2,svc2,vs2,hpa2) = getResourceStats()\n", - " if dp1==dp2 and svc1==svc2 and vs1==vs2 and hpa1==hpa2:\n", + " (dp2, svc2, vs2, hpa2) = getResourceStats()\n", + " if dp1 == dp2 and svc1 == svc2 and vs1 == vs2 and hpa1 == hpa2:\n", " break\n", " time.sleep(1)\n", - "assert(dp1==dp2)\n", - "assert(svc1==svc2)\n", - "assert(vs1==vs2)\n", - "assert(hpa1==hpa2)" + "assert dp1 == dp2\n", + "assert svc1 == svc2\n", + "assert vs1 == vs2\n", + "assert hpa1 == hpa2" ] }, { diff --git a/notebooks/seldon_client.ipynb b/notebooks/seldon_client.ipynb index 665e47fdb9..203634f7e2 100644 --- a/notebooks/seldon_client.ipynb +++ b/notebooks/seldon_client.ipynb @@ -50,7 +50,7 @@ "metadata": {}, "outputs": [], "source": [ - "TOKEN=\"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjM2MjA0ODYsImlhdCI6MTU2MzUzNDA4NiwiaXNzIjoiMzQuNjUuNzMuMjU1IiwianRpIjoiYjllNDQxOGQtZjNmNC00NTIyLTg5ODEtNDcxOTY0ODNmODg3IiwidWlmIjoiZXlKcGMzTWlPaUpvZEhSd2N6b3ZMek0wTGpZMUxqY3pMakkxTlRvMU5UVTJMMlJsZUNJc0luTjFZaUk2SWtOcFVYZFBSMFUwVG1wbk1GbHBNV3RaYW1jMFRGUlNhVTU2VFhSUFZFSm9UMU13ZWxreVVYaE9hbGw0V21wVk1FNXFXVk5DVjNoMldUSkdjeUlzSW1GMVpDSTZJbXQxWW1WbWJHOTNMV0YxZEdoelpYSjJhV05sTFc5cFpHTWlMQ0psZUhBaU9qRTFOak0yTWpBME9EWXNJbWxoZENJNk1UVTJNelV6TkRBNE5pd2lZWFJmYUdGemFDSTZJbE5OWlZWRGJUQmFOVkZoUTNCdVNHTndRMWgwTVZFaUxDSmxiV0ZwYkNJNkltRmtiV2x1UUhObGJHUnZiaTVwYnlJc0ltVnRZV2xzWDNabGNtbG1hV1ZrSWpwMGNuVmxMQ0p1WVcxbElqb2lZV1J0YVc0aWZRPT0ifQ.7CQIz4A1s9m6lJeWTqpz_JKGArGX4e_zpRCOXXjVRJgguB3z48rSfei_KL7niMCWpruhU11c8UIw9E79PwHNNw\"" + "TOKEN = \"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjM2MjA0ODYsImlhdCI6MTU2MzUzNDA4NiwiaXNzIjoiMzQuNjUuNzMuMjU1IiwianRpIjoiYjllNDQxOGQtZjNmNC00NTIyLTg5ODEtNDcxOTY0ODNmODg3IiwidWlmIjoiZXlKcGMzTWlPaUpvZEhSd2N6b3ZMek0wTGpZMUxqY3pMakkxTlRvMU5UVTJMMlJsZUNJc0luTjFZaUk2SWtOcFVYZFBSMFUwVG1wbk1GbHBNV3RaYW1jMFRGUlNhVTU2VFhSUFZFSm9UMU13ZWxreVVYaE9hbGw0V21wVk1FNXFXVk5DVjNoMldUSkdjeUlzSW1GMVpDSTZJbXQxWW1WbWJHOTNMV0YxZEdoelpYSjJhV05sTFc5cFpHTWlMQ0psZUhBaU9qRTFOak0yTWpBME9EWXNJbWxoZENJNk1UVTJNelV6TkRBNE5pd2lZWFJmYUdGemFDSTZJbE5OWlZWRGJUQmFOVkZoUTNCdVNHTndRMWgwTVZFaUxDSmxiV0ZwYkNJNkltRmtiV2x1UUhObGJHUnZiaTVwYnlJc0ltVnRZV2xzWDNabGNtbG1hV1ZrSWpwMGNuVmxMQ0p1WVcxbElqb2lZV1J0YVc0aWZRPT0ifQ.7CQIz4A1s9m6lJeWTqpz_JKGArGX4e_zpRCOXXjVRJgguB3z48rSfei_KL7niMCWpruhU11c8UIw9E79PwHNNw\"" ] }, { @@ -70,8 +70,8 @@ "metadata": {}, "outputs": [], "source": [ - "deployment_name=\"test1\"\n", - "namespace=\"default\"" + "deployment_name = \"test1\"\n", + "namespace = \"default\"" ] }, { @@ -80,10 +80,20 @@ "metadata": {}, "outputs": [], "source": [ - "from seldon_core.seldon_client import SeldonClient, SeldonChannelCredentials, SeldonCallCredentials\n", - "sc = SeldonClient(deployment_name=deployment_name,namespace=namespace,gateway_endpoint=ISTIO_GATEWAY,debug=True,\n", - " channel_credentials=SeldonChannelCredentials(verify=False),\n", - " call_credentials=SeldonCallCredentials(token=TOKEN))" + "from seldon_core.seldon_client import (\n", + " SeldonCallCredentials,\n", + " SeldonChannelCredentials,\n", + " SeldonClient,\n", + ")\n", + "\n", + "sc = SeldonClient(\n", + " deployment_name=deployment_name,\n", + " namespace=namespace,\n", + " gateway_endpoint=ISTIO_GATEWAY,\n", + " debug=True,\n", + " channel_credentials=SeldonChannelCredentials(verify=False),\n", + " call_credentials=SeldonCallCredentials(token=TOKEN),\n", + ")" ] }, { @@ -92,7 +102,7 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"istio\",transport=\"rest\",shape=(1,4))\n", + "r = sc.predict(gateway=\"istio\", transport=\"rest\", shape=(1, 4))\n", "print(r)" ] }, @@ -121,7 +131,7 @@ "outputs": [], "source": [ "# Set to folder where the httpbin certificates are\n", - "ISTIO_HTTPBIN_CERT_FOLDER='/home/clive/work/istio/httpbin.example.com'" + "ISTIO_HTTPBIN_CERT_FOLDER = \"/home/clive/work/istio/httpbin.example.com\"" ] }, { @@ -141,8 +151,8 @@ "metadata": {}, "outputs": [], "source": [ - "deployment_name=\"mymodel\"\n", - "namespace=\"default\"" + "deployment_name = \"mymodel\"\n", + "namespace = \"default\"" ] }, { @@ -151,12 +161,26 @@ "metadata": {}, "outputs": [], "source": [ - "from seldon_core.seldon_client import SeldonClient, SeldonChannelCredentials, SeldonCallCredentials\n", - "sc = SeldonClient(deployment_name=deployment_name,namespace=namespace,gateway_endpoint=\"httpbin.example.com\",debug=True,\n", - " channel_credentials=SeldonChannelCredentials(certificate_chain_file=ISTIO_HTTPBIN_CERT_FOLDER+'/2_intermediate/certs/ca-chain.cert.pem',\n", - " root_certificates_file=ISTIO_HTTPBIN_CERT_FOLDER+'/4_client/certs/httpbin.example.com.cert.pem',\n", - " private_key_file=ISTIO_HTTPBIN_CERT_FOLDER+'/4_client/private/httpbin.example.com.key.pem'\n", - " ))" + "from seldon_core.seldon_client import (\n", + " SeldonCallCredentials,\n", + " SeldonChannelCredentials,\n", + " SeldonClient,\n", + ")\n", + "\n", + "sc = SeldonClient(\n", + " deployment_name=deployment_name,\n", + " namespace=namespace,\n", + " gateway_endpoint=\"httpbin.example.com\",\n", + " debug=True,\n", + " channel_credentials=SeldonChannelCredentials(\n", + " certificate_chain_file=ISTIO_HTTPBIN_CERT_FOLDER\n", + " + \"/2_intermediate/certs/ca-chain.cert.pem\",\n", + " root_certificates_file=ISTIO_HTTPBIN_CERT_FOLDER\n", + " + \"/4_client/certs/httpbin.example.com.cert.pem\",\n", + " private_key_file=ISTIO_HTTPBIN_CERT_FOLDER\n", + " + \"/4_client/private/httpbin.example.com.key.pem\",\n", + " ),\n", + ")" ] }, { @@ -165,7 +189,7 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"istio\",transport=\"rest\",shape=(1,4))\n", + "r = sc.predict(gateway=\"istio\", transport=\"rest\", shape=(1, 4))\n", "print(r)" ] }, @@ -175,7 +199,7 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"istio\",transport=\"grpc\",shape=(1,4))\n", + "r = sc.predict(gateway=\"istio\", transport=\"grpc\", shape=(1, 4))\n", "print(r)" ] } diff --git a/notebooks/server_examples.ipynb b/notebooks/server_examples.ipynb index 3f6ce6cba0..55ac7daafe 100644 --- a/notebooks/server_examples.ipynb +++ b/notebooks/server_examples.ipynb @@ -148,7 +148,8 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"sklearn\",namespace=\"seldon\")" + "\n", + "sc = SeldonClient(deployment_name=\"sklearn\", namespace=\"seldon\")" ] }, { @@ -157,9 +158,9 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\",shape=(1,4))\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\", shape=(1, 4))\n", "print(r)\n", - "assert(r.success==True)" + "assert r.success == True" ] }, { @@ -175,9 +176,9 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"grpc\",shape=(1,4))\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"grpc\", shape=(1, 4))\n", "print(r)\n", - "assert(r.success==True)" + "assert r.success == True" ] }, { @@ -285,17 +286,13 @@ "metadata": {}, "outputs": [], "source": [ - "import requests\n", "import json\n", "\n", + "import requests\n", + "\n", "inference_request = {\n", " \"inputs\": [\n", - " {\n", - " \"name\": \"predict\",\n", - " \"shape\": [1, 4],\n", - " \"datatype\": \"FP32\",\n", - " \"data\": [[1, 2, 3, 4]]\n", - " }\n", + " {\"name\": \"predict\", \"shape\": [1, 4], \"datatype\": \"FP32\", \"data\": [[1, 2, 3, 4]]}\n", " ]\n", "}\n", "\n", @@ -421,7 +418,8 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"xgboost\",namespace=\"seldon\")" + "\n", + "sc = SeldonClient(deployment_name=\"xgboost\", namespace=\"seldon\")" ] }, { @@ -430,9 +428,9 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\",shape=(1,4))\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\", shape=(1, 4))\n", "print(r)\n", - "assert(r.success==True)" + "assert r.success == True" ] }, { @@ -448,9 +446,9 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"grpc\",shape=(1,4))\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"grpc\", shape=(1, 4))\n", "print(r)\n", - "assert(r.success==True)" + "assert r.success == True" ] }, { @@ -558,17 +556,13 @@ "metadata": {}, "outputs": [], "source": [ - "import requests\n", "import json\n", "\n", + "import requests\n", + "\n", "inference_request = {\n", " \"inputs\": [\n", - " {\n", - " \"name\": \"predict\",\n", - " \"shape\": [1, 4],\n", - " \"datatype\": \"FP32\",\n", - " \"data\": [[1, 2, 3, 4]]\n", - " }\n", + " {\"name\": \"predict\", \"shape\": [1, 4], \"datatype\": \"FP32\", \"data\": [[1, 2, 3, 4]]}\n", " ]\n", "}\n", "\n", @@ -680,7 +674,8 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"tfserving\",namespace=\"seldon\")" + "\n", + "sc = SeldonClient(deployment_name=\"tfserving\", namespace=\"seldon\")" ] }, { @@ -696,9 +691,9 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\",shape=(1,784))\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\", shape=(1, 784))\n", "print(r)\n", - "assert(r.success==True)" + "assert r.success == True" ] }, { @@ -714,9 +709,9 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"grpc\",shape=(1,784))\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"grpc\", shape=(1, 784))\n", "print(r)\n", - "assert(r.success==True)" + "assert r.success == True" ] }, { @@ -933,7 +928,8 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", - "sc = SeldonClient(deployment_name=\"mlflow\",namespace=\"seldon\")" + "\n", + "sc = SeldonClient(deployment_name=\"mlflow\", namespace=\"seldon\")" ] }, { @@ -942,9 +938,9 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"rest\",shape=(1,11))\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"rest\", shape=(1, 11))\n", "print(r)\n", - "assert(r.success==True)" + "assert r.success == True" ] }, { @@ -974,9 +970,9 @@ "metadata": {}, "outputs": [], "source": [ - "r = sc.predict(gateway=\"ambassador\",transport=\"grpc\",shape=(1,11))\n", + "r = sc.predict(gateway=\"ambassador\", transport=\"grpc\", shape=(1, 11))\n", "print(r)\n", - "assert(r.success==True)" + "assert r.success == True" ] }, { diff --git a/notebooks/timeouts.ipynb b/notebooks/timeouts.ipynb index 400d9af823..a477f811c5 100644 --- a/notebooks/timeouts.ipynb +++ b/notebooks/timeouts.ipynb @@ -68,9 +68,10 @@ "source": [ "from IPython.core.magic import register_line_cell_magic\n", "\n", + "\n", "@register_line_cell_magic\n", "def writetemplate(line, cell):\n", - " with open(line, 'w') as f:\n", + " with open(line, \"w\") as f:\n", " f.write(cell.format(**globals()))" ] }, diff --git a/notebooks/triton_examples.ipynb b/notebooks/triton_examples.ipynb index 947ecfd7be..9a62965afd 100644 --- a/notebooks/triton_examples.ipynb +++ b/notebooks/triton_examples.ipynb @@ -86,16 +86,27 @@ } ], "source": [ - "import tensorflow as tf\n", - "import matplotlib.pyplot as plt\n", "import os\n", "\n", + "import matplotlib.pyplot as plt\n", + "import tensorflow as tf\n", + "\n", "train, test = tf.keras.datasets.cifar10.load_data()\n", "X_test, y_test = test\n", - "X_test = X_test.astype('float32') / 255\n", + "X_test = X_test.astype(\"float32\") / 255\n", "print(X_test.shape, y_test.shape)\n", - "class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',\n", - " 'dog', 'frog', 'horse', 'ship', 'truck']" + "class_names = [\n", + " \"airplane\",\n", + " \"automobile\",\n", + " \"bird\",\n", + " \"cat\",\n", + " \"deer\",\n", + " \"dog\",\n", + " \"frog\",\n", + " \"horse\",\n", + " \"ship\",\n", + " \"truck\",\n", + "]" ] }, { @@ -212,26 +223,32 @@ } ], "source": [ - "from subprocess import run, Popen, PIPE\n", "import json\n", + "from subprocess import PIPE, Popen, run\n", + "\n", "import numpy as np\n", - "idx=1\n", - "test_example=X_test[idx:idx+1].tolist()\n", - "payload='{\"inputs\":[{\"name\":\"input_1\",\"datatype\":\"FP32\",\"shape\":[1, 32, 32, 3],\"data\":'+f\"{test_example}\"+'}]}'\n", - "cmd=f\"\"\"curl -d '{payload}' \\\n", + "\n", + "idx = 1\n", + "test_example = X_test[idx : idx + 1].tolist()\n", + "payload = (\n", + " '{\"inputs\":[{\"name\":\"input_1\",\"datatype\":\"FP32\",\"shape\":[1, 32, 32, 3],\"data\":'\n", + " + f\"{test_example}\"\n", + " + \"}]}\"\n", + ")\n", + "cmd = f\"\"\"curl -d '{payload}' \\\n", " http://localhost:8003/seldon/seldon/cifar10/v2/models/cifar10/infer \\\n", " -H \"Content-Type: application/json\"\n", "\"\"\"\n", - "ret = Popen(cmd, shell=True,stdout=PIPE)\n", + "ret = Popen(cmd, shell=True, stdout=PIPE)\n", "raw = ret.stdout.read().decode(\"utf-8\")\n", - "res=json.loads(raw)\n", - "arr=np.array(res[\"outputs\"][0][\"data\"])\n", + "res = json.loads(raw)\n", + "arr = np.array(res[\"outputs\"][0][\"data\"])\n", "X = X_test[idx].reshape(1, 32, 32, 3)\n", "plt.imshow(X.reshape(32, 32, 3))\n", - "plt.axis('off')\n", + "plt.axis(\"off\")\n", "plt.show()\n", - "print(\"class:\",class_names[y_test[idx][0]])\n", - "print(\"prediction:\",class_names[arr.argmax()])" + "print(\"class:\", class_names[y_test[idx][0]])\n", + "print(\"prediction:\", class_names[arr.argmax()])" ] }, { @@ -357,26 +374,32 @@ } ], "source": [ - "from subprocess import run, Popen, PIPE\n", "import json\n", + "from subprocess import PIPE, Popen, run\n", + "\n", "import numpy as np\n", - "idx=1\n", - "test_example=X_test[idx:idx+1].tolist()\n", - "payload='{\"inputs\":[{\"name\":\"input_1:0\",\"datatype\":\"FP32\",\"shape\":[1, 32, 32, 3],\"data\":'+f\"{test_example}\"+'}]}'\n", - "cmd=f\"\"\"curl -d '{payload}' \\\n", + "\n", + "idx = 1\n", + "test_example = X_test[idx : idx + 1].tolist()\n", + "payload = (\n", + " '{\"inputs\":[{\"name\":\"input_1:0\",\"datatype\":\"FP32\",\"shape\":[1, 32, 32, 3],\"data\":'\n", + " + f\"{test_example}\"\n", + " + \"}]}\"\n", + ")\n", + "cmd = f\"\"\"curl -d '{payload}' \\\n", " http://localhost:8003/seldon/seldon/cifar10/v2/models/cifar10/infer \\\n", " -H \"Content-Type: application/json\"\n", "\"\"\"\n", - "ret = Popen(cmd, shell=True,stdout=PIPE)\n", + "ret = Popen(cmd, shell=True, stdout=PIPE)\n", "raw = ret.stdout.read().decode(\"utf-8\")\n", - "res=json.loads(raw)\n", - "arr=np.array(res[\"outputs\"][0][\"data\"])\n", + "res = json.loads(raw)\n", + "arr = np.array(res[\"outputs\"][0][\"data\"])\n", "X = X_test[idx].reshape(1, 32, 32, 3)\n", "plt.imshow(X.reshape(32, 32, 3))\n", - "plt.axis('off')\n", + "plt.axis(\"off\")\n", "plt.show()\n", - "print(\"class:\",class_names[y_test[idx][0]])\n", - "print(\"prediction:\",class_names[arr.argmax()])" + "print(\"class:\", class_names[y_test[idx][0]])\n", + "print(\"prediction:\", class_names[arr.argmax()])" ] }, { @@ -494,12 +517,15 @@ "import torchvision.transforms as transforms\n", "\n", "transform = transforms.Compose(\n", - " [transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])\n", - "testset = torchvision.datasets.CIFAR10(root='./data', train=False,\n", - " download=True, transform=transform)\n", + " [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]\n", + ")\n", + "testset = torchvision.datasets.CIFAR10(\n", + " root=\"./data\", train=False, download=True, transform=transform\n", + ")\n", "\n", - "testloader = torch.utils.data.DataLoader(testset, batch_size=10,\n", - " shuffle=False, num_workers=2)\n", + "testloader = torch.utils.data.DataLoader(\n", + " testset, batch_size=10, shuffle=False, num_workers=2\n", + ")\n", "for data in testloader:\n", " images, labels = data\n", " break" @@ -532,28 +558,34 @@ } ], "source": [ - "from subprocess import run, Popen, PIPE\n", "import json\n", + "from subprocess import PIPE, Popen, run\n", + "\n", "import numpy as np\n", - "idx=3\n", - "test_example=images[idx:idx+1]\n", + "\n", + "idx = 3\n", + "test_example = images[idx : idx + 1]\n", "test_example = test_example.tolist()\n", - "payload='{\"inputs\":[{\"name\":\"input__0\",\"datatype\":\"FP32\",\"shape\":[1, 3, 32, 32],\"data\":'+f\"{test_example}\"+'}]}'\n", - "cmd=f\"\"\"curl -d '{payload}' \\\n", + "payload = (\n", + " '{\"inputs\":[{\"name\":\"input__0\",\"datatype\":\"FP32\",\"shape\":[1, 3, 32, 32],\"data\":'\n", + " + f\"{test_example}\"\n", + " + \"}]}\"\n", + ")\n", + "cmd = f\"\"\"curl -d '{payload}' \\\n", " http://localhost:8003/seldon/seldon/cifar10/v2/models/cifar10/infer \\\n", " -H \"Content-Type: application/json\"\n", "\"\"\"\n", - "ret = Popen(cmd, shell=True,stdout=PIPE)\n", + "ret = Popen(cmd, shell=True, stdout=PIPE)\n", "raw = ret.stdout.read().decode(\"utf-8\")\n", - "res=json.loads(raw)\n", - "arr=np.array(res[\"outputs\"][0][\"data\"])\n", + "res = json.loads(raw)\n", + "arr = np.array(res[\"outputs\"][0][\"data\"])\n", "X = X_test[idx].reshape(1, 32, 32, 3)\n", "plt.imshow(X.reshape(32, 32, 3))\n", - "plt.axis('off')\n", + "plt.axis(\"off\")\n", "plt.show()\n", "\n", - "print(\"class:\",class_names[labels[idx]])\n", - "print(\"prediction:\",class_names[arr.argmax()])" + "print(\"class:\", class_names[labels[idx]])\n", + "print(\"prediction:\", class_names[arr.argmax()])" ] }, { @@ -676,26 +708,32 @@ } ], "source": [ - "from subprocess import run, Popen, PIPE\n", "import json\n", + "from subprocess import PIPE, Popen, run\n", + "\n", "import numpy as np\n", - "idx=1\n", - "test_example=X_test[idx:idx+1].tolist()\n", - "payload='{\"inputs\":[{\"name\":\"input_1\",\"datatype\":\"FP32\",\"shape\":[1, 32, 32, 3],\"data\":'+f\"{test_example}\"+'}]}'\n", - "cmd=f\"\"\"curl -d '{payload}' \\\n", + "\n", + "idx = 1\n", + "test_example = X_test[idx : idx + 1].tolist()\n", + "payload = (\n", + " '{\"inputs\":[{\"name\":\"input_1\",\"datatype\":\"FP32\",\"shape\":[1, 32, 32, 3],\"data\":'\n", + " + f\"{test_example}\"\n", + " + \"}]}\"\n", + ")\n", + "cmd = f\"\"\"curl -d '{payload}' \\\n", " http://localhost:8003/seldon/seldon/multi/v2/models/cifar10/infer \\\n", " -H \"Content-Type: application/json\"\n", "\"\"\"\n", - "ret = Popen(cmd, shell=True,stdout=PIPE)\n", + "ret = Popen(cmd, shell=True, stdout=PIPE)\n", "raw = ret.stdout.read().decode(\"utf-8\")\n", - "res=json.loads(raw)\n", - "arr=np.array(res[\"outputs\"][0][\"data\"])\n", + "res = json.loads(raw)\n", + "arr = np.array(res[\"outputs\"][0][\"data\"])\n", "X = X_test[idx].reshape(1, 32, 32, 3)\n", "plt.imshow(X.reshape(32, 32, 3))\n", - "plt.axis('off')\n", + "plt.axis(\"off\")\n", "plt.show()\n", - "print(\"class:\",class_names[y_test[idx][0]])\n", - "print(\"prediction:\",class_names[arr.argmax()])" + "print(\"class:\", class_names[y_test[idx][0]])\n", + "print(\"prediction:\", class_names[arr.argmax()])" ] }, { diff --git a/python/Makefile b/python/Makefile index faa7d586e5..016a6c0664 100644 --- a/python/Makefile +++ b/python/Makefile @@ -95,7 +95,7 @@ push_conda: @echo "Alternatively use anaconda upload to publish on own channel" setup_linter: - pip install black==20.8b1 isort==5.7.0 + pip install black==20.8b1 isort==5.7.0 nbqa==0.10.0 fmt: black \ @@ -104,6 +104,12 @@ fmt: isort \ ./ ../testing/scripts ../operator/helm ../operator/hack \ --skip proto --skip seldon_core/proto --skip .eggs --skip .tox + nbqa black \ + ../ --nbqa-skip-bad-cells --nbqa-mutate \ + --nbqa-exclude "(proto|seldon_core/proto/|.eggs|.tox|_README\.ipynb)" + nbqa isort \ + ../ --profile black --nbqa-skip-bad-cells --nbqa-mutate \ + --nbqa-exclude "(proto|seldon_core/proto/|.eggs|.tox|_README\.ipynb)" lint: licenses black \ diff --git a/servers/mlflowserver/test/mlflow_example.ipynb b/servers/mlflowserver/test/mlflow_example.ipynb index 76f4d37472..cd076ca970 100644 --- a/servers/mlflowserver/test/mlflow_example.ipynb +++ b/servers/mlflowserver/test/mlflow_example.ipynb @@ -77,9 +77,11 @@ "outputs": [], "source": [ "import sys\n", + "\n", "sys.path.append(\"..\")\n", - "from mlflowserver.MLFlowServer import MLFlowServer\n", - "import os" + "import os\n", + "\n", + "from mlflowserver.MLFlowServer import MLFlowServer" ] }, { @@ -88,7 +90,7 @@ "metadata": {}, "outputs": [], "source": [ - "m = MLFlowServer(\"mlruns/0/\"+next(os.walk('mlruns/0'))[1][0]+\"/artifacts/model\")\n", + "m = MLFlowServer(\"mlruns/0/\" + next(os.walk(\"mlruns/0\"))[1][0] + \"/artifacts/model\")\n", "m.load()" ] }, @@ -109,7 +111,7 @@ } ], "source": [ - "m.predict([[1,2,3,4,5,6,7,8,9,10,11]], feature_names=[])" + "m.predict([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]], feature_names=[])" ] }, { @@ -283,7 +285,7 @@ } ], "source": [ - "print(\"mlruns/0/\"+next(os.walk(\"mlruns/0\"))[1][0]+\"/artifacts/model\")" + "print(\"mlruns/0/\" + next(os.walk(\"mlruns/0\"))[1][0] + \"/artifacts/model\")" ] }, { diff --git a/servers/sklearnserver/test/sklearn_iris.ipynb b/servers/sklearnserver/test/sklearn_iris.ipynb index a1ffc1bb09..72d2ba6f31 100644 --- a/servers/sklearnserver/test/sklearn_iris.ipynb +++ b/servers/sklearnserver/test/sklearn_iris.ipynb @@ -36,31 +36,34 @@ } ], "source": [ - "import numpy as np\n", "import os\n", - "from sklearn.linear_model import LogisticRegression\n", - "from sklearn.pipeline import Pipeline\n", + "\n", "import joblib\n", + "import numpy as np\n", "from sklearn import datasets\n", + "from sklearn.linear_model import LogisticRegression\n", + "from sklearn.pipeline import Pipeline\n", + "\n", "\n", "def main():\n", " clf = LogisticRegression()\n", - " p = Pipeline([('clf', clf)])\n", - " print('Training model...')\n", + " p = Pipeline([(\"clf\", clf)])\n", + " print(\"Training model...\")\n", " p.fit(X, y)\n", - " print('Model trained!')\n", + " print(\"Model trained!\")\n", "\n", - " filename_p = 'model.joblib'\n", - " print('Saving model in %s' % filename_p)\n", + " filename_p = \"model.joblib\"\n", + " print(\"Saving model in %s\" % filename_p)\n", " joblib.dump(p, filename_p)\n", - " print('Model saved!')\n", - " \n", + " print(\"Model saved!\")\n", + "\n", + "\n", "if __name__ == \"__main__\":\n", - " print('Loading iris data set...')\n", + " print(\"Loading iris data set...\")\n", " iris = datasets.load_iris()\n", " X, y = iris.data, iris.target\n", - " print('Dataset loaded!')\n", - " main()\n" + " print(\"Dataset loaded!\")\n", + " main()" ] }, { @@ -444,9 +447,8 @@ "metadata": {}, "outputs": [], "source": [ - "def x(a=None,b=2):\n", - " print(a,b)\n", - " " + "def x(a=None, b=2):\n", + " print(a, b)" ] }, { @@ -463,7 +465,7 @@ } ], "source": [ - "x(b=3,a=1)" + "x(b=3, a=1)" ] }, { diff --git a/servers/xgboostserver/test/xgboost_iris.ipynb b/servers/xgboostserver/test/xgboost_iris.ipynb index b816e4c5c3..cd4bf9d771 100644 --- a/servers/xgboostserver/test/xgboost_iris.ipynb +++ b/servers/xgboostserver/test/xgboost_iris.ipynb @@ -13,27 +13,29 @@ "metadata": {}, "outputs": [], "source": [ + "import os\n", + "\n", "import xgboost as xgb\n", "from sklearn.datasets import load_iris\n", - "import os\n", "\n", "model_dir = \".\"\n", "BST_FILE = \"model.bst\"\n", "\n", "iris = load_iris()\n", - "y = iris['target']\n", - "X = iris['data']\n", + "y = iris[\"target\"]\n", + "X = iris[\"data\"]\n", "dtrain = xgb.DMatrix(X, label=y)\n", - "param = {'max_depth': 6,\n", - " 'eta': 0.1,\n", - " 'silent': 1,\n", - " 'nthread': 4,\n", - " 'num_class': 10,\n", - " 'objective': 'multi:softmax'\n", - " }\n", + "param = {\n", + " \"max_depth\": 6,\n", + " \"eta\": 0.1,\n", + " \"silent\": 1,\n", + " \"nthread\": 4,\n", + " \"num_class\": 10,\n", + " \"objective\": \"multi:softmax\",\n", + "}\n", "xgb_model = xgb.train(params=param, dtrain=dtrain)\n", "model_file = os.path.join((model_dir), BST_FILE)\n", - "xgb_model.save_model(model_file)\n" + "xgb_model.save_model(model_file)" ] }, { diff --git a/testing/benchmarking/svcOrch/svcOrch.ipynb b/testing/benchmarking/svcOrch/svcOrch.ipynb index c65bddc395..c619a9920c 100644 --- a/testing/benchmarking/svcOrch/svcOrch.ipynb +++ b/testing/benchmarking/svcOrch/svcOrch.ipynb @@ -41,7 +41,8 @@ "outputs": [], "source": [ "import sys\n", - "sys.path.append('../')\n", + "\n", + "sys.path.append(\"../\")\n", "from vegeta_utils import *" ] }, @@ -195,9 +196,9 @@ } ], "source": [ - "results = run_vegeta_test(\"tf_vegeta_cfg.yaml\",\"vegeta_1worker.yaml\",\"60m\")\n", + "results = run_vegeta_test(\"tf_vegeta_cfg.yaml\", \"vegeta_1worker.yaml\", \"60m\")\n", "print(json.dumps(results, indent=4))\n", - "mean_with_executor=results[\"latencies\"][\"mean\"]" + "mean_with_executor = results[\"latencies\"][\"mean\"]" ] }, { @@ -318,9 +319,9 @@ } ], "source": [ - "results = run_vegeta_test(\"tf_standalone_vegeta_cfg.yaml\",\"vegeta_1worker.yaml\",\"60m\")\n", + "results = run_vegeta_test(\"tf_standalone_vegeta_cfg.yaml\", \"vegeta_1worker.yaml\", \"60m\")\n", "print(json.dumps(results, indent=4))\n", - "mean_no_executor=results[\"latencies\"][\"mean\"]" + "mean_no_executor = results[\"latencies\"][\"mean\"]" ] }, { @@ -338,7 +339,7 @@ ], "source": [ "diff = (mean_with_executor - mean_no_executor) / 1e6\n", - "print(\"Diff in ms\",diff)" + "print(\"Diff in ms\", diff)" ] }, { @@ -534,9 +535,9 @@ } ], "source": [ - "results = run_ghz_test(\"flowers.bin\",\"ghz_1worker.yaml\",\"60m\")\n", + "results = run_ghz_test(\"flowers.bin\", \"ghz_1worker.yaml\", \"60m\")\n", "print(json.dumps(results, indent=4))\n", - "mean_with_executor=results[\"average\"]" + "mean_with_executor = results[\"average\"]" ] }, { @@ -692,9 +693,9 @@ } ], "source": [ - "results = run_ghz_test(\"flowers.bin\",\"ghz_standalone_1worker.yaml\",\"60m\")\n", + "results = run_ghz_test(\"flowers.bin\", \"ghz_standalone_1worker.yaml\", \"60m\")\n", "print(json.dumps(results, indent=4))\n", - "mean_no_executor=results[\"average\"]" + "mean_no_executor = results[\"average\"]" ] }, { @@ -712,7 +713,7 @@ ], "source": [ "diff = (mean_with_executor - mean_no_executor) / 1e6\n", - "print(\"Diff in ms\",diff)" + "print(\"Diff in ms\", diff)" ] }, { diff --git a/testing/benchmarking/tensorflow/tensorflow.ipynb b/testing/benchmarking/tensorflow/tensorflow.ipynb index 67491ffb51..e9ce023a0c 100644 --- a/testing/benchmarking/tensorflow/tensorflow.ipynb +++ b/testing/benchmarking/tensorflow/tensorflow.ipynb @@ -63,7 +63,8 @@ "outputs": [], "source": [ "import sys\n", - "sys.path.append('../')\n", + "\n", + "sys.path.append(\"../\")\n", "from vegeta_utils import *" ] }, @@ -228,9 +229,9 @@ } ], "source": [ - "results = run_vegeta_test(\"tf_vegeta_cfg.yaml\",\"vegeta_max.yaml\",\"11m\")\n", + "results = run_vegeta_test(\"tf_vegeta_cfg.yaml\", \"vegeta_max.yaml\", \"11m\")\n", "print(json.dumps(results, indent=4))\n", - "saturation_throughput=int(results[\"throughput\"])" + "saturation_throughput = int(results[\"throughput\"])" ] }, { @@ -247,7 +248,7 @@ } ], "source": [ - "print(\"Max Throughtput=\",saturation_throughput)" + "print(\"Max Throughtput=\", saturation_throughput)" ] }, { @@ -399,8 +400,8 @@ } ], "source": [ - "rate=saturation_throughput\n", - "duration=\"10m\"\n", + "rate = saturation_throughput\n", + "duration = \"10m\"\n", "%env DURATION=$duration\n", "%env RATE=$rate/1s\n", "!cat vegeta_cfg.tmpl.yaml | envsubst > vegeta.tmp.yaml\n", @@ -455,7 +456,7 @@ } ], "source": [ - "results = run_vegeta_test(\"tf_vegeta_cfg.yaml\",\"vegeta.tmp.yaml\",\"11m\")\n", + "results = run_vegeta_test(\"tf_vegeta_cfg.yaml\", \"vegeta.tmp.yaml\", \"11m\")\n", "print(json.dumps(results, indent=4))" ] }, diff --git a/testing/notebooks/microservice_tests.ipynb b/testing/notebooks/microservice_tests.ipynb index 650974a5ea..81ff364716 100644 --- a/testing/notebooks/microservice_tests.ipynb +++ b/testing/notebooks/microservice_tests.ipynb @@ -20,6 +20,7 @@ "outputs": [], "source": [ "from seldon_core.seldon_client import SeldonClient\n", + "\n", "sc = SeldonClient()" ] }, @@ -58,7 +59,7 @@ } ], "source": [ - "p = sc.microservice(method=\"predict\",transport=\"rest\")\n", + "p = sc.microservice(method=\"predict\", transport=\"rest\")\n", "print(p)" ] }, @@ -97,7 +98,9 @@ } ], "source": [ - "p = sc.microservice(method=\"predict\",transport=\"grpc\",microservice_endpoint=\"localhost:5001\")\n", + "p = sc.microservice(\n", + " method=\"predict\", transport=\"grpc\", microservice_endpoint=\"localhost:5001\"\n", + ")\n", "print(p)" ] }, @@ -147,7 +150,7 @@ } ], "source": [ - "p = sc.microservice(method=\"aggregate\",transport=\"rest\",ndatas=2)\n", + "p = sc.microservice(method=\"aggregate\", transport=\"rest\", ndatas=2)\n", "print(p)" ] }, @@ -197,7 +200,12 @@ } ], "source": [ - "p = sc.microservice(method=\"aggregate\",transport=\"grpc\",ndatas=2,microservice_endpoint=\"localhost:5001\")\n", + "p = sc.microservice(\n", + " method=\"aggregate\",\n", + " transport=\"grpc\",\n", + " ndatas=2,\n", + " microservice_endpoint=\"localhost:5001\",\n", + ")\n", "print(p)" ] }, @@ -207,9 +215,14 @@ "metadata": {}, "outputs": [], "source": [ - "p = sc.microservice(method=\"predict\",transport=\"rest\")\n", + "p = sc.microservice(method=\"predict\", transport=\"rest\")\n", "print(p)\n", - "f = sc.microservice_feedback(prediction_request=p.request,prediction_response=p.response,reward=1.0,transport=\"rest\")\n", + "f = sc.microservice_feedback(\n", + " prediction_request=p.request,\n", + " prediction_response=p.response,\n", + " reward=1.0,\n", + " transport=\"rest\",\n", + ")\n", "print(f)" ] }, @@ -219,9 +232,17 @@ "metadata": {}, "outputs": [], "source": [ - "p = sc.microservice(method=\"predict\",transport=\"grpc\",microservice_endpoint=\"localhost:5001\")\n", + "p = sc.microservice(\n", + " method=\"predict\", transport=\"grpc\", microservice_endpoint=\"localhost:5001\"\n", + ")\n", "print(p)\n", - "f = sc.microservice_feedback(prediction_request=p.request,prediction_response=p.response,reward=1.0,transport=\"grpc\",microservice_endpoint=\"localhost:5001\")\n", + "f = sc.microservice_feedback(\n", + " prediction_request=p.request,\n", + " prediction_response=p.response,\n", + " reward=1.0,\n", + " transport=\"grpc\",\n", + " microservice_endpoint=\"localhost:5001\",\n", + ")\n", "print(f)" ] }, @@ -231,7 +252,7 @@ "metadata": {}, "outputs": [], "source": [ - "p = sc.microservice(method=\"predict\",transport=\"rest\",bin_data=b\"123\")\n", + "p = sc.microservice(method=\"predict\", transport=\"rest\", bin_data=b\"123\")\n", "print(p)" ] }, @@ -241,7 +262,7 @@ "metadata": {}, "outputs": [], "source": [ - "p = sc.microservice(method=\"predict\",transport=\"rest\",str_data=\"123\")\n", + "p = sc.microservice(method=\"predict\", transport=\"rest\", str_data=\"123\")\n", "print(p)" ] }, @@ -251,7 +272,7 @@ "metadata": {}, "outputs": [], "source": [ - "p = sc.microservice(method=\"aggregate\",transport=\"rest\",datas=[\"123\",\"456\"])\n", + "p = sc.microservice(method=\"aggregate\", transport=\"rest\", datas=[\"123\", \"456\"])\n", "print(p)" ] }, @@ -261,7 +282,12 @@ "metadata": {}, "outputs": [], "source": [ - "p = sc.microservice(method=\"predict\",transport=\"grpc\",microservice_endpoint=\"localhost:5001\",bin_data=b\"123\")\n", + "p = sc.microservice(\n", + " method=\"predict\",\n", + " transport=\"grpc\",\n", + " microservice_endpoint=\"localhost:5001\",\n", + " bin_data=b\"123\",\n", + ")\n", "print(p)" ] }, @@ -271,7 +297,12 @@ "metadata": {}, "outputs": [], "source": [ - "p = sc.microservice(method=\"predict\",transport=\"grpc\",microservice_endpoint=\"localhost:5001\",str_data=\"123\")\n", + "p = sc.microservice(\n", + " method=\"predict\",\n", + " transport=\"grpc\",\n", + " microservice_endpoint=\"localhost:5001\",\n", + " str_data=\"123\",\n", + ")\n", "print(p)" ] }, @@ -281,7 +312,12 @@ "metadata": {}, "outputs": [], "source": [ - "p = sc.microservice(method=\"aggregate\",transport=\"grpc\",microservice_endpoint=\"localhost:5001\",datas=[\"123\",\"456\"])\n", + "p = sc.microservice(\n", + " method=\"aggregate\",\n", + " transport=\"grpc\",\n", + " microservice_endpoint=\"localhost:5001\",\n", + " datas=[\"123\", \"456\"],\n", + ")\n", "print(p)" ] }, @@ -293,16 +329,17 @@ "source": [ "import inspect\n", "\n", + "\n", "class Myclass(object):\n", - " \n", - " def __init__(self,a=1,b=2):\n", + " def __init__(self, a=1, b=2):\n", " self.a = a\n", " self.b = b\n", - " \n", - " def f1(self,c=2,d=4):\n", + "\n", + " def f1(self, c=2, d=4):\n", " print(vars(self))\n", " print(vars())\n", - " \n", + "\n", + "\n", "x = Myclass()\n", "x.f1()" ] diff --git a/util/kafka/create_request_datasets.ipynb b/util/kafka/create_request_datasets.ipynb index aeeb16df20..893fdba519 100644 --- a/util/kafka/create_request_datasets.ipynb +++ b/util/kafka/create_request_datasets.ipynb @@ -18,10 +18,11 @@ "metadata": {}, "outputs": [], "source": [ - "import tensorflow as tf\n", - "from tensorflow_serving.apis import prediction_service_pb2_grpc, predict_pb2\n", + "import json\n", + "\n", "import grpc\n", - "import json" + "import tensorflow as tf\n", + "from tensorflow_serving.apis import predict_pb2, prediction_service_pb2_grpc" ] }, { @@ -38,10 +39,14 @@ "outputs": [], "source": [ "(X_train, y_train), (X_test, y_test) = tf.keras.datasets.cifar10.load_data()\n", - "X_train = X_train.astype('float32') / 255\n", - "X_test = X_test.astype('float32') / 255\n", - "y_train = y_train.astype('int64').reshape(-1,)\n", - "y_test = y_test.astype('int64').reshape(-1,)" + "X_train = X_train.astype(\"float32\") / 255\n", + "X_test = X_test.astype(\"float32\") / 255\n", + "y_train = y_train.astype(\"int64\").reshape(\n", + " -1,\n", + ")\n", + "y_test = y_test.astype(\"int64\").reshape(\n", + " -1,\n", + ")" ] }, { @@ -57,10 +62,10 @@ "metadata": {}, "outputs": [], "source": [ - "with open(\"cifar10_tensorflow.json\",\"w\") as f:\n", - " for idx in range(0,X_train.shape[0]):\n", - " row = X_train[idx:idx+1]\n", - " data = {\"instances\":row.tolist()}\n", + "with open(\"cifar10_tensorflow.json\", \"w\") as f:\n", + " for idx in range(0, X_train.shape[0]):\n", + " row = X_train[idx : idx + 1]\n", + " data = {\"instances\": row.tolist()}\n", " dataStr = json.dumps(data) + \"\\n\"\n", " f.write(dataStr)\n", " f.close()" @@ -79,16 +84,16 @@ "metadata": {}, "outputs": [], "source": [ - "with open(\"cifar10_tensorflow.proto\",\"wb\") as f:\n", - " for idx in range(0,X_train.shape[0]):\n", - " row = X_train[idx:idx+1]\n", + "with open(\"cifar10_tensorflow.proto\", \"wb\") as f:\n", + " for idx in range(0, X_train.shape[0]):\n", + " row = X_train[idx : idx + 1]\n", " request = predict_pb2.PredictRequest()\n", " request.model_spec.name = \"resnet32\"\n", " request.model_spec.signature_name = \"serving_default\"\n", - " request.inputs[\"input_1\"].CopyFrom(tf.make_tensor_proto(X_train[idx:idx+1]))\n", + " request.inputs[\"input_1\"].CopyFrom(tf.make_tensor_proto(X_train[idx : idx + 1]))\n", " dataStr = request.SerializeToString()\n", " l = len(dataStr)\n", - " lb = l.to_bytes(4, byteorder='big', signed=True)\n", + " lb = l.to_bytes(4, byteorder=\"big\", signed=True)\n", " f.write(lb)\n", " f.write(dataStr)\n", " f.close()"