Seldon deployment of income classifier and Alibi anchor explainer

The objective of this tutorial is to build a “loan approval” predictor using the Income classifier dataset to showcase the importance of black-box model explainers, which in this case are built using our open source framework Alibi. The diagram of this tutorial is as follows:

deploy-overview

In this tutorial we will follow the following steps:

  1. Train a model to predict loan approvals
  2. Containerise and deploy your model
  3. Create an explainer to understand predictions
  4. Containerise and deploy your explainer
  5. Test the predictions as well as explanations

Before you start

Make sure you install the following dependencies, as they are critical for this example to work:

  • Helm v3.0.0+
  • A Kubernetes cluster running v1.13 or above (minkube / docker-for-windows work well if enough RAM)
  • kubectl v1.14+
  • ksonnet v0.13.1+
  • kfctl 0.5.1 - Please use this exact version as there are major changes every few months
  • Python 3.6+
  • Python DEV requirements (we’ll install them below)

You can follow this notebook to setup your cluster.

Let’s get started! 🚀🔥

Install python dependencies

[1]:
!cat requirements-dev.txt
xai==0.0.5
seldon_core==0.5.1
alibi==0.3.2
dill==0.3.1
scikit-learn==0.20.1
[2]:
!pip install -r requirements-dev.txt
Requirement already satisfied: xai==0.0.5 in /home/rskolasinski/.local/lib/python3.7/site-packages (from -r requirements-dev.txt (line 1)) (0.0.5)
Requirement already satisfied: seldon_core==0.5.1 in /home/rskolasinski/.local/lib/python3.7/site-packages (from -r requirements-dev.txt (line 2)) (0.5.1)
Requirement already satisfied: alibi==0.3.2 in /home/rskolasinski/.local/lib/python3.7/site-packages (from -r requirements-dev.txt (line 3)) (0.3.2)
Processing /home/rskolasinski/.cache/pip/wheels/b6/26/8f/152327a2b78a0c2c3166e5d20d331bd4fb1272e810836fed76/dill-0.3.1.dev0-cp37-none-any.whl
Requirement already satisfied: scikit-learn==0.20.1 in /home/rskolasinski/.local/lib/python3.7/site-packages (from -r requirements-dev.txt (line 5)) (0.20.1)
Requirement already satisfied: pyparsing==2.3.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from xai==0.0.5->-r requirements-dev.txt (line 1)) (2.3.0)
Requirement already satisfied: six==1.12.0 in /usr/lib/python3/dist-packages (from xai==0.0.5->-r requirements-dev.txt (line 1)) (1.12.0)
Requirement already satisfied: scipy==1.1.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from xai==0.0.5->-r requirements-dev.txt (line 1)) (1.1.0)
Requirement already satisfied: cycler==0.10.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from xai==0.0.5->-r requirements-dev.txt (line 1)) (0.10.0)
Requirement already satisfied: matplotlib==3.0.2 in /home/rskolasinski/.local/lib/python3.7/site-packages (from xai==0.0.5->-r requirements-dev.txt (line 1)) (3.0.2)
Requirement already satisfied: kiwisolver==1.0.1 in /home/rskolasinski/.local/lib/python3.7/site-packages (from xai==0.0.5->-r requirements-dev.txt (line 1)) (1.0.1)
Requirement already satisfied: numpy==1.15.4 in /home/rskolasinski/.local/lib/python3.7/site-packages (from xai==0.0.5->-r requirements-dev.txt (line 1)) (1.15.4)
Requirement already satisfied: python-dateutil==2.7.5 in /home/rskolasinski/.local/lib/python3.7/site-packages (from xai==0.0.5->-r requirements-dev.txt (line 1)) (2.7.5)
Requirement already satisfied: pandas==0.23.4 in /home/rskolasinski/.local/lib/python3.7/site-packages (from xai==0.0.5->-r requirements-dev.txt (line 1)) (0.23.4)
Requirement already satisfied: pytz==2018.7 in /home/rskolasinski/.local/lib/python3.7/site-packages (from xai==0.0.5->-r requirements-dev.txt (line 1)) (2018.7)
Requirement already satisfied: protobuf<4.0.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (3.11.1)
Requirement already satisfied: Flask-OpenTracing<1.2.0,>=1.1.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (1.1.0)
Requirement already satisfied: opentracing<2.3.0,>=2.2.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (2.2.0)
Requirement already satisfied: jaeger-client<4.2.0,>=4.1.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (4.1.0)
Requirement already satisfied: pyaml<20.0.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (19.12.0)
Requirement already satisfied: gunicorn<20.1.0,>=19.9.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (20.0.4)
Requirement already satisfied: Flask<2.0.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (1.1.1)
Requirement already satisfied: setuptools>=41.0.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (42.0.2)
Requirement already satisfied: flatbuffers<2.0.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (1.11)
Requirement already satisfied: azure-storage-blob<3.0.0,>=2.0.1 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (2.1.0)
Requirement already satisfied: requests<3.0.0 in /usr/lib/python3/dist-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (2.21.0)
Requirement already satisfied: grpcio-opentracing<1.2.0,>=1.1.4 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (1.1.4)
Requirement already satisfied: minio<6.0.0,>=4.0.9 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (5.0.5)
Requirement already satisfied: grpcio<2.0.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (1.25.0)
Requirement already satisfied: redis<4.0.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (3.3.11)
Requirement already satisfied: Flask-cors<4.0.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (3.0.8)
Requirement already satisfied: tensorflow<2.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.15.0)
Requirement already satisfied: spacy in /home/rskolasinski/.local/lib/python3.7/site-packages (from alibi==0.3.2->-r requirements-dev.txt (line 3)) (2.2.3)
Requirement already satisfied: beautifulsoup4 in /home/rskolasinski/.local/lib/python3.7/site-packages (from alibi==0.3.2->-r requirements-dev.txt (line 3)) (4.8.1)
Requirement already satisfied: scikit-image in /home/rskolasinski/.local/lib/python3.7/site-packages (from alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.16.2)
Requirement already satisfied: Pillow in /usr/lib/python3/dist-packages (from alibi==0.3.2->-r requirements-dev.txt (line 3)) (6.1.0)
Requirement already satisfied: threadloop<2,>=1 in /home/rskolasinski/.local/lib/python3.7/site-packages (from jaeger-client<4.2.0,>=4.1.0->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (1.0.2)
Requirement already satisfied: tornado<6,>=4.3 in /home/rskolasinski/.local/lib/python3.7/site-packages (from jaeger-client<4.2.0,>=4.1.0->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (5.1.1)
Requirement already satisfied: thrift in /home/rskolasinski/.local/lib/python3.7/site-packages (from jaeger-client<4.2.0,>=4.1.0->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (0.13.0)
Requirement already satisfied: PyYAML in /usr/lib/python3/dist-packages (from pyaml<20.0.0->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (5.1.2)
Requirement already satisfied: Werkzeug>=0.15 in /home/rskolasinski/.local/lib/python3.7/site-packages (from Flask<2.0.0->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (0.16.0)
Requirement already satisfied: Jinja2>=2.10.1 in /home/rskolasinski/.local/lib/python3.7/site-packages (from Flask<2.0.0->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (2.10.3)
Requirement already satisfied: click>=5.1 in /home/rskolasinski/.local/lib/python3.7/site-packages (from Flask<2.0.0->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (7.0)
Requirement already satisfied: itsdangerous>=0.24 in /home/rskolasinski/.local/lib/python3.7/site-packages (from Flask<2.0.0->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (1.1.0)
Requirement already satisfied: azure-common>=1.1.5 in /home/rskolasinski/.local/lib/python3.7/site-packages (from azure-storage-blob<3.0.0,>=2.0.1->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (1.1.23)
Requirement already satisfied: azure-storage-common~=2.1 in /home/rskolasinski/.local/lib/python3.7/site-packages (from azure-storage-blob<3.0.0,>=2.0.1->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (2.1.0)
Requirement already satisfied: urllib3 in /usr/lib/python3/dist-packages (from minio<6.0.0,>=4.0.9->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (1.24.1)
Requirement already satisfied: certifi in /usr/lib/python3/dist-packages (from minio<6.0.0,>=4.0.9->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (2018.8.24)
Requirement already satisfied: tensorflow-estimator==1.15.1 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.15.1)
Requirement already satisfied: google-pasta>=0.1.6 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.1.8)
Requirement already satisfied: keras-applications>=1.0.8 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.0.8)
Requirement already satisfied: gast==0.2.2 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.2.2)
Requirement already satisfied: astor>=0.6.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.8.1)
Requirement already satisfied: tensorboard<1.16.0,>=1.15.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.15.0)
Requirement already satisfied: absl-py>=0.7.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.8.1)
Requirement already satisfied: opt-einsum>=2.3.2 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (3.1.0)
Requirement already satisfied: wrapt>=1.11.1 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.11.2)
Requirement already satisfied: wheel>=0.26 in /usr/lib/python3/dist-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.32.3)
Requirement already satisfied: keras-preprocessing>=1.0.5 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.1.0)
Requirement already satisfied: termcolor>=1.1.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.1.0)
Requirement already satisfied: cymem<2.1.0,>=2.0.2 in /home/rskolasinski/.local/lib/python3.7/site-packages (from spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (2.0.3)
Requirement already satisfied: blis<0.5.0,>=0.4.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.4.1)
Requirement already satisfied: catalogue<1.1.0,>=0.0.7 in /home/rskolasinski/.local/lib/python3.7/site-packages (from spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.0.8)
Requirement already satisfied: srsly<1.1.0,>=0.1.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.2.0)
Requirement already satisfied: plac<1.2.0,>=0.9.6 in /home/rskolasinski/.local/lib/python3.7/site-packages (from spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.1.3)
Requirement already satisfied: wasabi<1.1.0,>=0.4.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.4.2)
Requirement already satisfied: murmurhash<1.1.0,>=0.28.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.0.2)
Requirement already satisfied: preshed<3.1.0,>=3.0.2 in /home/rskolasinski/.local/lib/python3.7/site-packages (from spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (3.0.2)
Requirement already satisfied: thinc<7.4.0,>=7.3.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (7.3.1)
Requirement already satisfied: soupsieve>=1.2 in /home/rskolasinski/.local/lib/python3.7/site-packages (from beautifulsoup4->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.9.5)
Requirement already satisfied: imageio>=2.3.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from scikit-image->alibi==0.3.2->-r requirements-dev.txt (line 3)) (2.6.1)
Requirement already satisfied: PyWavelets>=0.4.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from scikit-image->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.1.1)
Requirement already satisfied: networkx>=2.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from scikit-image->alibi==0.3.2->-r requirements-dev.txt (line 3)) (2.4)
Requirement already satisfied: MarkupSafe>=0.23 in /home/rskolasinski/.local/lib/python3.7/site-packages (from Jinja2>=2.10.1->Flask<2.0.0->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (1.1.1)
Requirement already satisfied: cryptography in /usr/lib/python3/dist-packages (from azure-storage-common~=2.1->azure-storage-blob<3.0.0,>=2.0.1->seldon_core==0.5.1->-r requirements-dev.txt (line 2)) (2.6.1)
Requirement already satisfied: h5py in /home/rskolasinski/.local/lib/python3.7/site-packages (from keras-applications>=1.0.8->tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (2.10.0)
Requirement already satisfied: markdown>=2.6.8 in /home/rskolasinski/.local/lib/python3.7/site-packages (from tensorboard<1.16.0,>=1.15.0->tensorflow<2.0->alibi==0.3.2->-r requirements-dev.txt (line 3)) (3.1.1)
Requirement already satisfied: importlib-metadata>=0.20; python_version < "3.8" in /home/rskolasinski/.local/lib/python3.7/site-packages (from catalogue<1.1.0,>=0.0.7->spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (1.2.0)
Requirement already satisfied: tqdm<5.0.0,>=4.10.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from thinc<7.4.0,>=7.3.0->spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (4.40.2)
Requirement already satisfied: decorator>=4.3.0 in /home/rskolasinski/.local/lib/python3.7/site-packages (from networkx>=2.0->scikit-image->alibi==0.3.2->-r requirements-dev.txt (line 3)) (4.4.1)
Requirement already satisfied: zipp>=0.5 in /home/rskolasinski/.local/lib/python3.7/site-packages (from importlib-metadata>=0.20; python_version < "3.8"->catalogue<1.1.0,>=0.0.7->spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (0.6.0)
Requirement already satisfied: more-itertools in /home/rskolasinski/.local/lib/python3.7/site-packages (from zipp>=0.5->importlib-metadata>=0.20; python_version < "3.8"->catalogue<1.1.0,>=0.0.7->spacy->alibi==0.3.2->-r requirements-dev.txt (line 3)) (8.0.2)
Installing collected packages: dill
  Found existing installation: dill 0.3.1.dev0
    Uninstalling dill-0.3.1.dev0:
      Successfully uninstalled dill-0.3.1.dev0
  Rolling back uninstall of dill
  Moving to /home/rskolasinski/.local/bin/get_objgraph
   from /tmp/pip-uninstall-d3876fu7/get_objgraph
  Moving to /home/rskolasinski/.local/bin/undill
   from /tmp/pip-uninstall-d3876fu7/undill
  Moving to /home/rskolasinski/.local/lib/python3.7/site-packages/dill-0.3.1.dev0.dist-info/
   from /home/rskolasinski/.local/lib/python3.7/site-packages/~ill-0.3.1.dev0.dist-info
  Moving to /home/rskolasinski/.local/lib/python3.7/site-packages/dill/
   from /home/rskolasinski/.local/lib/python3.7/site-packages/~ill
ERROR: Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: '/usr/local/lib/python3.7/dist-packages/dill-0.3.1.dev0.dist-info'
Consider using the `--user` option or check the permissions.

Setup Seldon Core

Use the setup notebook to Setup Cluster with Ambassador Ingress and Install Seldon Core. Instructions also online.

1) Train a model to predict loan approvals

[3]:
import alibi
import numpy as np

adult = alibi.datasets.fetch_adult()

data = adult.data
labels = adult.target
feature_names = adult.feature_names
category_map = adult.category_map

# define train and test set
np.random.seed(0)
data_perm = np.random.permutation(np.c_[data, labels])
data = data_perm[:, :-1]
labels = data_perm[:, -1]

idx = 30000
X_train, y_train = data[:idx, :], labels[:idx]
X_test, y_test = data[idx + 1:, :], labels[idx + 1:]
[4]:
from sklearn.preprocessing import LabelEncoder, StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer

# feature transformation pipeline
ordinal_features = [x for x in range(len(feature_names)) if x not in list(category_map.keys())]
ordinal_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='median')),
                                      ('scaler', StandardScaler())])

categorical_features = list(category_map.keys())
categorical_transformer = Pipeline(steps=[('imputer', SimpleImputer(strategy='median')),
                                          ('onehot', OneHotEncoder(handle_unknown='ignore'))])

preprocessor = ColumnTransformer(transformers=[('num', ordinal_transformer, ordinal_features),
                                               ('cat', categorical_transformer, categorical_features)])
[5]:
preprocessor.fit(data)
[5]:
ColumnTransformer(n_jobs=None, remainder='drop', sparse_threshold=0.3,
         transformer_weights=None,
         transformers=[('num', Pipeline(memory=None,
     steps=[('imputer', SimpleImputer(copy=True, fill_value=None, missing_values=nan,
       strategy='median', verbose=0)), ('scaler', StandardScaler(copy=True, with_mean=True, with_std=True))]), [0, 8, 9, 10]), ('cat', Pipeline(memory=None,
     steps=[(...oat64'>, handle_unknown='ignore',
       n_values=None, sparse=True))]), [1, 2, 3, 4, 5, 6, 7, 11])])
[6]:
from sklearn.ensemble import RandomForestClassifier

np.random.seed(0)
clf = RandomForestClassifier(n_estimators=50)
clf.fit(preprocessor.transform(X_train), y_train)
[6]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='auto', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=50, n_jobs=None,
            oob_score=False, random_state=None, verbose=0,
            warm_start=False)
[7]:
import xai
pred = clf.predict(preprocessor.transform(X_test))
xai.metrics_plot(y_test, pred)
[7]:
target
precision 0.708042
recall 0.661765
specificity 0.914271
accuracy 0.853906
auc 0.788018
f1 0.684122
../_images/examples_alibi_anchor_tabular_10_1.png

2) Containerise and deploy your model

The steps to cotainerise a model with Seldon are always consistent, and require the following steps:

  1. Save the model artefacts in the model folder
  2. Write a wrapper with a predict function
  3. Add the python requirements
  4. Add the Source2Image configuration so the script knows which Model.py file to use
  5. Run the s2i command to build the image
  6. Deploy your image with a Seldon Graph Definition

Once you’ve deployed it, you are able to test it with Curl or with our Python SeldonClient

Let’s start containerising it - we’ll be using the following folder for this:

[8]:
!mkdir -p pipeline/pipeline_steps/loanclassifier

2.1 - Save the trained model in the folder

[9]:
import dill

with open("pipeline/pipeline_steps/loanclassifier/preprocessor.dill", "wb") as prep_f:
    dill.dump(preprocessor, prep_f)

with open("pipeline/pipeline_steps/loanclassifier/model.dill", "wb") as model_f:
    dill.dump(clf, model_f)

2.2 - Write a python wrapper for the loan approval model

[10]:
%%writefile pipeline/pipeline_steps/loanclassifier/Model.py
import dill

class Model:
    def __init__(self, *args, **kwargs):

        with open("preprocessor.dill", "rb") as prep_f:
            self.preprocessor = dill.load(prep_f)
        with open("model.dill", "rb") as model_f:
            self.clf = dill.load(model_f)

    def predict(self, X, feature_names=[]):
        print("Received: " + str(X))
        X_prep = self.preprocessor.transform(X)
        proba = self.clf.predict_proba(X_prep)
        print("Predicted: " + str(proba))
        return proba
Overwriting pipeline/pipeline_steps/loanclassifier/Model.py

2.3 - Add the python requirements for the image

[11]:
%%writefile pipeline/pipeline_steps/loanclassifier/requirements.txt
scikit-learn==0.20.1
dill==0.3.1
scikit-image==0.15.0
scikit-learn==0.20.1
scipy==1.1.0
numpy==1.15.4
Overwriting pipeline/pipeline_steps/loanclassifier/requirements.txt

2.4 - Create the source2image configuration file

[12]:
!mkdir -p pipeline/pipeline_steps/loanclassifier/.s2i
[13]:
%%writefile pipeline/pipeline_steps/loanclassifier/.s2i/environment
MODEL_NAME=Model
API_TYPE=REST
SERVICE_TYPE=MODEL
PERSISTENCE=0
Overwriting pipeline/pipeline_steps/loanclassifier/.s2i/environment

2.5 - Now we can build the image

[14]:
!s2i build pipeline/pipeline_steps/loanclassifier seldonio/seldon-core-s2i-python37:0.18 loanclassifier:0.1
---> Installing application source...
---> Installing dependencies ...
Looking in links: /whl
Collecting scikit-learn==0.20.1 (from -r requirements.txt (line 1))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/b0/3a/0802b78f697ae04ba06f49d0ebc6e872f2c470687c3e61ad8ef523e125c3/scikit_learn-0.20.1-cp37-cp37m-manylinux1_x86_64.whl (5.4MB)
Collecting dill==0.3.1 (from -r requirements.txt (line 2))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/3e/ad/31932a4e2804897e6fd2f946d53df51dd9b4aa55e152b5404395d00354d1/dill-0.3.1.tar.gz (151kB)
  WARNING: Requested dill==0.3.1 from https://files.pythonhosted.org/packages/3e/ad/31932a4e2804897e6fd2f946d53df51dd9b4aa55e152b5404395d00354d1/dill-0.3.1.tar.gz#sha256=d3ddddf2806a7bc9858b20c02dc174396795545e9d62f243b34481fd26eb3e2c (from -r requirements.txt (line 2)), but installing version 0.3.1.dev0
Collecting scikit-image==0.15.0 (from -r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/2e/21/ea56c8bb2e8112837dd71aebeb2ac67913e784911c0d7f493a593fa1a207/scikit_image-0.15.0-cp37-cp37m-manylinux1_x86_64.whl (26.3MB)
Collecting scipy==1.1.0 (from -r requirements.txt (line 5))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/40/de/0c22c6754370ba6b1fa8e53bd6e514d4a41a181125d405a501c215cbdbd6/scipy-1.1.0-cp37-cp37m-manylinux1_x86_64.whl (31.2MB)
Collecting numpy==1.15.4 (from -r requirements.txt (line 6))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/38/39/f73e104d44f19a6203e786d5204532e214443ea2954917b27f3229e7639b/numpy-1.15.4-cp37-cp37m-manylinux1_x86_64.whl (13.8MB)
Collecting imageio>=2.0.1 (from scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/1a/de/f7f985018f462ceeffada7f6e609919fbcc934acd9301929cba14bc2c24a/imageio-2.6.1-py3-none-any.whl (3.3MB)
Collecting PyWavelets>=0.4.0 (from scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/62/bd/592c7242fdd1218a96431512e77265c50812315ef72570ace85e1cfae298/PyWavelets-1.1.1-cp37-cp37m-manylinux1_x86_64.whl (4.4MB)
Collecting matplotlib!=3.0.0,>=2.0.0 (from scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/61/42/3e92d7aa64295483fbca20a86c89b34d0cb43cffaadaffe028793902d790/matplotlib-3.1.2-cp37-cp37m-manylinux1_x86_64.whl (13.1MB)
Collecting pillow>=4.3.0 (from scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/89/3e/31c2e5385d7588016c6f7ac552e81c3fff2bef4bc61b6f82f8177752405c/Pillow-6.2.1-cp37-cp37m-manylinux1_x86_64.whl (2.1MB)
Collecting networkx>=2.0 (from scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/41/8f/dd6a8e85946def36e4f2c69c84219af0fa5e832b018c970e92f2ad337e45/networkx-2.4-py3-none-any.whl (1.6MB)
Collecting cycler>=0.10 (from matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/site-packages (from matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3)) (2.8.1)
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 (from matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/c0/0c/fc2e007d9a992d997f04a80125b0f183da7fb554f1de701bbb70a8e7d479/pyparsing-2.4.5-py2.py3-none-any.whl (67kB)
Collecting kiwisolver>=1.0.1 (from matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/93/f8/518fb0bb89860eea6ff1b96483fbd9236d5ee991485d0f3eceff1770f654/kiwisolver-1.1.0-cp37-cp37m-manylinux1_x86_64.whl (90kB)
Collecting decorator>=4.3.0 (from networkx>=2.0->scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/8f/b7/f329cfdc75f3d28d12c65980e4469e2fa373f1953f5df6e370e84ea2e875/decorator-4.4.1-py2.py3-none-any.whl
Requirement already satisfied: six in /usr/local/lib/python3.7/site-packages (from cycler>=0.10->matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3)) (1.13.0)
Requirement already satisfied: setuptools in /usr/local/lib/python3.7/site-packages (from kiwisolver>=1.0.1->matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3)) (41.0.1)
Building wheels for collected packages: dill
Building wheel for dill (setup.py): started
Building wheel for dill (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/b6/26/8f/152327a2b78a0c2c3166e5d20d331bd4fb1272e810836fed76
Successfully built dill
Installing collected packages: numpy, scipy, scikit-learn, dill, pillow, imageio, PyWavelets, cycler, pyparsing, kiwisolver, matplotlib, decorator, networkx, scikit-image
Found existing installation: numpy 1.17.4
Uninstalling numpy-1.17.4:
Successfully uninstalled numpy-1.17.4
Successfully installed PyWavelets-1.1.1 cycler-0.10.0 decorator-4.4.1 dill-0.3.1.dev0 imageio-2.6.1 kiwisolver-1.1.0 matplotlib-3.1.2 networkx-2.4 numpy-1.15.4 pillow-6.2.1 pyparsing-2.4.5 scikit-image-0.15.0 scikit-learn-0.20.1 scipy-1.1.0
WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
WARNING: You are using pip version 19.1.1, however version 19.3.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Build completed successfully

or if using Minikube

[15]:
%%bash
eval $(minikube docker-env)
s2i build pipeline/pipeline_steps/loanclassifier seldonio/seldon-core-s2i-python37:0.18 loanclassifier:0.1
---> Installing application source...
---> Installing dependencies ...
Looking in links: /whl
Collecting scikit-learn==0.20.1 (from -r requirements.txt (line 1))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/b0/3a/0802b78f697ae04ba06f49d0ebc6e872f2c470687c3e61ad8ef523e125c3/scikit_learn-0.20.1-cp37-cp37m-manylinux1_x86_64.whl (5.4MB)
Collecting dill==0.3.1 (from -r requirements.txt (line 2))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/3e/ad/31932a4e2804897e6fd2f946d53df51dd9b4aa55e152b5404395d00354d1/dill-0.3.1.tar.gz (151kB)
  WARNING: Requested dill==0.3.1 from https://files.pythonhosted.org/packages/3e/ad/31932a4e2804897e6fd2f946d53df51dd9b4aa55e152b5404395d00354d1/dill-0.3.1.tar.gz#sha256=d3ddddf2806a7bc9858b20c02dc174396795545e9d62f243b34481fd26eb3e2c (from -r requirements.txt (line 2)), but installing version 0.3.1.dev0
Collecting scikit-image==0.15.0 (from -r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/2e/21/ea56c8bb2e8112837dd71aebeb2ac67913e784911c0d7f493a593fa1a207/scikit_image-0.15.0-cp37-cp37m-manylinux1_x86_64.whl (26.3MB)
Collecting scipy==1.1.0 (from -r requirements.txt (line 5))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/40/de/0c22c6754370ba6b1fa8e53bd6e514d4a41a181125d405a501c215cbdbd6/scipy-1.1.0-cp37-cp37m-manylinux1_x86_64.whl (31.2MB)
Collecting numpy==1.15.4 (from -r requirements.txt (line 6))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/38/39/f73e104d44f19a6203e786d5204532e214443ea2954917b27f3229e7639b/numpy-1.15.4-cp37-cp37m-manylinux1_x86_64.whl (13.8MB)
Collecting PyWavelets>=0.4.0 (from scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/62/bd/592c7242fdd1218a96431512e77265c50812315ef72570ace85e1cfae298/PyWavelets-1.1.1-cp37-cp37m-manylinux1_x86_64.whl (4.4MB)
Collecting pillow>=4.3.0 (from scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/89/3e/31c2e5385d7588016c6f7ac552e81c3fff2bef4bc61b6f82f8177752405c/Pillow-6.2.1-cp37-cp37m-manylinux1_x86_64.whl (2.1MB)
Collecting networkx>=2.0 (from scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/41/8f/dd6a8e85946def36e4f2c69c84219af0fa5e832b018c970e92f2ad337e45/networkx-2.4-py3-none-any.whl (1.6MB)
Collecting imageio>=2.0.1 (from scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/1a/de/f7f985018f462ceeffada7f6e609919fbcc934acd9301929cba14bc2c24a/imageio-2.6.1-py3-none-any.whl (3.3MB)
Collecting matplotlib!=3.0.0,>=2.0.0 (from scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/61/42/3e92d7aa64295483fbca20a86c89b34d0cb43cffaadaffe028793902d790/matplotlib-3.1.2-cp37-cp37m-manylinux1_x86_64.whl (13.1MB)
Collecting decorator>=4.3.0 (from networkx>=2.0->scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/8f/b7/f329cfdc75f3d28d12c65980e4469e2fa373f1953f5df6e370e84ea2e875/decorator-4.4.1-py2.py3-none-any.whl
Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/site-packages (from matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3)) (2.8.1)
Collecting cycler>=0.10 (from matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
Collecting kiwisolver>=1.0.1 (from matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/93/f8/518fb0bb89860eea6ff1b96483fbd9236d5ee991485d0f3eceff1770f654/kiwisolver-1.1.0-cp37-cp37m-manylinux1_x86_64.whl (90kB)
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 (from matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/c0/0c/fc2e007d9a992d997f04a80125b0f183da7fb554f1de701bbb70a8e7d479/pyparsing-2.4.5-py2.py3-none-any.whl (67kB)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/site-packages (from python-dateutil>=2.1->matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3)) (1.13.0)
Requirement already satisfied: setuptools in /usr/local/lib/python3.7/site-packages (from kiwisolver>=1.0.1->matplotlib!=3.0.0,>=2.0.0->scikit-image==0.15.0->-r requirements.txt (line 3)) (41.0.1)
Building wheels for collected packages: dill
Building wheel for dill (setup.py): started
Building wheel for dill (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/b6/26/8f/152327a2b78a0c2c3166e5d20d331bd4fb1272e810836fed76
Successfully built dill
Installing collected packages: numpy, scipy, scikit-learn, dill, PyWavelets, pillow, decorator, networkx, imageio, cycler, kiwisolver, pyparsing, matplotlib, scikit-image
Found existing installation: numpy 1.17.4
Uninstalling numpy-1.17.4:
Successfully uninstalled numpy-1.17.4
Successfully installed PyWavelets-1.1.1 cycler-0.10.0 decorator-4.4.1 dill-0.3.1.dev0 imageio-2.6.1 kiwisolver-1.1.0 matplotlib-3.1.2 networkx-2.4 numpy-1.15.4 pillow-6.2.1 pyparsing-2.4.5 scikit-image-0.15.0 scikit-learn-0.20.1 scipy-1.1.0
WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
WARNING: You are using pip version 19.1.1, however version 19.3.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Build completed successfully

2.6 - And deploy it to Kubernetes

[16]:
%%writefile pipeline/pipeline_steps/loanclassifier/loanclassifiermodel.yaml
apiVersion: machinelearning.seldon.io/v1alpha2
kind: SeldonDeployment
metadata:
  labels:
    app: seldon
  name: loanclassifier
spec:
  name: loanclassifier
  predictors:
  - componentSpecs:
    - spec:
        containers:
        - image: loanclassifier:0.1
          name: model
    graph:
      children: []
      name: model
      type: MODEL
      endpoint:
        type: REST
    name: loanclassifier
    replicas: 1
Overwriting pipeline/pipeline_steps/loanclassifier/loanclassifiermodel.yaml
[18]:
!kubectl apply -f pipeline/pipeline_steps/loanclassifier/loanclassifiermodel.yaml
seldondeployment.machinelearning.seldon.io/loanclassifier created
[31]:
!kubectl get pods
NAME                                                     READY   STATUS    RESTARTS   AGE
ambassador-69b784f9d5-242jz                              1/1     Running   0          99s
ambassador-69b784f9d5-b2655                              1/1     Running   0          99s
ambassador-69b784f9d5-ckrt2                              1/1     Running   0          99s
loanclassifier-loanclassifier-164157f-645c997d57-vqjv4   2/2     Running   0          95s

Now that it’s deployed we can test it with curl

IMPORTANT: If you are using minikube (instead of docker desktop) you have to forward the port first with:

kubectl port-forward svc/ambassador 8003:80
[32]:
# We'll use the output of the first item:
X_test[:1]
[32]:
array([[52,  4,  0,  2,  8,  4,  2,  0,  0,  0, 60,  9]])
[33]:
%%bash
curl -X POST -H 'Content-Type: application/json' \
    -d "{'data': {'names': ['text'], 'ndarray': [[52,  4,  0,  2,  8,  4,  2,  0,  0,  0, 60,  9]]}}" \
    http://localhost:8003/seldon/seldon/loanclassifier/api/v0.1/predictions
{
  "meta": {
    "puid": "sg5tdicpcqtclkohhct1uukc52",
    "tags": {
    },
    "routing": {
    },
    "requestPath": {
      "model": "loanclassifier:0.1"
    },
    "metrics": []
  },
  "data": {
    "names": ["t:0", "t:1"],
    "ndarray": [[0.86, 0.14]]
  }
}
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   356  100   264  100    92   1571    547 --:--:-- --:--:-- --:--:--  2131

And we can also test it with the Python SeldonClient

[34]:
from seldon_core.seldon_client import SeldonClient

batch = X_test[:1]

sc = SeldonClient(
    gateway="ambassador",
    gateway_endpoint="localhost:8003",
    deployment_name="loanclassifier",
    payload_type="ndarray",
    namespace="seldon",
    transport="rest")

client_prediction = sc.predict(data=batch)

print(client_prediction)
Success:True message:
Request:
data {
  ndarray {
    values {
      list_value {
        values {
          number_value: 52.0
        }
        values {
          number_value: 4.0
        }
        values {
          number_value: 0.0
        }
        values {
          number_value: 2.0
        }
        values {
          number_value: 8.0
        }
        values {
          number_value: 4.0
        }
        values {
          number_value: 2.0
        }
        values {
          number_value: 0.0
        }
        values {
          number_value: 0.0
        }
        values {
          number_value: 0.0
        }
        values {
          number_value: 60.0
        }
        values {
          number_value: 9.0
        }
      }
    }
  }
}

Response:
meta {
  puid: "v7dkibmv78ajvekrujc4nrlc8m"
  requestPath {
    key: "model"
    value: "loanclassifier:0.1"
  }
}
data {
  names: "t:0"
  names: "t:1"
  ndarray {
    values {
      list_value {
        values {
          number_value: 0.86
        }
        values {
          number_value: 0.14
        }
      }
    }
  }
}

3) Create an explainer to understand predictions

[35]:
from alibi.explainers import AnchorTabular

predict_fn = lambda x: clf.predict(preprocessor.transform(x))
explainer = AnchorTabular(predict_fn, feature_names, categorical_names=category_map)
[36]:
explainer.fit(X_train, disc_perc=[25, 50, 75])
[37]:
idx = 0
class_names = ['<=50K', '>50K']
predict_fn(X_test[idx].reshape(1, -1))
[37]:
array([0])
[38]:
X_train[:1]
[38]:
array([[27,  4,  4,  2,  1,  4,  4,  0,  0,  0, 44,  9]])
[39]:
explanation = explainer.explain(X_test[idx], threshold=0.95)

print('Anchor: %s' % (' AND '.join(explanation['names'])))
print('Precision: %.2f' % explanation['precision'])
print('Coverage: %.2f' % explanation['coverage'])
Anchor: Marital Status = Separated AND Sex = Female
Precision: 0.96
Coverage: 0.11

However we need to explain our remotely deployed model in production

For this we can actually create a predict_remote_fn that uses our SeldonClient to interact with the production model

[40]:
from seldon_core.utils import get_data_from_proto

def predict_remote_fn(X):
    from seldon_core.seldon_client import SeldonClient
    from seldon_core.utils import get_data_from_proto

    kwargs = {
        "gateway": "ambassador",
        "deployment_name": "loanclassifier",
        "payload_type": "ndarray",
        "namespace": "seldon",
        "transport": "rest"
    }

    try:
        kwargs["gateway_endpoint"] = "localhost:8003"
        sc = SeldonClient(**kwargs)
        prediction = sc.predict(data=X)
    except:
        # If we are inside the container, we need to reach the ambassador service directly
        kwargs["gateway_endpoint"] = "ambassador:80"
        sc = SeldonClient(**kwargs)
        prediction = sc.predict(data=X)

    y = get_data_from_proto(prediction.response)
    return y

# So the anchor is now connected with the remote model
explainer = AnchorTabular(predict_remote_fn, feature_names, categorical_names=category_map)

We train the anchor explainer with the remote model

[41]:
explainer.fit(X_train, disc_perc=[25, 50, 75])

We now can get explanations of the remote model

[43]:
explanation = explainer.explain(X_test[idx], threshold=0.95)

print('Anchor: %s' % (' AND '.join(explanation['names'])))
print('Precision: %.2f' % explanation['precision'])
print('Coverage: %.2f' % explanation['coverage'])
Anchor: Marital Status = Separated AND Sex = Female
Precision: 0.96
Coverage: 0.11

4) Containerise and deploy your explainer

Once again we will follow the same steps to cotainerise a model with Seldon are always consistent, and require the following steps:

  1. Save the model artefacts in the model folder
  2. Write a wrapper with a predict function
  3. Add the python requirements
  4. Add the Source2Image configuration so the script knows which Model.py file to use
  5. Run the s2i command to build the image
  6. Deploy your image with a Seldon Graph Definition

Once you’ve deployed it, you are able to test it with Curl or with our Python SeldonClient

Let’s start containerising it - we’ll be using the following folder for this:

[44]:
!mkdir -p pipeline/pipeline_steps/loanclassifier-explainer

1) Save the model artefacts in the model folder

[45]:
import dill

with open("pipeline/pipeline_steps/loanclassifier-explainer/explainer.dill", "wb") as x_f:
    dill.dump(explainer, x_f)

2) Write a wrapper with a predict function

[46]:
%%writefile pipeline/pipeline_steps/loanclassifier-explainer/Explainer.py
import dill
import json
import numpy as np

class Explainer:
    def __init__(self, *args, **kwargs):

        with open("explainer.dill", "rb") as x_f:
            self.explainer = dill.load(x_f)

    def predict(self, X, feature_names=[]):
        print("Received: " + str(X))
        explanation = self.explainer.explain(X)
        print("Predicted: " + str(explanation))
        return json.dumps(explanation, cls=NumpyEncoder)

class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (
        np.int_, np.intc, np.intp, np.int8, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32, np.uint64)):
            return int(obj)
        elif isinstance(obj, (np.float_, np.float16, np.float32, np.float64)):
            return float(obj)
        elif isinstance(obj, (np.ndarray,)):
            return obj.tolist()
        return json.JSONEncoder.default(self, obj)
Overwriting pipeline/pipeline_steps/loanclassifier-explainer/Explainer.py

3) Add the python requirements

[47]:
%%writefile pipeline/pipeline_steps/loanclassifier-explainer/requirements.txt
scikit-learn==0.20.1
dill==0.3.1.
alibi==0.3.2
seldon-core==0.5.1
Overwriting pipeline/pipeline_steps/loanclassifier-explainer/requirements.txt

4) Add the Source2Image configuration so the script knows which Model.py file to use

[48]:
!mkdir pipeline/pipeline_steps/loanclassifier-explainer/.s2i
mkdir: cannot create directory ‘pipeline/pipeline_steps/loanclassifier-explainer/.s2i’: File exists
[49]:
%%writefile pipeline/pipeline_steps/loanclassifier-explainer/.s2i/environment
MODEL_NAME=Explainer
API_TYPE=REST
SERVICE_TYPE=MODEL
PERSISTENCE=0
Overwriting pipeline/pipeline_steps/loanclassifier-explainer/.s2i/environment

5) Run the s2i command to build the image

[52]:
!s2i build pipeline/pipeline_steps/loanclassifier-explainer seldonio/seldon-core-s2i-python37:0.18 loanclassifier-explainer:0.1
---> Installing application source...
---> Installing dependencies ...
Looking in links: /whl
Collecting scikit-learn==0.20.1 (from -r requirements.txt (line 1))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/b0/3a/0802b78f697ae04ba06f49d0ebc6e872f2c470687c3e61ad8ef523e125c3/scikit_learn-0.20.1-cp37-cp37m-manylinux1_x86_64.whl (5.4MB)
Collecting dill==0.3.1. (from -r requirements.txt (line 2))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/3e/ad/31932a4e2804897e6fd2f946d53df51dd9b4aa55e152b5404395d00354d1/dill-0.3.1.tar.gz (151kB)
  WARNING: Requested dill==0.3.1. from https://files.pythonhosted.org/packages/3e/ad/31932a4e2804897e6fd2f946d53df51dd9b4aa55e152b5404395d00354d1/dill-0.3.1.tar.gz#sha256=d3ddddf2806a7bc9858b20c02dc174396795545e9d62f243b34481fd26eb3e2c (from -r requirements.txt (line 2)), but installing version 0.3.1.dev0
Collecting alibi==0.3.2 (from -r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/00/e7/54214fcf84a65339d6c993121da52edea52b56d39e6ec87ad30c755d665a/alibi-0.3.2-py3-none-any.whl (81kB)
Requirement already satisfied: seldon-core==0.5.1 in ./python (from -r requirements.txt (line 4)) (0.5.1)
Requirement already satisfied: numpy>=1.8.2 in /usr/local/lib/python3.7/site-packages (from scikit-learn==0.20.1->-r requirements.txt (line 1)) (1.17.4)
Collecting scipy>=0.13.3 (from scikit-learn==0.20.1->-r requirements.txt (line 1))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/f2/18/f788042dc7a73d0176e073909c00a6765c953986cae6d8cc13782a4bcd05/scipy-1.3.3-cp37-cp37m-manylinux1_x86_64.whl (25.2MB)
Collecting Pillow (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/89/3e/31c2e5385d7588016c6f7ac552e81c3fff2bef4bc61b6f82f8177752405c/Pillow-6.2.1-cp37-cp37m-manylinux1_x86_64.whl (2.1MB)
Requirement already satisfied: requests in /usr/local/lib/python3.7/site-packages (from alibi==0.3.2->-r requirements.txt (line 3)) (2.22.0)
Collecting beautifulsoup4 (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/3b/c8/a55eb6ea11cd7e5ac4bacdf92bac4693b90d3ba79268be16527555e186f0/beautifulsoup4-4.8.1-py3-none-any.whl (101kB)
Collecting pandas (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/63/e0/a1b39cdcb2c391f087a1538bc8a6d62a82d0439693192aef541d7b123769/pandas-0.25.3-cp37-cp37m-manylinux1_x86_64.whl (10.4MB)
Collecting spacy (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/91/76/1f30264c433f9c3c84171fa03f4b6bb5f3303df7781d21554d25045873f4/spacy-2.2.3-cp37-cp37m-manylinux1_x86_64.whl (10.4MB)
Collecting tensorflow<2.0 (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/92/2b/e3af15221da9ff323521565fa3324b0d7c7c5b1d7a8ca66984c8d59cb0ce/tensorflow-1.15.0-cp37-cp37m-manylinux2010_x86_64.whl (412.3MB)
Collecting scikit-image (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/dc/48/454bf836d302465475e02bc0468b879302145b07a005174c409a5b5869c7/scikit_image-0.16.2-cp37-cp37m-manylinux1_x86_64.whl (26.5MB)
Requirement already satisfied: Flask<2.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.1)
Requirement already satisfied: Flask-cors<4.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (3.0.8)
Requirement already satisfied: redis<4.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (3.3.11)
Requirement already satisfied: flatbuffers<2.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (1.11)
Requirement already satisfied: protobuf<4.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (3.10.0)
Requirement already satisfied: grpcio<2.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (1.25.0)
Requirement already satisfied: Flask-OpenTracing<1.2.0,>=1.1.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.0)
Requirement already satisfied: opentracing<2.3.0,>=2.2.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (2.2.0)
Requirement already satisfied: jaeger-client<4.2.0,>=4.1.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (4.1.0)
Requirement already satisfied: grpcio-opentracing<1.2.0,>=1.1.4 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.4)
Requirement already satisfied: pyaml<20.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (19.4.1)
Requirement already satisfied: gunicorn<20.1.0,>=19.9.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (20.0.0)
Requirement already satisfied: minio<6.0.0,>=4.0.9 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (5.0.5)
Requirement already satisfied: azure-storage-blob<3.0.0,>=2.0.1 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (2.1.0)
Requirement already satisfied: setuptools>=41.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (41.0.1)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/site-packages (from requests->alibi==0.3.2->-r requirements.txt (line 3)) (2019.9.11)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/site-packages (from requests->alibi==0.3.2->-r requirements.txt (line 3)) (1.25.7)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/local/lib/python3.7/site-packages (from requests->alibi==0.3.2->-r requirements.txt (line 3)) (3.0.4)
Requirement already satisfied: idna<2.9,>=2.5 in /usr/local/lib/python3.7/site-packages (from requests->alibi==0.3.2->-r requirements.txt (line 3)) (2.8)
Collecting soupsieve>=1.2 (from beautifulsoup4->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/81/94/03c0f04471fc245d08d0a99f7946ac228ca98da4fa75796c507f61e688c2/soupsieve-1.9.5-py2.py3-none-any.whl
Requirement already satisfied: pytz>=2017.2 in /usr/local/lib/python3.7/site-packages (from pandas->alibi==0.3.2->-r requirements.txt (line 3)) (2019.3)
Requirement already satisfied: python-dateutil>=2.6.1 in /usr/local/lib/python3.7/site-packages (from pandas->alibi==0.3.2->-r requirements.txt (line 3)) (2.8.1)
Collecting plac<1.2.0,>=0.9.6 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/86/85/40b8f66c2dd8f4fd9f09d59b22720cffecf1331e788b8a0cab5bafb353d1/plac-1.1.3-py2.py3-none-any.whl
Collecting murmurhash<1.1.0,>=0.28.0 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/73/fc/10eeacb926ec1e88cd62f79d9ac106b0a3e3fe5ff1690422d88c29bd0909/murmurhash-1.0.2-cp37-cp37m-manylinux1_x86_64.whl
Collecting wasabi<1.1.0,>=0.4.0 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/ff/ef/e8266e158ed32bf5f723fac862b6518833d0b53ca183165a8718f212c0d5/wasabi-0.4.2-py3-none-any.whl
Collecting blis<0.5.0,>=0.4.0 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/0a/8c/f1b2aad385de78db151a6e9728026f311dee8bd480f2edc28a0175a543b6/blis-0.4.1-cp37-cp37m-manylinux1_x86_64.whl (3.7MB)
Collecting cymem<2.1.0,>=2.0.2 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/e1/79/6ce05ecf4d50344e29749ea7db7ddf427589228fb8fe89b29718c38c27c5/cymem-2.0.3-cp37-cp37m-manylinux1_x86_64.whl
Collecting preshed<3.1.0,>=3.0.2 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/6c/5b/ae4da6230eb48df353b199f53532c8407d0e9eb6ed678d3d36fa75ac391c/preshed-3.0.2-cp37-cp37m-manylinux1_x86_64.whl (118kB)
Collecting thinc<7.4.0,>=7.3.0 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/32/53/d11d2faa6921e55c37ad2cd56b0866a9e6df647fb547cfb69a50059d759c/thinc-7.3.1-cp37-cp37m-manylinux1_x86_64.whl (2.2MB)
Collecting srsly<1.1.0,>=0.1.0 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/00/5a/9a3288b648a0c5c86d0a2ef972b0a8062ff1088658da8165b370564ef346/srsly-0.2.0-cp37-cp37m-manylinux1_x86_64.whl (185kB)
Collecting catalogue<1.1.0,>=0.0.7 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/4f/d5/46ff975f0d7d055cf95557b944fd5d29d9dfb37a4341038e070f212b24fe/catalogue-0.0.8-py2.py3-none-any.whl
Collecting opt-einsum>=2.3.2 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/b8/83/755bd5324777875e9dff19c2e59daec837d0378c09196634524a3d7269ac/opt_einsum-3.1.0.tar.gz (69kB)
Collecting termcolor>=1.1.0 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz
Collecting absl-py>=0.7.0 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/3b/72/e6e483e2db953c11efa44ee21c5fdb6505c4dffa447b4263ca8af6676b62/absl-py-0.8.1.tar.gz (103kB)
Collecting astor>=0.6.0 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/c3/88/97eef84f48fa04fbd6750e62dcceafba6c63c81b7ac1420856c8dcc0a3f9/astor-0.8.1-py2.py3-none-any.whl
Requirement already satisfied: six>=1.10.0 in /usr/local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3)) (1.13.0)
Collecting gast==0.2.2 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/4e/35/11749bf99b2d4e3cceb4d55ca22590b0d7c2c62b9de38ac4a4a7f4687421/gast-0.2.2.tar.gz
Collecting keras-applications>=1.0.8 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/71/e3/19762fdfc62877ae9102edf6342d71b28fbfd9dea3d2f96a882ce099b03f/Keras_Applications-1.0.8-py3-none-any.whl (50kB)
Collecting tensorflow-estimator==1.15.1 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/de/62/2ee9cd74c9fa2fa450877847ba560b260f5d0fb70ee0595203082dafcc9d/tensorflow_estimator-1.15.1-py2.py3-none-any.whl (503kB)
Requirement already satisfied: wheel>=0.26 in /usr/local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3)) (0.33.1)
Collecting google-pasta>=0.1.6 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/c3/fd/1e86bc4837cc9a3a5faf3db9b1854aa04ad35b5f381f9648fbe81a6f94e4/google_pasta-0.1.8-py3-none-any.whl (57kB)
Collecting tensorboard<1.16.0,>=1.15.0 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/1e/e9/d3d747a97f7188f48aa5eda486907f3b345cd409f0a0850468ba867db246/tensorboard-1.15.0-py3-none-any.whl (3.8MB)
Collecting wrapt>=1.11.1 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/23/84/323c2415280bc4fc880ac5050dddfb3c8062c2552b34c2e512eb4aa68f79/wrapt-1.11.2.tar.gz
Collecting keras-preprocessing>=1.0.5 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/28/6a/8c1f62c37212d9fc441a7e26736df51ce6f0e38455816445471f10da4f0a/Keras_Preprocessing-1.1.0-py2.py3-none-any.whl (41kB)
Collecting imageio>=2.3.0 (from scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/1a/de/f7f985018f462ceeffada7f6e609919fbcc934acd9301929cba14bc2c24a/imageio-2.6.1-py3-none-any.whl (3.3MB)
Collecting PyWavelets>=0.4.0 (from scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/62/bd/592c7242fdd1218a96431512e77265c50812315ef72570ace85e1cfae298/PyWavelets-1.1.1-cp37-cp37m-manylinux1_x86_64.whl (4.4MB)
Collecting networkx>=2.0 (from scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/41/8f/dd6a8e85946def36e4f2c69c84219af0fa5e832b018c970e92f2ad337e45/networkx-2.4-py3-none-any.whl (1.6MB)
Collecting matplotlib!=3.0.0,>=2.0.0 (from scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/61/42/3e92d7aa64295483fbca20a86c89b34d0cb43cffaadaffe028793902d790/matplotlib-3.1.2-cp37-cp37m-manylinux1_x86_64.whl (13.1MB)
Requirement already satisfied: Werkzeug>=0.15 in /usr/local/lib/python3.7/site-packages (from Flask<2.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (0.16.0)
Requirement already satisfied: Jinja2>=2.10.1 in /usr/local/lib/python3.7/site-packages (from Flask<2.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (2.10.3)
Requirement already satisfied: itsdangerous>=0.24 in /usr/local/lib/python3.7/site-packages (from Flask<2.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.0)
Requirement already satisfied: click>=5.1 in /usr/local/lib/python3.7/site-packages (from Flask<2.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (7.0)
Requirement already satisfied: tornado<6,>=4.3 in /usr/local/lib/python3.7/site-packages (from jaeger-client<4.2.0,>=4.1.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (5.1.1)
Requirement already satisfied: threadloop<2,>=1 in /usr/local/lib/python3.7/site-packages (from jaeger-client<4.2.0,>=4.1.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (1.0.2)
Requirement already satisfied: thrift in /usr/local/lib/python3.7/site-packages (from jaeger-client<4.2.0,>=4.1.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (0.13.0)
Requirement already satisfied: PyYAML in /usr/local/lib/python3.7/site-packages (from pyaml<20.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (5.1.2)
Requirement already satisfied: azure-storage-common~=2.1 in /usr/local/lib/python3.7/site-packages (from azure-storage-blob<3.0.0,>=2.0.1->seldon-core==0.5.1->-r requirements.txt (line 4)) (2.1.0)
Requirement already satisfied: azure-common>=1.1.5 in /usr/local/lib/python3.7/site-packages (from azure-storage-blob<3.0.0,>=2.0.1->seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.23)
Collecting tqdm<5.0.0,>=4.10.0 (from thinc<7.4.0,>=7.3.0->spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/7f/32/5144caf0478b1f26bd9d97f510a47336cf4ac0f96c6bc3b5af20d4173920/tqdm-4.40.2-py2.py3-none-any.whl (55kB)
Collecting importlib-metadata>=0.20; python_version < "3.8" (from catalogue<1.1.0,>=0.0.7->spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/e9/71/1a1e0ed0981bb6a67bce55a210f168126b7ebd2065958673797ea66489ca/importlib_metadata-1.3.0-py2.py3-none-any.whl
Collecting h5py (from keras-applications>=1.0.8->tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/3f/c0/abde58b837e066bca19a3f7332d9d0493521d7dd6b48248451a9e3fe2214/h5py-2.10.0-cp37-cp37m-manylinux1_x86_64.whl (2.9MB)
Collecting markdown>=2.6.8 (from tensorboard<1.16.0,>=1.15.0->tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/c0/4e/fd492e91abdc2d2fcb70ef453064d980688762079397f779758e055f6575/Markdown-3.1.1-py2.py3-none-any.whl (87kB)
Collecting decorator>=4.3.0 (from networkx>=2.0->scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/8f/b7/f329cfdc75f3d28d12c65980e4469e2fa373f1953f5df6e370e84ea2e875/decorator-4.4.1-py2.py3-none-any.whl
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 (from matplotlib!=3.0.0,>=2.0.0->scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/c0/0c/fc2e007d9a992d997f04a80125b0f183da7fb554f1de701bbb70a8e7d479/pyparsing-2.4.5-py2.py3-none-any.whl (67kB)
Collecting cycler>=0.10 (from matplotlib!=3.0.0,>=2.0.0->scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
Collecting kiwisolver>=1.0.1 (from matplotlib!=3.0.0,>=2.0.0->scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/93/f8/518fb0bb89860eea6ff1b96483fbd9236d5ee991485d0f3eceff1770f654/kiwisolver-1.1.0-cp37-cp37m-manylinux1_x86_64.whl (90kB)
Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/lib/python3.7/site-packages (from Jinja2>=2.10.1->Flask<2.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.1)
Requirement already satisfied: cryptography in /usr/local/lib/python3.7/site-packages (from azure-storage-common~=2.1->azure-storage-blob<3.0.0,>=2.0.1->seldon-core==0.5.1->-r requirements.txt (line 4)) (2.8)
Collecting zipp>=0.5 (from importlib-metadata>=0.20; python_version < "3.8"->catalogue<1.1.0,>=0.0.7->spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/74/3d/1ee25a26411ba0401b43c6376d2316a71addcc72ef8690b101b4ea56d76a/zipp-0.6.0-py2.py3-none-any.whl
Requirement already satisfied: cffi!=1.11.3,>=1.8 in /usr/local/lib/python3.7/site-packages (from cryptography->azure-storage-common~=2.1->azure-storage-blob<3.0.0,>=2.0.1->seldon-core==0.5.1->-r requirements.txt (line 4)) (1.13.2)
Collecting more-itertools (from zipp>=0.5->importlib-metadata>=0.20; python_version < "3.8"->catalogue<1.1.0,>=0.0.7->spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/68/03/0604cec1ea13c9f063dd50f900d1a36160334dd3cfb01fd0e638f61b46ba/more_itertools-8.0.2-py3-none-any.whl (40kB)
Requirement already satisfied: pycparser in /usr/local/lib/python3.7/site-packages (from cffi!=1.11.3,>=1.8->cryptography->azure-storage-common~=2.1->azure-storage-blob<3.0.0,>=2.0.1->seldon-core==0.5.1->-r requirements.txt (line 4)) (2.19)
Building wheels for collected packages: dill, opt-einsum, termcolor, absl-py, gast, wrapt
Building wheel for dill (setup.py): started
Building wheel for dill (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/b6/26/8f/152327a2b78a0c2c3166e5d20d331bd4fb1272e810836fed76
Building wheel for opt-einsum (setup.py): started
Building wheel for opt-einsum (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/2c/b1/94/43d03e130b929aae7ba3f8d15cbd7bc0d1cb5bb38a5c721833
Building wheel for termcolor (setup.py): started
Building wheel for termcolor (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/7c/06/54/bc84598ba1daf8f970247f550b175aaaee85f68b4b0c5ab2c6
Building wheel for absl-py (setup.py): started
Building wheel for absl-py (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/a7/15/a0/0a0561549ad11cdc1bc8fa1191a353efd30facf6bfb507aefc
Building wheel for gast (setup.py): started
Building wheel for gast (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/5c/2e/7e/a1d4d4fcebe6c381f378ce7743a3ced3699feb89bcfbdadadd
Building wheel for wrapt (setup.py): started
Building wheel for wrapt (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/d7/de/2e/efa132238792efb6459a96e85916ef8597fcb3d2ae51590dfd
Successfully built dill opt-einsum termcolor absl-py gast wrapt
Installing collected packages: scipy, scikit-learn, dill, Pillow, soupsieve, beautifulsoup4, pandas, plac, murmurhash, wasabi, blis, cymem, preshed, tqdm, srsly, thinc, more-itertools, zipp, importlib-metadata, catalogue, spacy, opt-einsum, termcolor, absl-py, astor, gast, h5py, keras-applications, tensorflow-estimator, google-pasta, markdown, tensorboard, wrapt, keras-preprocessing, tensorflow, imageio, PyWavelets, decorator, networkx, pyparsing, cycler, kiwisolver, matplotlib, scikit-image, alibi
Successfully installed Pillow-6.2.1 PyWavelets-1.1.1 absl-py-0.8.1 alibi-0.3.2 astor-0.8.1 beautifulsoup4-4.8.1 blis-0.4.1 catalogue-0.0.8 cycler-0.10.0 cymem-2.0.3 decorator-4.4.1 dill-0.3.1.dev0 gast-0.2.2 google-pasta-0.1.8 h5py-2.10.0 imageio-2.6.1 importlib-metadata-1.3.0 keras-applications-1.0.8 keras-preprocessing-1.1.0 kiwisolver-1.1.0 markdown-3.1.1 matplotlib-3.1.2 more-itertools-8.0.2 murmurhash-1.0.2 networkx-2.4 opt-einsum-3.1.0 pandas-0.25.3 plac-1.1.3 preshed-3.0.2 pyparsing-2.4.5 scikit-image-0.16.2 scikit-learn-0.20.1 scipy-1.3.3 soupsieve-1.9.5 spacy-2.2.3 srsly-0.2.0 tensorboard-1.15.0 tensorflow-1.15.0 tensorflow-estimator-1.15.1 termcolor-1.1.0 thinc-7.3.1 tqdm-4.40.2 wasabi-0.4.2 wrapt-1.11.2 zipp-0.6.0
WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
WARNING: You are using pip version 19.1.1, however version 19.3.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Build completed successfully

or if using minikube

[53]:
%%bash
eval $(minikube docker-env)
s2i build pipeline/pipeline_steps/loanclassifier-explainer seldonio/seldon-core-s2i-python37:0.18 loanclassifier-explainer:0.1
---> Installing application source...
---> Installing dependencies ...
Looking in links: /whl
Collecting scikit-learn==0.20.1 (from -r requirements.txt (line 1))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/b0/3a/0802b78f697ae04ba06f49d0ebc6e872f2c470687c3e61ad8ef523e125c3/scikit_learn-0.20.1-cp37-cp37m-manylinux1_x86_64.whl (5.4MB)
Collecting dill==0.3.1. (from -r requirements.txt (line 2))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/3e/ad/31932a4e2804897e6fd2f946d53df51dd9b4aa55e152b5404395d00354d1/dill-0.3.1.tar.gz (151kB)
  WARNING: Requested dill==0.3.1. from https://files.pythonhosted.org/packages/3e/ad/31932a4e2804897e6fd2f946d53df51dd9b4aa55e152b5404395d00354d1/dill-0.3.1.tar.gz#sha256=d3ddddf2806a7bc9858b20c02dc174396795545e9d62f243b34481fd26eb3e2c (from -r requirements.txt (line 2)), but installing version 0.3.1.dev0
Collecting alibi==0.3.2 (from -r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/00/e7/54214fcf84a65339d6c993121da52edea52b56d39e6ec87ad30c755d665a/alibi-0.3.2-py3-none-any.whl (81kB)
Requirement already satisfied: seldon-core==0.5.1 in ./python (from -r requirements.txt (line 4)) (0.5.1)
Collecting scipy>=0.13.3 (from scikit-learn==0.20.1->-r requirements.txt (line 1))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/f2/18/f788042dc7a73d0176e073909c00a6765c953986cae6d8cc13782a4bcd05/scipy-1.3.3-cp37-cp37m-manylinux1_x86_64.whl (25.2MB)
Requirement already satisfied: numpy>=1.8.2 in /usr/local/lib/python3.7/site-packages (from scikit-learn==0.20.1->-r requirements.txt (line 1)) (1.17.4)
Requirement already satisfied: requests in /usr/local/lib/python3.7/site-packages (from alibi==0.3.2->-r requirements.txt (line 3)) (2.22.0)
Collecting tensorflow<2.0 (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/92/2b/e3af15221da9ff323521565fa3324b0d7c7c5b1d7a8ca66984c8d59cb0ce/tensorflow-1.15.0-cp37-cp37m-manylinux2010_x86_64.whl (412.3MB)
Collecting beautifulsoup4 (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/3b/c8/a55eb6ea11cd7e5ac4bacdf92bac4693b90d3ba79268be16527555e186f0/beautifulsoup4-4.8.1-py3-none-any.whl (101kB)
Collecting Pillow (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/89/3e/31c2e5385d7588016c6f7ac552e81c3fff2bef4bc61b6f82f8177752405c/Pillow-6.2.1-cp37-cp37m-manylinux1_x86_64.whl (2.1MB)
Collecting pandas (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/63/e0/a1b39cdcb2c391f087a1538bc8a6d62a82d0439693192aef541d7b123769/pandas-0.25.3-cp37-cp37m-manylinux1_x86_64.whl (10.4MB)
Collecting spacy (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/91/76/1f30264c433f9c3c84171fa03f4b6bb5f3303df7781d21554d25045873f4/spacy-2.2.3-cp37-cp37m-manylinux1_x86_64.whl (10.4MB)
Collecting scikit-image (from alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/dc/48/454bf836d302465475e02bc0468b879302145b07a005174c409a5b5869c7/scikit_image-0.16.2-cp37-cp37m-manylinux1_x86_64.whl (26.5MB)
Requirement already satisfied: Flask<2.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.1)
Requirement already satisfied: Flask-cors<4.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (3.0.8)
Requirement already satisfied: redis<4.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (3.3.11)
Requirement already satisfied: flatbuffers<2.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (1.11)
Requirement already satisfied: protobuf<4.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (3.10.0)
Requirement already satisfied: grpcio<2.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (1.25.0)
Requirement already satisfied: Flask-OpenTracing<1.2.0,>=1.1.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.0)
Requirement already satisfied: opentracing<2.3.0,>=2.2.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (2.2.0)
Requirement already satisfied: jaeger-client<4.2.0,>=4.1.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (4.1.0)
Requirement already satisfied: grpcio-opentracing<1.2.0,>=1.1.4 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.4)
Requirement already satisfied: pyaml<20.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (19.4.1)
Requirement already satisfied: gunicorn<20.1.0,>=19.9.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (20.0.0)
Requirement already satisfied: minio<6.0.0,>=4.0.9 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (5.0.5)
Requirement already satisfied: azure-storage-blob<3.0.0,>=2.0.1 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (2.1.0)
Requirement already satisfied: setuptools>=41.0.0 in /usr/local/lib/python3.7/site-packages (from seldon-core==0.5.1->-r requirements.txt (line 4)) (41.0.1)
Requirement already satisfied: idna<2.9,>=2.5 in /usr/local/lib/python3.7/site-packages (from requests->alibi==0.3.2->-r requirements.txt (line 3)) (2.8)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /usr/local/lib/python3.7/site-packages (from requests->alibi==0.3.2->-r requirements.txt (line 3)) (3.0.4)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.7/site-packages (from requests->alibi==0.3.2->-r requirements.txt (line 3)) (2019.9.11)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /usr/local/lib/python3.7/site-packages (from requests->alibi==0.3.2->-r requirements.txt (line 3)) (1.25.7)
Collecting termcolor>=1.1.0 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/8a/48/a76be51647d0eb9f10e2a4511bf3ffb8cc1e6b14e9e4fab46173aa79f981/termcolor-1.1.0.tar.gz
Collecting tensorboard<1.16.0,>=1.15.0 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/1e/e9/d3d747a97f7188f48aa5eda486907f3b345cd409f0a0850468ba867db246/tensorboard-1.15.0-py3-none-any.whl (3.8MB)
Requirement already satisfied: wheel>=0.26 in /usr/local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3)) (0.33.1)
Collecting absl-py>=0.7.0 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/3b/72/e6e483e2db953c11efa44ee21c5fdb6505c4dffa447b4263ca8af6676b62/absl-py-0.8.1.tar.gz (103kB)
Collecting wrapt>=1.11.1 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/23/84/323c2415280bc4fc880ac5050dddfb3c8062c2552b34c2e512eb4aa68f79/wrapt-1.11.2.tar.gz
Collecting tensorflow-estimator==1.15.1 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/de/62/2ee9cd74c9fa2fa450877847ba560b260f5d0fb70ee0595203082dafcc9d/tensorflow_estimator-1.15.1-py2.py3-none-any.whl (503kB)
Collecting opt-einsum>=2.3.2 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/b8/83/755bd5324777875e9dff19c2e59daec837d0378c09196634524a3d7269ac/opt_einsum-3.1.0.tar.gz (69kB)
Collecting astor>=0.6.0 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/c3/88/97eef84f48fa04fbd6750e62dcceafba6c63c81b7ac1420856c8dcc0a3f9/astor-0.8.1-py2.py3-none-any.whl
Collecting gast==0.2.2 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/4e/35/11749bf99b2d4e3cceb4d55ca22590b0d7c2c62b9de38ac4a4a7f4687421/gast-0.2.2.tar.gz
Requirement already satisfied: six>=1.10.0 in /usr/local/lib/python3.7/site-packages (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3)) (1.13.0)
Collecting keras-preprocessing>=1.0.5 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/28/6a/8c1f62c37212d9fc441a7e26736df51ce6f0e38455816445471f10da4f0a/Keras_Preprocessing-1.1.0-py2.py3-none-any.whl (41kB)
Collecting google-pasta>=0.1.6 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/c3/fd/1e86bc4837cc9a3a5faf3db9b1854aa04ad35b5f381f9648fbe81a6f94e4/google_pasta-0.1.8-py3-none-any.whl (57kB)
Collecting keras-applications>=1.0.8 (from tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/71/e3/19762fdfc62877ae9102edf6342d71b28fbfd9dea3d2f96a882ce099b03f/Keras_Applications-1.0.8-py3-none-any.whl (50kB)
Collecting soupsieve>=1.2 (from beautifulsoup4->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/81/94/03c0f04471fc245d08d0a99f7946ac228ca98da4fa75796c507f61e688c2/soupsieve-1.9.5-py2.py3-none-any.whl
Requirement already satisfied: python-dateutil>=2.6.1 in /usr/local/lib/python3.7/site-packages (from pandas->alibi==0.3.2->-r requirements.txt (line 3)) (2.8.1)
Requirement already satisfied: pytz>=2017.2 in /usr/local/lib/python3.7/site-packages (from pandas->alibi==0.3.2->-r requirements.txt (line 3)) (2019.3)
Collecting murmurhash<1.1.0,>=0.28.0 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/73/fc/10eeacb926ec1e88cd62f79d9ac106b0a3e3fe5ff1690422d88c29bd0909/murmurhash-1.0.2-cp37-cp37m-manylinux1_x86_64.whl
Collecting wasabi<1.1.0,>=0.4.0 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/ff/ef/e8266e158ed32bf5f723fac862b6518833d0b53ca183165a8718f212c0d5/wasabi-0.4.2-py3-none-any.whl
Collecting plac<1.2.0,>=0.9.6 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/86/85/40b8f66c2dd8f4fd9f09d59b22720cffecf1331e788b8a0cab5bafb353d1/plac-1.1.3-py2.py3-none-any.whl
Collecting blis<0.5.0,>=0.4.0 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/0a/8c/f1b2aad385de78db151a6e9728026f311dee8bd480f2edc28a0175a543b6/blis-0.4.1-cp37-cp37m-manylinux1_x86_64.whl (3.7MB)
Collecting srsly<1.1.0,>=0.1.0 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/00/5a/9a3288b648a0c5c86d0a2ef972b0a8062ff1088658da8165b370564ef346/srsly-0.2.0-cp37-cp37m-manylinux1_x86_64.whl (185kB)
Collecting cymem<2.1.0,>=2.0.2 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/e1/79/6ce05ecf4d50344e29749ea7db7ddf427589228fb8fe89b29718c38c27c5/cymem-2.0.3-cp37-cp37m-manylinux1_x86_64.whl
Collecting thinc<7.4.0,>=7.3.0 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/32/53/d11d2faa6921e55c37ad2cd56b0866a9e6df647fb547cfb69a50059d759c/thinc-7.3.1-cp37-cp37m-manylinux1_x86_64.whl (2.2MB)
Collecting preshed<3.1.0,>=3.0.2 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/6c/5b/ae4da6230eb48df353b199f53532c8407d0e9eb6ed678d3d36fa75ac391c/preshed-3.0.2-cp37-cp37m-manylinux1_x86_64.whl (118kB)
Collecting catalogue<1.1.0,>=0.0.7 (from spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/4f/d5/46ff975f0d7d055cf95557b944fd5d29d9dfb37a4341038e070f212b24fe/catalogue-0.0.8-py2.py3-none-any.whl
Collecting matplotlib!=3.0.0,>=2.0.0 (from scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/61/42/3e92d7aa64295483fbca20a86c89b34d0cb43cffaadaffe028793902d790/matplotlib-3.1.2-cp37-cp37m-manylinux1_x86_64.whl (13.1MB)
Collecting PyWavelets>=0.4.0 (from scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/62/bd/592c7242fdd1218a96431512e77265c50812315ef72570ace85e1cfae298/PyWavelets-1.1.1-cp37-cp37m-manylinux1_x86_64.whl (4.4MB)
Collecting networkx>=2.0 (from scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/41/8f/dd6a8e85946def36e4f2c69c84219af0fa5e832b018c970e92f2ad337e45/networkx-2.4-py3-none-any.whl (1.6MB)
Collecting imageio>=2.3.0 (from scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/1a/de/f7f985018f462ceeffada7f6e609919fbcc934acd9301929cba14bc2c24a/imageio-2.6.1-py3-none-any.whl (3.3MB)
Requirement already satisfied: Jinja2>=2.10.1 in /usr/local/lib/python3.7/site-packages (from Flask<2.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (2.10.3)
Requirement already satisfied: itsdangerous>=0.24 in /usr/local/lib/python3.7/site-packages (from Flask<2.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.0)
Requirement already satisfied: Werkzeug>=0.15 in /usr/local/lib/python3.7/site-packages (from Flask<2.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (0.16.0)
Requirement already satisfied: click>=5.1 in /usr/local/lib/python3.7/site-packages (from Flask<2.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (7.0)
Requirement already satisfied: tornado<6,>=4.3 in /usr/local/lib/python3.7/site-packages (from jaeger-client<4.2.0,>=4.1.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (5.1.1)
Requirement already satisfied: threadloop<2,>=1 in /usr/local/lib/python3.7/site-packages (from jaeger-client<4.2.0,>=4.1.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (1.0.2)
Requirement already satisfied: thrift in /usr/local/lib/python3.7/site-packages (from jaeger-client<4.2.0,>=4.1.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (0.13.0)
Requirement already satisfied: PyYAML in /usr/local/lib/python3.7/site-packages (from pyaml<20.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (5.1.2)
Requirement already satisfied: azure-common>=1.1.5 in /usr/local/lib/python3.7/site-packages (from azure-storage-blob<3.0.0,>=2.0.1->seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.23)
Requirement already satisfied: azure-storage-common~=2.1 in /usr/local/lib/python3.7/site-packages (from azure-storage-blob<3.0.0,>=2.0.1->seldon-core==0.5.1->-r requirements.txt (line 4)) (2.1.0)
Collecting markdown>=2.6.8 (from tensorboard<1.16.0,>=1.15.0->tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/c0/4e/fd492e91abdc2d2fcb70ef453064d980688762079397f779758e055f6575/Markdown-3.1.1-py2.py3-none-any.whl (87kB)
Collecting h5py (from keras-applications>=1.0.8->tensorflow<2.0->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/3f/c0/abde58b837e066bca19a3f7332d9d0493521d7dd6b48248451a9e3fe2214/h5py-2.10.0-cp37-cp37m-manylinux1_x86_64.whl (2.9MB)
Collecting tqdm<5.0.0,>=4.10.0 (from thinc<7.4.0,>=7.3.0->spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/7f/32/5144caf0478b1f26bd9d97f510a47336cf4ac0f96c6bc3b5af20d4173920/tqdm-4.40.2-py2.py3-none-any.whl (55kB)
Collecting importlib-metadata>=0.20; python_version < "3.8" (from catalogue<1.1.0,>=0.0.7->spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/e9/71/1a1e0ed0981bb6a67bce55a210f168126b7ebd2065958673797ea66489ca/importlib_metadata-1.3.0-py2.py3-none-any.whl
Collecting cycler>=0.10 (from matplotlib!=3.0.0,>=2.0.0->scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/f7/d2/e07d3ebb2bd7af696440ce7e754c59dd546ffe1bbe732c8ab68b9c834e61/cycler-0.10.0-py2.py3-none-any.whl
Collecting kiwisolver>=1.0.1 (from matplotlib!=3.0.0,>=2.0.0->scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/93/f8/518fb0bb89860eea6ff1b96483fbd9236d5ee991485d0f3eceff1770f654/kiwisolver-1.1.0-cp37-cp37m-manylinux1_x86_64.whl (90kB)
Collecting pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 (from matplotlib!=3.0.0,>=2.0.0->scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/c0/0c/fc2e007d9a992d997f04a80125b0f183da7fb554f1de701bbb70a8e7d479/pyparsing-2.4.5-py2.py3-none-any.whl (67kB)
Collecting decorator>=4.3.0 (from networkx>=2.0->scikit-image->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/8f/b7/f329cfdc75f3d28d12c65980e4469e2fa373f1953f5df6e370e84ea2e875/decorator-4.4.1-py2.py3-none-any.whl
Requirement already satisfied: MarkupSafe>=0.23 in /usr/local/lib/python3.7/site-packages (from Jinja2>=2.10.1->Flask<2.0.0->seldon-core==0.5.1->-r requirements.txt (line 4)) (1.1.1)
Requirement already satisfied: cryptography in /usr/local/lib/python3.7/site-packages (from azure-storage-common~=2.1->azure-storage-blob<3.0.0,>=2.0.1->seldon-core==0.5.1->-r requirements.txt (line 4)) (2.8)
Collecting zipp>=0.5 (from importlib-metadata>=0.20; python_version < "3.8"->catalogue<1.1.0,>=0.0.7->spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/74/3d/1ee25a26411ba0401b43c6376d2316a71addcc72ef8690b101b4ea56d76a/zipp-0.6.0-py2.py3-none-any.whl
Requirement already satisfied: cffi!=1.11.3,>=1.8 in /usr/local/lib/python3.7/site-packages (from cryptography->azure-storage-common~=2.1->azure-storage-blob<3.0.0,>=2.0.1->seldon-core==0.5.1->-r requirements.txt (line 4)) (1.13.2)
Collecting more-itertools (from zipp>=0.5->importlib-metadata>=0.20; python_version < "3.8"->catalogue<1.1.0,>=0.0.7->spacy->alibi==0.3.2->-r requirements.txt (line 3))
  WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
Downloading https://files.pythonhosted.org/packages/68/03/0604cec1ea13c9f063dd50f900d1a36160334dd3cfb01fd0e638f61b46ba/more_itertools-8.0.2-py3-none-any.whl (40kB)
Requirement already satisfied: pycparser in /usr/local/lib/python3.7/site-packages (from cffi!=1.11.3,>=1.8->cryptography->azure-storage-common~=2.1->azure-storage-blob<3.0.0,>=2.0.1->seldon-core==0.5.1->-r requirements.txt (line 4)) (2.19)
Building wheels for collected packages: dill, termcolor, absl-py, wrapt, opt-einsum, gast
Building wheel for dill (setup.py): started
Building wheel for dill (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/b6/26/8f/152327a2b78a0c2c3166e5d20d331bd4fb1272e810836fed76
Building wheel for termcolor (setup.py): started
Building wheel for termcolor (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/7c/06/54/bc84598ba1daf8f970247f550b175aaaee85f68b4b0c5ab2c6
Building wheel for absl-py (setup.py): started
Building wheel for absl-py (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/a7/15/a0/0a0561549ad11cdc1bc8fa1191a353efd30facf6bfb507aefc
Building wheel for wrapt (setup.py): started
Building wheel for wrapt (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/d7/de/2e/efa132238792efb6459a96e85916ef8597fcb3d2ae51590dfd
Building wheel for opt-einsum (setup.py): started
Building wheel for opt-einsum (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/2c/b1/94/43d03e130b929aae7ba3f8d15cbd7bc0d1cb5bb38a5c721833
Building wheel for gast (setup.py): started
Building wheel for gast (setup.py): finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/5c/2e/7e/a1d4d4fcebe6c381f378ce7743a3ced3699feb89bcfbdadadd
Successfully built dill termcolor absl-py wrapt opt-einsum gast
Installing collected packages: scipy, scikit-learn, dill, termcolor, markdown, absl-py, tensorboard, wrapt, tensorflow-estimator, opt-einsum, astor, gast, keras-preprocessing, google-pasta, h5py, keras-applications, tensorflow, soupsieve, beautifulsoup4, Pillow, pandas, murmurhash, wasabi, plac, blis, srsly, cymem, preshed, tqdm, thinc, more-itertools, zipp, importlib-metadata, catalogue, spacy, cycler, kiwisolver, pyparsing, matplotlib, PyWavelets, decorator, networkx, imageio, scikit-image, alibi
Successfully installed Pillow-6.2.1 PyWavelets-1.1.1 absl-py-0.8.1 alibi-0.3.2 astor-0.8.1 beautifulsoup4-4.8.1 blis-0.4.1 catalogue-0.0.8 cycler-0.10.0 cymem-2.0.3 decorator-4.4.1 dill-0.3.1.dev0 gast-0.2.2 google-pasta-0.1.8 h5py-2.10.0 imageio-2.6.1 importlib-metadata-1.3.0 keras-applications-1.0.8 keras-preprocessing-1.1.0 kiwisolver-1.1.0 markdown-3.1.1 matplotlib-3.1.2 more-itertools-8.0.2 murmurhash-1.0.2 networkx-2.4 opt-einsum-3.1.0 pandas-0.25.3 plac-1.1.3 preshed-3.0.2 pyparsing-2.4.5 scikit-image-0.16.2 scikit-learn-0.20.1 scipy-1.3.3 soupsieve-1.9.5 spacy-2.2.3 srsly-0.2.0 tensorboard-1.15.0 tensorflow-1.15.0 tensorflow-estimator-1.15.1 termcolor-1.1.0 thinc-7.3.1 tqdm-4.40.2 wasabi-0.4.2 wrapt-1.11.2 zipp-0.6.0
WARNING: Url '/whl' is ignored. It is either a non-existing path or lacks a specific scheme.
WARNING: You are using pip version 19.1.1, however version 19.3.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Build completed successfully

6) Deploy your image with a Seldon Graph Definition

[57]:
%%writefile pipeline/pipeline_steps/loanclassifier-explainer/loanclassifiermodel-explainer.yaml
apiVersion: machinelearning.seldon.io/v1alpha2
kind: SeldonDeployment
metadata:
  labels:
    app: seldon
  name: loanclassifier-explainer
spec:
  name: loanclassifier-explainer
  predictors:
  - componentSpecs:
    - spec:
        containers:
        - image: loanclassifier-explainer:0.1
          name: model-explainer
    graph:
      children: []
      name: model-explainer
      type: MODEL
      endpoint:
        type: REST
    name: loanclassifier-explainer
    replicas: 1
Overwriting pipeline/pipeline_steps/loanclassifier-explainer/loanclassifiermodel-explainer.yaml
[58]:
!kubectl apply -f pipeline/pipeline_steps/loanclassifier-explainer/loanclassifiermodel-explainer.yaml
seldondeployment.machinelearning.seldon.io/loanclassifier-explainer configured
[60]:
!kubectl get pods
NAME                                                              READY   STATUS    RESTARTS   AGE
ambassador-69b784f9d5-242jz                                       1/1     Running   0          9m7s
ambassador-69b784f9d5-b2655                                       1/1     Running   0          9m7s
ambassador-69b784f9d5-ckrt2                                       1/1     Running   0          9m7s
loanclassifier-explainer-loanclassifier-explainer-8444816-fvb8r   2/2     Running   0          33s
loanclassifier-loanclassifier-164157f-645c997d57-vqjv4            2/2     Running   0          9m3s

Now that it’s deployed we can query it

IMPORTANT: If you are using minikube (instead of docker desktop) you have to forward the port first with:

kubectl port-forward svc/ambassador 8003:80

First we can try Curl

[61]:
%%bash
curl -X POST -H 'Content-Type: application/json' \
    -d "{'data': {'names': ['text'], 'ndarray': [[52,  4,  0,  2,  8,  4,  2,  0,  0,  0, 60, 9]] }}" \
    http://localhost:8003/seldon/seldon/loanclassifier-explainer/api/v0.1/predictions
{
  "meta": {
    "puid": "v8jc8np25vg8e0olfg3k5nfee4",
    "tags": {
    },
    "routing": {
    },
    "requestPath": {
      "model-explainer": "loanclassifier-explainer:0.1"
    },
    "metrics": []
  },
  "strData": "{\"names\": [\"Marital Status \u003d Separated\", \"Sex \u003d Female\"], \"precision\": 0.96, \"coverage\": 0.1042, \"raw\": {\"feature\": [3, 7], \"mean\": [0.8784933171324423, 0.96], \"precision\": [0.8784933171324423, 0.96], \"coverage\": [0.1753, 0.1042], \"examples\": [{\"covered\": [[67, 0, 4, 2, 0, 0, 4, 1, 3818, 0, 11, 9], [31, 4, 0, 2, 5, 0, 4, 1, 0, 0, 45, 9], [28, 4, 4, 2, 6, 1, 4, 1, 0, 0, 50, 9], [39, 6, 3, 2, 7, 1, 4, 0, 0, 1721, 15, 9], [25, 4, 1, 2, 1, 1, 4, 1, 0, 0, 40, 9], [50, 0, 5, 2, 0, 0, 4, 1, 0, 0, 60, 9], [34, 7, 4, 2, 2, 1, 2, 1, 0, 0, 40, 9], [20, 4, 4, 2, 7, 3, 4, 0, 0, 0, 32, 9], [36, 4, 5, 2, 5, 0, 4, 1, 0, 1977, 50, 9], [51, 7, 2, 2, 8, 0, 4, 1, 7298, 0, 40, 9]], \"covered_true\": [[25, 4, 1, 2, 1, 1, 4, 1, 0, 0, 30, 9], [34, 4, 3, 2, 7, 1, 4, 0, 0, 0, 35, 9], [60, 4, 4, 2, 1, 0, 4, 1, 0, 0, 40, 9], [55, 6, 4, 2, 6, 1, 4, 1, 0, 0, 40, 9], [27, 4, 6, 2, 5, 1, 4, 1, 0, 0, 50, 9], [33, 6, 4, 2, 8, 0, 4, 1, 0, 0, 45, 9], [56, 4, 4, 2, 2, 0, 4, 1, 0, 0, 40, 9], [30, 4, 4, 2, 2, 1, 4, 1, 0, 0, 65, 9], [28, 4, 4, 2, 2, 0, 2, 1, 0, 0, 40, 9], [52, 4, 0, 2, 8, 0, 4, 1, 0, 0, 40, 9]], \"covered_false\": [[43, 7, 2, 2, 5, 4, 4, 0, 0, 0, 40, 9], [39, 4, 1, 2, 6, 0, 4, 1, 7298, 0, 55, 9], [39, 4, 4, 2, 1, 1, 4, 0, 13550, 0, 45, 9], [43, 4, 6, 2, 5, 0, 4, 1, 15024, 0, 55, 9], [45, 4, 1, 2, 5, 4, 4, 0, 0, 0, 48, 9], [22, 6, 4, 2, 5, 4, 4, 0, 99999, 0, 40, 5], [41, 4, 2, 2, 5, 0, 4, 1, 0, 0, 60, 9], [53, 4, 4, 2, 6, 0, 4, 1, 15024, 0, 60, 9], [42, 4, 5, 2, 8, 1, 4, 1, 0, 0, 40, 9], [55, 5, 4, 2, 6, 4, 4, 0, 0, 0, 50, 9]], \"uncovered_true\": [], \"uncovered_false\": []}, {\"covered\": [[20, 4, 4, 2, 7, 3, 4, 0, 0, 0, 32, 9], [35, 4, 4, 2, 4, 1, 4, 0, 1151, 0, 40, 9], [29, 4, 4, 2, 6, 3, 4, 0, 0, 0, 40, 9], [42, 2, 1, 2, 5, 5, 4, 0, 0, 0, 40, 9], [28, 0, 4, 2, 0, 3, 4, 0, 0, 0, 20, 0], [78, 4, 4, 2, 7, 1, 2, 0, 2964, 0, 40, 9], [39, 4, 1, 2, 8, 4, 2, 0, 0, 0, 60, 9], [35, 4, 1, 2, 5, 1, 1, 0, 0, 0, 40, 7], [59, 0, 3, 2, 0, 1, 4, 0, 0, 0, 40, 1], [24, 4, 1, 2, 5, 1, 4, 0, 0, 0, 40, 9]], \"covered_true\": [[22, 4, 4, 2, 1, 3, 4, 0, 0, 0, 40, 5], [18, 0, 4, 2, 0, 3, 4, 0, 0, 0, 40, 9], [44, 4, 5, 2, 5, 5, 4, 0, 0, 0, 45, 9], [48, 4, 4, 2, 1, 1, 4, 0, 2463, 0, 40, 9], [21, 4, 4, 2, 8, 1, 4, 0, 4101, 0, 40, 9], [59, 4, 4, 2, 1, 5, 4, 0, 0, 0, 40, 9], [59, 0, 3, 2, 0, 1, 4, 0, 0, 0, 40, 1], [77, 4, 4, 2, 7, 1, 4, 0, 0, 0, 20, 9], [56, 2, 1, 2, 8, 4, 4, 0, 0, 0, 40, 9], [20, 4, 4, 2, 7, 1, 4, 0, 0, 0, 20, 9]], \"covered_false\": [[43, 7, 2, 2, 5, 4, 4, 0, 0, 0, 40, 9], [43, 4, 5, 2, 8, 1, 4, 0, 0, 0, 50, 9], [31, 4, 1, 2, 5, 1, 2, 0, 14084, 0, 60, 9], [45, 5, 1, 2, 8, 5, 1, 0, 99999, 0, 25, 0], [39, 4, 4, 2, 1, 1, 4, 0, 13550, 0, 45, 9], [63, 6, 4, 2, 5, 5, 4, 0, 20051, 0, 10, 9], [45, 4, 1, 2, 5, 4, 4, 0, 0, 0, 48, 9], [31, 4, 5, 2, 5, 1, 4, 0, 14084, 0, 50, 9], [62, 4, 4, 2, 2, 1, 4, 0, 8614, 0, 39, 9], [22, 6, 4, 2, 5, 4, 4, 0, 99999, 0, 40, 5]], \"uncovered_true\": [], \"uncovered_false\": []}], \"all_precision\": 0, \"num_preds\": 1000101, \"names\": [\"Marital Status \u003d Separated\", \"Sex \u003d Female\"], \"instance\": [[52, 4, 0, 2, 8, 4, 2, 0, 0, 0, 60, 9]], \"prediction\": 0}, \"meta\": {\"name\": \"AnchorTabular\"}}"
}
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3513  100  3421  100    92   1983     53  0:00:01  0:00:01 --:--:--  2035

5) Test production predictions and explanations

We create a seldon client to send requests to the deployed model as well as the explainer. Here is the diagram of the deployed models:

image0

[62]:
sc = SeldonClient(
    gateway="ambassador",
    gateway_endpoint="localhost:8003",
    payload_type="ndarray",
    namespace="seldon",
    transport="rest")

Let’s have a look at the datapoint we’ll use for this prediction

[63]:
to_explain = X_test[:1]
print(to_explain)
[[52  4  0  2  8  4  2  0  0  0 60  9]]

We get the prediction from the model in production

[64]:
resp = sc.predict(data=to_explain, deployment_name="loanclassifier").response
pred = get_data_from_proto(resp)
print('Predicted Label: %s' % ("POSITIVE" if pred[0][0] < 0.5 else "NEGATIVE"))
print('Predicted Probabilities: %s' % pred[0])
Predicted Label: NEGATIVE
Predicted Probabilities: [0.86 0.14]

By checking our test label, we can see it is indeed correct

[65]:
print('Actual Label: %s' % ("POSITIVE" if y_test[0] == 1 else "NEGATIVE"))
Actual Label: NEGATIVE

Now we can use our deployed explainer to explain our prediction

[66]:
import json
explanation = sc.predict(data=to_explain, deployment_name="loanclassifier-explainer")
exp = json.loads(explanation.response.strData)

print('Anchor: %s' % (' AND '.join(exp['names'])))
Anchor: Marital Status = Separated AND Sex = Female