优化与调优¶
本指南涵盖了 vLLM V1 的优化策略和性能调优。
抢占¶
由于 transformer 架构的自回归特性,有时 KV 缓存空间不足以处理所有批处理请求。在这种情况下,vLLM 可以抢占请求以释放 KV 缓存空间给其他请求。当有足够的 KV 缓存空间再次可用时,被抢占的请求会被重新计算。发生这种情况时,您可能会看到以下警告
WARNING 05-09 00:49:33 scheduler.py:1057 Sequence group 0 is preempted by PreemptionMode.RECOMPUTE mode because there is not enough KV cache space. This can affect the end-to-end performance. Increase gpu_memory_utilization or tensor_parallel_size to provide more KV cache memory. total_cumulative_preemption_cnt=1
虽然此机制确保了系统的鲁棒性,但抢占和重新计算可能会对端到端延迟产生不利影响。如果您经常遇到抢占情况,请考虑以下措施
- 增加
gpu_memory_utilization
。vLLM 使用此内存百分比预分配 GPU 缓存。通过提高利用率,您可以提供更多 KV 缓存空间。 - 减少
max_num_seqs
或max_num_batched_tokens
。这会减少批处理中的并发请求数量,从而需要更少的 KV 缓存空间。 - 增加
tensor_parallel_size
。这将模型权重分片到多个 GPU 上,从而使每个 GPU 拥有更多可用于 KV 缓存的内存。但是,增加此值可能会导致过多的同步开销。 - 增加
pipeline_parallel_size
。这将模型层分布到多个 GPU 上,减少每个 GPU 上模型权重所需的内存,间接为 KV 缓存留下更多可用内存。但是,增加此值可能会导致延迟损失。
您可以通过 vLLM 公开的 Prometheus 指标监控抢占请求数量。此外,您可以通过设置 disable_log_stats=False
来记录累计抢占请求数量。
在 vLLM V1 中,默认的抢占模式是 RECOMPUTE
而非 SWAP
,因为在 V1 架构中重新计算的开销更低。
分块预填充¶
分块预填充允许 vLLM 将大型预填充处理成更小的块,并与解码请求一起进行批处理。此功能通过更好地平衡计算密集型(预填充)和内存密集型(解码)操作,有助于提高吞吐量和降低延迟。
在 vLLM V1 中,分块预填充默认始终启用。这与 vLLM V0 不同,后者是根据模型特性有条件地启用。
启用分块预填充后,调度策略会优先处理解码请求。它会在调度任何预填充操作之前批处理所有待处理的解码请求。当 max_num_batched_tokens
预算中存在可用 token 时,它会调度待处理的预填充。如果待处理的预填充请求无法容纳在 max_num_batched_tokens
中,它会自动将其分块。
此策略有两个优点
- 它提高了 ITL 和生成解码,因为解码请求具有优先权。
- 通过将计算密集型(预填充)和内存密集型(解码)请求放在同一批处理中,有助于实现更好的 GPU 利用率。
使用分块预填充进行性能调优¶
您可以通过调整 max_num_batched_tokens
来调优性能
- 较小的值(例如 2048)可以获得更好的 token 间延迟 (ITL),因为减慢解码速度的预填充较少。
- 较大的值可以获得更好的首个 token 延迟 (TTFT),因为您可以在批处理中处理更多预填充 token。
- 为了获得最佳吞吐量,我们建议设置
max_num_batched_tokens > 8096
,特别是对于大型 GPU 上的较小模型。 - 如果
max_num_batched_tokens
与max_model_len
相同,则几乎等同于 V0 的默认调度策略(除了它仍然优先处理解码)。
from vllm import LLM
# Set max_num_batched_tokens to tune performance
llm = LLM(model="meta-llama/Llama-3.1-8B-Instruct", max_num_batched_tokens=16384)
更多详细信息请参阅相关论文 (https://arxiv.org/pdf/2401.08671 或 https://arxiv.org/pdf/2308.16369)。
并行策略¶
vLLM 支持多种并行策略,可以结合使用以优化不同硬件配置下的性能。
张量并行 (TP)¶
张量并行将模型参数在每个模型层内分片到多个 GPU 上。这是单节点内大型模型推理最常用的策略。
何时使用
- 当模型太大无法放入单个 GPU 时
- 当您需要降低每个 GPU 的内存压力以留出更多 KV 缓存空间来提高吞吐量时
from vllm import LLM
# Split model across 4 GPUs
llm = LLM(model="meta-llama/Llama-3.3-70B-Instruct", tensor_parallel_size=4)
对于太大无法放入单个 GPU 的模型(例如 70B 参数模型),张量并行是必不可少的。
流水线并行 (PP)¶
流水线并行将模型层分布到多个 GPU 上。每个 GPU 按顺序处理模型的不同部分。
何时使用
- 当您已经最大化了高效张量并行但需要进一步分布式模型,或跨节点时
- 对于层分布比张量分片更有效的非常深且窄的模型
流水线并行可以与张量并行结合使用,适用于超大型模型
from vllm import LLM
# Combine pipeline and tensor parallelism
llm = LLM(
model="meta-llama/Llama-3.3-70B-Instruct,
tensor_parallel_size=4,
pipeline_parallel_size=2
)
专家并行 (EP)¶
专家并行是 Mixture of Experts (MoE) 模型的一种特殊并行形式,其中不同的专家网络分布在多个 GPU 上。
何时使用
- 专门用于 MoE 模型(如 DeepSeekV3, Qwen3MoE, Llama-4)
- 当您希望平衡专家计算负载跨多个 GPU 时
通过设置 enable_expert_parallel=True
可以启用专家并行,这将对 MoE 层使用专家并行而不是张量并行。它将使用与您为张量并行设置的相同程度的并行。
数据并行 (DP)¶
数据并行在多个 GPU 集上复制整个模型,并并行处理不同批次的请求。
何时使用
- 当您有足够的 GPU 复制整个模型时
- 当您需要扩展吞吐量而不是模型大小时
- 在多用户环境中,请求批次之间的隔离是有益的
数据并行可以与其他并行策略结合使用,通过 data_parallel_size=N
设置。请注意,MoE 层将根据张量并行大小和数据并行大小的乘积进行分片。
降低内存使用¶
如果您遇到内存不足问题,请考虑以下策略
上下文长度与批处理大小¶
您可以通过限制上下文长度和批处理大小来降低内存使用
from vllm import LLM
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
max_model_len=2048, # Limit context window
max_num_seqs=4 # Limit batch size
)
调整 CUDA 图编译¶
V1 中的 CUDA 图编译比 V0 使用更多内存。您可以通过调整编译级别来降低内存使用
from vllm import LLM
from vllm.config import CompilationConfig, CompilationLevel
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
compilation_config=CompilationConfig(
level=CompilationLevel.PIECEWISE,
cudagraph_capture_sizes=[1, 2, 4, 8] # Capture fewer batch sizes
)
)
或者,如果您不关心延迟或整体性能,可以使用 enforce_eager=True
完全禁用 CUDA 图编译
from vllm import LLM
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
enforce_eager=True # Disable CUDA graph compilation
)
多模态模型¶
对于多模态模型,您可以通过限制每个请求的图片/视频数量来降低内存使用