Gradio 是一种使用简单直观的 Python API 测试和演示机器学习应用的好方法。结合 Modal 以开发者为先的云基础设施,您可以利用强大的 GPU 更快地运行大型模型。而且您不需要云服务提供商的账户,也不需要任何配置文件。
在本教程中,我们将引导您设置一个 Modal 账户,在 Modal 上部署一个简单的 Gradio 应用,并讨论 Gradio 粘性会话要求和处理并发性的一些细节。
让我们部署一个 Gradio 风格的“Hello, world”应用,它允许用户输入他们的名字,然后回复一个简短的问候语。我们不会在应用中原样使用此代码,但了解最初的 Gradio 版本是什么样子很有用。
import gradio as gr
# A simple Gradio interface for a greeting function
def greet(name):
return f"Hello {name}!"
demo = gr.Interface(fn=greet, inputs="text", outputs="text")
demo.launch()要在 Modal 上部署此应用,您需要
在开始之前,如果您还没有 Modal 账户,则需要创建一个。然后您可以使用这些账户凭据进行身份验证来设置您的环境。
pip install modalmodal setup太棒了,现在我们可以开始构建我们的应用了!
modal.Image首先,让我们创建一个名为 gradio_app.py 的新文件,导入 modal,并定义我们的镜像。Modal Images 是通过对我们的 Image 实例顺序调用方法来定义的。
对于这个简单的应用,我们将
debian_slim 镜像开始,fastapi 和 gradio。import modal
app = modal.App("gradio-app")
web_image = modal.Image.debian_slim(python_version="3.12").uv_pip_install(
"fastapi[standard]",
"gradio",
)请注意,您不需要在本地环境中安装 gradio 或 fastapi——本地只需要 modal。
像许多 Gradio 应用一样,上面的示例通过在脚本末尾对我们的演示调用 launch() 来运行。然而,Modal 运行的是函数,而不是脚本——准确地说是无服务器函数。
为了让 Modal 来提供我们的 demo 服务,我们可以利用 Gradio 和 Modal 对 fastapi 应用的支持。我们使用 @modal.asgi_app() 函数装饰器来部署该函数返回的 Web 应用。我们使用 mount_gradio_app 函数将 Gradio demo 作为路由添加到 Web 应用中。
with web_image.imports():
import gradio as gr
from gradio.routes import mount_gradio_app
from fastapi import FastAPI
@app.function(
image=web_image,
max_containers = 1, # we'll come to this later
)
@modal.concurrent(max_inputs=100) # allow multiple users at one time
@modal.asgi_app()
def ui():
"""A simple Gradio interface for a greeting function."""
def greet(name):
return f"Hello {name}!"
demo = gr.Interface(fn=greet, inputs="text", outputs="text")
return mount_gradio_app(app=FastAPI(), blocks=demo, path="/")让我们快速回顾一下这里发生了什么
Image.imports 上下文管理器来定义我们的导入。当您的函数在云中运行时,这些导入将可用。ui 中,并用 @app.function 装饰它,将其封装为 Modal 无服务器函数。我们将镜像和其他参数(我们稍后会讨论)作为输入提供给装饰器。@modal.concurrent 装饰器,它允许每个容器同时处理多个请求。@modal.asgi_app 装饰器,它告诉 Modal 这个特定的函数正在提供一个 ASGI 应用(这里是一个 fastapi 应用)。要使用此装饰器,您的 ASGI 应用需要作为函数的返回值。要部署应用,只需运行以下命令
modal deploy <path-to-file>第一次运行应用时,Modal 将构建并缓存镜像,这大约需要 30 秒。只要您不更改镜像,后续部署只需几秒钟。
镜像构建完成后,Modal 将打印您的 Web 应用 URL 和 Modal 仪表板 URL。Web 应用 URL 应类似于 https://{workspace}-{environment}--gradio-app-ui.modal.run。将其粘贴到 Web 浏览器中并试用您的应用!
Modal Function 是无服务器的,这意味着每个客户端请求都是独立的。虽然这有助于自动扩展,但如果您的应用需要某种服务器端状态,则需要格外小心。
Gradio 依赖于 REST API,它本身是无状态的。但它确实需要粘性会话,这意味着来自特定客户端的每个请求都必须路由到同一个容器。然而,Modal 在这方面不做任何保证。
满足此约束的一种简单方法是在 @app.function 装饰器中设置 max_containers = 1,并将 @modal.concurrent 的 max_inputs 参数设置为一个相当大的数字——就像我们上面所做的那样。这意味着 Modal 不会启动超过一个容器来为您的应用提供请求服务,这有效地满足了粘性会话要求。
Gradio 和 Modal 都有并发性和队列的概念,要充分利用您的计算资源,需要了解它们如何相互作用。
Modal 将客户端请求排队到每个已部署的 Function,并同时执行请求,直到达到该 Function 的并发限制。如果请求传入且并发限制已满足,Modal 将启动一个新的容器——直到达到为该 Function 设置的最大值。在我们的案例中,我们的 Gradio 应用由一个 Modal Function 表示,因此所有请求共享一个队列和并发限制。因此,Modal 限制了运行时请求的总数,无论它们在做什么。
另一方面,Gradio 允许开发者使用多个队列,每个队列都有自己的并发限制。然后可以将一个或多个事件监听器分配给一个队列,这对于管理计算开销大的请求的 GPU 资源非常有用。
仔细思考这些队列和限制如何相互作用,可以帮助您优化应用的性能和资源利用率,同时避免共享或丢失状态等不良结果。
管理 GPU 利用率的另一种选择是将您的 GPU 计算部署在它们自己的 Modal Function 中,并从 Gradio 应用内部调用此远程 Function。这使您可以充分利用 Modal 的无服务器自动扩展功能,同时将所有客户端 HTTP 请求路由到单个 Gradio CPU 容器。