我们非常激动地宣布 vLLM V1 的 alpha 版本发布,这是对 vLLM 核心架构的一次重大升级。基于我们在过去 1.5 年 vLLM 开发过程中吸取的经验教训,我们重新审视了关键的设计决策,整合了各种功能,并简化了代码库,以增强灵活性和可扩展性。V1 已经实现了最先进的性能,并且有望获得更多的优化。最棒的是,用户可以无缝启用 V1——只需设置 VLLM_USE_V1=1 环境变量,无需对现有 API 进行任何更改。在未来几周的测试和反馈收集之后,我们计划将 V1 转换为默认引擎。

为什么选择 vLLM V1?

从 vLLM V0 中学习

在过去的 1.5 年中,vLLM 在支持各种模型、功能和硬件后端方面取得了显著的成功。然而,当我们的社区进行水平扩展时,我们在简化系统以及在整个堆栈中垂直整合各种优化方面面临挑战。功能通常是独立开发的,这使得有效地、干净地组合它们变得困难。随着时间的推移,技术债务积累,促使我们重新审视我们的基础设计。

V1 的目标

基于上述动机,vLLM V1 的设计目标是:

  • 提供一个简单、模块化且易于 hack 的代码库
  • 确保高性能,并具有接近零的 CPU 开销。
  • 关键优化整合到一个统一的架构中。
  • 通过默认启用功能/优化,实现零配置

V1 的范围

vLLM V1 对其核心组件进行了全面的重新架构,包括调度器、KV 缓存管理器、worker、采样器和 API 服务器。然而,它仍然与 vLLM V0 共享许多代码,例如模型实现、GPU 内核、分布式控制平面和各种实用程序函数。这种方法使 V1 能够利用 V0 建立的广泛覆盖范围和稳定性,同时显著增强性能和降低代码复杂性。

vLLM V1 的新特性?

1. 优化的执行循环和 API 服务器

作为一个成熟的连续批处理引擎和 OpenAI 兼容的 API 服务器,vLLM 的核心执行循环依赖于 CPU 操作来管理模型前向传递之间的请求状态。随着 GPU 变得越来越快,并显著减少了模型执行时间,API 服务器运行、调度工作、准备输入、反标记化输出以及向用户流式传输响应等任务的 CPU 开销变得越来越明显。当在 NVIDIA H100 GPU 上运行像 Llama-8B 这样的小型模型时,这个问题尤其明显,因为 GPU 上的执行时间低至约 5 毫秒。

v0.6.0 版本中,vLLM 引入了一个使用 ZeroMQ 进行 IPC 的多进程 API 服务器,实现了 API 服务器和 AsyncLLM 之间的重叠。vLLM V1 通过将多进程架构更深入地集成到 AsyncLLM 的核心中来扩展这一点,创建了一个隔离的 EngineCore 执行循环,该循环专门专注于调度器和模型执行器。这种设计允许 CPU 密集型任务(如标记化、多模态输入处理、反标记化和请求流式传输)与核心执行循环之间更大的重叠,从而最大化模型吞吐量。

2. 简单而灵活的调度器

vLLM V1 引入了一个简单而灵活的调度器。它通过统一处理用户给定的提示词 tokens 和模型生成的输出 tokens,消除了传统的“预填充”和“解码”阶段之间的区别。调度决策表示为一个简单的字典,例如 {request_id: num_tokens},它指定了在每个步骤中为每个请求处理的 tokens 数量。我们发现这种表示足够通用,可以支持分块预填充、前缀缓存和推测性解码等功能。例如,分块预填充调度可以无缝实现:在固定的 tokens 预算下,调度器动态地决定为每个请求分配多少 tokens(如上图所示)。

3. 零开销前缀缓存

与 V0 一样,vLLM V1 使用基于哈希的前缀缓存和基于 LRU 的缓存淘汰。在 V0 中,启用前缀缓存有时会导致显著的 CPU 开销,当缓存命中率较低时,会导致性能大幅下降。因此,默认情况下禁用它。在 V1 中,我们优化了数据结构以实现恒定时间的缓存淘汰,并仔细地最小化了 Python 对象创建开销。这使得 V1 的前缀缓存引入了接近零的性能下降,即使在缓存命中率为 0% 的情况下也是如此。

以下是一些基准测试结果。在我们的实验中,我们观察到,即使在缓存命中率为 0% 的情况下,V1 的前缀缓存造成的吞吐量下降也小于 1%,而在缓存命中率较高时,它将性能提高了数倍。由于接近零的开销,我们现在在 V1 中默认启用前缀缓存。

4. 用于张量并行推理的简洁架构

vLLM V1 引入了一个简洁高效的张量并行推理架构,有效地解决了 V0 的局限性。在 V0 中,调度器和 Worker 0 位于同一进程中,以减少向 worker 广播输入数据时的进程间通信开销。然而,这种设计引入了一个不对称的架构,增加了复杂性。V1 通过在 worker 端缓存请求状态,并在每个步骤中仅传输增量更新(差异)来克服这个问题。这种优化最大限度地减少了进程间通信,允许调度器和 Worker 0 在不同的进程中运行,从而形成一个简洁的对称架构。此外,V1 抽象化了大部分分布式逻辑,使 worker 在单 GPU 和多 GPU 设置中以相同的方式运行。

5. 高效的输入准备

在 vLLM V0 中,模型的输入张量和元数据在每个步骤中都会重新创建,这通常会导致显著的 CPU 开销。为了优化这一点,V1 实现了 持久批处理技术,该技术缓存输入张量,并在每个步骤中仅对其应用差异。此外,V1 通过广泛使用 Numpy 操作而不是 Python 的原生操作,最大限度地减少了更新张量时的 CPU 开销。

6. torch.compile 和分段 CUDA 图

V1 利用 vLLM 的 torch.compile 集成来自动优化模型。这使 V1 能够高效地支持各种模型,同时最大限度地减少编写自定义内核的需求。此外,V1 引入了分段 CUDA 图,以缓解 CUDA 图的局限性。我们正在准备关于 torch.compile 集成和分段 CUDA 图的专门博客文章,所以请继续关注更多更新

7. 增强对多模态 LLM 的支持

vLLM V1 将多模态大型语言模型 (MLLM) 视为一等公民,并在其支持方面引入了几项关键改进。

首先,V1 通过将其移动到非阻塞进程来优化多模态输入预处理。例如,图像文件(例如,JPG 或 PNG)必须转换为像素值张量,裁剪和变换,然后才能馈送到模型中。这种预处理可能会消耗大量的 CPU 周期,可能导致 GPU 空闲。为了解决这个问题,V1 将预处理任务卸载到单独的进程,防止它阻塞 GPU worker,并添加预处理缓存,以便如果请求共享相同的多模态输入,则可以在请求之间重用已处理的输入。

其次,V1 为多模态输入引入了前缀缓存。除了 tokens ID 的哈希之外,图像哈希也用于识别图像输入的 KV 缓存。这种改进对于包含图像输入的多轮对话尤其有益。

第三,V1 为具有“编码器缓存”的 MLLM 启用了分块预填充调度。在 V0 中,图像输入和文本输入必须在同一步骤中处理,因为 LLM 解码器的 token 依赖于视觉嵌入,这些视觉嵌入在该步骤之后被丢弃。借助编码器缓存,V1 临时存储视觉嵌入,允许调度器将文本输入拆分为块并在多个步骤中处理它们,而无需在每个步骤中重新生成视觉嵌入。

8. FlashAttention 3

vLLM V1 的最后一块拼图是集成 FlashAttention 3。考虑到 V1 的高度动态性——例如在同一批次中组合预填充和解码——一个灵活且高性能的注意力内核至关重要。FlashAttention 3 有效地满足了这一要求,为广泛的功能提供了强大的支持,同时在各种用例中保持了卓越的性能。

性能

得益于广泛的架构增强,vLLM V1 实现了最先进的吞吐量和延迟,与 V0 相比,吞吐量提高了高达 1.7 倍不包括多步调度)。这些显著的性能提升源于整个堆栈中全面的 CPU 开销减少。对于像 Qwen2-VL 这样的视觉语言模型 (VLM),由于 V1 增强了对 VLM 的支持,改进更加明显。

  • 文本模型:Llama 3.1 8B 和 Llama 3.3 70B

我们使用 ShareGPT 数据集测量了 vLLM V0 和 V1 在 Llama 3.1 8B 和 Llama 3.3 70B 模型上的性能。V1 展示了比 V0 持续更低的延迟,尤其是在高 QPS 下,这归功于它实现的更高吞吐量。鉴于 V0 和 V1 使用的内核几乎相同,性能差异主要归因于 V1 中的架构改进(减少的 CPU 开销)。

  • 视觉语言模型:Qwen2-VL

我们通过使用 VisionArena 数据集测试 Qwen2-VL 来评估 VLM 的性能。V1 提供了比 V0 更大的加速,这要归功于其改进的 VLM 支持,这得益于两项关键改进:将输入处理卸载到单独的进程,以及为多模态查询实施更灵活的调度。我们还要指出,前缀缓存现在在 V1 中原生支持多模态模型,但此处将跳过基准测试结果。

  • 展望未来

虽然这些改进意义重大,但我们认为这仅仅是一个开始。重新设计的架构提供了一个坚实的基础,这将使新功能的快速开发成为可能。我们期待在未来几周内分享更多的增强功能。请继续关注更多更新!

局限性与未来工作

虽然 vLLM V1 显示出令人鼓舞的结果,但它仍处于 alpha 阶段,并且缺少 V0 中的一些功能。以下是一些说明:

模型支持
V1 支持仅解码器 Transformer 模型,如 Llama,混合专家 (MoE) 模型,如 Mixtral,以及一些 VLM,如 Qwen2-VL。所有量化方法均受支持。但是,V1 目前不支持编码器-解码器架构,如多模态 Llama 3.2、基于 Mamba 的模型,如 Jamba 或嵌入模型。请查看我们的文档,以获取更详细的支持模型列表。

功能限制
V1 目前缺乏对 log probs、prompt log probs 采样参数、流水线并行、结构化解码、推测性解码、Prometheus 指标和 LoRA 的支持。我们正在积极努力弥合此功能差距,并为 V1 引擎添加全新的优化。

硬件支持
V1 目前仅支持 Ampere 或更高版本的 NVIDIA GPU。我们正在积极努力将支持扩展到其他硬件后端,如 TPU。

最后,请注意,您可以继续使用 V0 并保持向后兼容性,而无需设置 VLLM_USE_V1=1

如何开始使用

要使用 vLLM V1:

  1. 使用 pip install vllm --upgrade 安装最新版本的 vLLM。
  2. 设置环境变量 export VLLM_USE_V1=1
  3. 使用 vLLM 的 Python API 或 OpenAI 兼容服务器 (vllm serve <model-name>)。您无需对现有 API 进行任何更改。

请试用并分享您的反馈!

致谢

我们衷心感谢 vLLM V1 的设计建立并增强了几个开源 LLM 推理引擎,包括 LightLLMLMDeploySGLangTGITRT-LLM。这些引擎对我们的工作产生了重大影响,我们从中获得了宝贵的见解。

V1 重新架构是整个 vLLM 团队和社区持续共同努力的结果。以下是为此里程碑做出贡献的不完整列表:

  • 加州大学伯克利分校、Neural Magic(现在的 Red Hat)、Anyscale 和 Roblox 主要共同推动了这项工作。
  • Woosuk Kwon 发起了该项目并实现了调度器和模型运行器。
  • Robert Shaw 实现了优化的执行循环和 API 服务器。
  • Cody Yu 实现了文本和图像输入的高效前缀缓存。
  • Roger Wang 领导了 V1 中整体增强的 MLLM 支持。
  • Kaichao You 领导了 torch.compile 集成并实现了分段 CUDA 图。
  • Tyler Michael Smith 使用 Python 多进程实现了张量并行支持。
  • Rui Qiao 使用 Ray 实现了张量并行支持,并且正在实现流水线并行支持。
  • Lucas Wilkinson 添加了对 FlashAttention 3 的支持。
  • Alexander Matveev 实现了多模态输入的优化预处理器,并且正在实现 TPU 支持。
  • Sourashis Roy 在采样器中实现了 logit 惩罚。
  • Cyrus Leung 领导了 MLLM 输入处理重构工作,并帮助将其集成到 V1 中。
  • Russell Bryant 解决了几个与多进程相关的问题。
  • Nick Hill 优化了引擎循环和 API 服务器。
  • Ricky XuChen Zhang 帮助重构了 KV 缓存管理器。
  • Jie LiMichael Goin 帮助进行了 MLLM 支持和优化。
  • Aaron Pham 正在实现结构化解码支持。
  • Varun Sundar Rabindranath 正在实现多 LoRA 支持。
  • Andrew Feldman 正在实现 log probs 和 prompt log probs 支持。
  • Lily Liu 正在实现推测性解码支持。
  • Kuntai Du 正在实现预填充分解和 KV 缓存传输支持。
  • Simon MoZhuohan Li 为 V1 系统设计做出了贡献。