ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Ray Serve 部署 Stable Diffusion 图像生成服务:从模型加载到弹性伸缩的完整实战

Ray Serve 部署 Stable Diffusion 图像生成服务:从模型加载到弹性伸缩的完整实战 Ray Serve 部署 Stable Diffusion 图像生成服务从模型加载到弹性伸缩的完整实战【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray导读本文基于 Ray 官方仓库中的 Stable Diffusion 教程doc/source/serve/tutorials/stable-diffusion.md完整讲解如何用 Ray Serve 将一个 Stable Diffusion XL 图像生成模型封装为 HTTP 服务。你将学会用 FastAPI 定义/imagine接口、用 DeploymentHandle 串联入口 模型两个 Deployment、通过serve run一条命令启动服务以及利用min_replicas: 0的自动伸缩配置在 GPU 上实现无请求不占资源、有请求自动拉起的按需推理。文中代码与配置均取自仓库中的 stable_diffusion.py并辅以 Serve 源码佐证其底层机制。1. 示例概览与架构这个示例在 Ray Serve 上运行一个 Stable Diffusion 图像生成应用。它由两个 Deployment 组成APIIngress基于 FastAPI 的 HTTP 入口接收用户的 prompt 请求并把推理任务转发给下游模型 DeploymentStableDiffusionXL真正持有 SDXL 模型的 GPU 推理 Deployment负责执行文生图text-to-image扩散采样。两者通过DeploymentHandle以远程调用的方式协作入口与模型解耦模型层可以独立水平扩展。整个应用以APIIngress.bind(StableDiffusionXL.bind())组合成一个 Serve Application启动后对外暴露http://127.0.0.1:8000/imagine接口。本示例使用的模型为stabilityai/stable-diffusion-xl-base-1.0Web 框架为 FastAPI。2. 环境安装运行本示例需要先安装 Ray Serve 以及推理相关的依赖pip install ray[serve] requests torch diffusers0.35.2 transformers各依赖的职责如下依赖用途ray[serve]Ray 分布式运行时与 Serve 组件requests客户端发送 HTTP 请求、下载结果图片torch深度学习框架驱动扩散模型推理diffusers0.35.2Hugging Face 扩散模型管线DiffusionPipelinetransformers加载 SDXL 所需的文本编码器等模型组件注意示例代码在 2023 年编写当时依赖为diffusers0.33.1、transformers4.51.3见 stable_diffusion.py 中__main__的 runtime_env 写法。教程正文指定了diffusers0.35.2实际运行时请以你所用 Ray 版本兼容的依赖组合为准。推理需要一张可用的 CUDA GPU。将下面第 3 节中的代码保存为stable_diffusion.py即可按第 4 节方式启动。3. 代码逐段解析完整示例代码位于 doc/source/serve/doc_code/stable_diffusion.py这里按职责拆解。3.1 导入与 FastAPI 入口APIIngressfrom io import BytesIO from fastapi import FastAPI from fastapi.responses import Response import torch from ray import serve from ray.serve.handle import DeploymentHandle app FastAPI() serve.deployment(num_replicas1) serve.ingress(app) class APIIngress: def __init__(self, diffusion_model_handle: DeploymentHandle) - None: self.handle diffusion_model_handle app.get( /imagine, responses{200: {content: {image/png: {}}}}, response_classResponse, ) async def generate(self, prompt: str, img_size: int 512): assert len(prompt), prompt parameter cannot be empty image await self.handle.generate.remote(prompt, img_sizeimg_size) file_stream BytesIO() image.save(file_stream, PNG) return Response(contentfile_stream.getvalue(), media_typeimage/png)几个关键点serve.deployment(num_replicas1)声明该 Deployment 固定 1 个副本作为轻量入口无需伸缩serve.ingress(app)把 FastAPI 应用挂到 Deployment 上。源码中该装饰器的定义见 python/ray/serve/api.py其作用是把 ASGI 应用包装进 Deployment用于解析 HTTP 请求构造函数接收一个DeploymentHandle类型的参数——这是 Ray Serve 注入子 Deployment 句柄的约定写法。DeploymentHandle类定义见 python/ray/serve/handle.pyawait self.handle.generate.remote(prompt, img_sizeimg_size)通过 handle 异步调用下游StableDiffusionXL.generate方法remote()返回的是一个可等待对象await后得到 PIL Image接口响应头声明image/png媒体类型最终把 PNG 二进制作为 HTTP 响应体返回。3.2 GPU 推理模型StableDiffusionXLserve.deployment( ray_actor_options{num_gpus: 1}, autoscaling_config{min_replicas: 0, max_replicas: 2}, ) class StableDiffusionXL: def __init__(self): from diffusers import DiffusionPipeline model_id stabilityai/stable-diffusion-xl-base-1.0 self.pipe DiffusionPipeline.from_pretrained( model_id, torch_dtypetorch.float16, variantfp16, use_safetensorsTrue ) self.pipe self.pipe.to(cuda) def generate(self, prompt: str, img_size: int 512): assert len(prompt), prompt parameter cannot be empty with torch.autocast(cuda): image self.pipe(prompt, heightimg_size, widthimg_size).images[0] return image关键点ray_actor_options{num_gpus: 1}要求每个副本占用 1 张 GPU。Serve 会将该字段传递给 Ray Actor 的调度选项源码见 python/ray/serve/deployment.py 的ray_actor_options属性autoscaling_config{min_replicas: 0, max_replicas: 2}启用自动伸缩副本数在 02 之间按流量动态调整详见第 5 节模型加载使用 FP16 精度torch_dtypetorch.float16并指定variantfp16下载官方 fp16 权重、use_safetensorsTrue使用 safetensors 格式兼顾显存占用与加载安全generate在torch.autocast(cuda)上下文里执行一次扩散采样返回self.pipe(...).images[0]这张 PIL 图像。3.3 组装应用entrypoint APIIngress.bind(StableDiffusionXL.bind())bind()把 Deployment 类实例化为一个带参数的 Application 蓝图嵌套的bind表达依赖关系APIIngress 在启动时自动拿到 StableDiffusionXL 的 DeploymentHandle。4. 启动服务serve run在stable_diffusion.py所在目录执行serve run stable_diffusion:entrypointserve run是 Ray Serve 的命令行入口其实现位于 python/ray/serve/scripts.py。该命令会解析module:attribute形式的导入路径导入stable_diffusion模块并取到entrypoint若 Ray 尚未初始化自动执行ray.init(...)源码见 scripts.py启动 Serve 控制器与 HTTP 代理默认监听127.0.0.1:8000部署应用并阻塞等待方便观察日志。serve run还支持--runtime-env、--working-dir、--route-prefix、--name等选项见 scripts.py例如可指定--name my-sdxl为应用命名也可以传入一个 Serve config YAML 文件来声明多应用与 HTTP 选项。启动成功后终端会输出类似下面的日志(ServeController pid362, ip10.0.44.233) INFO 2023-03-08 16:44:57,579 controller 362 http_state.py:129 - Starting HTTP proxy with name SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-7396d5a9efdb59ee01b7befba448433f6c6fc734cfa5421d415da1b3 on node 7396d5a9efdb59ee01b7befba448433f6c6fc734cfa5421d415da1b3 listening on 127.0.0.1:8000 (ServeController pid362, ip10.0.44.233) INFO 2023-03-08 16:44:57,588 controller 362 http_state.py:133 - Starting HTTP proxy with name SERVE_CONTROLLER_ACTOR:SERVE_PROXY_ACTOR-a30ea53938547e0bf88ce8672e578f0067be26a7e26d23465c46300b on node a30ea53938547e0bf88ce8672e578f0067be26a7e26d23465c46300b listening on 127.0.0.1:8000 (ProxyActor pid439, ip10.0.44.233) INFO: Started server process [439] (ProxyActor pid5779) INFO: Started server process [5779] (ServeController pid362, ip10.0.44.233) INFO 2023-03-08 16:44:59,362 controller 362 deployment_state.py:1333 - Adding 1 replica to deployment APIIngress. 2023-03-08 16:45:01,316 SUCC string:93 -- Deployed Serve app successfully.日志要点Starting HTTP proxy ... listening on 127.0.0.1:8000HTTP 代理已在 8000 端口就绪Adding 1 replica to deployment APIIngress控制器开始为入口 Deployment 创建副本Deployed Serve app successfully.应用部署成功可以开始接收请求。5. 从 0 到 1 的 GPU 自动伸缩核心机制教程特别强调了一个设计autoscaling_config将min_replicas设为 0意味着StableDiffusionXL初始没有任何副本只有当请求真正到达时才会拉起副本当一段时间没有请求时Serve 会把它缩回 0 个副本以释放 GPU 资源。这套机制在源码中的落点是AutoscalingConfig类python/ray/serve/config.py相关字段说明字段默认值作用min_replicas1最小副本数设为 0 表示允许缩容到零scale-to-zeromax_replicas1最大副本数必须不小于min_replicastarget_ongoing_requests2每个副本的目标并发请求数含排队缩放器以此为依据决定扩缩容look_back_period_s30.0指标聚合的回看时间窗口upscale_delay_s30.0检测到需要扩容后等待的秒数防止抖动downscale_delay_s600.0缩容到 0 的值前的等待秒数downscale_to_zero_delay_sNone从 1 缩到 0 前的等待秒数不设则沿用downscale_delay_supscaling_factor/downscaling_factorNone每次扩容/缩容决策的乘性增益系数抑制震荡当min_replicas0时Autoscaler 周期性地聚合回看窗口内的请求指标与target_ongoing_requests比较后把副本数调整到 02 之间逻辑见 python/ray/serve/_private/application_state.py 中AutoscalingConfig(**new_config)的装配。值得注意的是缩容到 0 虽然省 GPU但恢复服务时会引入冷启动延迟——重新拉起副本需要重新加载 SDXL 模型数 GB 权重首次请求会明显变慢。因此该模式适合低频、突发型的调用场景。6. 发送请求并保存图片服务启动后用下面的 Python 代码发起推理请求import requests prompt a cute cat is dancing on the grass. input %20.join(prompt.split( )) resp requests.get(fhttp://127.0.0.1:8000/imagine?prompt{input}) with open(output.png, wb) as f: f.write(resp.content)说明因为接口通过 URL query 接收 prompt所以这里先把句子中的空格替换为%20编码避免中文/空格破坏 URL请求返回的响应体就是 PNG 图片的二进制内容直接写入output.png即可也可以携带可选参数img_size默认 512控制生成分辨率例如?prompt...img_size768该参数会原样传给generate()中的height/width。仓库中的示例文件在__main__分支里给出了完整自测流程stable_diffusion.py调用serve.run(entrypoint)后先通过 handle 远程触发一次推理预热再走 HTTP 拉取图片并断言output.png存在。这也可以作为不依赖 CLI、在脚本内直接部署 Serve 的参考写法——对应serve.run的 API 定义见 python/ray/serve/api.py。7. 小结与扩展建议通过本文你已经掌握了一条完整的SDXL 模型服务化链路两段式部署FastAPI 入口与 GPU 模型推理分离通过DeploymentHandle解耦一条命令上线serve run stable_diffusion:entrypoint即完成控制器启动、应用部署按需占用 GPUmin_replicas: 0实现 scale-to-zero兼顾成本与弹性。基于此模板可继续扩展的方向多模型/多尺寸为不同模型如 SD 1.5、SDXL-Turbo各建一个 Deployment入口按请求参数路由批处理与队列给generate增加 batch 逻辑利用max_ongoing_requests控制并发生产配置改用 Serve config YAMLserve run config.yaml管理多应用、HTTP 选项与日志配置客户端调用方式除 HTTP 外也可通过 DeploymentHandle 在 Python 内直接调用降低序列化开销。【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址: https://gitcode.com/gh_mirrors/ra/ray创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表