Repository: gradio-app/gradio

Issue:
Interpretation doesn't work in Tensorflow 1.x 
For TF 1.x models, interpretation doesn't set up the correct session


Discussion:

Resolving patch:
diff --git a/gradio/interface.py b/gradio/interface.py
--- a/gradio/interface.py
+++ b/gradio/interface.py
@@ -3,8 +3,6 @@
 interface using the input and output types.
 """
 
-import tempfile
-import webbrowser
 from gradio.inputs import InputComponent
 from gradio.outputs import OutputComponent
 from gradio import networking, strings, utils
@@ -12,8 +10,8 @@
 import requests
 import random
 import time
+import webbrowser
 import inspect
-from IPython import get_ipython
 import sys
 import weakref
 import analytics
@@ -209,21 +207,14 @@ def run_prediction(self, processed_input, return_duration=False):
             start = time.time()
             if self.capture_session and self.session is not None:
                 graph, sess = self.session
-                with graph.as_default():
-                    with sess.as_default():
-                        prediction = predict_fn(*processed_input)
+                with graph.as_default(), sess.as_default():
+                    prediction = predict_fn(*processed_input)
             else:
                 try:
                     prediction = predict_fn(*processed_input)
                 except ValueError as exception:
-                    if str(exception).endswith("is not an element of this "
-                                               "graph."):
-                        raise ValueError("It looks like you might be using "
-                                         "tensorflow < 2.0. Please "
-                                         "pass capture_session=True in "
-                                         "Interface to avoid the 'Tensor is "
-                                         "not an element of this graph.' "
-                                         "error.")
+                    if str(exception).endswith("is not an element of this graph."):
+                        raise ValueError(strings.en["TF1_ERROR"])
                     else:
                         raise exception
             duration = time.time() - start
@@ -238,17 +229,11 @@ def run_prediction(self, processed_input, return_duration=False):
         else:
             return predictions
 
-
-    def process(self, raw_input, predict_fn=None):
+    def process(self, raw_input):
         """
-        :param raw_input: a list of raw inputs to process and apply the
-        prediction(s) on.
-        :param predict_fn: which function to process. If not provided, all of the model functions are used.
-        :return:
-        processed output: a list of processed  outputs to return as the
-        prediction(s).
-        duration: a list of time deltas measuring inference time for each
-        prediction fn.
+        :param raw_input: a list of raw inputs to process and apply the prediction(s) on.
+        processed output: a list of processed  outputs to return as the prediction(s).
+        duration: a list of time deltas measuring inference time for each prediction fn.
         """
         processed_input = [input_interface.preprocess(raw_input[i])
                            for i, input_interface in enumerate(self.input_interfaces)]
@@ -258,6 +243,11 @@ def process(self, raw_input, predict_fn=None):
         return processed_output, durations
     
     def interpret(self, raw_input):
+        """
+        Runs the interpretation command for the machine learning model. Handles both the "default" out-of-the-box
+        interpretation for a certain set of UI component types, as well as the custom interpretation case.
+        :param raw_input: a list of raw inputs to apply the interpretation(s) on.
+        """
         if self.interpretation == "default":
             interpreter = gradio.interpretation.default()
             processed_input = []
@@ -270,9 +260,22 @@ def interpret(self, raw_input):
             interpretation = interpreter(self, processed_input)
         else:
             processed_input = [input_interface.preprocess(raw_input[i])
-                                for i, input_interface in enumerate(self.input_interfaces)]
+                               for i, input_interface in enumerate(self.input_interfaces)]
             interpreter = self.interpretation
-            interpretation = interpreter(*processed_input)
+
+            if self.capture_session and self.session is not None:
+                graph, sess = self.session
+                with graph.as_default(), sess.as_default():
+                    interpretation = interpreter(*processed_input)
+            else:
+                try:
+                    interpretation = interpreter(*processed_input)
+                except ValueError as exception:
+                    if str(exception).endswith("is not an element of this graph."):
+                        raise ValueError(strings.en["TF1_ERROR"])
+                    else:
+                        raise exception
+
             if len(raw_input) == 1:
                 interpretation = [interpretation]
         return interpretation
@@ -422,9 +425,9 @@ def launch(self, inline=None, inbrowser=None, share=False, debug=False):
         if not is_in_interactive_mode:
             self.run_until_interrupted(thread, path_to_local_server)
 
-
         return app, path_to_local_server, share_url
 
+
 def reset_all():
     for io in Interface.get_instances():
         io.close()
diff --git a/gradio/interpretation.py b/gradio/interpretation.py
--- a/gradio/interpretation.py
+++ b/gradio/interpretation.py
@@ -1,6 +1,5 @@
 from gradio.inputs import Image, Textbox
 from gradio.outputs import Label
-from gradio import processing_utils
 from skimage.segmentation import slic
 import numpy as np
 
@@ -8,6 +7,7 @@
     Image: "numpy",
 }
 
+
 def default(separator=" ", n_segments=20):
     """
     Basic "default" interpretation method that uses "leave-one-out" to explain predictions for
diff --git a/gradio/strings.py b/gradio/strings.py
--- a/gradio/strings.py
+++ b/gradio/strings.py
@@ -7,4 +7,6 @@
     "PUBLIC_SHARE_TRUE": "To create a public link, set `share=True` in the argument to `launch()`.",
     "MODEL_PUBLICLY_AVAILABLE_URL": "Model available publicly at: {} (may take up to a minute for link to be usable)",
     "GENERATING_PUBLIC_LINK": "Generating public link (may take a few seconds...):",
+    "TF1_ERROR": "It looks like you might be using tensorflow < 2.0. Please pass capture_session=True in Interface() to"
+                 " avoid the 'Tensor is not an element of this graph.' error."
 }


Test patch:
diff --git a/test/test_interpretation.py b/test/test_interpretation.py
new file mode 100644
--- /dev/null
+++ b/test/test_interpretation.py
@@ -0,0 +1,47 @@
+import unittest
+import gradio.interpretation
+import gradio.test_data
+from gradio.processing_utils import decode_base64_to_image
+from gradio import Interface
+import numpy as np
+
+
+class TestDefault(unittest.TestCase):
+    def setUp(self):
+        self.default_method = gradio.interpretation.default()
+
+    def test_default_text(self):
+        max_word_len = lambda text: max([len(word) for word in text.split(" ")])
+        text_interface = Interface(max_word_len, "textbox", "label")
+        interpretation = self.default_method(text_interface, ["quickest brown fox"])[0]		
+        self.assertGreater(interpretation[0][1], 0)  # Checks to see if the first letter has >0 score.
+        self.assertEqual(interpretation[-1][1], 0)  # Checks to see if the last letter has 0 score.
+
+    def test_default_image(self):
+        max_pixel_value = lambda img: img.max()
+        img_interface = Interface(max_pixel_value, "image", "label")
+        array = np.zeros((100,100))
+        array[0, 0] = 1
+        interpretation = self.default_method(img_interface, [array])[0]
+        self.assertGreater(interpretation[0][0], 0)  # Checks to see if the top-left has >0 score.
+        
+
+class TestCustom(unittest.TestCase):
+    def test_custom_text(self):
+        max_word_len = lambda text: max([len(word) for word in text.split(" ")])
+        custom = lambda text: [(char, 1) for char in text]
+        text_interface = Interface(max_word_len, "textbox", "label", interpretation=custom)
+        result = text_interface.interpret(["quickest brown fox"])[0]
+        self.assertEqual(result[0][1], 1)  # Checks to see if the first letter has score of 1.
+
+    def test_custom_img(self):
+        max_pixel_value = lambda img: img.max()
+        custom = lambda img: img.tolist()
+        img_interface = Interface(max_pixel_value, "image", "label", interpretation=custom)
+        result = img_interface.interpret([gradio.test_data.BASE64_IMAGE])[0]
+        expected_result = np.asarray(decode_base64_to_image(gradio.test_data.BASE64_IMAGE).convert('RGB')).tolist()
+        self.assertEqual(result, expected_result)
+        
+
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file