上一篇文章是介绍了安装与使用,Gradio的web界面演示与交互机器学习模型,安装和使用《1》
了解到这个gradio,真是个贴心的产品,接下来更多的关注一些重要的细节特征,让我们去更完善和熟练的使用它。
1、简单计算器的示例
我们可以先直接运行代码,看下效果
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("不能除以0")
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="简单计算器",
description="简单的计算器例子,下面还有示例可以点击试用",
)
demo.launch()
比前面介绍的参数多了一些:
examples:表示里面可以写一些示例,这样用户点击这些示例就可以直接进行测试,不需要手动输入了。
title:程序的标题
description:程序的一些说明
其中在calculator函数中出现有,raise gr.Error("不能除以0")这样的自定义错误,对用户还是比较友好的,不然就是一个Error,可能用户不知道问题错在哪儿。
可以看出新增的这三个参数都更好地帮助用户去理解和使用你的应用。
当然为了更好的提示用户,我们还可以将第二个文本框"number"修改成gr.Number(label="数字",info="如果为除数,不要输入0")
这样更直观的告知用户,也就直接避免了除以0的错误等浪费时间的情况出现了。
2、标志
默认情况下,一个接口将有flag“标志”按钮,就是那个输出按钮。当用户测试您的界面时,看到输入带有有趣的输出,例如错误或意外的模型行为,他们可以标记输入以供您检查。由flaging_dir = 参数提供给Interface构造函数的目录中,一个CSV文件将记录标记的输入。如果接口涉及文件数据,例如Image和Audio组件,则将创建文件夹来存储这些标记的数据。
比如,我们点击上面演示的计算器的输出按钮flag
那么就会将这些输入输出的信息给保存在csv文件里面,这个文件在flagged文件夹中。如果输入输出是图片的话,将有输入输出的文件夹来分别保存它们各自的图片。
图中就是当前位置的flagged文件夹,打开log.csv文件的内容,这个对于一些调试的反馈可以起到一定的作用,帮助我们改进这个应用。
3、样式
界面的美观和一些重点样式显示还是很有必要的,想要在gradio中修改样式,最简单的方法就是主题,里面定义了一些自带主题,我们可以先来查看下:
print(dir(gr.themes))
#['Base', 'Color', 'Default', 'Font', 'Glass', 'GoogleFont', 'Monochrome', 'Size', 'Soft', 'ThemeClass', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'base', 'builder', 'colors', 'default', 'glass', 'monochrome', 'sizes', 'soft', 'utils']
我们使用其中一个看下效果会是怎么样的(也是属于Interface中的参数):
theme=gr.themes.Soft()
鼠标经过示例也会进行高亮显示。
这些是做好的主题,也可以做额外的样式,比如设置整个容器框的背景色css=".gradio-container {background-color: #445566}"
4、队列
如果你的应用预计流量很大,使用queue()方法来控制处理速率。这将调用队列,以便一次只处理一定数量的请求。队列使用websockets,这也可以防止网络超时,所以如果你的函数的推理时间很长(> 1分钟),你应该使用队列。
用法很简单,分别在Interface和Blocks中的应用,其实是一样的,启动前加一个queue():
demo = gr.Interface(...).queue()
demo.launch()
with gr.Blocks() as demo:
#...
demo.queue()
demo.launch()
当然也可以控制一次处理的请求数量:demo.queue(concurrency_count=3)
也可以只指定某些函数在block中排队:
import gradio as gr
with gr.Blocks() as demo2:
num1 = gr.Number()
num2 = gr.Number()
output = gr.Number()
gr.Button("Add").click(
lambda a, b: a + b, [num1, num2], output)
gr.Button("Multiply").click(
lambda a, b: a * b, [num1, num2], output, queue=True)
demo2.queue()
demo2.launch()
这里就是对乘法做队列的意思,使用了匿名函数,同样的输入是两个,对应着参数是两个。
5、迭代输出
所谓迭代输出就是说,不是一次性显示出来,而是将过程也显示出来,比如,ChatGPT提问之后的答案就是每次几个词这样的输出,或者是Midjourney生成图片的时候,也不是一次性输出,而是从模糊到清晰再到最终图片的一个过程都显示出来。
那么我们这里就不使用常规函数,还是用Gradio提供的生成器函数,就是说让函数产生一系列的值,而不是单个返回值。
通常做法是将yield语句放入某种循环中。这里我们就模拟类似Midjourney生成图像的一个过程:
import gradio as gr
import numpy as np
import time
def fake_diffusion(steps):
for _ in range(steps):
time.sleep(1)
image = np.random.random((200, 200, 3))
yield image
image = "https://gradio-builds.s3.amazonaws.com/diffusion_image/cute_dog.jpg"
yield image
#官方例子这里的滑动块是浮点数,需要整数,不然迭代次数出错,加一个step,每次是1即可
demo = gr.Interface(fake_diffusion, inputs=gr.Slider(1, 10, 3,step=1), outputs="image")
demo.queue()
demo.launch()
滑动块每次滑动就是1为整数的步进,输入的数量就是上面函数迭代几次随机图像(彩色噪点,模拟生成图像的过程),通过yield来做生成器,将生成过程反馈到界面。动态图如下:
6、进度条
对于比较耗时的操作,我们使用进度条来让用户知道进展情况,这里也是使用Progress中tqdm方法,在以前的文章:Python中tqdm进度条的详细介绍(安装程序与耗时的迭代)有更详细的介绍,有兴趣的可以点击进去看看。
import gradio as gr
import time
def slowly_reverse(word,progress=gr.Progress()):
progress(0, desc="开始...")
time.sleep(1)
progress(0.05)
new_string = ""
for letter in progress.tqdm(word, desc="反转中..."):
time.sleep(0.25)
new_string = letter + new_string
return new_string
demo = gr.Interface(slowly_reverse, gr.Text(), gr.Text())
if __name__ == "__main__":
demo.queue(concurrency_count=10).launch()
做了一个动态图演示如下:
7、批处理
Gradio支持传递批处理函数的能力。批处理函数就是接受一组输入并返回一组预测的函数。
7.1、Interfacce示例
import gradio as gr
import time
def trim_words(words, lens):
trimmed_words = []
time.sleep(5)
for w, l in zip(words, lens):
trimmed_words.append(w[:int(l)])
return [trimmed_words]
demo = gr.Interface(trim_words, ["textbox", "number"], "textbox", batch=True, max_batch_size=16)
demo.queue()
demo.launch()
7.2、Blocks示例
import gradio as gr
with gr.Blocks() as demo:
with gr.Row():
word = gr.Textbox(label="word")
leng = gr.Number(label="leng")
output = gr.Textbox(label="Output")
with gr.Row():
run = gr.Button()
event = run.click(trim_words, [word, leng], output, batch=True, max_batch_size=16)
demo.queue()
demo.launch()
从例子中看到,可以并行处理16个请求(总推理时间为5秒),而不是单独处理每个请求(总推理时间为80秒)。