vLLM

vLLM #

https://docs.vllm.ai/en/stable/index.html

vLLM是一个快速且易于使用的库,用于大型语言模型(LLM)的推理(inference)和部署服务(serving)。

vLLM灵活且易于使用,具备以下特点:

  • 与流行的HuggingFace模型无缝集成
  • 通过各种解码算法(包括parallel sampling, beam search,等)提供高吞吐量服务
  • 支持分布式推理的张量并行和管道并行
  • 流式输出(Streaming outputs)
  • 兼容OpenAI的API服务器
  • 支持NVIDIA GPU、AMD CPU和GPU、Intel CPU和GPU、PowerPC CPU、TPU,以及AWS Trainium和Inferentia Accelerators
  • 前缀缓存(Prefix caching support)支持
  • Multi-lora支持

安装 #

参考链接https://docs.vllm.ai/en/stable/getting_started/installation.html

要求 #

  • OS: Linux
  • Python: 3.8–3.12
  • GPU: compute capability 7.0 or higher (e.g., V100, T4, RTX20xx, A100, L4, H100, etc.)

实验环境

  • OS: Ubuntu 24.04
  • Python: 3.11
  • GPU: NVIDIA GeForce RTX 4090
  • CUDA Version: 12.6

使用pip安装vLLM #

创建安装目录,将安装vLLM到当前用户的家目录的vllm目录下:

1mkdir ~/vllm
2cd ~/vllm

创建python虚拟环境:

1python3.11 -m venv .venv

激活虚拟环境并更新一下pip:

1source .venv/bin/activate
2pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple -v

安装vllm:

1pip install vllm -i https://mirrors.aliyun.com/pypi/simple -v

安装成功后查看一下.venv目录的大小:

1du -sh .venv
26.4G    .venv

注意

强烈建议使用pip安装vLLM。因为pip可以安装带有独立库包(如 NCCL)的 torch,而conda安装的torch是静态链接的NCCL。这可能导致vLLM在尝试使用NCCL时出现问题。有关更多细节,请参见此问题

注意

目前,vLLM的二进制文件默认使用CUDA 12.1和公共PyTorch发行版本进行编译。 另外还提供了使用 CUDA 11.8 和公共 PyTorch 发行版本编译的 vLLM 二进制文件:

1export VLLM_VERSION=0.6.1.post1
2export PYTHON_VERSION=310
3pip install https://github.com/vllm-project/vllm/releases/download/v${VLLM_VERSION}/vllm-${VLLM_VERSION}+cu118-cp${PYTHON_VERSION}-cp${PYTHON_VERSION}-manylinux1_x86_64.whl --extra-index-url https://download.pytorch.org/whl/cu118

为了获得最佳性能,vLLM 需要编译许多 CUDA 内核。不幸的是,这种编译会导致与其他 CUDA 版本和 PyTorch 版本的二进制不兼容,即使是相同的PyTorch版本在不同的构建配置下也会出现此问题。

如果你使用不同的CUDA版本或希望使用现有的 PyTorch 安装,你需要从源代码构建 vLLM。有关说明,请参见下

最后为当前虚拟环境生成一个requirements.txt记录一下安装的vllm版本(可选):

1pip freeze --local > requirements.txt
2
3cat requirements.txt | grep vllm
4vllm==0.6.2

快速开始使用vLLM #

参考链接https://docs.vllm.ai/en/stable/getting_started/quickstart.html

本节的目标是为大型语言模型构建API服务器,启动一个兼容OpenAI的API服务器。

创建兼容OpenAI API接口的服务器 #

注意

默认情况下,vLLM从HuggingFace下载模型。如果希望使用ModelScope的模型,请设置环境变量:

1export VLLM_USE_MODELSCOPE=True

vLLM可以作为实现OpenAI API协议的服务器进行部署。这使得vLLM可以作为使用OpenAI API的应用程序的替代品。默认情况下,它在http://localhost:8000启动服务器。可以通过--host--port参数指定地址。

继续在vllm安装目录下,同时激活虚拟环境:

1cd ~/vllm
2source .venv/bin/activate

单机多卡可设置CUDA_VISIBLE_DEVICES环境变量

1export CUDA_VISIBLE_DEVICES=1

这样vllm将使用第二个GPU。

下面以Qwen/Qwen2.5-7B-Instruct为例(预先使用huggingface-cli下载了Qwen/Qwen2.5-7B-Instruct):

1export HF_HUB_OFFLINE=1
2vllm serve Qwen/Qwen2.5-7B-Instruct \
3  --served-model-name qwen2.5-7b-instruct \
4  --enable-auto-tool-choice \
5  --tool-call-parser hermes \
6  --max-model-len=32768 \
7  --port 8000
  • --host 和 –port 参数指定地址。
  • --model 参数指定模型名称。
  • --chat-template 参数指定聊天模板。
  • --served-model-name 指定服务模型的名称。
  • --max-model-len 指定模型的最大长度。
  • --api-key指定一个API KEY。
  • --enable-auto-tool-choice
  • --tool-call-parser {mistral,hermes}

更多参数参考文档:

HF_HUB_OFFLINE环境变量

设置了HF_HUB_OFFLINE=1将不会向Hugging Face Hub发起任何HTTP调用。 注意,如果不设置HF_HUB_OFFLINE=1即使模型的最新文件已经缓存,在vllm serve时仍然会向Hugging Face Hub发送HTTP请求以检查是否有新版本可用。设置HF_HUB_OFFLINE=1将跳过此检测,从而加快加载时间,这也特别适合服务器没有外网访问时。

关于Chat Template #

为了让语言模型支持聊天协议,vLLM要求模型在其分词器配置中包含一个聊天模板。聊天模板是一个 Jinja2 模板,它指定了角色、消息和其他聊天特定标记如何在输入中编码。

一些模型即使经过了指令/聊天微调,也没有提供聊天模板。对于这些模型,可以在 --chat-template 参数中手动指定它们的聊天模板,可以是聊天模板文件的路径,也可以是字符串形式的模板。没有聊天模板,服务器将无法处理聊天,所有聊天请求都会报错。

1vllm serve <model> --chat-template ./path-to-chat-template.jinja

vLLM 社区为流行的模型提供了一组聊天模板。可以在这里的examples目录中找到它们。

测试OpenAI API接口的服务器 #

通过curl 命令查看当前的模型列表:

 1curl -s http://localhost:8000/v1/models | jq .
 2
 3{
 4  "object": "list",
 5  "data": [
 6    {
 7      "id": "qwen2.5-7b-instruct",
 8      "object": "model",
 9      "owned_by": "vllm",
10      "root": "Qwen/Qwen2.5-7B-Instruct",
11      "parent": null,
12      "max_model_len": 32768,
13      "permission": [
14        {
15          ...
16        }
17      ]
18    }
19  ]
20}

通过curl命令测试chat completions API:

 1curl -s http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" -d '{
 2  "model": "qwen2.5-7b-instruct",
 3  "messages": [
 4    {"role": "system", "content": "你是一个数学家."},
 5    {"role": "user", "content": "9.11和9.8这两个小数谁比较大?"}
 6  ],
 7  "max_tokens": 512
 8}' | jq '.choices[0].message.content'
 9
10"要比较9.11和9.8这两个小数的大小,可以从它们的小数点后每一位数字进行比较:\n\n1. 首先比较整数部分:两个数的整数部分都是9,相等。\n2. 接下来比较小数点后的第一位:9.11的小数点后第一位是1,而9.8的小数点后第一位是8。由于1小于8,可以得出9.11小于9.8。\n\n因此,9.8大于9.11。"

通过curl命令测试tool calling:

 1curl -s http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" -d '{
 2  "model": "qwen2.5-7b-instruct",
 3  "messages": [
 4    { "role": "user", "content": "What is 3 * 12? Also, what is 11 + 49?" }
 5  ],
 6  "parallel_tool_calls": false,
 7  "tools": [
 8    {
 9      "type": "function",
10      "function":  {
11        "name": "add",
12        "description": "Add two integers.",
13        "parameters": {
14            "type": "object",
15            "properties": {
16                "a": {"type": "integer"},
17                "b": {"type": "integer"}
18            },
19            "required": ["a", "b"]
20        }
21      }
22    },
23    {
24      "type": "function",
25      "function":  {
26        "name": "multiply",
27        "description": "Multiply two integers.",
28        "parameters": {
29            "type": "object",
30            "properties": {
31                "a": {"type": "integer"},
32                "b": {"type": "integer"}
33            },
34            "required": ["a", "b"]
35        }
36      }
37    }
38  ]
39}' | jq '.choices[0].message.tool_calls'
 1[
 2  {
 3    "id": "chatcmpl-tool-998a251823304412859b1eb5c79c3cd6",
 4    "type": "function",
 5    "function": {
 6      "name": "multiply",
 7      "arguments": "{\"a\": 3, \"b\": 12}"
 8    }
 9  },
10  {
11    "id": "chatcmpl-tool-b928bc51d4c44f5e90434afedc0e4a2d",
12    "type": "function",
13    "function": {
14      "name": "add",
15      "arguments": "{\"a\": 11, \"b\": 49}"
16    }
17  }

使用systemd配置为系统服务 #

使用systemd将前面部署的qwen2.5-7b-instruct配置为系统服务。

/etc/systemd/system/qwen2.5-7b-instruct.service:

 1[Unit]
 2Description=qwen2.5-7b-instruct
 3After=network.target
 4
 5[Service]
 6Type=simple
 7Environment="CUDA_VISIBLE_DEVICES=1"
 8Environment="HF_HUB_OFFLINE=1"
 9WorkingDirectory=/home/<thuser>/vllm
10User=<theuser>
11ExecStart=/bin/bash -c 'source .venv/bin/activate && \
12    vllm serve Qwen/Qwen2.5-7B-Instruct \
13        --served-model-name qwen2.5-7b-instruct \
14        --enable-auto-tool-choice \
15        --tool-call-parser hermes \
16        --max-model-len=32768 \
17        --port 8000'
18
19Restart=always
20RestartSec=3
21
22[Install]
23WantedBy=multi-user.target
1systemctl enable qwen2.5-7b-instruct

启动服务:

1systemctl start qwen2.5-7b-instruct

查看启动日志:

1journalctl -u qwen2.5-7b-instruct -f

分布式推理和服务(Distributed Inference and Serving) #

https://docs.vllm.ai/en/stable/serving/distributed_serving.html

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

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

  • 单GPU(非分布式推理 no distributed inference):如果你的模型适合单个GPU,可能不需要使用分布式推理。只需使用单个GPU进行推理即可。

  • 单节点多GPU(张量并行推理 tensor parallel inference):如果你的模型太大而无法装入单个GPU,但可以装入具有多个GPU的单个节点,则可以使用张量并行。张量并行大小是你要使用的GPU数量。例如,如果单个节点有4个GPU,可以将张量并行大小设置为4(--tensor-parallel-size 4 )。

  • 多节点多GPU(张量并行加流水线并行推理 tensor parallel plus pipeline parallel inference):如果你的模型太大而无法装入单个节点,可以同时使用张量并行和流水线并行。张量并行大小是每个节点中要使用的GPU数量,流水线并行大小是要使用的节点数量。例如,如果你在2个节点中有16个GPU(每个节点8个GPU),可以将张量并行大小设置为8,将流水线并行大小设置为2(--tensor-parallel-size 8 --pipeline-parallel-size 2)。

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

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

注意

有一种特殊情况:如果模型适合具有多个GPU的单个节点,但GPU数量无法均匀地划分模型大小,则可以使用流水线并行。流水线并行沿着层拆分模型,并支持不均匀的拆分。在这种情况下,张量并行大小应为1,流水线并行大小应为GPU的数量

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

vLLM支持分布式张量并行推理和服务。目前,支持Megatron-LM’s tensor parallel algorithm。还支持流水线并行作为在线服务的beta功能。我们使用Ray或Python原生多进程来管理分布式运行时。在单节点部署时可以使用多进程,而多节点推理目前需要Ray。

当不在Ray placement group中运行,且同一节点上有足够的GPU可用于配置的tensor_parallel_size时,默认将使用多进程,否则将使用Ray。可以通过LLM类的distributed-executor-backend参数或API服务器的--distributed-executor-backend参数来覆盖此默认设置。将其设置为mp表示使用多进程,或ray表示使用Ray。在多进程情况下,不需要安装Ray。

要使用LLM类进行多GPU推理,请将tensor_parallel_size参数设置为您想要使用的GPU数量。例如,要在4个GPU上运行推理:

1from vllm import LLM
2llm = LLM("facebook/opt-13b", tensor_parallel_size=4)
3output = llm.generate("San Franciso is a")

要运行多GPU服务,在启动服务器时传入--tensor-parallel-size参数。例如,要在4个GPU上运行API服务器:

1vllm serve facebook/opt-13b \
2    --tensor-parallel-size 4

还可以额外指定--pipeline-parallel-size来启用流水线并行。例如,要在8个GPU上运行具有流水线并行和张量并行的API服务器:

1vllm serve gpt2 \
2    --tensor-parallel-size 4 \
3    --pipeline-parallel-size 2

注意

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

多节点推理和服务 #

Multi-Node Inference and Serving

单节点多卡推理和服务 #

© 2024 青蛙小白