跳到內容

最佳化與調優

本指南涵蓋 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 將大型預填充分塊處理,並將其與解碼請求一起批處理。此功能透過更好地平衡計算密集型(預填充)和記憶體密集型(解碼)操作來提高吞吐量和延遲。

在 V1 中,**只要可行,分塊預填充預設啟用**。啟用分塊預填充後,排程策略會優先處理解碼請求。它會對所有待處理的解碼請求進行批處理,然後再排程任何預填充操作。當 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 > 8192,特別是對於在大型 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 層將根據張量並行大小和資料並行大小的乘積進行分片。

用於多模態編碼器的批次級 DP

預設情況下,TP 用於對多模態編碼器的權重進行分片,就像對語言解碼器一樣,以減少每個 GPU 的記憶體和計算負載。

但是,由於多模態編碼器的大小與語言解碼器相比非常小,因此 TP 的收益相對較小。另一方面,TP 由於在每層之後都執行 all-reduce 操作,會產生顯著的通訊開銷。

鑑於此,透過 TP 分片批處理輸入資料,實質上執行批次級 DP,可能會更有優勢。研究表明,對於 tensor_parallel_size=8,這可以將吞吐量和 TTFT 提高約 10%。對於使用未經硬體最佳化的 Conv3D 操作的視覺編碼器,批次級 DP 可以比常規 TP 提高 40%。

儘管如此,由於多模態編碼器的權重會在每個 TP 秩上覆制,因此記憶體消耗會略有增加,如果您已經勉強能容納模型,可能會導致 OOM。

您可以設定 mm_encoder_tp_mode="data" 來啟用批次級 DP,例如:

from vllm import LLM

llm = LLM(
    model="Qwen/Qwen2.5-VL-72B-Instruct",
    tensor_parallel_size=4,
    # When mm_encoder_tp_mode="data",
    # the vision encoder uses TP=4 (not DP=1) to shard the input data,
    # so the TP size becomes the effective DP size.
    # Note that this is independent of the DP size for language decoder which is used in expert parallel setting.
    mm_encoder_tp_mode="data",
    # The language decoder uses TP=4 to shard the weights regardless
    # of the setting of mm_encoder_tp_mode
)

重要

批次級 DP 不應與 API 請求級 DP(由 data_parallel_size 控制)混淆。

批次級 DP 需要按模型實現,並透過在模型類中設定 supports_encoder_tp_data = True 來啟用。無論如何,您都需要在引擎引數中設定 mm_encoder_tp_mode="data" 來使用此功能。

已知支援的模型(附帶相應基準測試)

輸入處理

並行處理

您可以透過API 伺服器擴充套件並行執行輸入處理。當輸入處理(在 API 伺服器內部執行)成為模型執行(在引擎核心內部執行)的瓶頸,並且您有剩餘的 CPU 容量時,這很有用。

# Run 4 API processes and 1 engine core process
vllm serve Qwen/Qwen2.5-VL-3B-Instruct --api-server-count 4

# Run 4 API processes and 2 engine core processes
vllm serve Qwen/Qwen2.5-VL-3B-Instruct --api-server-count 4 -dp 2

注意

API 伺服器擴充套件僅適用於線上推理。

警告

預設情況下,每個 API 伺服器使用 8 個 CPU 執行緒來載入請求資料中的媒體項(例如影像)。

如果應用 API 伺服器擴充套件,請考慮調整 VLLM_MEDIA_LOADING_THREAD_COUNT 以避免 CPU 資源耗盡。

注意

API 伺服器擴充套件會停用多模態 IPC 快取,因為它需要 API 和引擎核心程序之間的一對一對應關係。

這不會影響多模態處理器快取

多模態快取

多模態快取可避免在多輪對話中經常發生的相同多模態資料的重複傳輸或處理。

處理器快取

多模態處理器快取會自動啟用,以避免在 BaseMultiModalProcessor 中重複處理相同的多模態輸入。

IPC 快取

當 API (P0) 和引擎核心 (P1) 程序之間存在一對一對應關係時,多模態 IPC 快取會自動啟用,以避免它們之間重複傳輸相同的多模態輸入。

鍵複製快取

預設情況下,IPC 快取使用**鍵複製快取**,其中快取鍵同時存在於 API (P0) 和引擎核心 (P1) 程序中,但實際快取資料僅駐留在 P1 中。

共享記憶體快取

當涉及多個工作程序時(例如,當 TP > 1 時),**共享記憶體快取**更有效。可以透過設定 mm_processor_cache_type="shm" 來啟用此功能。在此模式下,快取鍵儲存在 P0 上,而快取資料本身則駐留在所有程序都可以訪問的共享記憶體中。

配置

您可以透過設定 mm_processor_cache_gb 的值(預設為 4 GiB)來調整快取的大小。

如果您從快取中獲益不多,可以透過 mm_processor_cache_gb=0 完全停用 IPC 和處理器快取。

示例

# Use a larger cache
llm = LLM(
    model="Qwen/Qwen2.5-VL-3B-Instruct",
    mm_processor_cache_gb=8,
)

# Use a shared-memory based IPC cache
llm = LLM(
    model="Qwen/Qwen2.5-VL-3B-Instruct",
    tensor_parallel_size=2,
    mm_processor_cache_type="shm",
    mm_processor_cache_gb=8,
)

# Disable the cache
llm = LLM(
    model="Qwen/Qwen2.5-VL-3B-Instruct",
    mm_processor_cache_gb=0,
)

快取放置

根據配置,P0P1 上的多模態快取的內容如下:

mm_processor_cache_type 快取型別 P0 快取 P1 引擎快取 P1 工作程序快取 最大記憶體
lru 處理器快取 K + V 不適用 不適用 mm_processor_cache_gb * data_parallel_size
lru 鍵複製快取 K K + V 不適用 mm_processor_cache_gb * api_server_count
shm 共享記憶體快取 K 不適用 V mm_processor_cache_gb * api_server_count
不適用 停用 不適用 不適用 不適用 0

K:儲存多模態專案的雜湊值
V:儲存多模態專案的處理後張量資料