非常优秀的一个开源库Gradio,几行代码完成部署快速搭建AI算法可视化部署演示,直接启动零配置实现微信分享、公网分享、内网穿透,包含项目搭建和案例分享
原创
为何一再沦落2024-03-21 22:45:06博主文章分类:Python相关©著作权
文章标签开源人工智能算法ai分享文章分类Html/CSS前端开发
非常优秀的一个开源库Gradio,几行代码完成部署快速搭建AI算法可视化部署演示,直接启动零配置实现微信分享、公网分享、内网穿透,包含项目搭建和案例分享。
Gradio是一个功能丰富的Python库,可以让您轻松创建和共享自己的交互式机器学习和深度学习模型。
以下是Gradio库的一些主要功能:
创建交互式接口 Gradio库使得创建交互式接口变得非常简单。您只需要定义一个函数来表示您的模型或应用程序,Gradio库将使用这个函数来创建一个用户友好的交互式界面,让用户输入参数并查看输出结果。
支持多种输入和输出类型 Gradio库支持多种输入和输出类型,包括文本、图像、音频和视频。您可以轻松地定义自己的输入和输出类型,并将其与您的模型或应用程序相关联。
自定义样式和布局 Gradio库允许您自定义您的交互式界面的样式和布局。您可以选择不同的主题、字体和颜色方案,并对界面进行布局。
使用预训练模型 Gradio库支持使用预训练的机器学习和深度学习模型。您可以选择一个预训练模型,并将其与自己的数据集或应用程序相关联。
构建复杂的交互式应用程序 Gradio库不仅可以创建简单的交互式接口,还可以构建复杂的交互式应用程序。您可以将多个模型或应用程序组合成一个大型的交互式应用程序,并在一个界面中显示它们。
部署到Web Gradio库支持将您的交互式应用程序部署到Web上,以便用户可以通过互联网访问它们。您可以使用Gradio库提供的API密钥将您的应用程序部署到Gradio官方网站上,也可以将它们部署到自己的Web服务器上。
Gradio(现在称为gr.Interface)是一个开源的Python库,它允许开发者快速创建可与机器学习模型交互的Web应用程序。Gradio的主要优势在于其易用性和灵活性,使得即使是没有前端开发经验的数据科学家和机器学习工程师也能够轻松地将他们的模型部署为用户友好的界面。以下是Gradio的一些主要使用场景:
- 模型演示和测试:
数据科学家和机器学习工程师经常需要向同事、管理层或潜在客户展示他们的模型。Gradio提供了一种快速创建交互式演示的方式,用户可以通过Web界面上传数据、调整参数,并实时查看模型的输出结果。这种方式有助于更好地解释模型的工作原理和性能。 - 数据收集和标注:
在机器学习项目中,收集和标注数据是一个耗时且关键的步骤。Gradio可以用来创建一个数据标注界面,让非技术用户(如标注员)能够上传数据、进行标注,并将结果直接保存到模型的训练数据集中。这不仅提高了数据收集的效率,还有助于提高数据质量。 - 模型验证和调优:
在模型开发过程中,开发者需要不断验证模型的性能并进行调优。Gradio可以快速搭建一个模型验证界面,允许用户输入不同的参数或数据,实时查看模型的预测结果和性能指标。这有助于开发者快速迭代和优化模型。 - 教育和培训:
Gradio可以用于创建交互式的教育工具,帮助学生和初学者理解复杂的机器学习概念。通过可视化的界面和实时反馈,学习者可以更直观地看到模型是如何工作的,以及不同参数是如何影响模型输出的。 - 商业应用和产品开发:
对于希望将机器学习技术商业化的公司来说,Gradio提供了一种快速将模型转化为产品原型的方式。通过Gradio创建的Web应用可以作为产品的前端,让用户直接与模型交互,从而验证市场需求和用户体验。 - 研究和开发:
在研究环境中,Gradio可以帮助研究人员创建交互式的实验平台,以便快速测试新算法或模型。研究人员可以通过Gradio界面收集实验数据,实时观察实验结果,并据此调整研究方向。 - 社区和开源项目:
对于开源项目,Gradio可以用来创建一个社区驱动的模型测试和改进平台。开发者可以邀请社区成员通过Web界面测试模型、提供反馈,并共同参与模型的优化过程。
Gradio的使用场景非常广泛,它降低了机器学习模型部署的门槛,使得更多的人能够参与到模型的开发、测试和应用中来。通过Gradio,开发者可以专注于模型的核心算法,而不必担心前端开发的复杂性。这种工具的普及,无疑将推动机器学习技术的快速发展和广泛应用。
常用的两款AI可视化交互应用比较:
Gradio
Gradio的优势在于易用性,代码结构相比Streamlit简单,只需简单定义输入和输出接口即可快速构建简单的交互页面,更轻松部署模型。适合场景相对简单,想要快速部署应用的开发者。便于分享:gradio可以在启动应用时设置share=True参数创建外部分享链接,可以直接在微信中分享给用户使用。
复制
方便调试:gradio可以在jupyter中直接展示页面,更加方便调试。
Streamlit
Streamlit的优势在于可扩展性,相比Gradio复杂,完全熟练使用需要一定时间。可以使用Python编写完整的包含前后端的交互式应用。适合场景相对复杂,想要构建丰富多样交互页面的开发者。
复制
Gradio官网链接:https://gradio.app/
- 安装&基本用法
Python第三方库Gradio快速上手,当前版本V3.27.0
python版本要求3.7及以上
pip install gradio
#为了更快安装,可以使用清华镜像源
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple gradio
- 1.
- 2.
- 3.
- 4.
安装完直接在IDE上启动快速,
1.1 快速入门
import gradio as gr
#输入文本处理程序
def greet(name):
return "Hello " + name + "!"
#接口创建函数
#fn设置处理函数,inputs设置输入接口组件,outputs设置输出接口组件
#fn,inputs,outputs都是必填函数
demo = gr.Interface(fn=greet, inputs="text", outputs="text")
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
运行程序后,打开 http://localhost:7860 即可看到网页效果。左边是文本输入框,右边是结果展示框。Clear按钮用于重置网页状态,Submit按钮用于执行处理程序,Flag按钮用于保存结果到本地。
#执行结果
Running on local URL: http://127.0.0.1:7860
To create a public link, set `share=True` in `launch()`.
- 1.
- 2.
- 3.
- 4.
打开浏览器使用即可
在本地开发时,如果你想将代码作为Python脚本运行,你可以使用Gradio CLI在重载模式下启动应用程序,这将提供无缝和快速的开发。
gradio app.py
- 1.
也可以做python app.py,但它不会提供自动重新加载机制。
2.基本参数|支持的接口
2.1 Interface类以及基础模块
Gradio 可以包装几乎任何 Python 函数为易于使用的用户界面。从上面例子我们看到,简单的基于文本的函数。但这个函数还可以处理很多类型。
Interface类通过以下三个参数进行初始化:
fn:包装的函数
inputs:输入组件类型,(例如:“text”、"image)
ouputs:输出组件类型,(例如:“text”、"image)
通过这三个参数,我们可以快速创建一个接口并发布他们。
最常用的基础模块构成。
- 应用界面:gr.Interface(简易场景), gr.Blocks(定制化场景)
- 输入输出:gr.Image(图像), gr.Textbox(文本框), gr.DataFrame(数据框), gr.Dropdown(下拉选项), gr.Number(数字), gr.Markdown, gr.Files
- 控制组件:gr.Button(按钮)
- 布局组件:gr.Tab(标签页), gr.Row(行布局), gr.Column(列布局)
1.2.1 自定义输入组件
import gradio as gr
def greet(name):
return "Hello " + name + "!"
demo = gr.Interface(
fn=greet,
# 自定义输入框
# 具体设置方法查看官方文档
inputs=gr.Textbox(lines=3, placeholder="Name Here...",label="my input"),
outputs="text",
)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
Interface.launch()方法返回三个值
- app,为 Gradio 演示提供支持的 FastAPI 应用程序
- local_url,本地地址
- share_url,公共地址,当share=True时生成
import gradio as gr
def greet(name):
return "Hello " + name + "!"
iface = gr.Interface(
fn=greet,
inputs=gr.inputs.Textbox(lines=2, placeholder="Name Here..."),
outputs="text",
)
if __name__ == "__main__":
app, local_url, share_url = iface.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
1.2.2 多个输入和输出
对于复杂程序,输入列表中的每个组件按顺序对应于函数的一个参数。输出列表中的每个组件按顺序排列对应于函数返回的一个值。
import gradio as gr
#该函数有3个输入参数和2个输出参数
def greet(name, is_morning, temperature):
salutation = "Good morning" if is_morning else "Good evening"
greeting = f"{salutation} {name}. It is {temperature} degrees today"
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()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
inputs列表里的每个字段按顺序对应函数的每个参数,outputs同理。
Gradio提供了多种输入和输出类型,以帮助您创建更复杂的交互式应用程序。以下是一些常见的输入和输出类型:
text:文本输入或输出
number:数字输入或输出
slider:滑块输入
checkbox:复选框输入
radio:单选按钮输入
dropdown:下拉菜单输入
image:图像输入或输出
file:文件输入或输出
例如,以下代码演示了如何使用Gradio创建一个具有多个输入和输出组件的应用程序:
import gradio as gr
import requests
import json
def translate(text, target_language):
url = "<https://translation.googleapis.com/language/translate/v2>"
params = {
"q": text,
"target": target_language,
"key": "YOUR_API_KEY"
}
response = requests.post(url, params=params)
return response.json()["data"]["translations"][0]["translatedText"]
iface = gr.Interface(
fn=translate,
inputs=[
gr.inputs.Textbox(label="输入文本"),
gr.inputs.Dropdown(
["英语", "西班牙语", "法语", "德语", "日语"],
label="目标语言"
)
],
outputs=gr.outputs.Textbox(label="翻译结果")
)
iface.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
在上面的示例中,我们定义了一个名为translate的函数,该函数接受一个文本输入和一个下拉菜单输入,并使用Google翻译API将文本翻译成所选语言。然后,我们使用gr.Interface类创建一个新的Gradio界面,并将translate函数作为输入和输出函数传递给它。我们使用Textbox和Dropdown类创建了两个输入组件,并使用Textbox类创建了一个输出组件。最后,我们调用了launch方法来启动Gradio应用程序。
Gradio布局详解
Gradio的默认布局非常简单,但您也可以使用Gradio组件的高级选项来自定义应用程序的布局。以下是一些常见的布局选项:
cols:指定输入和输出组件的列数
rows:指定输入和输出组件的行数
inputs:指定输入组件的位置和大小
outputs:指定输出组件的位置和大小
例如,以下代码演示了如何使用Gradio的高级布局选项来自定义应用程序的布局:
以下是一个使用Gradio的示例程序,它将两个数字相加:
import gradio as gr
def add(num1, num2):
return num1 + num2
iface = gr.Interface(
fn=add,
inputs=[
gr.inputs.Number(label="第一个数字"),
gr.inputs.Number(label="第二个数字")
],
outputs=gr.outputs.Textbox(label="结果", location="below")
cols=2,
rows=2
)
iface.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
在上面的代码中,我们定义了一个名为add的函数,该函数接受两个数字输入,并返回它们的和。然后,我们使用gr.Interface类创建一个新的Gradio界面,并将add函数作为输入和输出函数传递给它。我们使用Number类创建了两个数字输入组件,并使用Textbox类创建了一个输出组件,将输入和输出组件分别放置在两个列和两个行中。最后,我们调用了launch方法来启动Gradio应用程序。
通过使用cols、rows、inputs和outputs选项,您可以轻松地自定义Gradio应用程序的布局和样式,以满足您的需求。
1.2.3 图像组件
Gradio支持许多类型的组件,如image、dataframe、video。使用示例如下:
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
#shape设置输入图像大小
demo = gr.Interface(sepia, gr.Image(shape=(200, 200)), "image")
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
当使用Image组件作为输入时,函数将收到一个维度为(w,h,3)的numpy数组,按照RGB的通道顺序排列。要注意的是,我们的输入图像组件带有一个编辑按钮,可以对图像进行裁剪和放大。以这种方式处理图像可以帮助揭示机器学习模型中的偏差或隐藏的缺陷。此外对于输入组件有个shape参数,指的设置输入图像大小。但是处理方式是保持长宽比的情况下,将图像最短边缩放为指定长度,然后按照中心裁剪方式裁剪最长边到指定长度。当图像不大的情况,一种更好的方式是不设置shape,这样直接传入原图。输入组件Image也可以设置输入类型type,比如type=filepath设置传入处理图像的路径。具体可以查看官方文档,文档写的很清楚。
1.2.4 动态界面接口:简单计算器模板实时变化
在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
iface = gr.Interface(
calculator,
["number", gr.inputs.Radio(["add", "subtract", "multiply", "divide"]), "number"],
"number",
live=True,
)
iface.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
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":
if num2 == 0:
# 设置报错弹窗
raise gr.Error("Cannot divide by zero!")
return num1 / num2
demo = gr.Interface(
calculator,
# 设置输入
[
"number",
gr.Radio(["add", "subtract", "multiply", "divide"]),
"number"
],
# 设置输出
"number",
# 设置输入参数示例
examples=[
[5, "add", 3],
[4, "divide", 2],
[-4, "multiply", 2.5],
[0, "subtract", 1.2],
],
# 设置网页标题
title="Toy Calculator",
# 左上角的描述文字
description="Here's a sample toy calculator. Enjoy!",
# 左下角的文字
article = "Check out the examples",
)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
Gradio的部署
Gradio支持多种部署方式,包括本地部署、云部署和Web应用程序部署。本地部署适用于测试和开发环境,而云部署和Web应用程序部署适用于生产环境。以下是一些常见的部署选项:
本地部署
要在本地部署Gradio应用程序,您需要在本地计算机上安装Gradio库,并使用launch方法启动应用程序。以下是一个简单的示例,展示了如何在本地部署Gradio应用程序:
import gradio as gr
def greet(name):
return "Hello, " + name + "!"
iface = gr.Interface(fn=greet, inputs="text", outputs="text")
iface.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
在上面的代码中,我们定义了一个名为greet的函数,该函数接受一个名为name的文本输入,并返回一个包含问候语的文本输出。然后,我们使用gr.Interface类创建一个新的Gradio界面,并将greet函数作为输入和输出函数传递给它。最后,我们调用了launch方法来启动Gradio应用程序。
Web应用程序部署
要将Gradio应用程序部署为Web应用程序,您需要使用Flask框架将应用程序打包为Web服务。以下是一个简单的示例,展示了如何使用Flask框架将Gradio应用程序部署为Web服务:
import gradio as gr
from flask import Flask, render_template, request
app = Flask(__name__)
def greet(name):
return "Hello, " + name + "!"
iface = gr.Interface(fn=greet, inputs="text", outputs="text")
@app.route("/")
def index():
return render_template("index.html")
@app.route("/api/greet", methods=["POST"])
def api():
data = request.get_json(force=True)
name = data["name"]
return {"result": iface.process([name])[0]}
if __name__ == "__main__":
app.run()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
在上面的代码中,我们使用Flask框架创建了一个名为app的Web应用程序,并定义了一个名为greet的函数,该函数接受一个名为name的文本输入,并返回一个包含问候语的文本输出。然后,我们使用gr.Interface类创建一个新的Gradio界面,并将greet函数作为输入和输出函数传递给它。最后,我们使用Flask框架将应用程序部署为Web服务,并将Gradio界面的输入和输出与Flask框架的路由和视图函数配对。
通过使用以上部署选项,您可以将Gradio应用程序部署到各种环境中,从而使您的模型更易于使用和理解。
2.2 interface进阶使用
2.2.1 interface状态
全局变量
全局变量的好处就是在调用函数后仍然能够保存,例如在机器学习中通过全局变量从外部加载一个大型模型,并在函数内部使用它,以便每次函数调用都不需要重新加载模型。下面就展示了全局变量使用的好处。
import gradio as gr
scores = []
def track_score(score):
scores.append(score)
#返回分数top3
top_scores = sorted(scores, reverse=True)[:3]
return top_scores
demo = gr.Interface(
track_score,
gr.Number(label="Score"),
gr.JSON(label="Top Scores")
)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
会话状态
Gradio支持的另一种数据持久性是会话状态,数据在一个页面会话中的多次提交中持久存在。然而,数据不会在你模型的不同用户之间共享。会话状态的典型例子就是聊天机器人,你想访问用户之前提交的信息,但你不能将聊天记录存储在一个全局变量中,因为那样的话,聊天记录会在不同的用户之间乱成一团。注意该状态会在每个页面内的提交中持续存在,但如果您在另一个标签页中加载该演示(或刷新页面),该演示将不会共享聊天历史。
要在会话状态下存储数据,你需要做三件事。
在你的函数中传入一个额外的参数,它代表界面的状态。
在函数的最后,将状态的更新值作为一个额外的返回值返回。
在添加输入和输出时添加state组件。
import random
import gradio as gr
def chat(message, history):
history = history or []
message = message.lower()
if message.startswith("how many"):
response = random.randint(1, 10)
elif message.startswith("how"):
response = random.choice(["Great", "Good", "Okay", "Bad"])
elif message.startswith("where"):
response = random.choice(["Here", "There", "Somewhere"])
else:
response = "I don't know"
history.append((message, response))
return history, history
#设置一个对话窗
chatbot = gr.Chatbot().style(color_map=("green", "pink"))
demo = gr.Interface(
chat,
# 添加state组件
["text", "state"],
[chatbot, "state"],
# 设置没有保存数据的按钮
allow_flagging="never",
)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
2.2.2 interface交互
实时变化
在Interface中设置live=True,则输出会跟随输入实时变化。这个时候界面不会有submit按钮,因为不需要手动提交输入。
同1.2.4
流模式
在许多情形下,我们的输入是实时视频流或者音频流,那么意味这数据不停地发送到后端,这是可以采用streaming模式处理数据。
import gradio as gr
import numpy as np
def flip(im):
return np.flipud(im)
demo = gr.Interface(
flip,
gr.Image(source="webcam", streaming=True),
"image",
live=True
)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
2.3自定制组件:Blocks构建应用
相比Interface,Blocks提供了一个低级别的API,用于设计具有更灵活布局和数据流的网络应用。Blocks允许控制组件在页面上出现的位置,处理复杂的数据流(例如,输出可以作为其他函数的输入),并根据用户交互更新组件的属性可见性。可以定制更多组件,更多详细定制可查看文档
2.3.1 简单演示
import gradio as gr
def greet(name):
return "Hello " + name + "!"
with gr.Blocks() as demo:
#设置输入组件
name = gr.Textbox(label="Name")
# 设置输出组件
output = gr.Textbox(label="Output Box")
#设置按钮
greet_btn = gr.Button("Greet")
#设置按钮点击事件
greet_btn.click(fn=greet, inputs=name, outputs=output)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
Blocks方式需要with语句添加组件,如果不设置布局方式,那么组件将按照创建的顺序垂直出现在应用程序中,运行界面
2.3.2 多模块应用☆
import numpy as np
import gradio as gr
def flip_text(x):
return x[::-1]
def flip_image(x):
return np.fliplr(x)
with gr.Blocks() as demo:
#用markdown语法编辑输出一段话
gr.Markdown("Flip text or image files using this demo.")
# 设置tab选项卡
with gr.Tab("Flip Text"):
#Blocks特有组件,设置所有子组件按垂直排列
#垂直排列是默认情况,不加也没关系
with gr.Column():
text_input = gr.Textbox()
text_output = gr.Textbox()
text_button = gr.Button("Flip")
with gr.Tab("Flip Image"):
#Blocks特有组件,设置所有子组件按水平排列
with gr.Row():
image_input = gr.Image()
image_output = gr.Image()
image_button = gr.Button("Flip")
#设置折叠内容
with gr.Accordion("Open for More!"):
gr.Markdown("Look at me...")
text_button.click(flip_text, inputs=text_input, outputs=text_output)
image_button.click(flip_image, inputs=image_input, outputs=image_output)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
2.3.3 Flagging标记
相信有小伙伴已经注意到,输出框下有个Flag按钮。当测试您的模型的用户看到某个输入导致输出错误或意外的模型行为,他们可以标记这个输入让开发者知道。这个文件夹由Interface的flagging_dir参数指定,默认为’flagged’。将这些会导致错误的输入保存到一个csv文件。如果Interface包含文件数据,文件夹也会创建来保存这些标记数据。
打开log.csv展示如下:
2.3.4 样式、队列、生成器
样式
在Gradio官方文档,搜索不同的组件加.style(如image.style),可以获取该组件的样式参数设置样例。例如image组件的设置如下:
img = gr.Image("lion.jpg").style(height='24', rounded=False)
- 1.
队列
如果函数推理时间较长,比如目标检测;或者应用程序处理流量过大,则需要使用queue方法进行排队。queue方法使用websockets,可以防止网络超时。使用方式如下:
demo = gr.Interface(...).queue()
demo.launch()
#或
with gr.Blocks() as demo:
#...
demo.queue()
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
生成器
在某些情况下,你可能想显示一连串的输出,而不是单一的输出。例如,你可能有一个图像生成模型,如果你想显示在每个步骤中生成的图像,从而得到最终的图像。在这种情况下,你可以向Gradio提供一个生成器函数,而不是一个常规函数。下面是一个生成器的例子,每隔1秒返回1张图片。
import gradio as gr
import numpy as np
import time
#生成steps张图片,每隔1秒钟返回
def fake_diffusion(steps):
for _ in range(steps):
time.sleep(1)
image = np.random.randint(255, size=(300, 600, 3))
yield image
demo = gr.Interface(fake_diffusion,
#设置滑窗,最小值为1,最大值为10,初始值为3,每次改动增减1位
inputs=gr.Slider(1, 10, value=3, step=1),
outputs="image")
#生成器必须要queue函数
demo.queue()
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
2.4 Blocks进阶使用
2.4.1 Blocks事件
可交互设置
任何输入的组件内容都是可编辑的,而输出组件默认是不能编辑的。如果想要使得输出组件内容可编辑,设置interactive=True即可。
import gradio as gr
def greet(name):
return "Hello " + name + "!"
with gr.Blocks() as demo:
name = gr.Textbox(label="Name")
# 不可交互
# output = gr.Textbox(label="Output Box")
# 可交互
output = gr.Textbox(label="Output", interactive=True)
greet_btn = gr.Button("Greet")
greet_btn.click(fn=greet, inputs=name, outputs=output)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
事件设置
我们可以为不同的组件设置不同事件,如为输入组件添加change事件。可以进一步查看官方文档,看看组件还有哪些事件。
import gradio as gr
def welcome(name):
return f"Welcome to Gradio, {name}!"
with gr.Blocks() as demo:
gr.Markdown(
"""
# Hello World!
Start typing below to see the output.
""")
inp = gr.Textbox(placeholder="What is your name?")
out = gr.Textbox()
#设置change事件
inp.change(fn = welcome, inputs = inp, outputs = out)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
多个数据流
如果想处理多个数据流,只要设置相应的输入输出组件即可。
import gradio as gr
def increase(num):
return num + 1
with gr.Blocks() as demo:
a = gr.Number(label="a")
b = gr.Number(label="b")
# 要想b>a,则使得b = a+1
atob = gr.Button("b > a")
atob.click(increase, a, b)
# 要想a>b,则使得a = b+1
btoa = gr.Button("a > b")
btoa.click(increase, b, a)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
多输出值处理
下面的例子展示了输出多个值时,以列表形式表现的处理方式。
import gradio as gr
with gr.Blocks() as demo:
food_box = gr.Number(value=10, label="Food Count")
status_box = gr.Textbox()
def eat(food):
if food > 0:
return food - 1, "full"
else:
return 0, "hungry"
gr.Button("EAT").click(
fn=eat,
inputs=food_box,
#根据返回值改变输入组件和输出组件
outputs=[food_box, status_box]
)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
下面的例子展示了输出多个值时,以字典形式表现的处理方式。
组件配置修改
事件监听器函数的返回值通常是相应的输出组件的更新值。有时我们也想更新组件的配置,比如说可见性。在这种情况下,我们可以通过返回update函数更新组件的配置。
import gradio as gr
def change_textbox(choice):
#根据不同输入对输出控件进行更新
if choice == "short":
return gr.update(lines=2, visible=True, value="Short story: ")
elif choice == "long":
return gr.update(lines=8, visible=True, value="Long story...")
else:
return gr.update(visible=False)
with gr.Blocks() as demo:
radio = gr.Radio(
["short", "long", "none"], label="Essay Length to Write?"
)
text = gr.Textbox(lines=2, interactive=True)
radio.change(fn=change_textbox, inputs=radio, outputs=text)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
2.4.2 Blocks布局
Blocks应用的是html中的flexbox模型布局,默认情况下组件垂直排列。
组件水平排列
使用Row函数会将组件按照水平排列,但是在Row函数块里面的组件都会保持同等高度。
import gradio as gr
with gr.Blocks() as demo:
with gr.Row():
img1 = gr.Image()
text1 = gr.Text()
btn1 = gr.Button("button")
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
组件垂直排列与嵌套
组件通常是垂直排列,我们可以通过Row函数和Column函数生成不同复杂的布局。
import gradio as gr
with gr.Blocks() as demo:
with gr.Row():
text1 = gr.Textbox(label="t1")
slider2 = gr.Textbox(label="s2")
drop3 = gr.Dropdown(["a", "b", "c"], label="d3")
with gr.Row():
# scale与相邻列相比的相对宽度。例如,如果列A的比例为2,列B的比例为1,则A的宽度将是B的两倍。
# min_width设置最小宽度,防止列太窄
with gr.Column(scale=2, min_width=600):
text1 = gr.Textbox(label="prompt 1")
text2 = gr.Textbox(label="prompt 2")
inbtw = gr.Button("Between")
text4 = gr.Textbox(label="prompt 1")
text5 = gr.Textbox(label="prompt 2")
with gr.Column(scale=1, min_width=600):
img1 = gr.Image("test.jpg")
btn = gr.Button("Go")
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
组件可视化:输出可视化从无到有
如下所示,我们可以通过visible和update函数构建更为复杂的应用。
import gradio as gr
with gr.Blocks() as demo:
# 出错提示框
error_box = gr.Textbox(label="Error", visible=False)
# 输入框
name_box = gr.Textbox(label="Name")
age_box = gr.Number(label="Age")
symptoms_box = gr.CheckboxGroup(["Cough", "Fever", "Runny Nose"])
submit_btn = gr.Button("Submit")
# 输出不可见
with gr.Column(visible=False) as output_col:
diagnosis_box = gr.Textbox(label="Diagnosis")
patient_summary_box = gr.Textbox(label="Patient Summary")
def submit(name, age, symptoms):
if len(name) == 0:
return {error_box: gr.update(value="Enter name", visible=True)}
if age < 0 or age > 200:
return {error_box: gr.update(value="Enter valid age", visible=True)}
return {
output_col: gr.update(visible=True),
diagnosis_box: "covid" if "Cough" in symptoms else "flu",
patient_summary_box: f"{name}, {age} y/o"
}
submit_btn.click(
submit,
[name_box, age_box, symptoms_box],
[error_box, diagnosis_box, patient_summary_box, output_col],
)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
组件渲染:点击作为输入
在某些情况下,您可能希望在实际在UI中呈现组件之前定义组件。例如,您可能希望在相应的gr.Textbox输入上方显示使用gr.examples的示例部分。由于gr.Examples需要输入组件对象作为参数,因此您需要先定义输入组件,然后在定义gr.Exmples对象后再进行渲染。解决方法是在gr.Blocks()范围外定义gr.Textbox,并在UI中希望放置的任何位置使用组件的.render()方法。
import gradio as gr
input_textbox = gr.Textbox()
with gr.Blocks() as demo:
#提供示例输入给input_textbox,示例输入以嵌套列表形式设置
gr.Examples(["hello", "bonjour", "merhaba"], input_textbox)
# render函数渲染input_textbox
input_textbox.render()
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
2.4.3 样式修改
自定义css
要获得额外的样式功能,您可以设置行内css属性将任何样式给应用程序。如下所示。
import gradio as gr
#修改blocks的背景颜色
with gr.Blocks(css=".gradio-container {background-color: red}") as demo:
box1 = gr.Textbox(value="Good Job")
box2 = gr.Textbox(value="Failure")
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
元素选择
您可以向任何组件添加HTML元素。通过elem_id选择对应的css元素。
import gradio as gr
# 这里用的是id属性设置
with gr.Blocks(css="#warning {background-color: red}") as demo:
box1 = gr.Textbox(value="Good Job", elem_id="warning")
box2 = gr.Textbox(value="Failure")
box3 = gr.Textbox(value="None", elem_id="warning")
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 应用分享
3.1 互联网分享
如果运行环境能够连接互联网,在launch函数中设置share参数为True,那么运行程序后。Gradio的服务器会提供XXXXX.gradio.app地址。通过其他设备,比如手机或者笔记本电脑,都可以访问该应用。这种方式下该链接只是本地服务器的代理,不会存储通过本地应用程序发送的任何数据。这个链接在有效期内是免费的,好处就是不需要自己搭建服务器,坏处就是太慢了,毕竟数据经过别人的服务器。
demo.launch(share=True)
- 1.
3.2 huggingface托管
为了便于向合作伙伴永久展示我们的模型App,可以将gradio的模型部署到 HuggingFace的 Space托管空间中,完全免费的哦。
方法如下:
1,注册huggingface账号:https://huggingface.co/join
2,在space空间中创建项目:https://huggingface.co/spaces
3,创建好的项目有一个Readme文档,可以根据说明操作,也可以手工编辑app.py和requirements.txt文件。
3.3 局域网分享
通过设置server_name=‘0.0.0.0’(表示使用本机ip),server_port(可不改,默认值是7860)。那么可以通过本机ip:端口号在局域网内分享应用。
#show_error为True表示在控制台显示错误信息。
demo.launch(server_name='0.0.0.0', server_port=8080, show_error=True)
- 1.
- 2.
这里host地址可以自行在电脑查询,C:\Windows\System32\drivers\etc\hosts 修改一下即可 127.0.0.1再制定端口号
3.4 密码验证
在首次打开网页前,可以设置账户密码。比如auth参数为(账户,密码)的元组数据。这种模式下不能够使用queue函数。
demo.launch(auth=("admin", "pass1234"))
- 1.
如果想设置更为复杂的账户密码和密码提示,可以通过函数设置校验规则。
#账户和密码相同就可以通过
def same_auth(username, password):
return username == password
demo.launch(auth=same_auth,auth_message="username and password must be the same")
- 1.
- 2.
- 3.
- 4.
4.案例升级展示
4.1 文本分类
pip install gradio, ultralytics, transformers, torchkeras
- 1.
import gradio as gr
from transformers import pipeline
pipe = pipeline("text-classification")
def clf(text):
result = pipe(text)
label = result[0]['label']
score = result[0]['score']
res = {label:score,'POSITIVE' if label=='NEGATIVE' else 'NEGATIVE': 1-score}
return res
demo = gr.Interface(fn=clf, inputs="text", outputs="label")
gr.close_all()
demo.launch(share=True)
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
4.2 图像分类
import gradio as gr
import pandas as pd
from ultralytics import YOLO
from skimage import data
from PIL import Image
model = YOLO('yolov8n-cls.pt')
def predict(img):
result = model.predict(source=img)
df = pd.Series(result[0].names).to_frame()
df.columns = ['names']
df['probs'] = result[0].probs
df = df.sort_values('probs',ascending=False)
res = dict(zip(df['names'],df['probs']))
return res
gr.close_all()
demo = gr.Interface(fn = predict,inputs = gr.Image(type='pil'), outputs = gr.Label(num_top_classes=5),
examples = ['cat.jpeg','people.jpeg','coffee.jpeg'])
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
4.3 目标检测
import gradio as gr
import pandas as pd
from skimage import data
from ultralytics.yolo.data import utils
model = YOLO('yolov8n.pt')
#load class_names
yaml_path = str(Path(ultralytics.__file__).parent/'datasets/coco128.yaml')
class_names = utils.yaml_load(yaml_path)['names']
def detect(img):
if isinstance(img,str):
img = get_url_img(img) if img.startswith('http') else Image.open(img).convert('RGB')
result = model.predict(source=img)
if len(result[0].boxes.boxes)>0:
vis = plots.plot_detection(img,boxes=result[0].boxes.boxes,
class_names=class_names, min_score=0.2)
else:
vis = img
return vis
with gr.Blocks() as demo:
gr.Markdown("# yolov8目标检测演示")
with gr.Tab("捕捉摄像头喔"):
in_img = gr.Image(source='webcam',type='pil')
button = gr.Button("执行检测",variant="primary")
gr.Markdown("## 预测输出")
out_img = gr.Image(type='pil')
button.click(detect,
inputs=in_img,
outputs=out_img)
gr.close_all()
demo.queue(concurrency_count=5)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
4.4 图片筛选器
尽管gradio的设计初衷是为了快速创建机器学习用户交互页面。但实际上,通过组合gradio的各种组件,用户可以很方便地实现非常实用的各种应用小工具。
例如: 数据分析展示dashboard, 数据标注工具, 制作一个小游戏界面等等。
本范例我们将应用 gradio来构建一个图片筛选器,从百度爬取的一堆猫咪表情包中刷选一些我们喜欢的出来。
pip install -U torchkeras
- 1.
import torchkeras
from torchkeras.data import download_baidu_pictures
download_baidu_pictures('猫咪表情包',100)
import gradio as gr
from PIL import Image
import time,os
from pathlib import Path
base_dir = '猫咪表情包'
selected_dir = 'selected'
files = [str(x) for x in
Path(base_dir).rglob('*.jp*g')
if 'checkpoint' not in str(x)]
def show_img(path):
return Image.open(path)
def fn_before(done,todo):
...
return done,todo,path,img
def fn_next(done,todo):
...
return done,todo,path,img
def save_selected(img_path):
...
return msg
def get_default_msg():
...
return msg
with gr.Blocks() as demo:
with gr.Row():
total = gr.Number(len(files),label='总数量')
with gr.Row(scale = 1):
bn_before = gr.Button("上一张")
bn_next = gr.Button("下一张")
with gr.Row(scale = 2):
done = gr.Number(0,label='已完成')
todo = gr.Number(len(files),label='待完成')
path = gr.Text(files[0],lines=1, label='当前图片路径')
feedback_button = gr.Button("选择图片",variant="primary")
msg = gr.TextArea(value=get_default_msg,lines=3,max_lines = 5)
img = gr.Image(value = show_img(files[0]),type='pil')
bn_before.click(fn_before,
inputs= [done,todo],
outputs=[done,todo,path,img])
bn_next.click(fn_next,
inputs= [done,todo],
outputs=[done,todo,path,img])
feedback_button.click(save_selected,
inputs = path,
outputs = msg
)
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
经典案例简单的 RGB 转灰度:
import gradio as gr
import cv2
def to_black(image):
output = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
return output
interface = gr.Interface(fn=to_black, inputs="image", outputs="image")
interface.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
用 interface.lauch()把页面一发布,一个本地静态交互页面就完成了!在浏览器输入http://127.0.0.1:7860/,查收你的页面:
上传一张图片,点击「SUBMIT」
对于任何图像处理类的 ML 代码来说,只要定义好一个图像输入>>模型推理>>返回图片的函数(逻辑和 RGB 转灰度图本质上没区别),放到 fn 中即可。
增加 example
可以在页面下方添加供用户选择的测试样例。
在 gr.Interface 里的 examples 中放入图片路径,格式为[[路径 1],[路径 2],…]。
import gradio as gr
import cv2
def to_black(image):
output = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
return output
interface = gr.Interface(fn=to_black, inputs="image", outputs="image",
examples=[["gradio/test.png"]])
interface.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
增加 example 不仅能让你的 UI 界面更美观,逻辑更完善,也有一些其他意义:比如做了一个图像去噪算法,但是用户手头并没有躁点照片,example 能让他更快的体验到效果
创建一个外部访问链接
创建外部访问链接非常简单,只需要 launch(share=True)即可,在打印信息中会看到你的外部访问链接。
需要注意:免费用户的链接可以使用 24 小时,想要长期的话需要在 gradio 官方购买云服务。
文本分类
在 Gradio 中搭建一个实用的自然语言处理应用最少只需要三行代码!让我们三行代码来搭建一个文本分类模型的演示系统,这里使用的模型是 uer/roberta-base-finetuned-dianping-chinese,代码如下
#导入gradio
import gradio as gr
#导入transformers相关包
from transformers import *
#通过Interface加载pipeline并启动服务
gr.Interface.from_pipeline(pipeline("text-classification", model="uer/roberta-base-finetuned-dianping-chinese")).launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
过程中需要加载一个 400MB 的模型。
直接运行即可,运行后,服务默认会启动在本地的 7860 端口,打开链接即可。
可以在左侧输入待分类文本,而后点击 submit 按钮,右侧便会展示出预测的标签及概率,如下图所示
阅读理解,代码如下:
#导入gradio
import gradio as gr
#导入transformers相关包
from transformers import *
#通过Interface加载pipeline并启动服务
gr.Interface.from_pipeline(pipeline("question-answering", model="uer/roberta-base-finetuned-dianping-chinese")).launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
再次打开,可以看到界面中除了几个按钮外的内容全部进行了更新,变成了阅读理解相关的内容,输入部分包括了 context 和 question 两部分,输出也变成了 answer 和 score 两部分。
效果上不佳可以考虑重新加载以及微调模型。
完善页面
尽管我们快速的启动了一个 demo,但是页面整体还是较为简陋的,除了标题和实际的调用部分,缺少一些其他内容,我们可以通过配置几个简单的参数,将页面进行完善,还是以阅读理解任务为例,代码如下:
import gradio as gr
from transformers import *
#标题
title = "抽取式问答"
#标题下的描述,支持md格式
description = "输入上下文与问题后,点击submit按钮,可从上下文中抽取出答案,赶快试试吧!"
#输入样例
examples = [
["普希金从那里学习人民的语言,吸取了许多有益的养料,这一切对普希金后来的创作产生了很大的影响。这两年里,普希金创作了不少优秀的作品,如《囚徒》、《致大海》、《致凯恩》和《假如生活欺骗了你》等几十首抒情诗,叙事诗《努林伯爵》,历史剧《鲍里斯·戈都诺夫》,以及《叶甫盖尼·奥涅金》前六章。", "著名诗歌《假如生活欺骗了你》的作者是"],
["普希金从那里学习人民的语言,吸取了许多有益的养料,这一切对普希金后来的创作产生了很大的影响。这两年里,普希金创作了不少优秀的作品,如《囚徒》、《致大海》、《致凯恩》和《假如生活欺骗了你》等几十首抒情诗,叙事诗《努林伯爵》,历史剧《鲍里斯·戈都诺夫》,以及《叶甫盖尼·奥涅金》前六章。", "普希金创作的叙事诗叫什么"]
]
#页面最后的信息,可以选择引用文章,支持md格式
article = "感兴趣的小伙伴可以阅读[gradio专栏]()"
gr.Interface.from_pipeline(
pipeline("question-answering", model="uer/roberta-base-chinese-extractive-qa"),
title=title, description=description, examples=examples, article=article).launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
运行上述代码,将看到如下页面,这里的 example 是可以点击的,点击后将自动填充至 context 和 question 中
由于 description 和 article 字段支持 md 语法,因此我们可以根据需求,自行的去丰富完善各部分内容
Interface 使用详解
前面的内容中构建演示系统都是基于 pipeline 的,各个部分的模块都是定义好的,快速启动的同时,在灵活性上有所欠缺。
简单的说,就需要两步:
第一步,定义执行函数;
第二步,绑定执行函数并指定输入输出组件。
假设还是阅读理解任务,但是我们这次不适用基于 pipeline 的加载方式,而是自定义实现,要求输入包含 context、question,输出包含 answer 和 score,但是这里的 answer 要求要把问题拼接上,如前面的示例,answer 为普希金,这里的答案要变为:著名诗歌《假如生活欺骗了你》的作者是:普希金 ,针对这一需求,我们看下要如何实现。
首先,定义执行函数。该函数输入包括 context 和 question 两部分,输出包括 answer 和 score,本质上还是调用 pipeline 进行推理,但是在答案生成时我们做了额外的拼接处理。
qa = pipeline("question-answering", model="uer/roberta-base-chinese-extractive-qa")
def custom_predict(context, question):
answer_result = qa(context=context, question=question)
answer = question + ": " + answer_result["answer"]
score = answer_result["score"]
return answer, score
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
接下来,在 Interface 中绑定执行函数并指定输入输出组件,fn 字段绑定执行函数;inputs 字段指定输入组件,这里是 context 和 question 两个文本输入,因此 inputs 字段的值为[“text”, “text”]数组(这里的 text 表示输入组件为 TextBox,text 只是一种便捷的指定方式);outputs 字段指定输出组件,answer 是文本输出,score 可以用标签输出,这里采取了和 inputs 字段不一样的创建方式,我们直接创建了对应的组件,这种方式的使用优势在于可以对组件进行更精细的配置,例如这里我们便分别指定了两个输出模块的 label 。
gr.Interface(fn=custom_predict, inputs=["text", "text"], outputs=[gr.Textbox(label="answer"), gr.Label(label="score")],
title=title, description=description, examples=examples, article=article).launch()
- 1.
- 2.
注意点:
输入输出要与函数的输入输出个数一致
outputs 字段,推荐使用创建的方式,否则页面显示的标签都是 output*,不够清晰
完整代码:
import gradio as gr
from transformers import *
#标题
title = "抽取式问答"
#题下的描述,支持md格式
description = "输入上下文与问题后,点击submit按钮,可从上下文中抽取出答案,赶快试试吧!"
#输入样例
examples = [
["普希金从那里学习人民的语言,吸取了许多有益的养料,这一切对普希金后来的创作产生了很大的影响。这两年里,普希金创作了不少优秀的作品,如《囚徒》、《致大海》、《致凯恩》和《假如生活欺骗了你》等几十首抒情诗,叙事诗《努林伯爵》,历史剧《鲍里斯·戈都诺夫》,以及《叶甫盖尼·奥涅金》前六章。", "著名诗歌《假如生活欺骗了你》的作者是"],
["普希金从那里学习人民的语言,吸取了许多有益的养料,这一切对普希金后来的创作产生了很大的影响。这两年里,普希金创作了不少优秀的作品,如《囚徒》、《致大海》、《致凯恩》和《假如生活欺骗了你》等几十首抒情诗,叙事诗《努林伯爵》,历史剧《鲍里斯·戈都诺夫》,以及《叶甫盖尼·奥涅金》前六章。", "普希金创作的叙事诗叫什么"]
]
#页面最后的信息,可以选择引用文章,支持md格式
article = "感兴趣的小伙伴可以阅读[gradio专栏]()"
qa = pipeline("question-answering", model="uer/roberta-base-chinese-extractive-qa")
def custom_predict(context, question):
answer_result = qa(context=context, question=question)
answer = question + ": " + answer_result["answer"]
score = answer_result["score"]
return answer, score
gr.Interface(fn=custom_predict, inputs=["text", "text"], outputs=[gr.Textbox(label="answer"), gr.Label(label="score")],
title=title, description=description, examples=examples, article=article).launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
可以看到,其他的部分与我们使用 pipeline 创建的方式都一致,只是在 answer 部分有了变化。通过这种方式,我们可以创建出更加复杂的包含任意输入、输出的系统。
Blocks 使用详解
事实上,Interface 是一个更加高级的组件,虽然它已经支持了了一定的自定义内容,但是灵活性还是略差一些,如果有注意的话,可以回到上文看下,所有的组件都是被划分为了左右两部分,左侧输入,右侧输出。使用 Interface 就要接受这样的默认设定,那么假设你现在就想做成上下结构,上面输入,下面输出,那么,我们就需要用到 Block。
Blocks 是比 Interface 更加底层一些的模块,支持一些简单的自定义排版,那么下面就让我们来重构一下上面组件排列。整体是上下结构,从上到下,依次是 context 输入、question 输入,clear 按钮和 submit 按钮(在一横排),answer 输出,score 输出,其余如 title、examples 等内容不变,代码如下
import gradio as gr
from transformers import *
title = "抽取式问答"
description = "输入上下文与问题后,点击submit按钮,可从上下文中抽取出答案,赶快试试吧!"
examples = [
["普希金从那里学习人民的语言,吸取了许多有益的养料,这一切对普希金后来的创作产生了很大的影响。这两年里,普希金创作了不少优秀的作品,如《囚徒》、《致大海》、《致凯恩》和《假如生活欺骗了你》等几十首抒情诗,叙事诗《努林伯爵》,历史剧《鲍里斯·戈都诺夫》,以及《叶甫盖尼·奥涅金》前六章。", "著名诗歌《假如生活欺骗了你》的作者是"],
["普希金从那里学习人民的语言,吸取了许多有益的养料,这一切对普希金后来的创作产生了很大的影响。这两年里,普希金创作了不少优秀的作品,如《囚徒》、《致大海》、《致凯恩》和《假如生活欺骗了你》等几十首抒情诗,叙事诗《努林伯爵》,历史剧《鲍里斯·戈都诺夫》,以及《叶甫盖尼·奥涅金》前六章。", "普希金创作的叙事诗叫什么"]
]
article = "感兴趣的小伙伴可以阅读实用指南]()"
#预测函数
qa = pipeline("question-answering", model="uer/roberta-base-chinese-extractive-qa")
def custom_predict(context, question):
answer_result = qa(context=context, question=question)
answer = question + ": " + answer_result["answer"]
score = answer_result["score"]
return answer, score
#清除输入输出
def clear_input():
return "", "", "", ""
#构建Blocks上下文
with gr.Blocks() as demo:
gr.Markdown("# 抽取式问答")
gr.Markdown("输入上下文与问题后,点击submit按钮,可从上下文中抽取出答案,赶快试试吧!")
with gr.Column(): # 列排列
context = gr.Textbox(label="context")
question = gr.Textbox(label="question")
with gr.Row(): # 行排列
clear = gr.Button("clear")
submit = gr.Button("submit")
with gr.Column(): # 列排列
answer = gr.Textbox(label="answer")
score = gr.Label(label="score")
#绑定submit点击函数
submit.click(fn=custom_predict, inputs=[context, question], outputs=[answer, score])
# 绑定clear点击函数
clear.click(fn=clear_input, inputs=[], outputs=[context, question, answer, score])
gr.Examples(examples, inputs=[context, question])
gr.Markdown("感兴趣的小伙伴可以阅读实用指南]()")
demo.launch()
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
当我们的服务启动起来后,还是在本地的,虽然访问是能访问了,但是还是会受到网络的限制。Gradio 提供了一种非常方便的方式,可以使得本地的服务在任何地方都可以调用。代码上,我们只需要在 launch 方法调用时,指定 share 参数值为 True。服务除了有一个本地地址,还有一个公网的地址https://11886.gradio.app,虽然时间只有72小时
demo.launch(inbrowser=True, inline=False, validate=False, share=True)
- 1.
inbrowser - 模型是否应在新的浏览器窗口中启动。
inline - 模型是否应该嵌入在交互式 python 环境中(如 jupyter notebooks 或 colab notebooks)。
validate - gradio 是否应该在启动之前尝试验证接口模型兼容性。
share - 是否应创建共享模型的公共链接。用于处理。
Gradio-Lite: 完全在浏览器里运行的无服务器 Gradio
Gradio 是一个经常用于创建交互式机器学习应用的 Python 库。在以前按照传统方法,如果想对外分享 Gradio 应用,就需要依赖服务器设备和相关资源,而这对于自己部署的开发人员来说并不友好。
欢迎 Gradio-lite ( @gradio/lite ): 一个通过 Pyodide 1 在浏览器中直接运行 Gradio 的库。在本文中,我们会详细介绍 @gradio/lite 是什么,然后浏览示例代码,并与您讨论使用 Gradio-lite 运行 Gradio 应用所带来的优势。
@gradio/lite 是什么?
@gradio/lite 是一个 JavaScript 库,可以使开发人员直接在 Web 浏览器中运行 Gradio 应用,它通过 Pyodide 来实现这一能力。Pyodide 是可以将 Python 代码在浏览器环境中解释执行的 WebAssembly 专用 Python 运行时。有了 @gradio/lite ,你可以 使用常规的 Python 代码编写 Gradio 应用 ,它将不再需要服务端基础设施,可以 顺畅地在浏览器中运行 。
开始使用
让我们用 @gradio/lite 来构建一个 “Hello World” Gradio 应用。
- 导入 JS 和 CSS
首先如果没有现成的 HTML 文件,需要创建一个新的。添加以下代码导入与 @gradio/lite 包对应的 JavaScript 和 CSS:
<html>
<head>
<script type="module" crossorigin src="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.css" />
</head>
</html>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
通常来说你应该使用最新版本的 @gradio/lite ,可以前往 查看可用版本信息。
- 创建 标签
在你的 HTML 页面的 body 中某处 (你希望 Gradio 应用渲染显示的地方),创建开闭配对的 标签。
<html>
<head>
<script type="module" crossorigin src="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.css" />
</head>
<body>
<gradio-lite>
</gradio-lite>
</body>
</html>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
注意: 你可以将 theme 属性添加到 标签中,从而强制使用深色或浅色主题 (默认情况下它遵循系统主题)。例如:
<gradio-lite theme="dark">
...
</gradio-lite>
- 1.
- 2.
- 3.
- 在标签内编写 Gradio 应用
现在就可以像平常一样用 Python 编写 Gradio 应用了!但是一定要注意,由于这是 Python 所以空格和缩进很重要。
<html>
<head>
<script type="module" crossorigin src="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.css" />
</head>
<body>
<gradio-lite>
import gradio as gr
def greet(name):
return "Hello, " + name + "!"
gr.Interface(greet, "textbox", "textbox").launch()
</gradio-lite>
</body>
</html>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
基本的流程就是这样!现在你应该能够在浏览器中打开 HTML 页面,并看到刚才编写的 Gradio 应用了!只不过由于 Pyodide 需要花一些时间在浏览器中安装,初始加载 Gradio 应用可能需要一段时间。
调试提示: 所有错误 (包括 Python 错误) 都将打印到浏览器中的检查器控制台中,所以如果要查看 Gradio-lite 应用中的任何错误,请打开浏览器的检查器工具 (inspector)。
更多例子: 添加额外的文件和依赖
如果想要创建一个跨多个文件或具有自定义 Python 依赖的 Gradio 应用怎么办?通过 @gradio/lite 也可以实现!
多个文件
在 @gradio/lite 应用中添加多个文件非常简单: 使用 标签。你可以创建任意多个 标签,但每个标签都需要一个 name 属性,Gradio 应用的入口点应添加 entrypoint 属性。
下面是一个例子:
<gradio-lite>
<gradio-file name="app.py" entrypoint>
import gradio as gr
from utils import add
demo = gr.Interface(fn=add, inputs=["number", "number"], outputs="number")
demo.launch()
</gradio-file>
<gradio-file name="utils.py" >
def add(a, b):
return a + b
</gradio-file>
</gradio-lite>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
额外的依赖项
如果 Gradio 应用有其他依赖项,通常可以 使用 micropip 在浏览器中安装它们。我们创建了一层封装使得这个过程更加便捷了: 你只需用与 requirements.txt 相同的语法列出依赖信息,并用 标签包围它们即可。
在这里我们安装 transformers_js_py 来尝试直接在浏览器中运行文本分类模型!
<gradio-lite>
<gradio-requirements>
transformers_js_py
</gradio-requirements>
<gradio-file name="app.py" entrypoint>
from transformers_js import import_transformers_js
import gradio as gr
transformers = await import_transformers_js()
pipeline = transformers.pipeline
pipe = await pipeline('sentiment-analysis')
async def classify(text):
return await pipe(text)
demo = gr.Interface(classify, "textbox", "json")
demo.launch()
</gradio-file>
</gradio-lite>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
试一试: 你可以在 这个 Hugging Face Static Space 中看到上述示例,它允许你免费托管静态 (无服务器) Web 应用。访问此页面,即使离线你也能运行机器学习模型!
使用 @gradio/lite 的优势
- 无服务器部署
@gradio/lite 的主要优势在于它消除了对服务器基础设施的需求。这简化了 Gradio 应用的部署,减少了与服务器相关的成本,并且让分享 Gradio 应用变得更加容易。 - 低延迟
通过在浏览器中运行,@gradio/lite 能够为用户带来低延迟的交互体验。因为数据无需与服务器往复传输,这带来了更快的响应和更流畅的用户体验。 - 隐私和安全性
由于所有处理均在用户的浏览器内进行,所以 @gradio/lite 增强了隐私和安全性,用户数据保留在其个人设备上,让大家处理数据更加放心~
限制
目前, 使用 @gradio/lite 的最大缺点在于 Gradio 应用通常需要更长时间 (通常是 5-15 秒) 在浏览器中初始化。这是因为浏览器需要先加载 Pyodide 运行时,随后才能渲染 Python 代码。
并非所有 Python 包都受 Pyodide 支持。虽然 gradio 和许多其他流行包 (包括 numpy 、 scikit-learn 和 transformers-js ) 都可以在 Pyodide 中安装,但如果你的应用有许多依赖项,那么最好检查一下它们是否包含在 Pyodide 中,或者 通过 micropip 安装。
心动不如行动!
要想立刻尝试 @gradio/lite ,您可以复制并粘贴此代码到本地的 index.html 文件中,然后使用浏览器打开它:
<html>
<head>
<script type="module" crossorigin src="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.css" />
</head>
<body>
<gradio-lite>
import gradio as gr
def greet(name):
return "Hello, " + name + "!"
gr.Interface(greet, "textbox", "textbox").launch()
</gradio-lite>
</body>
</html>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
在 Gradio 网站上创建了一个 playground,你可以在那里交互式编辑代码然后即时看到结果!
Playground 地址: https://www.gradio.app/playground