We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Alibi explainer example times out
/kind bug

**What steps did you take and what happened:**

I am rolling out the Alibi Explainer example (as explained here https://github.com/kubeflow/kfserving/tree/v0.6.0/docs/samples/explanation/alibi/imagenet), although I have had to slightly adapt the InferenceService spec (see https://github.com/kubeflow/kfserving/issues/1707) as follows:

```
apiVersion: "serving.kubeflow.org/v1beta1"
kind: "InferenceService"
metadata:
  name: imagenet
  namespace: karl-schriek
spec:
  predictor:
    tensorflow:
      storageUri: "gs://seldon-models/tfserving/imagenet/model"
      resources:
        requests:
          cpu: 0.1
          memory: 5Gi                        
        limits:
          memory: 10Gi
  explainer:
    alibi:
      type: AnchorImages
      storageUri: "gs://seldon-models/tfserving/imagenet/explainer"
      config:
        batch_size: "1" # reduced from 25 in attempt to prevent timeout
        stop_on_first: "True"
        min_samples_start: "1"  # added in attempt to prevent timeout
      resources:
        requests:
          cpu: 0.5
          memory: 5Gi            
        limits:
          memory: 10Gi    
```

Predictor and explainer both roll out successfully. Requesting predictions work fine. Requesting an explaination on a single image results in an eventual timeout. The explainer Pod reports the following:

```
[I 210709 11:10:54 anchor_images:47] Calling explain on image of shape ((1, 299, 299, 3),)
[I 210709 11:10:54 anchor_images:48] anchor image call with {'batch_size': 1, 'stop_on_first': True}
```

After about 20  minutes it eventually also says the following:

```
skimage.measure.label's indexing starts from 0. In future version it will start from 1. To disable this warning, explicitely set the `start_label` parameter to 1.
[E 210709 11:30:11 web:1793] Uncaught exception POST /v1/models/imagenet:explain (127.0.0.1)
    HTTPServerRequest(protocol='http', host='imagenet-explainer-default.karl-schriek.svc.cluster.local', method='POST', uri='/v1/models/imagenet:explain', version='HTTP/1.1', remote_ip='127.0.0.1')
    Traceback (most recent call last):
      File "/usr/local/lib/python3.7/site-packages/tornado/web.py", line 1704, in _execute
        result = await result
      File "/kfserving/kfserving/handlers/http.py", line 105, in post
        response = await model(body, model_type=ModelType.EXPLAINER)
      File "/kfserving/kfserving/kfmodel.py", line 58, in __call__
        else self.explain(request)
      File "/alibiexplainer/alibiexplainer/explainer.py", line 84, in explain
        explanation = self.wrapper.explain(request["instances"])
      File "/alibiexplainer/alibiexplainer/anchor_images.py", line 49, in explain
        anchor_exp = self.anchors_image.explain(arr[0], **self.kwargs)
      File "/usr/local/lib/python3.7/site-packages/alibi/explainers/anchor_image.py", line 409, in explain
        return self.build_explanation(image, result, self.instance_label, params)
      File "/usr/local/lib/python3.7/site-packages/alibi/explainers/anchor_image.py", line 447, in build_explanation
        explanation = Explanation(meta=copy.deepcopy(self.meta), data=data)
    AttributeError: 'AnchorImage' object has no attribute 'meta'
[E 210709 11:30:11 web:2243] 500 POST /v1/models/imagenet:explain (127.0.0.1) 1157265.30ms
```

The documentation states that the explanation may take a while, but surely it shouldn't time out with just a single image? This looks like a timeout, but I am not really sure if the `AttributeError: 'AnchorImage' object has no attribute 'meta'` suggests otherwise.

**What did you expect to happen:**

I would expect the request to succeed within a reasonable space of time.


- Istio Version: 1.10.2
- Knative Version: 0.24
- KFServing Version: 0.6.0
- Kubeflow version: 1.3+
- Kubernetes version: 1.20


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `python/alibiexplainer/setup.py`
Content:
```
1 # Copyright 2019 kubeflow.org.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 from setuptools import setup, find_packages
16 
17 tests_require = [
18     'pytest',
19     'pytest-tornasync',
20     'mypy'
21 ]
22 
23 setup(
24     name='alibiexplainer',
25     version='0.6.0',
26     author_email='cc@seldon.io',
27     license='../../LICENSE.txt',
28     url='https://github.com/kubeflow/kfserving/python/kfserving/alibiexplainer',
29     description='Model Explaination Server. \
30                  Not intended for use outside KFServing Frameworks Images',
31     long_description=open('README.md').read(),
32     python_requires='>=3.6',
33     packages=find_packages("alibiexplainer"),
34     install_requires=[
35         "tensorflow==2.3.2",
36         "kfserving>=0.6.0",
37         "pandas>=0.24.2",
38         "nest_asyncio>=1.4.0",
39         "alibi==0.5.5",
40         "scikit-learn == 0.20.3",
41         "argparse>=1.4.0",
42         "requests>=2.22.0",
43         "joblib>=0.13.2",
44         "dill>=0.3.0",
45         "grpcio>=1.22.0",
46         "xgboost==1.0.2",
47         "shap==0.36.0",
48         "numpy<1.19.0"
49     ],
50     tests_require=tests_require,
51     extras_require={'test': tests_require}
52 )
53
```

Path: `docs/samples/explanation/alibi/imagenet/train_explainer.py`
Content:
```
1 from tensorflow.keras.applications.inception_v3 import InceptionV3
2 from alibi.explainers import AnchorImage
3 import dill
4 
5 model = InceptionV3(weights='imagenet')
6 
7 segmentation_fn = 'slic'
8 kwargs = {'n_segments': 15, 'compactness': 20, 'sigma': .5}
9 image_shape = (299, 299, 3)
10 explainer = AnchorImage(lambda x: model.predict(x), image_shape, segmentation_fn=segmentation_fn,
11                         segmentation_kwargs=kwargs,
12                         images_background=None)
13 
14 
15 explainer.predict_fn = None  # Clear explainer predict_fn as its a lambda and will be reset when loaded
16 with open("explainer.dill", 'wb') as f:
17     dill.dump(explainer, f)
18
```

Path: `python/alibiexplainer/alibiexplainer/anchor_text.py`
Content:
```
1 # Copyright 2019 kubeflow.org.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 import kfserving
15 import logging
16 import numpy as np
17 import spacy
18 import alibi
19 from alibi.api.interfaces import Explanation
20 from alibi.utils.download import spacy_model
21 from alibi.utils.wrappers import ArgmaxTransformer
22 from alibiexplainer.explainer_wrapper import ExplainerWrapper
23 from typing import Callable, List, Optional
24 
25 logging.basicConfig(level=kfserving.constants.KFSERVING_LOGLEVEL)
26 
27 
28 class AnchorText(ExplainerWrapper):
29     def __init__(
30         self,
31         predict_fn: Callable,
32         explainer: Optional[alibi.explainers.AnchorText],
33         spacy_language_model: str = "en_core_web_md",
34         **kwargs
35     ):
36         self.predict_fn = predict_fn
37         self.kwargs = kwargs
38         logging.info("Anchor Text args %s", self.kwargs)
39         if explainer is None:
40             logging.info("Loading Spacy Language model for %s", spacy_language_model)
41             spacy_model(model=spacy_language_model)
42             self.nlp = spacy.load(spacy_language_model)
43             logging.info("Language model loaded")
44         self.anchors_text = explainer
45 
46     def explain(self, inputs: List) -> Explanation:
47         if self.anchors_text is None:
48             self.anchors_text = alibi.explainers.AnchorText(self.nlp, self.predict_fn)
49 
50         # We assume the input has batch dimension but Alibi explainers presently assume no batch
51         input_words = inputs[0]
52 
53         # check if predictor returns predicted class or prediction probabilities for each class
54         # if needed adjust predictor so it returns the predicted class
55         if np.argmax(self.predict_fn([input_words]).shape) == 0:
56             self.anchors_text.predictor = self.predict_fn
57         else:
58             self.anchors_text.predictor = ArgmaxTransformer(self.predict_fn)
59 
60         anchor_exp = self.anchors_text.explain(input_words, **self.kwargs)
61         return anchor_exp
62
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/docs/samples/explanation/alibi/imagenet/train_explainer.py b/docs/samples/explanation/alibi/imagenet/train_explainer.py
deleted file mode 100644
--- a/docs/samples/explanation/alibi/imagenet/train_explainer.py
+++ /dev/null
@@ -1,17 +0,0 @@
-from tensorflow.keras.applications.inception_v3 import InceptionV3
-from alibi.explainers import AnchorImage
-import dill
-
-model = InceptionV3(weights='imagenet')
-
-segmentation_fn = 'slic'
-kwargs = {'n_segments': 15, 'compactness': 20, 'sigma': .5}
-image_shape = (299, 299, 3)
-explainer = AnchorImage(lambda x: model.predict(x), image_shape, segmentation_fn=segmentation_fn,
-                        segmentation_kwargs=kwargs,
-                        images_background=None)
-
-
-explainer.predict_fn = None  # Clear explainer predict_fn as its a lambda and will be reset when loaded
-with open("explainer.dill", 'wb') as f:
-    dill.dump(explainer, f)
diff --git a/python/alibiexplainer/alibiexplainer/anchor_text.py b/python/alibiexplainer/alibiexplainer/anchor_text.py
--- a/python/alibiexplainer/alibiexplainer/anchor_text.py
+++ b/python/alibiexplainer/alibiexplainer/anchor_text.py
@@ -45,7 +45,9 @@
 
     def explain(self, inputs: List) -> Explanation:
         if self.anchors_text is None:
-            self.anchors_text = alibi.explainers.AnchorText(self.nlp, self.predict_fn)
+            self.anchors_text = alibi.explainers.AnchorText(predictor=self.predict_fn,
+                                                            sampling_strategy='unknown',
+                                                            nlp=self.nlp)
 
         # We assume the input has batch dimension but Alibi explainers presently assume no batch
         input_words = inputs[0]
diff --git a/python/alibiexplainer/setup.py b/python/alibiexplainer/setup.py
--- a/python/alibiexplainer/setup.py
+++ b/python/alibiexplainer/setup.py
@@ -36,7 +36,7 @@
         "kfserving>=0.6.0",
         "pandas>=0.24.2",
         "nest_asyncio>=1.4.0",
-        "alibi==0.5.5",
+        "alibi==0.6.0",
         "scikit-learn == 0.20.3",
         "argparse>=1.4.0",
         "requests>=2.22.0",
@@ -44,8 +44,9 @@
         "dill>=0.3.0",
         "grpcio>=1.22.0",
         "xgboost==1.0.2",
-        "shap==0.36.0",
-        "numpy<1.19.0"
+        "shap==0.39.0",
+        "numpy<1.19.0",
+        'spacy[lookups]>=2.0.0, <4.0.0'
     ],
     tests_require=tests_require,
     extras_require={'test': tests_require}

{"golden_diff": "diff --git a/docs/samples/explanation/alibi/imagenet/train_explainer.py b/docs/samples/explanation/alibi/imagenet/train_explainer.py\ndeleted file mode 100644\n--- a/docs/samples/explanation/alibi/imagenet/train_explainer.py\n+++ /dev/null\n@@ -1,17 +0,0 @@\n-from tensorflow.keras.applications.inception_v3 import InceptionV3\n-from alibi.explainers import AnchorImage\n-import dill\n-\n-model = InceptionV3(weights='imagenet')\n-\n-segmentation_fn = 'slic'\n-kwargs = {'n_segments': 15, 'compactness': 20, 'sigma': .5}\n-image_shape = (299, 299, 3)\n-explainer = AnchorImage(lambda x: model.predict(x), image_shape, segmentation_fn=segmentation_fn,\n-                        segmentation_kwargs=kwargs,\n-                        images_background=None)\n-\n-\n-explainer.predict_fn = None  # Clear explainer predict_fn as its a lambda and will be reset when loaded\n-with open(\"explainer.dill\", 'wb') as f:\n-    dill.dump(explainer, f)\ndiff --git a/python/alibiexplainer/alibiexplainer/anchor_text.py b/python/alibiexplainer/alibiexplainer/anchor_text.py\n--- a/python/alibiexplainer/alibiexplainer/anchor_text.py\n+++ b/python/alibiexplainer/alibiexplainer/anchor_text.py\n@@ -45,7 +45,9 @@\n \n     def explain(self, inputs: List) -> Explanation:\n         if self.anchors_text is None:\n-            self.anchors_text = alibi.explainers.AnchorText(self.nlp, self.predict_fn)\n+            self.anchors_text = alibi.explainers.AnchorText(predictor=self.predict_fn,\n+                                                            sampling_strategy='unknown',\n+                                                            nlp=self.nlp)\n \n         # We assume the input has batch dimension but Alibi explainers presently assume no batch\n         input_words = inputs[0]\ndiff --git a/python/alibiexplainer/setup.py b/python/alibiexplainer/setup.py\n--- a/python/alibiexplainer/setup.py\n+++ b/python/alibiexplainer/setup.py\n@@ -36,7 +36,7 @@\n         \"kfserving>=0.6.0\",\n         \"pandas>=0.24.2\",\n         \"nest_asyncio>=1.4.0\",\n-        \"alibi==0.5.5\",\n+        \"alibi==0.6.0\",\n         \"scikit-learn == 0.20.3\",\n         \"argparse>=1.4.0\",\n         \"requests>=2.22.0\",\n@@ -44,8 +44,9 @@\n         \"dill>=0.3.0\",\n         \"grpcio>=1.22.0\",\n         \"xgboost==1.0.2\",\n-        \"shap==0.36.0\",\n-        \"numpy<1.19.0\"\n+        \"shap==0.39.0\",\n+        \"numpy<1.19.0\",\n+        'spacy[lookups]>=2.0.0, <4.0.0'\n     ],\n     tests_require=tests_require,\n     extras_require={'test': tests_require}\n", "issue": "Alibi explainer example times out\n/kind bug\r\n\r\n**What steps did you take and what happened:**\r\n\r\nI am rolling out the Alibi Explainer example (as explained here https://github.com/kubeflow/kfserving/tree/v0.6.0/docs/samples/explanation/alibi/imagenet), although I have had to slightly adapt the InferenceService spec (see https://github.com/kubeflow/kfserving/issues/1707) as follows:\r\n\r\n```\r\napiVersion: \"serving.kubeflow.org/v1beta1\"\r\nkind: \"InferenceService\"\r\nmetadata:\r\n  name: imagenet\r\n  namespace: karl-schriek\r\nspec:\r\n  predictor:\r\n    tensorflow:\r\n      storageUri: \"gs://seldon-models/tfserving/imagenet/model\"\r\n      resources:\r\n        requests:\r\n          cpu: 0.1\r\n          memory: 5Gi                        \r\n        limits:\r\n          memory: 10Gi\r\n  explainer:\r\n    alibi:\r\n      type: AnchorImages\r\n      storageUri: \"gs://seldon-models/tfserving/imagenet/explainer\"\r\n      config:\r\n        batch_size: \"1\" # reduced from 25 in attempt to prevent timeout\r\n        stop_on_first: \"True\"\r\n        min_samples_start: \"1\"  # added in attempt to prevent timeout\r\n      resources:\r\n        requests:\r\n          cpu: 0.5\r\n          memory: 5Gi            \r\n        limits:\r\n          memory: 10Gi    \r\n```\r\n\r\nPredictor and explainer both roll out successfully. Requesting predictions work fine. Requesting an explaination on a single image results in an eventual timeout. The explainer Pod reports the following:\r\n\r\n```\r\n[I 210709 11:10:54 anchor_images:47] Calling explain on image of shape ((1, 299, 299, 3),)\r\n[I 210709 11:10:54 anchor_images:48] anchor image call with {'batch_size': 1, 'stop_on_first': True}\r\n```\r\n\r\nAfter about 20  minutes it eventually also says the following:\r\n\r\n```\r\nskimage.measure.label's indexing starts from 0. In future version it will start from 1. To disable this warning, explicitely set the `start_label` parameter to 1.\r\n[E 210709 11:30:11 web:1793] Uncaught exception POST /v1/models/imagenet:explain (127.0.0.1)\r\n    HTTPServerRequest(protocol='http', host='imagenet-explainer-default.karl-schriek.svc.cluster.local', method='POST', uri='/v1/models/imagenet:explain', version='HTTP/1.1', remote_ip='127.0.0.1')\r\n    Traceback (most recent call last):\r\n      File \"/usr/local/lib/python3.7/site-packages/tornado/web.py\", line 1704, in _execute\r\n        result = await result\r\n      File \"/kfserving/kfserving/handlers/http.py\", line 105, in post\r\n        response = await model(body, model_type=ModelType.EXPLAINER)\r\n      File \"/kfserving/kfserving/kfmodel.py\", line 58, in __call__\r\n        else self.explain(request)\r\n      File \"/alibiexplainer/alibiexplainer/explainer.py\", line 84, in explain\r\n        explanation = self.wrapper.explain(request[\"instances\"])\r\n      File \"/alibiexplainer/alibiexplainer/anchor_images.py\", line 49, in explain\r\n        anchor_exp = self.anchors_image.explain(arr[0], **self.kwargs)\r\n      File \"/usr/local/lib/python3.7/site-packages/alibi/explainers/anchor_image.py\", line 409, in explain\r\n        return self.build_explanation(image, result, self.instance_label, params)\r\n      File \"/usr/local/lib/python3.7/site-packages/alibi/explainers/anchor_image.py\", line 447, in build_explanation\r\n        explanation = Explanation(meta=copy.deepcopy(self.meta), data=data)\r\n    AttributeError: 'AnchorImage' object has no attribute 'meta'\r\n[E 210709 11:30:11 web:2243] 500 POST /v1/models/imagenet:explain (127.0.0.1) 1157265.30ms\r\n```\r\n\r\nThe documentation states that the explanation may take a while, but surely it shouldn't time out with just a single image? This looks like a timeout, but I am not really sure if the `AttributeError: 'AnchorImage' object has no attribute 'meta'` suggests otherwise.\r\n\r\n**What did you expect to happen:**\r\n\r\nI would expect the request to succeed within a reasonable space of time.\r\n\r\n\r\n- Istio Version: 1.10.2\r\n- Knative Version: 0.24\r\n- KFServing Version: 0.6.0\r\n- Kubeflow version: 1.3+\r\n- Kubernetes version: 1.20\r\n\n", "before_files": [{"content": "# Copyright 2019 kubeflow.org.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom setuptools import setup, find_packages\n\ntests_require = [\n    'pytest',\n    'pytest-tornasync',\n    'mypy'\n]\n\nsetup(\n    name='alibiexplainer',\n    version='0.6.0',\n    author_email='cc@seldon.io',\n    license='../../LICENSE.txt',\n    url='https://github.com/kubeflow/kfserving/python/kfserving/alibiexplainer',\n    description='Model Explaination Server. \\\n                 Not intended for use outside KFServing Frameworks Images',\n    long_description=open('README.md').read(),\n    python_requires='>=3.6',\n    packages=find_packages(\"alibiexplainer\"),\n    install_requires=[\n        \"tensorflow==2.3.2\",\n        \"kfserving>=0.6.0\",\n        \"pandas>=0.24.2\",\n        \"nest_asyncio>=1.4.0\",\n        \"alibi==0.5.5\",\n        \"scikit-learn == 0.20.3\",\n        \"argparse>=1.4.0\",\n        \"requests>=2.22.0\",\n        \"joblib>=0.13.2\",\n        \"dill>=0.3.0\",\n        \"grpcio>=1.22.0\",\n        \"xgboost==1.0.2\",\n        \"shap==0.36.0\",\n        \"numpy<1.19.0\"\n    ],\n    tests_require=tests_require,\n    extras_require={'test': tests_require}\n)\n", "path": "python/alibiexplainer/setup.py"}, {"content": "from tensorflow.keras.applications.inception_v3 import InceptionV3\nfrom alibi.explainers import AnchorImage\nimport dill\n\nmodel = InceptionV3(weights='imagenet')\n\nsegmentation_fn = 'slic'\nkwargs = {'n_segments': 15, 'compactness': 20, 'sigma': .5}\nimage_shape = (299, 299, 3)\nexplainer = AnchorImage(lambda x: model.predict(x), image_shape, segmentation_fn=segmentation_fn,\n                        segmentation_kwargs=kwargs,\n                        images_background=None)\n\n\nexplainer.predict_fn = None  # Clear explainer predict_fn as its a lambda and will be reset when loaded\nwith open(\"explainer.dill\", 'wb') as f:\n    dill.dump(explainer, f)\n", "path": "docs/samples/explanation/alibi/imagenet/train_explainer.py"}, {"content": "# Copyright 2019 kubeflow.org.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport kfserving\nimport logging\nimport numpy as np\nimport spacy\nimport alibi\nfrom alibi.api.interfaces import Explanation\nfrom alibi.utils.download import spacy_model\nfrom alibi.utils.wrappers import ArgmaxTransformer\nfrom alibiexplainer.explainer_wrapper import ExplainerWrapper\nfrom typing import Callable, List, Optional\n\nlogging.basicConfig(level=kfserving.constants.KFSERVING_LOGLEVEL)\n\n\nclass AnchorText(ExplainerWrapper):\n    def __init__(\n        self,\n        predict_fn: Callable,\n        explainer: Optional[alibi.explainers.AnchorText],\n        spacy_language_model: str = \"en_core_web_md\",\n        **kwargs\n    ):\n        self.predict_fn = predict_fn\n        self.kwargs = kwargs\n        logging.info(\"Anchor Text args %s\", self.kwargs)\n        if explainer is None:\n            logging.info(\"Loading Spacy Language model for %s\", spacy_language_model)\n            spacy_model(model=spacy_language_model)\n            self.nlp = spacy.load(spacy_language_model)\n            logging.info(\"Language model loaded\")\n        self.anchors_text = explainer\n\n    def explain(self, inputs: List) -> Explanation:\n        if self.anchors_text is None:\n            self.anchors_text = alibi.explainers.AnchorText(self.nlp, self.predict_fn)\n\n        # We assume the input has batch dimension but Alibi explainers presently assume no batch\n        input_words = inputs[0]\n\n        # check if predictor returns predicted class or prediction probabilities for each class\n        # if needed adjust predictor so it returns the predicted class\n        if np.argmax(self.predict_fn([input_words]).shape) == 0:\n            self.anchors_text.predictor = self.predict_fn\n        else:\n            self.anchors_text.predictor = ArgmaxTransformer(self.predict_fn)\n\n        anchor_exp = self.anchors_text.explain(input_words, **self.kwargs)\n        return anchor_exp\n", "path": "python/alibiexplainer/alibiexplainer/anchor_text.py"}], "after_files": [{"content": "# Copyright 2019 kubeflow.org.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom setuptools import setup, find_packages\n\ntests_require = [\n    'pytest',\n    'pytest-tornasync',\n    'mypy'\n]\n\nsetup(\n    name='alibiexplainer',\n    version='0.6.0',\n    author_email='cc@seldon.io',\n    license='../../LICENSE.txt',\n    url='https://github.com/kubeflow/kfserving/python/kfserving/alibiexplainer',\n    description='Model Explaination Server. \\\n                 Not intended for use outside KFServing Frameworks Images',\n    long_description=open('README.md').read(),\n    python_requires='>=3.6',\n    packages=find_packages(\"alibiexplainer\"),\n    install_requires=[\n        \"tensorflow==2.3.2\",\n        \"kfserving>=0.6.0\",\n        \"pandas>=0.24.2\",\n        \"nest_asyncio>=1.4.0\",\n        \"alibi==0.6.0\",\n        \"scikit-learn == 0.20.3\",\n        \"argparse>=1.4.0\",\n        \"requests>=2.22.0\",\n        \"joblib>=0.13.2\",\n        \"dill>=0.3.0\",\n        \"grpcio>=1.22.0\",\n        \"xgboost==1.0.2\",\n        \"shap==0.39.0\",\n        \"numpy<1.19.0\",\n        'spacy[lookups]>=2.0.0, <4.0.0'\n    ],\n    tests_require=tests_require,\n    extras_require={'test': tests_require}\n)\n", "path": "python/alibiexplainer/setup.py"}, {"content": null, "path": "docs/samples/explanation/alibi/imagenet/train_explainer.py"}, {"content": "# Copyright 2019 kubeflow.org.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\nimport kfserving\nimport logging\nimport numpy as np\nimport spacy\nimport alibi\nfrom alibi.api.interfaces import Explanation\nfrom alibi.utils.download import spacy_model\nfrom alibi.utils.wrappers import ArgmaxTransformer\nfrom alibiexplainer.explainer_wrapper import ExplainerWrapper\nfrom typing import Callable, List, Optional\n\nlogging.basicConfig(level=kfserving.constants.KFSERVING_LOGLEVEL)\n\n\nclass AnchorText(ExplainerWrapper):\n    def __init__(\n        self,\n        predict_fn: Callable,\n        explainer: Optional[alibi.explainers.AnchorText],\n        spacy_language_model: str = \"en_core_web_md\",\n        **kwargs\n    ):\n        self.predict_fn = predict_fn\n        self.kwargs = kwargs\n        logging.info(\"Anchor Text args %s\", self.kwargs)\n        if explainer is None:\n            logging.info(\"Loading Spacy Language model for %s\", spacy_language_model)\n            spacy_model(model=spacy_language_model)\n            self.nlp = spacy.load(spacy_language_model)\n            logging.info(\"Language model loaded\")\n        self.anchors_text = explainer\n\n    def explain(self, inputs: List) -> Explanation:\n        if self.anchors_text is None:\n            self.anchors_text = alibi.explainers.AnchorText(predictor=self.predict_fn,\n                                                            sampling_strategy='unknown',\n                                                            nlp=self.nlp)\n\n        # We assume the input has batch dimension but Alibi explainers presently assume no batch\n        input_words = inputs[0]\n\n        # check if predictor returns predicted class or prediction probabilities for each class\n        # if needed adjust predictor so it returns the predicted class\n        if np.argmax(self.predict_fn([input_words]).shape) == 0:\n            self.anchors_text.predictor = self.predict_fn\n        else:\n            self.anchors_text.predictor = ArgmaxTransformer(self.predict_fn)\n\n        anchor_exp = self.anchors_text.explain(input_words, **self.kwargs)\n        return anchor_exp\n", "path": "python/alibiexplainer/alibiexplainer/anchor_text.py"}]}