There’s more to cover on the Interface class. This guide covers all the advanced features: Using Interpretation, custom styling, loading from the Hugging Face Hub, and using Parallel and Series.
Most models are black boxes such that the internal logic of the function is hidden from the end user. To encourage transparency, we’ve made it very easy to add interpretation to your model by simply setting the interpretation
keyword in the Interface
class to default
. This allows your users to understand what parts of the input are responsible for the output. Take a look at the simple interface below which shows an image classifier that also includes interpretation:
import requests
import tensorflow as tf
import gradio as gr
inception_net = tf.keras.applications.MobileNetV2() # load the model
# Download human-readable labels for ImageNet.
response = requests.get("https://git.io/JJkYN")
labels = response.text.split("\n")
def classify_image(inp):
inp = inp.reshape((-1, 224, 224, 3))
inp = tf.keras.applications.mobilenet_v2.preprocess_input(inp)
prediction = inception_net.predict(inp).flatten()
return {labels[i]: float(prediction[i]) for i in range(1000)}
image = gr.Image(shape=(224, 224))
label = gr.Label(num_top_classes=3)
demo = gr.Interface(
fn=classify_image, inputs=image, outputs=label, interpretation="default"
)
demo.launch()
In addition to default
, Gradio also includes Shapley-based interpretation, which provides more accurate interpretations, albeit usually with a slower runtime. To use this, simply set the interpretation
parameter to "shap"
(note: also make sure the python package shap
is installed). Optionally, you can modify the num_shap
parameter, which controls the tradeoff between accuracy and runtime (increasing this value generally increases accuracy). Here is an example:
gr.Interface(fn=classify_image,
inputs=image,
outputs=label,
interpretation="shap",
num_shap=5).launch()
This will work for any function, even if internally, the model is a complex neural network or some other black box. If you use Gradio’s default
or shap
interpretation, the output component must be a Label
. All common input components are supported. Here is an example with text input.
import gradio as gr
male_words, female_words = ["he", "his", "him"], ["she", "hers", "her"]
def gender_of_sentence(sentence):
male_count = len([word for word in sentence.split() if word.lower() in male_words])
female_count = len(
[word for word in sentence.split() if word.lower() in female_words]
)
total = max(male_count + female_count, 1)
return {"male": male_count / total, "female": female_count / total}
demo = gr.Interface(
fn=gender_of_sentence,
inputs=gr.Textbox(value="She went to his house to get her keys."),
outputs="label",
interpretation="default",
)
demo.launch()
So what is happening under the hood? With these interpretation methods, Gradio runs the prediction multiple times with modified versions of the input. Based on the results, you’ll see that the interface automatically highlights the parts of the text (or image, etc.) that contributed increased the likelihood of the class as red. The intensity of color corresponds to the importance of that part of the input. The parts that decrease the class confidence are highlighted blue.
You can also write your own interpretation function. The demo below adds custom interpretation to the previous demo. This function will take the same inputs as the main wrapped function. The output of this interpretation function will be used to highlight the input of each input component - therefore the function must return a list where the number of elements corresponds to the number of input components. To see the format for interpretation for each input component, check the Docs.
import re
import gradio as gr
male_words, female_words = ["he", "his", "him"], ["she", "hers", "her"]
def gender_of_sentence(sentence):
male_count = len([word for word in sentence.split() if word.lower() in male_words])
female_count = len(
[word for word in sentence.split() if word.lower() in female_words]
)
total = max(male_count + female_count, 1)
return {"male": male_count / total, "female": female_count / total}
# Number of arguments to interpretation function must
# match number of inputs to prediction function
def interpret_gender(sentence):
result = gender_of_sentence(sentence)
is_male = result["male"] > result["female"]
interpretation = []
for word in re.split("( )", sentence):
score = 0
token = word.lower()
if (is_male and token in male_words) or (not is_male and token in female_words):
score = 1
elif (is_male and token in female_words) or (
not is_male and token in male_words
):
score = -1
interpretation.append((word, score))
# Output must be a list of lists containing the same number of elements as inputs
# Each element corresponds to the interpretation scores for the given input
return [interpretation]
demo = gr.Interface(
fn=gender_of_sentence,
inputs=gr.Textbox(value="She went to his house to get her keys."),
outputs="label",
interpretation=interpret_gender,
)
demo.launch()
Learn more about Interpretation in the docs.
If you’d like to have more fine-grained control over any aspect of your demo, you can also write your own css or pass in a filepath to a css file, with the css
parameter of the Interface
class.
gr.Interface(..., css="body {background-color: red}")
If you’d like to reference external files in your css, preface the file path (which can be a relative or absolute path) with "file="
, for example:
gr.Interface(..., css="body {background-image: url('file=clouds.jpg')}")
Warning: Custom CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using custom CSS sparingly and instead using Themes whenever possible.
Gradio integrates nicely with the Hugging Face Hub, allowing you to load models and Spaces with just one line of code. To use this, simply use the load()
method in the Interface
class. So:
"model/"
or "huggingface/"
followed by the model name, like these examples:gr.Interface.load("huggingface/gpt2").launch();
gr.Interface.load("huggingface/EleutherAI/gpt-j-6B",
inputs=gr.Textbox(lines=5, label="Input Text") # customizes the input component
).launch()
"spaces/"
followed by the model name:gr.Interface.load("spaces/eugenesiow/remove-bg",
inputs="webcam",
title="Remove your webcam background!").launch()
One of the great things about loading Hugging Face models or spaces using Gradio is that you can then immediately use the resulting Interface
object just like function in your Python code (this works for every type of model/space: text, images, audio, video, and even multimodal models):
io = gr.Interface.load("models/EleutherAI/gpt-neo-2.7B")
io("It was the best of times") # outputs model completion
Gradio also lets you mix interfaces very easily using the gradio.Parallel
and gradio.Series
classes. Parallel
lets you put two similar models (if they have the same input type) in parallel to compare model predictions:
generator1 = gr.Interface.load("huggingface/gpt2")
generator2 = gr.Interface.load("huggingface/EleutherAI/gpt-neo-2.7B")
generator3 = gr.Interface.load("huggingface/EleutherAI/gpt-j-6B")
gr.Parallel(generator1, generator2, generator3).launch()
Series
lets you put models and spaces in series, piping the output of one model into the input of the next model.
generator = gr.Interface.load("huggingface/gpt2")
translator = gr.Interface.load("huggingface/t5-small")
gr.Series(generator, translator).launch()
# this demo generates text, then translates it to German, and outputs the final result.
And of course, you can also mix Parallel
and Series
together whenever that makes sense!
Learn more about Parallel and Series in the docs.