Serverless GPU 批量推理:分类与嵌入任务配置
讲解在 Serverless GPU 上批量运行文本分类与嵌入模型:用 vLLM 配置分类和嵌入端点,以 Modal 组织 GPU 函数,并通过任务拆分、并发边界与结果落盘完成验证。
批量文本分类与嵌入可以拆成独立任务,由 Serverless GPU 函数调用 vLLM:分类使用 /classify,嵌入按接口选择 Cohere 风格的 /v2/embed 或 OpenAI 兼容的 /v1/embeddings,路径见 vLLM 的 Pooling Models 文档。做 GPU服务器租用时,应先确认执行层确实提供 GPU,再配置模型、端点、并发边界与结果关联,不能只凭“Serverless”名称判断。
GPU服务器租用前,先确认执行层
把任务队列和结果存储放在 GPU 容器之外。Modal 的 GPU acceleration 文档说明,可以通过函数装饰器的 gpu 参数为 Function 附加 GPU,并要求账户中已有有效付款方式。官方给出的 GPU 回退配置示例是:
@app.function(gpu=["H100", "A100-40GB:2"])
Modal 会按列表顺序优先分配首选 GPU,再尝试后续类型。每个 Modal Function 拥有独立的自动扩缩容器池,Scaling out 文档说明其默认在没有待处理输入时缩至零。因此,应先把任务写入外部队列,再触发 Function;不要把容器内存当作持久队列。
分类与嵌入任务怎么配置
按 vLLM 的端点说明整理,可按下表选择任务路径:
| 任务 | 服务路径 | 配置要点 |
|---|---|---|
| 文本分类 | /classify |
分类模型若还要作为 scoring 或 rerank 模型,必须满足 num_labels=1 |
| Cohere 风格嵌入 | /v2/embed |
调用方需要该接口形状时使用 |
| OpenAI 兼容嵌入 | /v1/embeddings |
已有 OpenAI 兼容调用代码时优先核对这一路径 |
| 通用池化 | /pooling |
适用于所有 pooling model 类型 |
Pooling 模式可通过 --runner pooling 选择,但文档称自动检测通常已经足够,不需要无条件添加。vLLM 也明确表示,支持 pooling models 主要是为了便利,并不保证比直接使用 Hugging Face Transformers 或 Sentence Transformers 更快。
嵌入模型还要注意池化方式和输出维度。vLLM 的 Embedding Usages 文档建议优先使用专门按 embedding 目标训练的 pooling model;自动转换后的模型默认从最后一个 token 对应的归一化隐藏状态提取整个提示的 embedding。vLLM 支持通过 --convert embed 自动转换模型,但用途专一的模型更符合文档建议。
对于不支持 Matryoshka Embeddings 的模型,请求改变输出维度会返回错误。支持该能力时,可以用文档中的 --hf-overrides 示例开放指定维度:
vllm serve Snowflake/snowflake-arctic-embed-m-v1.5 --hf-overrides '{"matryoshka_dimensions":[256]}'
批量任务如何拆分和控制并发
在自建调度层中,为每条输入生成唯一 task_id,并记录任务类型、模型和端点。分类记录与嵌入记录应分开调度,避免重试其中一类任务时重复处理另一类结果。
并发边界可以按下面的关系核算:
在途任务数 = 批大小 × 同时运行的批数
不要照抄固定并发值;官方文档没有给出适用于所有模型的统一值。你需要结合当前执行层限额、模型所需显存和自行测得的运行情况设置上限。涉及 FastAPI API 层时,Concurrency and async / await 文档说明,普通 def 路径函数和依赖会进入外部线程池;如果不确定模型库是否支持 await,文档建议使用普通 def。这只影响 API 调度方式,不会自动增加 GPU 容量。
每批完成后,把 task_id、模型、端点、状态、分类标签或 embedding,以及重试状态写入外部存储。重试前先检查是否已有完成记录,避免同一任务重复写入。
怎样确认配置已经生效
先分别向 /classify 和选定的嵌入端点提交最小样本,确认服务返回,并把响应与原任务的 task_id 一起保存。嵌入结果还应记录实际输出维度,便于后续排查维度配置问题。具体请求体和响应字段应继续对照当前 API 页面,不要把其他接口的字段直接套用。
随后运行完整批次,比较输入任务标识与成功结果标识,把缺失项送入重试队列。任务清空后,再观察容器池是否按照平台当前规则缩容;本文不预设吞吐量、延迟或扩容时间。
常见出错点
- 端点选错:分类、两种嵌入接口和
/pooling的用途不同,应先核对调用方需要的接口形状。 - 维度请求报错:按 vLLM 的 Embedding Usages 文档检查模型是否支持 Matryoshka;不支持时不要反复修改请求维度。
- 评分接口未启用:分类模型只有在
num_labels=1时才能作为 scoring 模型启用相应接口。 - 任务在缩容后丢失:输入和结果必须先落到外部持久存储,不能依赖容器生命周期。
- 重试产生重复结果:写入前按
task_id做幂等检查。 - 把 pooling 当成性能保证:文档只说明提供便利,并未承诺相对 Transformers 或 Sentence Transformers 的性能提升。
本文步骤按正文所链接的官方文档整理,未进行运行或测量;使用前请对照当前版本检查。