跳到內容

最佳化與調優

本指南涵蓋了 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_seqsmax_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 不同,V0 中是根據模型特性有條件地啟用。

啟用分塊預填充後,排程策略會優先處理解碼請求。它會在排程任何預填充操作之前,批處理所有待處理的解碼請求。當 max_num_batched_tokens 預算中有可用 token 時,它會排程待處理的預填充。如果待處理的預填充請求無法適應 max_num_batched_tokens,它會自動將其分塊。

此策略有兩個優點:

  • 由於解碼請求被優先處理,它改善了 ITL(內部 Token 延遲)和生成解碼。
  • 它透過將計算密集型(預填充)和記憶體密集型(解碼)請求放在同一個批次中,有助於實現更好的 GPU 利用率。

使用分塊預填充進行效能調優

您可以透過調整 max_num_batched_tokens 來調整效能:

  • 較小的值(例如 2048)可以實現更好的內部 Token 延遲(ITL),因為預填充較少,不會減慢解碼速度。
  • 較大的值可以實現更好的首個 Token 生成時間(TTFT),因為您可以在一個批次中處理更多的預填充 token。
  • 為了獲得最佳吞吐量,我們建議將 max_num_batched_tokens > 8096,特別是對於大型 GPU 上的小型模型。
  • 如果 max_num_batched_tokensmax_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.08671https://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)

專家並行是一種針對混合專家(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 Graph 編譯

V1 中的 CUDA graph 編譯比 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 graph 編譯。

from vllm import LLM

llm = LLM(
    model="meta-llama/Llama-3.1-8B-Instruct",
    enforce_eager=True  # Disable CUDA graph compilation
)

多模態模型

對於多模態模型,您可以透過限制每個請求的影像/影片數量來減少記憶體使用。

from vllm import LLM

# Accept up to 2 images per prompt
llm = LLM(
    model="Qwen/Qwen2.5-VL-3B-Instruct",
    limit_mm_per_prompt={"image": 2}
)