vLLM #
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