Gradio 是一个可用于构建机器学习、数据科学相关 demo 和 web 应用的开源 python 库。
通过使用 Gradio, 您可以围绕机器学习模型或数据科学工作流,快速创建出漂亮的 UI 界面,同时可以在浏览器中进行图像拖拽、文本粘贴、声音录制、与 demo 进行交互等操作。
Gradio 适用于:
- 为客户、合伙人、用户、学生群体演示您的机器学习模型
- 使用自动共享链接功能快速部署您的模型,并且获得有关其性能的反馈信息
- 使用内置的操作和解释工具,以交互的方式调试您的模型
您可以在 https://gradio.app/getting_started[1] 找到下方入门指南的交互式版本。
快速开始
前提:使用 Gradio 要求 Python 版本 >= 3.7
项目地址
https://github.com/gradio-app/gradio
Gradio 解决了什么问题 ?😲
与他人共享您的机器学习模型、API 或数据科学工作流的最好方式之一就是创建一个交互式的 demo,并允许您的用户或同事可以在他们的浏览器中体验这个 demo。
基于 web 的演示 demo 很值得青睐,因为它可以让任何可直接使用浏览器的人(不仅仅是技术人员)直观地尝试他们自己的输入,并了解您所构建的内容。
但是创建此类基于 web 的 demo 会很困难,因为您需要了解支撑 web 应用的后端服务以及构建 UI 界面的前端开发知识(HTML、CSS、JavaScript )。
Gradio 允许您通过仅使用 Python 的方式构建 demo 并分享它们,并且通常只需要几行代码!让我们开始吧。
Hello, World ⚡
在让 Gradio 运行一个简单的 “Hello World” 示例之前,请先遵循以下三个步骤:
1、使用 pip 安装 Gradio,请注意 python 的版本最低要求是 3.7。
pip install gradio
2、以执行 python 脚本的方式(或直接在 notebook 中)运行下面这段代码:
import gradio as gr
def greet(name):
return "Hello " + name + "!!"
demo = gr.Interface(fn=greet, inputs="text", outputs="text")
demo.launch()
3、下方的 demo 会自动出现在 notebook 中,如果以 python 脚本方式运行的话,则会在浏览器中自动弹出 http://localhost:7860[2] 页面。
Interface 类 🧡
您可能会注意到,在上面创建的 demo 中,我们使用 gradio.Interface 类定义了一个对象。Interface 类几乎可以实现:以 UI 的方式装饰任何 python 函数。在示例中,我们使用了一个简单的、与文本相关的函数。但实际上,这个函数可以是任何东西:从音乐生成器到税收计算器,再到(最常见的)预训练机器学习模型的预测函数。
核心 Interface 类需要使用三个参数进行初始化:
- fn:被 UI 装饰的函数
- inputs:输入组件。如"text"、"image"、"audio"等
- outputs:输出组件。如"text"、"image"、"label"等
Gradio 支持 20 多种不同的组件类型,其中大部分都可以作为输入/输出组件(完整列表可参考 官方文档[3])。
组件属性
使用 Interface 的三个参数,您可以快速创建 UI 界面并 launch() 它们。但是如何您想修改 UI 样式或表现方式,要如何做呢?
假设您想要自定义一个文本输入场景,例如,您希望文本框更大并且带有输入提示。通过使用 Textbox 类代替 "text" 输入类型,您就可以通过组件属性实现更多的定制化方案:
import gradio as gr
def greet(name):
return "Hello " + name + "!"
demo = gr.Interface(
fn=greet,
inputs=gr.Textbox(lines=2, placeholder="Name Here..."),
outputs="text",
)
demo.launch()
想要查看 Gradio 支持的所有组件列表以及您可以使用哪些属性来自定义它们,请查阅 官方文档[3]。
多个输入与输出 🔥
假设您有一个更复杂的函数,有多个输入和输出。在下面的示例中,我们定义了一个函数,它的入参包含一个字符串、一个布尔值和一个数字,并返回一个字符串和一个数字。让我们看看此时要如何传递输入和输出组件列表。
import gradio as gr
def greet(name, is_morning, temperature):
salutation = "Good morning" if is_morning else "Good evening"
greeting = "%s %s. It is %s degrees today" % (salutation, name, temperature)
celsius = (temperature - 32) * 5 / 9
return greeting, round(celsius, 2)
demo = gr.Interface(
fn=greet,
inputs=["text", "checkbox", gr.Slider(0, 100)],
outputs=["text", "number"],
)
demo.launch()
您只需将组件放在列表中:inputs 列表中的每个组件按顺序对应于函数的参数之一,outputs 列表中的每个组件也都对应于函数返回的值之一,同样按顺序排列。
图像 🎨
让我们尝试一个“图像转图像”的功能!当使用 Image 组件时,您的函数将接收指定大小的 numpy 数组,其形状为 (width, height, 3),其中最后一个维度表示 RGB 值。我们将以 numpy 数组的形式返回图像。
import numpy as np
import gradio as gr
def sepia(input_img):
sepia_filter = np.array(
[[0.393, 0.769, 0.189], [0.349, 0.686, 0.168], [0.272, 0.534, 0.131]]
)
sepia_img = input_img.dot(sepia_filter.T)
sepia_img /= sepia_img.max()
return sepia_img
demo = gr.Interface(sepia, gr.Image(shape=(200, 200)), "image")
demo.launch()
此外,我们的图像输入界面带有一个“编辑”按钮 ✏️,它可以打开用于裁剪和放大图像的工具。我们发现以这种方式处理图像,有助于揭示机器学习模型中的偏差或隐藏缺陷。
除了图像,Gradio 还支持其他媒体类型,例如音频或视频。可在 官方文档[3] 中阅读这些内容。
DataFrame 与图表 📈
您可以使用 Gradio 来支持来自数据库或数据文件的输入和输出。例如 numpy
数组、pandas
dataframe 和绘图数据等。看看下面的演示(函数中复杂的数据操作可忽略):
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import gradio as gr
def sales_projections(employee_data):
sales_data = employee_data.iloc[:, 1:4].astype("int").to_numpy()
regression_values = np.apply_along_axis(
lambda row: np.array(np.poly1d(np.polyfit([0, 1, 2], row, 2))), 0, sales_data
)
projected_months = np.repeat(
np.expand_dims(np.arange(3, 12), 0), len(sales_data), axis=0
)
projected_values = np.array(
[
month * month * regression[0] + month * regression[1] + regression[2]
for month, regression in zip(projected_months, regression_values)
]
)
plt.plot(projected_values.T)
plt.legend(employee_data["Name"])
return employee_data, plt.gcf(), regression_values
demo = gr.Interface(
sales_projections,
gr.Dataframe(
headers=["Name", "Jan Sales", "Feb Sales", "Mar Sales"],
value=[["Jon", 12, 14, 18], ["Alice", 14, 17, 2], ["Sana", 8, 9.5, 12]],
),
["dataframe", "plot", "numpy"],
description="Enter sales figures for employees to predict sales trajectory over year.",
)
demo.launch()
使用示例数据作为输入 🦮
您可以提供用户可以轻松加载到模型中的示例数据。这有助于演示模型所期望的输入类型,并提供一种结合模型探索数据集的方法。要加载示例数据,您可以为 Interface 构造函数中的 examples= 关键字参数提供一个嵌套列表。其中外部列表中的每个子列表代表一个数据样本,子列表中的每个元素代表每个输入组件的实际输入。每个组件的示例数据格式在 官方文档[3] 中也有所提及。
import gradio as gr
def calculator(num1, operation, num2):
if operation == "add":
return num1 + num2
elif operation == "subtract":
return num1 - num2
elif operation == "multiply":
return num1 * num2
elif operation == "divide":
return num1 / num2
demo = gr.Interface(
calculator,
[gr.Number(4), gr.Radio(["add", "subtract", "multiply", "divide"]), "number"],
"number",
examples=[
[5, "add", 3],
[4, "divide", 2],
[-4, "multiply", 2.5],
[0, "subtract", 1.2],
],
title="test calculator",
description="heres a sample toy calculator. enjoy!",
)
demo.launch()
您可以将大型数据集加载到示例中,并通过 Gradio 浏览数据集并与之交互。示例将自动分页(您可以通过 Interface
的 examples_per_page
参数进行配置)。
实时界面 🪁
您可以通过在 Interface 中设置 live=True 来使界面自动刷新。这样一旦用户输入发生变化,界面就会重新计算。
import gradio as gr
def calculator(num1, operation, num2):
if operation == "add":
return num1 + num2
elif operation == "subtract":
return num1 - num2
elif operation == "multiply":
return num1 * num2
elif operation == "divide":
return num1 / num2
demo = gr.Interface(
calculator,
["number", gr.Radio(["add", "subtract", "multiply", "divide"]), "number"],
"number",
live=True,
)
demo.launch()
请注意,此处没有提交按钮,因为界面会在更改时自动重新提交。
标记 🚩
在界面的 output 下方,有一个“Flag”按钮。当测试您模型的用户看到带有有趣输出的输入时:例如错误或意外的模型行为,他们可以标记此时的输入以供界面创建者查看。在接口构造函数的 flagging_dir= 参数提供的目录中,会生成一个 CSV 文件用于记录标记的输入。如果接口涉及文件数据:例如图像和音频组件,则会创建文件夹来存储这些标记的数据。
例如,使用上面显示的计算器界面,我们会将标记数据存储在如下所示的标记目录中:
+-- calculator.py
+-- flagged/
| +-- logs.csv
flagged/logs.csv 内容:
num1,operation,num2,Output
5,add,7,12
6,subtract,1.5,4.5
使用上面实现的 sepia intereface,我们将标记数据存储在如下所示的标记目录中:
+-- sepia.py
+-- flagged/
| +-- logs.csv
| +-- im/
| | +-- 0.png
| | +-- 1.png
| +-- Output/
| | +-- 0.png
| | +-- 1.png
flagged/logs.csv 内容:
im,Output
im/0.png,Output/0.png
im/1.png,Output/1.png
您可以通过手动浏览标记目录来查看这些标记输入,或者通过将 examples= 参数指向标记目录将它们加载到 Gradio 接口的示例中。如果您希望用户提供标记的原因,您可以将字符串列表传递给 Interface 的 flagging_options 参数。用户在标记时必须选择其中一个字符串,该字符串将作为附加列保存到 CSV。
Blocks: 更好的灵活性与控制 🧱
Gradio 为用户提供了两个 API:(1) Interface,一个用于创建演示的高级抽象类(到目前为止我们一直在讨论),以及 (2) Blocks,一个用于设计具有更灵活布局的 Web 应用程序的低级 API 和数据流。
Blocks 允许您执行以下操作:将相关的演示组合在一起,更改组件在页面上的显示位置,处理复杂的数据流(例如,输出可以作为其他功能的输入),以及基于用户交互更新组件的属性/可见性等。——以上这些依然仅需要使用 Python。
例如,Blocks 使用 Python 中的嵌套 with 语句在页面上布局组件,如下所示:
import numpy as np
import gradio as gr
demo = gr.Blocks()
def flip_text(x):
return x[::-1]
def flip_image(x):
return np.fliplr(x)
with demo:
gr.Markdown("Flip text or image files using this demo.")
with gr.Tabs():
with gr.TabItem("Flip Text"):
text_input = gr.Textbox()
text_output = gr.Textbox()
text_button = gr.Button("Flip")
with gr.TabItem("Flip Image"):
with gr.Row():
image_input = gr.Image()
image_output = gr.Image()
image_button = gr.Button("Flip")
text_button.click(flip_text, inputs=text_input, outputs=text_output)
image_button.click(flip_image, inputs=image_input, outputs=image_output)
demo.launch()
如果您对 Blocks 的工作原理感兴趣,请阅读其专用指南[4]。
分享 Demo 🌎
通过在 launch() 方法中设置 share=True,可以轻松地公开共享 Gradio demo。像这样:
gr.Interface(classify_image, "image", "label").launch(share=True)
这样会生成一个公开的、可共享的链接,您可以将其发送给任何人。当您发送此链接时,另一方的用户可以在他们的浏览器中试用该模型。因为处理过程发生在您的设备上(只要您的设备保持开启),您不必担心任何打包任何依赖项。分享链接通常看起来像这样:XXXXXX.gradio.app。虽然链接是通过 Gradio URL 提供的,但我们只是您本地服务器的代理,不会存储通过接口发送的任何数据。
但是请记住,这些链接是可公开访问的,这意味着任何人都可以使用您的模型进行预测!因此,请确保不要通过您编写的函数公开任何敏感信息,或允许在您的设备上发生任何关键更改。如果您设置 share=False(默认值,colab notebook 除外),则仅创建一个本地链接,该链接可以通过 端口转发[5] 与特定用户共享。
共享链接在 72 小时后过期。