Gradio 月活用户突破 100 万!

阅读更多
Gradio logo
  1. 其他教程
  2. 设置演示以获得最佳性能

设置演示以获得最佳性能

假设你的 Gradio 演示在社交媒体上爆火——你有大量用户同时尝试使用它,并且你希望为你的用户提供最佳体验,或者换句话说,最大限度地减少每个用户在队列中等待看到预测结果的时间。

你如何配置你的 Gradio 演示以处理最大的流量?在本指南中,我们将深入探讨 Gradio 的 .queue() 方法的一些参数以及其他一些相关参数,并讨论如何设置这些参数,以便你可以同时为大量用户提供服务,并最大限度地减少延迟。

这是一份高级指南,因此请确保你已经了解 Gradio 的基础知识,例如如何创建和启动 Gradio Interface。无论你是在 Hugging Face Spaces 上还是在你自己的服务器上托管演示,本指南中的大多数信息都适用。

Gradio 队列系统概述

默认情况下,每个 Gradio 演示都包含一个内置的队列系统,可以扩展到数千个请求。当你的应用的用户提交请求(即向你的函数提交输入)时,Gradio 会将请求添加到队列中,并且请求通常按顺序处理(如下所述,这并不完全正确)。当用户的请求完成处理后,Gradio 服务器会使用服务器端事件 (SSE) 将结果返回给用户。与仅使用 HTTP POST 请求相比,SSE 协议有几个优点

(1)它们不会超时——如果大多数浏览器在短时间内(例如 1 分钟)没有收到对 POST 请求的响应,则会引发超时错误。如果你的推理函数运行时间超过 1 分钟,或者很多人同时尝试你的演示,从而导致延迟增加,这可能会成为问题。

(2)它们允许服务器向前端发送多个更新。这意味着,例如,服务器可以发送你的预测完成所需时间的实时 ETA。

要配置队列,只需在启动 InterfaceTabbedInterfaceChatInterface 或任何 Blocks 之前调用 .queue() 方法。这是一个示例

import gradio as gr

app = gr.Interface(lambda x:x, "image", "image")
app.queue()  # <-- Sets up a queue with default parameters
app.launch()

如何从队列中处理请求

当 Gradio 服务器启动时,会使用线程池来执行队列中的请求。默认情况下,此线程池的最大大小为 40(这是从 FastAPI 继承的默认值,Gradio 服务器基于 FastAPI)。但是,这意味着始终从队列中并行处理 40 个请求。

相反,Gradio 默认使用单函数单工作线程模型。这意味着每个工作线程仅分配一个来自你的 Gradio 应用中所有可能函数的函数。这确保你不会看到例如内存不足错误,因为多个工作线程同时调用机器学习模型。假设你的 Gradio 应用中有 3 个函数:A、B 和 C。你看到来自使用你的应用的用户的以下 7 个请求序列

1 2 3 4 5 6 7
-------------
A B A A C B A

最初,将分配 3 个工作线程来处理请求 1、2 和 5(对应于函数:A、B、C)。一旦这些工作线程中的任何一个完成,它们将开始处理队列中相同函数类型的下一个函数,例如,完成处理请求 1 的工作线程将开始处理请求 3,依此类推。

如果你想更改此行为,可以使用多个参数来配置队列并帮助减少延迟。让我们逐一介绍它们。

queue() 中的 default_concurrency_limit 参数

我们将探讨的第一个参数是 queue() 中的 default_concurrency_limit 参数。这控制了可以执行相同事件的工作线程数。默认情况下,这设置为 1,但你可以将其设置为更高的整数:210,甚至 None(在最后一种情况下,除了可用工作线程的总数外,没有限制)。

例如,如果你的 Gradio 应用不调用任何资源密集型函数,这将非常有用。如果你的应用仅查询外部 API,则可以将 default_concurrency_limit 设置得更高。增加此参数可以线性倍增你的服务器处理请求的能力

那么为什么不始终将此参数设置得更高呢?请记住,由于请求是并行处理的,因此每个请求都会消耗内存来存储数据和权重以进行处理。这意味着如果将 default_concurrency_limit 设置得太高,你可能会遇到内存不足错误。如果 default_concurrency_limit 太高,由于在不同工作线程之间切换的成本,你也可能开始获得递减的回报。

建议:尽可能提高 default_concurrency_limit 参数,同时继续看到性能提升,或者直到达到机器上的内存限制为止。你可以在此处阅读有关 Hugging Face Spaces 机器规格的信息

事件中的 concurrency_limit 参数

你还可以为每个事件单独设置可以并行处理的请求数。这些优先于先前描述的 default_concurrency_limit 参数。

为此,请设置任何事件监听器的 concurrency_limit 参数,例如 btn.click(..., concurrency_limit=20) 或在 InterfaceChatInterface 类中:例如 gr.Interface(..., concurrency_limit=20)。默认情况下,此参数设置为全局 default_concurrency_limit

launch() 中的 max_threads 参数

如果你的演示使用非异步函数,例如 def 而不是 async def,它们将在线程池中运行。此线程池的大小为 40,这意味着只能创建 40 个线程来运行你的非异步函数。如果你遇到此限制,可以使用 max_threads 增加线程池大小。默认值为 40。

提示: 您应该尽可能使用异步函数,以增加您的应用程序可以处理的并发请求数量。不占用大量 CPU 资源且快速的函数非常适合编写为 async 函数。 这篇指南 是关于这个概念的良好入门资料。

queue() 中的 max_size 参数

减少等待时间的更直接方式是阻止过多的人加入队列。您可以使用 queue()max_size 参数设置队列处理的最大请求数。如果请求到达时队列已达到最大容量,则该请求将不被允许加入队列,用户将收到队列已满且稍后重试的错误消息。默认情况下,max_size=None,这意味着加入队列的用户数量没有限制。

矛盾的是,设置 max_size 通常可以改善用户体验,因为它防止用户因过长的队列等待时间而感到沮丧。对您的演示更感兴趣和投入的用户将继续尝试加入队列,并且能够更快地获得结果。

建议:为了获得更好的用户体验,请根据您对用户愿意等待预测时间的合理预期,设置一个合理的 max_size 值。

事件中的 max_batch_size 参数

提高 Gradio 演示并行性的另一种方法是编写您的函数,使其可以接受批量输入。大多数深度学习模型可以比处理单个样本更有效地处理批量样本。

如果您编写的函数可以处理一批样本,Gradio 将自动将传入的请求批处理在一起,并将它们作为一批样本传递给您的函数。您需要将 batch 设置为 True (默认情况下为 False),并根据您的函数能够处理的最大样本数设置 max_batch_size (默认情况下为 4)。这两个参数可以传递给 gr.Interface() 或 Blocks 中的事件,例如 .click()

虽然设置批处理在概念上类似于让工作进程并行处理请求,但对于深度学习模型来说,它通常比设置 concurrency_count 更快。缺点是您可能需要稍微调整您的函数,使其接受批量样本而不是单个样本。

这是一个接受批量输入的函数的示例 - 它一次处理一个输入

import time

def trim_words(word, length):
    return word[:int(length)]

这是同一个函数被重写为接受一批样本

import time

def trim_words(words, lengths):
    trimmed_words = []
    for w, l in zip(words, lengths):
        trimmed_words.append(w[:int(l)])
    return [trimmed_words]

第二个函数可以与 batch=True 和适当的 max_batch_size 参数一起使用。

建议:如果可能,请将您的函数编写为接受批量样本,然后将 batch 设置为 True,并将 max_batch_size 设置为在您机器内存限制内尽可能高的值。

升级您的硬件(GPU、TPU 等)

如果您已完成上述所有操作,但您的演示仍然不够快,您可以升级模型运行所在的硬件。将模型从在 CPU 上运行更改为在 GPU 上运行,通常会使深度学习模型的推理时间提高 10 到 50 倍。

在 Hugging Face Spaces 上升级您的硬件尤其简单。只需单击您的 Space 中的“Settings(设置)”选项卡,然后选择您想要的 Space 硬件即可。

虽然您可能需要调整机器学习推理代码的部分内容以在 GPU 上运行(如果您使用的是 PyTorch,这是一个有用的指南),但 Gradio 完全不受硬件选择的影响,如果您将其与 CPU、GPU、TPU 或任何其他硬件一起使用,它也能完美运行!

注意:您的 GPU 内存与 CPU 内存不同,因此如果您升级硬件,您可能需要调整上面描述的 default_concurrency_limit 参数的值。

结论

恭喜!您现在知道如何设置 Gradio 演示以获得最佳性能。祝您的下一个爆款演示好运!