#!/usr/bin/env python
# coding: utf-8

# # Cifar10 Outlier Detection with NVIDIA Triton
# ![demo](./demo.png)
# 
# In this example we will deploy an image classification model along with an outlier detector trained on the same dataset. For in depth details on creating an outlier detection model for your own dataset see the [alibi-detect project](https://github.com/SeldonIO/alibi-detect) and associated [documentation](https://docs.seldon.io/projects/alibi-detect/en/latest/). You can find details for this [CIFAR10 example in their documentation](https://docs.seldon.io/projects/alibi-detect/en/latest/examples/od_vae_cifar10.html) as well.
# 
# 
# Prequisites:
# 
#   * [Knative eventing installed](https://knative.dev/docs/install/)
#     * Ensure the istio-ingressgateway is exposed as a loadbalancer (no auth in this demo)
#   * [Seldon Core installed](https://docs.seldon.io/projects/seldon-core/en/latest/workflow/install.html) 
#     * Ensure you install for istio, e.g. for the helm chart `--set istio.enabled=true`
#   * A cluster with NVIDIA GPUs available compatible with Triton Inference Server.
#     
#     Tested on GKE and Kind with Knative 0.18 and Istio 1.7.3

# In[ ]:


get_ipython().system('pip install -r requirements_notebook.txt')


# Ensure istio gateway installed

# In[3]:


get_ipython().system('kubectl apply -f ../../../notebooks/resources/seldon-gateway.yaml')


# ## Setup Resources

# In[1]:


get_ipython().system('kubectl create namespace cifar10')


# In[2]:


get_ipython().run_cell_magic('writefile', 'broker.yaml', 'apiVersion: eventing.knative.dev/v1\nkind: broker\nmetadata:\n name: default\n namespace: cifar10')


# In[3]:


get_ipython().system('kubectl create -f broker.yaml')


# In[4]:


get_ipython().run_cell_magic('writefile', 'event-display.yaml', 'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: hello-display\n  namespace: cifar10\nspec:\n  replicas: 1\n  selector:\n    matchLabels: &labels\n      app: hello-display\n  template:\n    metadata:\n      labels: *labels\n    spec:\n      containers:\n        - name: event-display\n          image: gcr.io/knative-releases/knative.dev/eventing-contrib/cmd/event_display\n\n---\n\nkind: Service\napiVersion: v1\nmetadata:\n  name: hello-display\n  namespace: cifar10\nspec:\n  selector:\n    app: hello-display\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 8080')


# In[5]:


get_ipython().system('kubectl apply -f event-display.yaml')


# Create the SeldonDeployment image classification model for Cifar10. We add in a `logger` for requests - the default destination is the namespace Knative Broker.

# In[6]:


get_ipython().run_cell_magic('writefile', 'cifar10.yaml', 'apiVersion: machinelearning.seldon.io/v1\nkind: SeldonDeployment\nmetadata:\n  name: triton-cifar10\n  namespace: cifar10\nspec:\n  predictors:\n  - componentSpecs:\n    - metadata: {}\n      spec:\n        containers:\n        - image: nvcr.io/nvidia/tritonserver:21.08-py3\n          name: cifar10\n          resources:\n            limits:\n              cpu: "1"\n              memory: 20Gi\n              nvidia.com/gpu: "1"\n            requests:\n              cpu: "1"\n              memory: 10Gi\n              nvidia.com/gpu: "1"\n    graph:\n      implementation: TRITON_SERVER\n      logger:\n        mode: all\n        url: http://broker-ingress.knative-eventing.svc.cluster.local/cifar10/default            \n      modelUri: gs://seldon-models/triton/tf_cifar10\n      name: cifar10\n      type: MODEL\n    name: default\n    replicas: 1\n  protocol: kfserving')


# In[7]:


get_ipython().system('kubectl apply -f cifar10.yaml')


# Create the pretrained VAE Cifar10 Outlier Detector. We forward replies to the message-dumper we started.

# In[9]:


get_ipython().run_cell_magic('writefile', 'cifar10od.yaml', 'apiVersion: serving.knative.dev/v1\nkind: Service\nmetadata:\n  name: vae-outlier\n  namespace: cifar10\nspec:\n  template:\n    metadata:\n      annotations:\n        autoscaling.knative.dev/minScale: "1"\n    spec:\n      containers:\n      - image: seldonio/alibi-detect-server:1.6.0-dev\n        imagePullPolicy: IfNotPresent\n        args:\n        - --model_name\n        - cifar10od\n        - --http_port\n        - \'8080\'\n        - --protocol\n        - kfserving.http\n        - --storage_uri\n        - gs://seldon-models/alibi-detect/od/OutlierVAE/cifar10\n        - --reply_url\n        - http://hello-display.cifar10\n        - --event_type\n        - io.seldon.serving.inference.outlier\n        - --event_source\n        - io.seldon.serving.cifar10od\n        - OutlierDetector')


# In[10]:


get_ipython().system('kubectl apply -f cifar10od.yaml')


# Create a Knative trigger to forward logging events to our Outlier Detector.

# In[11]:


get_ipython().run_cell_magic('writefile', 'trigger.yaml', 'apiVersion: eventing.knative.dev/v1\nkind: Trigger\nmetadata:\n  name: vaeoutlier-trigger\n  namespace: cifar10\nspec:\n  broker: default\n  filter:\n    attributes:\n      type: io.seldon.serving.inference.request\n  subscriber:\n    ref:\n      apiVersion: serving.knative.dev/v1\n      kind: Service\n      name: vae-outlier\n      namespace: cifar10')


# In[12]:


get_ipython().system('kubectl apply -f trigger.yaml')


# Get the IP address of the Istio Ingress Gateway. This assumes you have installed istio with a LoadBalancer.

# In[13]:


CLUSTER_IPS = get_ipython().getoutput("(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')")
CLUSTER_IP = CLUSTER_IPS[0]
print(CLUSTER_IP)


# Optionally add an authorization token here if you need one.Acquiring this token will be dependent on your auth setup.

# In[14]:


TOKEN = "Bearer <my-token>"


# If you are using Kind or Minikube you will need to port-forward to the istio ingressgateway and uncomment the following

# In[15]:


# CLUSTER_IP="localhost:8004"


# In[15]:


SERVICE_HOSTNAMES = get_ipython().getoutput('(kubectl get ksvc -n cifar10 vae-outlier -o jsonpath=\'{.status.url}\' | cut -d "/" -f 3)')
SERVICE_HOSTNAME_VAEOD = SERVICE_HOSTNAMES[0]
print(SERVICE_HOSTNAME_VAEOD)


# In[17]:


import json

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf

tf.keras.backend.clear_session()

import requests
from alibi_detect.od.vae import OutlierVAE
from alibi_detect.utils.perturbation import apply_mask
from alibi_detect.utils.visualize import plot_feature_outlier_image

train, test = tf.keras.datasets.cifar10.load_data()
X_train, y_train = train
X_test, y_test = test

X_train = X_train.astype("float32") / 255
X_test = X_test.astype("float32") / 255
print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)
classes = (
    "plane",
    "car",
    "bird",
    "cat",
    "deer",
    "dog",
    "frog",
    "horse",
    "ship",
    "truck",
)


def show(X):
    plt.imshow(X.reshape(32, 32, 3))
    plt.axis("off")
    plt.show()


def predict(X):
    formData = {
        "inputs": [
            {
                "name": "input_1",
                "datatype": "FP32",
                "shape": [1, 32, 32, 3],
                "data": X.flatten().tolist(),
            }
        ]
    }
    headers = {"Authorization": TOKEN, "Content-Type": "application/json"}
    res = requests.post(
        "http://"
        + CLUSTER_IP
        + "/seldon/cifar10/triton-cifar10/v2/models/cifar10/infer",
        json=formData,
        headers=headers,
    )
    if res.status_code == 200:
        return classes[np.array(res.json()["outputs"][0]["data"]).argmax()]
    else:
        print("Failed with ", res.status_code)
        return []


def outlier(X):
    formData = {
        "inputs": [
            {
                "name": "input_1",
                "datatype": "FP32",
                "shape": [1, 32, 32, 3],
                "data": X.flatten().tolist(),
            }
        ]
    }
    headers = {
        "Alibi-Detect-Return-Feature-Score": "true",
        "Alibi-Detect-Return-Instance-Score": "true",
        "ce-namespace": "default",
        "ce-modelid": "cifar10",
        "ce-type": "io.seldon.serving.inference.request",
        "ce-id": "1234",
        "ce-source": "localhost",
        "ce-specversion": "1.0",
    }
    headers["Host"] = SERVICE_HOSTNAME_VAEOD
    headers["Authorization"] = TOKEN
    res = requests.post("http://" + CLUSTER_IP + "/", json=formData, headers=headers)
    if res.status_code == 200:
        od = res.json()
        od["data"]["feature_score"] = np.array(od["data"]["feature_score"])
        od["data"]["instance_score"] = np.array(od["data"]["instance_score"])
        return od
    else:
        print("Failed with ", res.status_code)
        return []


# ## Normal Prediction

# In[18]:


idx = 1
X = X_train[idx : idx + 1]
show(X)
predict(X)


# Lets check the message dumper for an outlier detection prediction. This should be false.

# In[22]:


res = get_ipython().getoutput("kubectl logs -n cifar10 $(kubectl get pod -n cifar10 -l app=hello-display -o jsonpath='{.items[0].metadata.name}')")
data = []
for i in range(0, len(res)):
    if res[i] == "Data,":
        data.append(res[i + 1])
j = json.loads(json.loads(data[0]))
print("Outlier", j["data"]["is_outlier"] == [1])


# ## Outlier Prediction

# In[23]:


np.random.seed(0)
X_mask, mask = apply_mask(
    X.reshape(1, 32, 32, 3),
    mask_size=(10, 10),
    n_masks=1,
    channels=[0, 1, 2],
    mask_type="normal",
    noise_distr=(0, 1),
    clip_rng=(0, 1),
)


# In[24]:


show(X_mask)
predict(X_mask)


# Now lets check the message dumper for a new message. This should show we have found an outlier.

# In[25]:


res = get_ipython().getoutput("kubectl logs -n cifar10 $(kubectl get pod -n cifar10 -l app=hello-display -o jsonpath='{.items[0].metadata.name}')")
data = []
for i in range(0, len(res)):
    if res[i] == "Data,":
        data.append(res[i + 1])
j = json.loads(json.loads(data[-1]))
print("Outlier", j["data"]["is_outlier"] == [1])


# We will now call our outlier detector directly and ask for the feature scores to gain more information about why it predicted this instance was an outlier.

# In[26]:


od_preds = outlier(X_mask)


# We now plot those feature scores returned by the outlier detector along with our original image.

# In[27]:


plot_feature_outlier_image(od_preds, X_mask, X_recon=None)


# ## Tear Down

# In[28]:


get_ipython().system('kubectl delete ns cifar10')


# In[ ]:





#!/usr/bin/env python
# coding: utf-8

# # Cifar10 Outlier Detection with NVIDIA Triton
# ![demo](./demo.png)
# 
# In this example we will deploy an image classification model along with an outlier detector trained on the same dataset. For in depth details on creating an outlier detection model for your own dataset see the [alibi-detect project](https://github.com/SeldonIO/alibi-detect) and associated [documentation](https://docs.seldon.io/projects/alibi-detect/en/latest/). You can find details for this [CIFAR10 example in their documentation](https://docs.seldon.io/projects/alibi-detect/en/latest/examples/od_vae_cifar10.html) as well.
# 
# 
# Prequisites:
# 
#   * [Knative eventing installed](https://knative.dev/docs/install/)
#     * Ensure the istio-ingressgateway is exposed as a loadbalancer (no auth in this demo)
#   * [Seldon Core installed](https://docs.seldon.io/projects/seldon-core/en/latest/workflow/install.html) 
#     * Ensure you install for istio, e.g. for the helm chart `--set istio.enabled=true`
#   * A cluster with NVIDIA GPUs available compatible with Triton Inference Server.
#     
#     Tested on GKE and Kind with Knative 0.18 and Istio 1.7.3

# In[ ]:


get_ipython().system('pip install -r requirements_notebook.txt')


# Ensure istio gateway installed

# In[3]:


get_ipython().system('kubectl apply -f ../../../notebooks/resources/seldon-gateway.yaml')


# ## Setup Resources

# In[1]:


get_ipython().system('kubectl create namespace cifar10')


# In[2]:


get_ipython().run_cell_magic('writefile', 'broker.yaml', 'apiVersion: eventing.knative.dev/v1\nkind: broker\nmetadata:\n name: default\n namespace: cifar10')


# In[3]:


get_ipython().system('kubectl create -f broker.yaml')


# In[4]:


get_ipython().run_cell_magic('writefile', 'event-display.yaml', 'apiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: hello-display\n  namespace: cifar10\nspec:\n  replicas: 1\n  selector:\n    matchLabels: &labels\n      app: hello-display\n  template:\n    metadata:\n      labels: *labels\n    spec:\n      containers:\n        - name: event-display\n          image: gcr.io/knative-releases/knative.dev/eventing-contrib/cmd/event_display\n\n---\n\nkind: Service\napiVersion: v1\nmetadata:\n  name: hello-display\n  namespace: cifar10\nspec:\n  selector:\n    app: hello-display\n  ports:\n  - protocol: TCP\n    port: 80\n    targetPort: 8080')


# In[5]:


get_ipython().system('kubectl apply -f event-display.yaml')


# Create the SeldonDeployment image classification model for Cifar10. We add in a `logger` for requests - the default destination is the namespace Knative Broker.

# In[6]:


get_ipython().run_cell_magic('writefile', 'cifar10.yaml', 'apiVersion: machinelearning.seldon.io/v1\nkind: SeldonDeployment\nmetadata:\n  name: triton-cifar10\n  namespace: cifar10\nspec:\n  predictors:\n  - componentSpecs:\n    - metadata: {}\n      spec:\n        containers:\n        - image: nvcr.io/nvidia/tritonserver:21.08-py3\n          name: cifar10\n          resources:\n            limits:\n              cpu: "1"\n              memory: 20Gi\n              nvidia.com/gpu: "1"\n            requests:\n              cpu: "1"\n              memory: 10Gi\n              nvidia.com/gpu: "1"\n    graph:\n      implementation: TRITON_SERVER\n      logger:\n        mode: all\n        url: http://broker-ingress.knative-eventing.svc.cluster.local/cifar10/default            \n      modelUri: gs://seldon-models/triton/tf_cifar10\n      name: cifar10\n      type: MODEL\n    name: default\n    replicas: 1\n  protocol: kfserving')


# In[7]:


get_ipython().system('kubectl apply -f cifar10.yaml')


# Create the pretrained VAE Cifar10 Outlier Detector. We forward replies to the message-dumper we started.

# In[9]:


get_ipython().run_cell_magic('writefile', 'cifar10od.yaml', 'apiVersion: serving.knative.dev/v1\nkind: Service\nmetadata:\n  name: vae-outlier\n  namespace: cifar10\nspec:\n  template:\n    metadata:\n      annotations:\n        autoscaling.knative.dev/minScale: "1"\n    spec:\n      containers:\n      - image: seldonio/alibi-detect-server:1.6.0-dev\n        imagePullPolicy: IfNotPresent\n        args:\n        - --model_name\n        - cifar10od\n        - --http_port\n        - \'8080\'\n        - --protocol\n        - kfserving.http\n        - --storage_uri\n        - gs://seldon-models/alibi-detect/od/OutlierVAE/cifar10\n        - --reply_url\n        - http://hello-display.cifar10\n        - --event_type\n        - io.seldon.serving.inference.outlier\n        - --event_source\n        - io.seldon.serving.cifar10od\n        - OutlierDetector')


# In[10]:


get_ipython().system('kubectl apply -f cifar10od.yaml')


# Create a Knative trigger to forward logging events to our Outlier Detector.

# In[11]:


get_ipython().run_cell_magic('writefile', 'trigger.yaml', 'apiVersion: eventing.knative.dev/v1\nkind: Trigger\nmetadata:\n  name: vaeoutlier-trigger\n  namespace: cifar10\nspec:\n  broker: default\n  filter:\n    attributes:\n      type: io.seldon.serving.inference.request\n  subscriber:\n    ref:\n      apiVersion: serving.knative.dev/v1\n      kind: Service\n      name: vae-outlier\n      namespace: cifar10')


# In[12]:


get_ipython().system('kubectl apply -f trigger.yaml')


# Get the IP address of the Istio Ingress Gateway. This assumes you have installed istio with a LoadBalancer.

# In[13]:


CLUSTER_IPS = get_ipython().getoutput("(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')")
CLUSTER_IP = CLUSTER_IPS[0]
print(CLUSTER_IP)


# Optionally add an authorization token here if you need one.Acquiring this token will be dependent on your auth setup.

# In[14]:


TOKEN = "Bearer <my-token>"


# If you are using Kind or Minikube you will need to port-forward to the istio ingressgateway and uncomment the following

# In[15]:


# CLUSTER_IP="localhost:8004"


# In[15]:


SERVICE_HOSTNAMES = get_ipython().getoutput('(kubectl get ksvc -n cifar10 vae-outlier -o jsonpath=\'{.status.url}\' | cut -d "/" -f 3)')
SERVICE_HOSTNAME_VAEOD = SERVICE_HOSTNAMES[0]
print(SERVICE_HOSTNAME_VAEOD)


# In[17]:


import json

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf

tf.keras.backend.clear_session()

import requests
from alibi_detect.od.vae import OutlierVAE
from alibi_detect.utils.perturbation import apply_mask
from alibi_detect.utils.visualize import plot_feature_outlier_image

train, test = tf.keras.datasets.cifar10.load_data()
X_train, y_train = train
X_test, y_test = test

X_train = X_train.astype("float32") / 255
X_test = X_test.astype("float32") / 255
print(X_train.shape, y_train.shape, X_test.shape, y_test.shape)
classes = (
    "plane",
    "car",
    "bird",
    "cat",
    "deer",
    "dog",
    "frog",
    "horse",
    "ship",
    "truck",
)


def show(X):
    plt.imshow(X.reshape(32, 32, 3))
    plt.axis("off")
    plt.show()


def predict(X):
    formData = {
        "inputs": [
            {
                "name": "input_1",
                "datatype": "FP32",
                "shape": [1, 32, 32, 3],
                "data": X.flatten().tolist(),
            }
        ]
    }
    headers = {"Authorization": TOKEN, "Content-Type": "application/json"}
    res = requests.post(
        "http://"
        + CLUSTER_IP
        + "/seldon/cifar10/triton-cifar10/v2/models/cifar10/infer",
        json=formData,
        headers=headers,
    )
    if res.status_code == 200:
        return classes[np.array(res.json()["outputs"][0]["data"]).argmax()]
    else:
        print("Failed with ", res.status_code)
        return []


def outlier(X):
    formData = {
        "inputs": [
            {
                "name": "input_1",
                "datatype": "FP32",
                "shape": [1, 32, 32, 3],
                "data": X.flatten().tolist(),
            }
        ]
    }
    headers = {
        "Alibi-Detect-Return-Feature-Score": "true",
        "Alibi-Detect-Return-Instance-Score": "true",
        "ce-namespace": "default",
        "ce-modelid": "cifar10",
        "ce-type": "io.seldon.serving.inference.request",
        "ce-id": "1234",
        "ce-source": "localhost",
        "ce-specversion": "1.0",
    }
    headers["Host"] = SERVICE_HOSTNAME_VAEOD
    headers["Authorization"] = TOKEN
    res = requests.post("http://" + CLUSTER_IP + "/", json=formData, headers=headers)
    if res.status_code == 200:
        od = res.json()
        od["data"]["feature_score"] = np.array(od["data"]["feature_score"])
        od["data"]["instance_score"] = np.array(od["data"]["instance_score"])
        return od
    else:
        print("Failed with ", res.status_code)
        return []


# ## Normal Prediction

# In[18]:


idx = 1
X = X_train[idx : idx + 1]
show(X)
predict(X)


# Lets check the message dumper for an outlier detection prediction. This should be false.

# In[22]:


res = get_ipython().getoutput("kubectl logs -n cifar10 $(kubectl get pod -n cifar10 -l app=hello-display -o jsonpath='{.items[0].metadata.name}')")
data = []
for i in range(0, len(res)):
    if res[i] == "Data,":
        data.append(res[i + 1])
j = json.loads(json.loads(data[0]))
print("Outlier", j["data"]["is_outlier"] == [1])


# ## Outlier Prediction

# In[23]:


np.random.seed(0)
X_mask, mask = apply_mask(
    X.reshape(1, 32, 32, 3),
    mask_size=(10, 10),
    n_masks=1,
    channels=[0, 1, 2],
    mask_type="normal",
    noise_distr=(0, 1),
    clip_rng=(0, 1),
)


# In[24]:


show(X_mask)
predict(X_mask)


# Now lets check the message dumper for a new message. This should show we have found an outlier.

# In[25]:


res = get_ipython().getoutput("kubectl logs -n cifar10 $(kubectl get pod -n cifar10 -l app=hello-display -o jsonpath='{.items[0].metadata.name}')")
data = []
for i in range(0, len(res)):
    if res[i] == "Data,":
        data.append(res[i + 1])
j = json.loads(json.loads(data[-1]))
print("Outlier", j["data"]["is_outlier"] == [1])


# We will now call our outlier detector directly and ask for the feature scores to gain more information about why it predicted this instance was an outlier.

# In[26]:


od_preds = outlier(X_mask)


# We now plot those feature scores returned by the outlier detector along with our original image.

# In[27]:


plot_feature_outlier_image(od_preds, X_mask, X_recon=None)


# ## Tear Down

# In[28]:


get_ipython().system('kubectl delete ns cifar10')


# In[ ]:





#!/usr/bin/env python # coding: utf-8 # # Cifar10 Outlier Detection with NVIDIA Triton # ![demo](./demo.png) # # In this example we will deploy an image classification model along with an outlier detector trained on the same dataset. For in depth details on creating an outlier detection model for your own dataset see the [alibi-detect project](https://github.com/SeldonIO/alibi-detect) and associated [documentation](https://docs.seldon.io/projects/alibi-detect/en/latest/). You can find details for this [CIFAR10 example in their documentation](https://docs.seldon.io/projects/alibi-detect/en/latest/examples/od_vae_cifar10.html) as well. # # # Prequisites: # #   * [Knative eventing installed](https://knative.dev/docs/install/) #     * Ensure the istio-ingressgateway is exposed as a loadbalancer (no auth in this demo) #   * [Seldon Core installed](https://docs.seldon.io/projects/seldon-core/en/latest/workflow/install.html) #     * Ensure you install for istio, e.g. for the helm chart `--set istio.enabled=true` #   * A cluster with NVIDIA GPUs available compatible with Triton Inference Server. # #     Tested on GKE and Kind with Knative 0.18 and Istio 1.7.3 # In[ ]: # Ensure istio gateway installed # In[3]: # ## Setup Resources # In[1]: # In[2]: # In[3]: # In[4]: # In[5]: # Create the SeldonDeployment image classification model for Cifar10. We add in a `logger` for requests - the default destination is the namespace Knative Broker. # In[6]: # In[7]: # Create the pretrained VAE Cifar10 Outlier Detector. We forward replies to the message-dumper we started. # In[9]: # In[10]: # Create a Knative trigger to forward logging events to our Outlier Detector. # In[11]: # In[12]: # Get the IP address of the Istio Ingress Gateway. This assumes you have installed istio with a LoadBalancer. # In[13]: # Optionally add an authorization token here if you need one.Acquiring this token will be dependent on your auth setup. # In[14]: # If you are using Kind or Minikube you will need to port-forward to the istio ingressgateway and uncomment the following # In[15]: # CLUSTER_IP="localhost:8004" # In[15]: # In[17]: # ## Normal Prediction # In[18]: # Lets check the message dumper for an outlier detection prediction. This should be false. # In[22]: # ## Outlier Prediction # In[23]: # In[24]: # Now lets check the message dumper for a new message. This should show we have found an outlier. # In[25]: # We will now call our outlier detector directly and ask for the feature scores to gain more information about why it predicted this instance was an outlier. # In[26]: # We now plot those feature scores returned by the outlier detector along with our original image. # In[27]: # ## Tear Down # In[28]: # In[ ]: