在当今人工智能领域,大语言模型(LLM)的应用日益广泛,而优化和调优这些模型的性能成为了至关重要的任务。vLLM 作为一种高效的推理引擎,提供了多种策略来提升模型的性能。本文将深入探讨 vLLM V1 的优化与调优策略,帮助读者更好地理解和应用这些技术。
抢占式调度(Preemption)
由于 Transformer 架构的自回归特性,有时键值缓存(KV cache)空间不足以处理所有批量请求。在这种情况下,vLLM 可以通过抢占请求来释放 KV 缓存空间,以便为其他请求腾出空间。被抢占的请求会在有足够的 KV 缓存空间时重新计算。然而,这种机制可能会对端到端的延迟产生不利影响。
当频繁遇到抢占时,可以考虑以下措施:
-
• 增加
gpu_memory_utilization
,以便为 KV 缓存提供更多空间。 -
• 减少
max_num_seqs
或max_num_batched_tokens
,以减少批量中的并发请求数量。 -
• 增加
tensor_parallel_size
,将模型权重分布在多个 GPU 上,但需注意这可能会导致同步开销增加。 -
• 增加
pipeline_parallel_size
,将模型层分布在多个 GPU 上,间接为 KV 缓存腾出更多内存,但可能会带来延迟惩罚。
vLLM V1 默认采用 RECOMPUTE
模式而非 SWAP
模式,因为重新计算在 V1 架构中的开销较低。
分块预取(Chunked Prefill)
分块预取允许 vLLM 将大型预取操作分解为较小的块,并将它们与解码请求批量处理。这一特性有助于通过更好地平衡计算密集型(预取)和内存密集型(解码)操作来提高吞吐量和延迟。
在 vLLM V1 中,分块预取默认始终启用。其调度策略优先处理解码请求,先批量处理所有待处理的解码请求,然后再调度任何预取操作。如果 max_num_batched_tokens
预算中有可用令牌,则会调度待处理的预取操作。如果待处理的预取请求无法适应 max_num_batched_tokens
,则会自动将其分块。
这种策略的两大好处是:
-
• 提高了令牌间延迟(ITL)和解码生成,因为解码请求得到了优先处理。
-
• 有助于实现更好的 GPU 利用率,通过将计算密集型和内存密集型请求定位到同一批次。
通过调整 max_num_batched_tokens
可以优化性能:
-
• 较小的值(如 2048)可实现更好的 ITL,因为预取操作较少,不会拖慢解码速度。
-
• 较高的值可以实现更快的首次令牌时间(TTFT),因为可以在一个批次中处理更多的预取令牌。
-
• 对于较小模型在大型 GPU 上的最优吞吐量,建议将
max_num_batched_tokens
设置为大于 8096。
示例代码如下:
from vllm import LLM
# 设置 max_num_batched_tokens 以优化性能
llm = LLM(model="meta-llama/Llama-3.1-8B-Instruct", max_num_batched_tokens=16384)
并行策略(Parallelism Strategies)
vLLM 支持多种并行策略,这些策略可以组合使用,以在不同的硬件配置上优化性能。
张量并行(Tensor Parallelism)
张量并行将模型参数在每个模型层中的多个 GPU 上进行切分。当模型过大无法容纳在单个 GPU 上,或者需要减少每个 GPU 的内存压力以腾出更多 KV 缓存空间以提高吞吐量时,这种策略非常有用。
示例代码如下:
from vllm import LLM
# 将模型分布在 4 个 GPU 上
llm = LLM(model="meta-llama/Llama-3.3-70B-Instruct", tensor_parallel_size=4)
对于无法容纳在单个 GPU 上的大型模型(如 70B 参数模型),张量并行是必不可少的。
管道并行(Pipeline Parallelism)
管道并行将模型层分布在多个 GPU 上。每个 GPU 按顺序处理模型的不同部分。当已经充分利用了高效的张量并行,但需要进一步分布模型,或者跨节点分布时,或者对于非常深且窄的模型,层分布比张量切分更高效时,可以使用这种策略。
张量并行和管道并行可以组合使用,以应对非常大型的模型:
from vllm import LLM
# 组合管道和张量并行
llm = LLM(
model="meta-llama/Llama-3.3-70B-Instruct",
tensor_parallel_size=4,
pipeline_parallel_size=2
)
专家并行(Expert Parallelism)
专家并行是一种专门用于混合专家(MoE)模型的并行形式,将不同的专家网络分布在多个 GPU 上。对于特定的 MoE 模型,如 DeepSeekV3、Qwen3MoE、Llama-4,或者希望在 GPU 之间平衡专家计算负载时,可以使用这种策略。
专家并行通过设置 enable_expert_parallel=True
启用,将使用与张量并行相同并行度来代替 MoE 层的张量并行。
数据并行(Data Parallelism)
数据并行将整个模型在多个 GPU 集上进行复制,并并行处理不同的请求批次。当有足够的 GPU 来复制整个模型,需要扩展吞吐量而非模型大小,或者在多用户环境中,请求批次之间需要隔离时,可以使用这种策略。
数据并行可以与其他并行策略组合使用,并通过 data_parallel_size=N
进行设置。需要注意的是,MoE 层将根据张量并行大小和数据并行大小的乘积进行切分。
减少内存使用(Reducing Memory Usage)
如果遇到内存不足的问题,可以考虑以下策略:
上下文长度和批量大小
可以通过限制上下文长度和批量大小来减少内存使用:
from vllm import LLM
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
max_model_len=2048, # 限制上下文窗口
max_num_seqs=4 # 限制批量大小
)
调整 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] # 捕获更少的批量大小
)
)
如果对延迟或整体性能不敏感,可以完全禁用 CUDA 图编译:
from vllm import LLM
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
enforce_eager=True # 禁用 CUDA 图编译
)
多模态模型
对于多模态模型,可以通过限制每个请求中的图像/视频数量来减少内存使用:
from vllm import LLM
# 每个提示接受最多 2 张图像
llm = LLM(
model="Qwen/Qwen2.5-VL-3B-Instruct",
limit_mm_per_prompt={"image": 2}
)
总结与展望
vLLM 提供了丰富的优化和调优策略,涵盖了从抢占式调度、分块预取到各种并行策略以及内存优化等多个方面。通过合理应用这些策略,可以显著提升模型的性能和效率。然而,优化过程并非一成不变,需要根据具体的硬件配置、模型特性以及应用场景进行灵活调整。未来,随着硬件技术的进步和模型架构的不断创新,相信 vLLM 将持续进化,为开发者和研究人员提供更为强大的工具,助力大语言模型在各个领域的深入应用和创新发展。