分布式推理和服务#

如何决定分布式推理策略?#

在深入了解分布式推理和服务的细节之前,让我们先明确何时使用分布式推理以及有哪些可用的策略。常见的做法是:

  • 单 GPU(无分布式推理):如果你的模型适合单个 GPU,你可能不需要使用分布式推理。只需使用单个 GPU 来运行推理。

  • 单节点多 GPU(张量并行推理):如果你的模型太大,无法放入单个 GPU,但它可以放入具有多个 GPU 的单个节点,你可以使用张量并行。张量并行大小是你想要使用的 GPU 数量。例如,如果你在一个节点中有 4 个 GPU,你可以将张量并行大小设置为 4。

  • 多节点多 GPU(张量并行加流水线并行推理):如果你的模型太大,无法容纳在一个节点中,你可以使用张量并行和流水线并行。张量并行大小是你想要在每个节点中使用的 GPU 数量,流水线并行大小是你想要使用的节点数量。例如,如果你在 2 个节点中拥有 16 个 GPU(每个节点 8 个 GPU),你可以将张量并行大小设置为 8,流水线并行大小设置为 2。

简而言之,你应该增加 GPU 数量和节点数量,直到你有足够的 GPU 内存来容纳模型。张量并行大小应该是每个节点中的 GPU 数量,流水线并行大小应该是节点数量。

在添加足够的 GPU 和节点来容纳模型后,你可以先运行 vLLM,它会打印一些日志,例如“# GPU 块:790”。将该数字乘以“16”(块大小),你就可以大致得到当前配置下可以服务的最大令牌数。如果这个数字不令人满意,例如你想要更高的吞吐量,你可以进一步增加 GPU 或节点数量,直到块数量足够。

备注

有一种特殊情况:如果模型可以容纳在一个具有多个 GPU 的节点中,但 GPU 数量不能均匀地划分模型大小,你可以使用流水线并行,它会沿着层分割模型并支持不均匀分割。在这种情况下,张量并行大小应该为 1,流水线并行大小应该是 GPU 数量。

分布式推理和服务的详细信息#

vLLM 支持分布式张量并行推理和服务。目前,我们支持 Megatron-LM 的张量并行算法。我们还支持管道并行作为在线服务的测试功能。我们使用 Ray 或 Python 原生多进程来管理分布式运行时。在单节点部署时可以使用多进程,多节点推理目前需要 Ray。

在没有运行在 Ray 部署组中且同一节点上具有足够的 GPU 可用于配置的 tensor_parallel_size 时,将默认使用多进程,否则将使用 Ray。此默认值可以通过 LLMdistributed-executor-backend 参数或 --distributed-executor-backend API 服务器参数覆盖。将其设置为 mp 用于多进程或 ray 用于 Ray。对于多进程情况,不需要安装 Ray。

要使用 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 Franciso is a")

要运行多 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

备注

管道并行是测试功能。它仅支持在线服务以及 LLaMa、GPT2、Mixtral、Qwen、Qwen2 和 Nemotron 风格的模型。

多节点推理和服务#

如果单个节点没有足够的 GPU 来容纳模型,你可以使用多个节点运行模型。重要的是确保所有节点上的执行环境相同,包括模型路径和 Python 环境。推荐使用 Docker 镜像来确保相同的环境,并通过将它们映射到相同的 Docker 配置中来隐藏主机机器的异构性。

第一步是启动容器并将它们组织成一个集群。我们提供了一个辅助脚本 <vllm-project/vllm> 来启动集群。

选择一个节点作为头节点,并运行以下命令:

$ bash run_cluster.sh \
$                   vllm/vllm-openai \
$                   ip_of_head_node \
$                   --head \
$                   /path/to/the/huggingface/home/in/this/node

在其余工作节点上,运行以下命令:

$ bash run_cluster.sh \
$                   vllm/vllm-openai \
$                   ip_of_head_node \
$                   --worker \
$                   /path/to/the/huggingface/home/in/this/node

然后你将获得一个容器的 Ray 集群。请注意,你需要保持运行这些命令的 shell 处于活动状态以维持集群。任何 shell 断开连接都会终止集群。此外,请注意,参数 ip_of_head_node 应该是头节点的 IP 地址,所有工作节点都可以访问该地址。一个常见的误解是使用工作节点的 IP 地址,这是不正确的。

然后,在任何节点上,使用 docker exec -it node /bin/bash 进入容器,执行 ray status 检查 Ray 集群的状态。你应该看到正确数量的节点和 GPU。

之后,在任何节点上,你可以像往常一样使用 vLLM,就像你拥有一个节点上的所有 GPU 一样。常见的做法是将张量并行大小设置为每个节点的 GPU 数量,并将管道并行大小设置为节点数量。例如,如果你在 2 个节点中有 16 个 GPU(每个节点 8 个 GPU),你可以将张量并行大小设置为 8,并将管道并行大小设置为 2:

$ vllm serve /path/to/the/model/in/the/container \
$     --tensor-parallel-size 8 \
$     --pipeline-parallel-size 2

你也可以在没有管道并行的情况下使用张量并行,只需将张量并行大小设置为集群中的 GPU 数量。例如,如果你在 2 个节点中有 16 个 GPU(每个节点 8 个 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 通信。设置起来可能并不容易。有关更多信息,请参阅 健全性检查脚本。如果你需要为通信配置设置一些环境变量,可以将它们添加到 run_cluster.sh 脚本中,例如 -e NCCL_SOCKET_IFNAME=eth0。请注意,在 shell 中设置环境变量(例如 NCCL_SOCKET_IFNAME=eth0 vllm serve …)仅适用于同一节点中的进程,不适用于其他节点中的进程。在创建集群时设置环境变量是推荐的方法。有关更多信息,请参阅 讨论

警告

请确保你已将模型下载到所有节点(路径相同),或者模型已下载到所有节点都可以访问的某个分布式文件系统。

当你使用 Hugging Face 仓库 ID 来引用模型时,你应该将你的 Hugging Face 令牌追加到 run_cluster.sh 脚本中,例如 -e HF_TOKEN=。推荐的方式是先下载模型,然后使用路径来引用模型。