Qwen2.5-VL 使用 vLLM 部署运维实战指南¶
1. 环境准备¶
1.1 硬件要求¶
Qwen2.5-VL-3B-Instruct¶
- NVIDIA GPU:至少 12GB 显存
- 推荐显卡:NVIDIA A10(24GB)/RTX 4070Ti(12GB)/RTX 4080(16GB)
- 最低支持:NVIDIA RTX 3060 12GB
- 系统内存:至少 24GB(推荐 32GB)
- 存储空间:至少 20GB 可用空间(模型文件约 8GB)
Qwen2.5-VL-7B-Instruct¶
- NVIDIA GPU:至少 16GB 显存
- 推荐显卡:NVIDIA A10(24GB)/A4500(20GB)/RTX 4080(16GB)
- 最低支持:NVIDIA RTX 4080 16GB
- 系统内存:至少 32GB(推荐 48GB)
- 存储空间:至少 30GB 可用空间(模型文件约 16GB)
Qwen2.5-VL-72B-Instruct¶
- NVIDIA GPU:至少 80GB 显存(单卡部署)或多卡分布式部署
- 推荐显卡配置:
- 单卡:NVIDIA A100/H100 80GB
- 多卡:2-4张 NVIDIA A100 40GB 或 A800 40GB
- 多卡:2张 NVIDIA A100 80GB 或 H100 80GB
- 系统内存:至少 128GB(推荐 256GB)
- 存储空间:至少 200GB 可用空间(模型文件约 150GB)
1.2 软件要求¶
- vLLM 版本要求:
- vLLM >= 0.3.3(推荐 0.3.3)
- 3B/7B 模型:支持 vLLM 0.2.7 及以上版本
- 72B 模型:必须使用 vLLM 0.3.3 及以上版本
-
主要依赖版本:
- torch >= 2.1.0
- transformers >= 4.37.0
- accelerate >= 0.27.0
- ray >= 2.9.0(用于分布式推理)
-
操作系统:
- Ubuntu 20.04/22.04 LTS(推荐)
- CentOS ⅞(支持)
-
Rocky Linux 8/9(支持)
-
CUDA 要求:
- CUDA 11.8 及以上(推荐 CUDA 12.1)
- cuDNN 8.7.0 及以上
-
NVIDIA 驱动版本 >= 525.60.13
-
Python 环境:
- Python 3.8-3.10(推荐 Python 3.10)
- pip >= 23.0.1
-
virtualenv >= 20.0.0(推荐使用虚拟环境)
-
容器环境(推荐):
- Docker >= 24.0.0
- NVIDIA Container Toolkit >= 1.13.0
- docker-compose >= 2.20.0
1.3 网络要求¶
- 带宽:建议至少 100Mbps
- 延迟:建议低于 100ms
- 公网 IP(如需提供外部服务)
- 防火墙配置:开放服务端口(默认 8000)
1.4 推荐系统配置¶
开发测试环境¶
- CPU: AMD EPYC 7302 16核 或 Intel Xeon Gold 5315Y
- 内存: 64GB DDR4
- 存储: 512GB NVMe SSD
- GPU: NVIDIA A10 24GB
生产环境¶
- CPU: AMD EPYC 7713 64核 或 Intel Xeon Platinum 8358
- 内存: 256GB DDR4 ECC
- 存储: 2TB NVMe SSD(RAID 1)
- GPU: 2-4x NVIDIA A100 40GB 或 2x A100 80GB
- 网络: 万兆网卡
2. 安装部署¶
2.1 基础环境安装¶
# 创建虚拟环境
python -m venv venv
source venv/bin/activate
# 安装基础依赖
pip install torch==2.1.2 torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install vllm==0.3.3 transformers==4.37.2 accelerate==0.27.0
# 如果需要分布式部署,安装 Ray
pip install "ray[default]>=2.9.0"
2.2 Docker 部署(推荐)¶
- 创建 Dockerfile:
FROM nvidia/cuda:11.8.0-devel-ubuntu22.04
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
python3.10 \
python3-pip \
git \
&& rm -rf /var/lib/apt/lists/*
# 安装 Python 依赖
RUN pip3 install --no-cache-dir \
torch==2.1.2 \
vllm==0.3.3 \
transformers==4.37.2 \
accelerate==0.27.0 \
sentencepiece \
pillow \
ray>=2.9.0
# 设置环境变量
ENV CUDA_VISIBLE_DEVICES=all
# 下载模型(可选,也可以通过挂载卷的方式加载模型)
RUN pip3 install modelscope
RUN python3 -c "from modelscope import snapshot_download; snapshot_download('qwen/Qwen2.5-VL')"
EXPOSE 8000
CMD ["python3", "-m", "vllm.entrypoints.openai.api_server", \
"--host", "0.0.0.0", \
"--port", "8000", \
"--model", "qwen/Qwen2.5-VL", \
"--trust-remote-code"]
- 创建 docker-compose.yml:
version: '3'
services:
qwen-vl-vllm:
build: .
runtime: nvidia
environment:
- NVIDIA_VISIBLE_DEVICES=all
ports:
- "8000:8000"
volumes:
- ./models:/app/models # 如果使用本地模型
- ./images:/app/images # 用于存放测试图片
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
- 启动服务:
docker-compose up -d
2.3 使用本地模型¶
如果您已经将模型下载到本地,可以通过以下方式使用:
- 直接使用本地路径:
# 启动服务时指定本地模型路径
python -m vllm.entrypoints.openai.api_server \
--model /path/to/local/Qwen2.5-VL \
--trust-remote-code \
--host 0.0.0.0 \
--port 8000
- Docker 部署时挂载本地模型:
version: '3'
services:
qwen-vl-vllm:
build: .
runtime: nvidia
environment:
- NVIDIA_VISIBLE_DEVICES=all
# 使用本地模型
- VLLM_MODEL_PATH=/app/models/Qwen2.5-VL
# 如果使用 ModelScope,设置缓存目录
- MODELSCOPE_CACHE=/app/models
ports:
- "8000:8000"
volumes:
# 挂载本地模型目录
- /path/to/local/models:/app/models
command: >
python3 -m vllm.entrypoints.openai.api_server
--model /app/models/Qwen2.5-VL
--trust-remote-code
--host 0.0.0.0
--port 8000
- 使用环境变量配置:
# 设置模型路径环境变量
export VLLM_MODEL_PATH=/path/to/local/Qwen2.5-VL
# 如果使用 ModelScope,设置缓存目录
export MODELSCOPE_CACHE=/path/to/models/cache
# 启动服务
python -m vllm.entrypoints.openai.api_server \
--model $VLLM_MODEL_PATH \
--trust-remote-code \
--host 0.0.0.0 \
--port 8000
- 本地模型目录结构示例:
/path/to/local/Qwen2.5-VL/
├── config.json
├── configuration.json
├── generation_config.json
├── model.safetensors
├── pytorch_model.bin
├── special_tokens_map.json
├── tokenizer.json
└── tokenizer_config.json
注意事项: 1. 确保模型文件权限正确(读取权限) 2. Docker 部署时注意挂载目录的权限 3. 建议使用绝对路径避免路径解析问题 4. 如果模型文件较大,确保磁盘空间充足
2.4 直接部署¶
# 下载模型
pip install modelscope
python -c "from modelscope import snapshot_download; snapshot_download('qwen/Qwen2.5-VL')"
# 启动服务
python -m vllm.entrypoints.openai.api_server \
--model qwen/Qwen2.5-VL \
--trust-remote-code \
--host 0.0.0.0 \
--port 8000
3. 性能优化¶
3.1 显存优化¶
# 启动时添加显存优化参数
python -m vllm.entrypoints.openai.api_server \
--model qwen/Qwen2.5-VL \
--trust-remote-code \
--gpu-memory-utilization 0.85 \
--max-num-batched-tokens 4096 \
--max-num-seqs 256
3.2 多 GPU 部署¶
# 使用张量并行
python -m vllm.entrypoints.openai.api_server \
--model qwen/Qwen2.5-VL \
--trust-remote-code \
--tensor-parallel-size 2
3.3 量化部署¶
# 使用 AWQ 量化
python -m vllm.entrypoints.openai.api_server \
--model qwen/Qwen2.5-VL \
--trust-remote-code \
--quantization awq \
--dtype float16
4. API 调用示例¶
4.1 Python 示例¶
from openai import OpenAI
import base64
import json
def encode_image(image_path):
"""将图片转换为 base64 编码"""
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
# 初始化客户端
client = OpenAI(
base_url="http://localhost:8000/v1", # vLLM API 地址
api_key="dummy" # vLLM 不需要实际的 API key
)
# 1. 基础图文理解示例
def basic_vision_chat(image_path, question):
base64_image = encode_image(image_path)
completion = client.chat.completions.create(
model="qwen2.5-vl", # 或 "qwen2.5-vl-chat"
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": question},
{
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}
}
]
}
],
temperature=0.7,
max_tokens=2048
)
return completion.choices[0].message.content
# 2. 多轮对话示例
def multi_turn_chat(image_path):
base64_image = encode_image(image_path)
messages = [
{
"role": "user",
"content": [
{"type": "text", "text": "这张图片里有什么?"},
{
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}
}
]
},
{
"role": "assistant",
"content": "这是一张..." # 助手的回复
},
{
"role": "user",
"content": "请详细描述图中的..." # 用户的后续提问
}
]
completion = client.chat.completions.create(
model="qwen2.5-vl",
messages=messages,
temperature=0.7,
max_tokens=2048
)
return completion.choices[0].message.content
# 3. 批量处理示例
def batch_process_images(image_paths, question):
responses = []
for image_path in image_paths:
base64_image = encode_image(image_path)
completion = client.chat.completions.create(
model="qwen2.5-vl",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": question},
{
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}
}
]
}
],
temperature=0.7,
max_tokens=1024
)
responses.append({
'image': image_path,
'response': completion.choices[0].message.content
})
return responses
# 4. 流式输出示例
def stream_chat(image_path, question):
base64_image = encode_image(image_path)
completion = client.chat.completions.create(
model="qwen2.5-vl",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": question},
{
"type": "image_url",
"image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}
}
]
}
],
temperature=0.7,
max_tokens=2048,
stream=True # 启用流式输出
)
for chunk in completion:
if chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end="", flush=True)
# 使用示例
if __name__ == "__main__":
# 基础图文理解
response = basic_vision_chat("path/to/image.jpg", "这张图片里有什么?")
print("基础图文理解结果:", response)
# 多轮对话
response = multi_turn_chat("path/to/image.jpg")
print("多轮对话结果:", response)
# 批量处理
image_paths = ["image1.jpg", "image2.jpg", "image3.jpg"]
responses = batch_process_images(image_paths, "描述这张图片")
print("批量处理结果:", json.dumps(responses, ensure_ascii=False, indent=2))
# 流式输出
print("流式输出结果:")
stream_chat("path/to/image.jpg", "详细描述这张图片")
4.2 CURL 示例¶
# 1. 基础图文理解请求
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen2.5-vl",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "这张图片里有什么?"
},
{
"type": "image_url",
"image_url": {
"url": "data:image/jpeg;base64,..."
}
}
]
}
],
"temperature": 0.7,
"max_tokens": 2048
}'
# 2. 流式输出请求
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "qwen2.5-vl",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "这张图片里有什么?"
},
{
"type": "image_url",
"image_url": {
"url": "data:image/jpeg;base64,..."
}
}
]
}
],
"temperature": 0.7,
"max_tokens": 2048,
"stream": true
}'
4.3 注意事项¶
- 图片要求:
- 支持格式:JPEG、PNG、GIF(静态)
- 建议分辨率:小于 2048x2048
-
文件大小:建议小于 5MB
-
API 限制:
- 并发请求数:默认最大 256
- 超时时间:默认 300 秒
-
令牌数限制:默认最大 2048
-
错误处理:
- 图片格式错误:检查图片格式和大小
- 模型加载失败:检查模型路径和显存
-
超时错误:调整超时参数或减少处理内容
-
性能优化:
- 使用批量处理提高吞吐量
- 启用流式输出提升用户体验
- 合理设置并发数和超时时间