在當今人工智能快速發展的時代,大型語言模型(LLM)的推理和部署面臨著諸多挑戰,尤其是當模型規模日益龐大時,如何高效地利用硬件資源成為關鍵問題。vLLM 作為一種強大的工具,為分布式推理和部署提供了多種策略,本文將詳細探討其相關技術和應用場景,希望能對您提供有價值的參考。
分布式推理策略的選擇
在開始分布式推理和部署之前,明確何時采用分布式推理以及可選的策略至關重要。
1.?單 GPU 推理?:如果模型能夠在單個 GPU 內運行,那么無須使用分布式推理,直接利用單 GPU 進行推理即可,這是最簡單且高效的方式。
2.?單節點多 GPU(張量并行推理)?:當模型無法在單個 GPU 內運行,但可以在配備多個 GPU 的單個節點上容納時,張量并行(tensor parallelism)技術就派上了用場。張量并行的大小即為該節點上參與計算的 GPU 數量。例如,擁有 4 個 GPU 的單節點,可將張量并行大小設為 4,讓多個 GPU 協同工作完成推理任務。
3.?多節點多 GPU(張量并行與流水線并行相結合的推理)?:若模型規模巨大,以至于單個節點的 GPU 資源都無法滿足需求,此時需要利用張量并行與流水線并行(pipeline parallelism)的組合方案。張量并行大小對應每個節點上使用的 GPU 數量,流水線并行大小則是所用節點的數量。以 16 個 GPU 分布在 2 個節點(每個節點 8 個 GPU)為例,可將張量并行大小設為 8,流水線并行大小設為 2,從而在多個節點上高效地進行模型推理。
總的來說,應逐步增加 GPU 和節點的數量,直至 GPU 內存足以容納模型。確定好張量并行和流水線并行的大小后,先運行 vLLM,其會輸出類似 “# GPU blocks: 790” 的日志,將該數值乘以 16(塊大小),可大致估算出當前配置下能夠服務的最大 token 數。若此數值不理想,如期望更高的吞吐量,則可繼續增加 GPU 或節點數量,直至塊數量滿足需求。
另外,還有一種特殊情況:如果模型可以容納在單個節點的多個 GPU 中,但 GPU 數量無法整除模型大小,此時可以采用流水線并行。它沿著模型層進行分割,支持不均勻分割。在這種情況下,張量并行大小應為 1,流水線并行大小設為 GPU 的數量。
vLLM 在單節點上的運行
vLLM 支持分布式張量并行和流水線并行推理及服務。目前,其采用 Megatron-LM 的張量并行算法,并通過 Ray 或 Python 原生 multiprocessing 來管理分布式運行時。在單節點部署時,可使用 multiprocessing;而多節點推理目前需要 Ray。
默認情況下,當未在 Ray placement group 中運行且同一節點上有足夠的 GPU 滿足配置的 “tensor_parallel_size” 時,會使用 multiprocessing,也可以通過 “LLM” 類的 “distributed_executor_backend” 參數或 “--distributed-executor-backend” API 服務器參數來覆蓋此默認設置,將其設為 “mp” 表示使用 multiprocessing,“ray” 表示使用 Ray,且在 multiprocessing 情況下無須安裝 Ray。
1.?使用 LLM 類進行多 GPU 推理?:設置 “tensor_parallel_size” 參數為想要使用的 GPU 數量。例如,在 4 個 GPU 上運行推理:
from?vllm?import?LLM
llm = LLM("facebook/opt-13b", tensor_parallel_size=4)
output = llm.generate("San Francisco is a")
2.?啟動多 GPU 服務?:在啟動服務器時傳入 “--tensor-parallel-size” 參數。例如,在 4 個 GPU 上運行 API 服務器:
?vllm serve facebook/opt-13b \--tensor-parallel-size 4
此外,還可以通過指定 “--pipeline-parallel-size” 來啟用流水線并行。例如,在 8 個 GPU 上同時使用流水線并行和張量并行運行 API 服務器:
?vllm serve gpt2 \--tensor-parallel-size 4 \--pipeline-parallel-size 2
vLLM 在多節點上的運行
當單個節點的 GPU 資源不足以運行模型時,可利用多個節點來進行模型運行。確保所有節點的執行環境相同,包括模型路徑和 Python 環境至關重要。推薦使用 docker 鏡像來保證環境一致性,并通過將主機映射到相同的 docker 配置來隱藏主機硬件的異構性。
1.?啟動容器并組建集群?:vLLM ?在github上,提供了示例腳本 examples/online_serving/run_cluster.sh 來啟動集群。需注意,該腳本以非管理權限啟動 docker,這在運行分析和跟蹤工具時可能無法訪問 GPU 性能計數器。若需此權限,可在 docker run 命令中使用 “--cap-add” 選項添加 “CAP_SYS_ADMIN” 權限。
選擇一個節點作為主節點,運行以下命令:
bash run_cluster.sh \vllm/vllm-openai \ip_of_head_node \--head?\/path/to/the/huggingface/home/in/this/node \-e VLLM_HOST_IP=ip_of_this_node
在其余的工作節點上,運行以下命令:
bash run_cluster.sh \vllm/vllm-openai \ip_of_head_node \--worker \/path/to/the/huggingface/home/in/this/node \-e VLLM_HOST_IP=ip_of_this_node
這樣就形成了一個由容器組成的 Ray 集群。需要注意的是,運行這些命令的 shell 必須保持運行狀態以維持集群,任何 shell 斷開連接都會導致集群終止。此外,參數 “ip_of_head_node” 應為主節點的 IP 地址,且該 IP 地址必須能夠被所有工作節點訪問。每個工作節點的 IP 地址應通過 “VLLM_HOST_IP” 環境變量指定,并且各節點的 IP 地址必須不同。要確保集群中的節點可以通過指定的 IP 地址相互通信。
值得注意的是,出于安全和性能考慮,最好將 “VLLM_HOST_IP” 設置為私有網絡段上的地址。因為通過此網絡發送的流量未加密,且端點之間交換的數據格式如果被惡意方獲取網絡訪問權限,可能存在執行任意代碼的風險,所以必須確保該網絡無法被任何不受信任的方訪問。
注意:由于這是一個由容器組成的 Ray 集群,所有后續命令都應在容器內執行,否則會在主機上執行命令,而主機未連接到 Ray 集群。要進入容器,可以使用 “docker exec -it node /bin/bash” 命令。
進入容器后,可執行 “ray status” 和 “ray list nodes” 命令來檢查 Ray 集群的狀態,應能看到正確的節點數量和 GPU 數量。
2.?在集群中運行 vLLM?:在任意節點再次進入容器后,像在單節點上運行 vLLM 一樣,只需在該節點上運行 “vllm” 命令,即可利用 Ray 集群中所有節點的 GPU 資源。通常的做法是將張量并行大小設置為每個節點上的 GPU 數量,流水線并行大小設置為節點數量。例如,若擁有 16 個 GPU 分布在 2 個節點(每個節點 8 個 GPU),可設置張量并行大小為 8,流水線并行大小為 2:
?vllm serve /path/to/the/model/in/the/container \--tensor-parallel-size 8 \--pipeline-parallel-size 2
也可以僅使用張量并行而不使用流水線并行,只需將張量并行大小設置為集群中 GPU 的總數。例如,若 2 個節點(每個節點 8 個 GPU)共有 16 個 GPU,可設置張量并行大小為 16:
vllm serve /path/to/the/model/in/the/container \--tensor-parallel-size 16
為使張量并行性能優異,需確保節點間的通信高效,例如使用高速網卡(如 Infiniband)。要正確設置集群以使用 Infiniband,可在 “run_cluster.sh” 腳本中添加類似 “--privileged -e NCCL_IB_HCA=mlx5” 的額外參數。可咨詢系統管理員以獲取更多關于設置標志的信息。一種確認 Infiniband 是否正常工作的方法是運行帶有 “NCCL_DEBUG=TRACE” 環境變量的 vLLM,例如 “NCCL_DEBUG=TRACE vllm serve ...”,然后查看日志中的 NCCL 版本和所用網絡。如果日志中出現 “[send] via NET/Socket”,則表示 NCCL 使用原始 TCP Socket,這對于跨節點的張量并行來說效率不高;如果出現 “[send] via NET/IB/GDRDMA”,則表示 NCCL 使用了帶 GPU-Direct RDMA 的 Infiniband,這是一種高效的通信方式。
注意:在啟動 Ray 集群后,最好還檢查節點間的 GPU - GPU 通信,這可能需要進行一些復雜的設置。可參考 sanity check 腳本來獲取更多信息(https://docs.vllm.ai/en/latest/usage/troubleshooting.html#incorrect-hardwaredriver)。如果需要設置一些環境變量來配置通信,建議在創建集群時將它們添加到 “run_cluster.sh” 腳本中,例如 “-e NCCL_SOCKET_IFNAME=eth0”。因為僅在 shell 中設置環境變量(如 “NCCL_SOCKET_IFNAME=eth0 vllm serve ...”)僅對同一節點上的進程有效,而無法對其他節點上的進程生效。
另外,要確保在所有節點上下載了模型(路徑相同),或者模型被下載到所有節點都可以訪問的分布式文件系統中。當使用 huggingface 倉庫 ID 來引用模型時,應在 “run_cluster.sh” 腳本中追加你的 huggingface 令牌,例如 “-e HF_TOKEN=” 。推薦的做法是先下載模型,然后使用路徑來引用模型。
注意:如果在多節點推理時,盡管集群中有足夠的 GPU,卻一直收到 “Error: No available node types can fulfill resource request” 的錯誤消息,很可能是因為節點具有多個 IP 地址,而 vLLM 無法找到正確的 IP 地址。請確保 vLLM 和 Ray 使用相同的 IP 地址。可以在 “run_cluster.sh” 腳本中為每個節點正確設置 “VLLM_HOST_IP” 環境變量,并通過 “ray status” 和 “ray list nodes” 查看 Ray 使用的 IP 地址。
綜上所述,vLLM 的分布式推理和部署策略為應對大型語言模型的運行挑戰提供了靈活且高效的解決方案。無論是單節點多 GPU 還是多節點多 GPU 的場景,都能通過合理配置張量并行和流水線并行的大小,充分利用集群資源,實現高效的模型推理。在實際應用中,需根據具體硬件環境和模型規模,仔細調整相關參數,并注意各種潛在的問題和注意事項,以確保 vLLM 能夠穩定、高效地運行,為人工智能領域的研究和應用提供有力支持。