适用系统:Rocky Linux / CentOS / RHEL 适用于本地 GPU + Docker 部署 Qwen2.5-VL-7B-Instruct 完整路线
一、基础环境准备
二、核心组件依赖部署
三、启动 Docker 推理服务
四、部署验证(图片推理脚本)
略,可参考我另一个文章:Shell脚本一键部署Docker(包含内网环境)-CSDN博客
# 添加 NVIDIA 源并安装 nvidia-docker2
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | \
sudo tee /etc/yum.repos.d/nvidia-docker.repo
yum install -y nvidia-docker2
systemctl restart docker
# 测试 GPU 是否可用
docker run --rm --gpus all nvidia/cuda:12.2.0-base-ubuntu22.04 nvidia-smi
# /etc/docker/daemon.json
{
"registry-mirrors": [
"http://hub-mirror.c.163.com",
"https://docker.aityp.com",
"https://docker.m.daocloud.io",
"https://dockerproxy.com",
"https://docker.mirrors.ustc.edu.cn",
"https://docker.nju.edu.cn"
],
"data-root": "/data/docker",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
},
"default-runtime": "nvidia"
}
这样可以默认使用 GPU,无需每次写 --runtime=nvidia
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh
# 配置镜像源
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --set show_channel_urls yes
# 创建 Python 3.10 环境
conda create -n qwen2.5 python=3.10 -y
conda activate qwen2.5
cd /usr/local
git clone https://github.com/QwenLM/Qwen2.5-VL.git
mv Qwen2.5-VL qwen2.5
cd /usr/local/qwen2.5
pip install -r requirements_web_demo.txt
pip install qwen-vl-utils
pip install 'qwen-vl-utils[decord]'
pip install modelscope
decord
:支持视频处理
modelscope
:中科大模型软件组件,用于加载和编解码模型
from modelscope import snapshot_download
model_name = "qwen/Qwen2.5-VL-7B-Instruct"
save_dir = "/usr/local/models/Qwen2.5-VL/model"
model_dir = snapshot_download(
model_name,
cache_dir=save_dir,
revision="master",
ignore_file_pattern=[".git*", "*.bin"],
max_workers=8
)
print(f"模型已下载至:{model_dir}")
根据实际下载结构: /usr/local/models/Qwen2.5-VL/model/qwen/Qwen2___5-VL-7B-Instruct
modelscope download --model Qwen/Qwen2.5-VL-7B-Instruct --local_dir ./
docker pull vllm/vllm-openai:latest
docker run -d \
--name vllm-qwen2.5-vl \
--gpus all \
--shm-size=16g \
-v /usr/local/models/Qwen2.5-VL/model/qwen/Qwen2___5-VL-7B-Instruct:/models \
-p 8000:8000 \
--env CUDA_VISIBLE_DEVICES=0,1 \
vllm/vllm-openai:latest \
--model /models \
--tokenizer /models \
--dtype float16 \
--tensor-parallel-size 2 \
--gpu-memory-utilization 0.90 \
--max-num-batched-tokens 4096 \
--max-model-len 4096
#启动参数可以根据本地实际需求更改
参数 | 含义 |
---|---|
--gpus all |
启用全部 GPU |
--shm-size=16g |
增加共享内存防止 OOM 错误 |
-v ...:/models |
将本地模型路径挂载到容器 |
-p 8000:8000 |
暴露推理服务端口 |
--tensor-parallel-size 2 |
启用两张 GPU 并行推理 |
--dtype float16 |
使用 FP16 节省显存并加速推理 |
--gpu-memory-utilization 0.90 |
控制单 GPU 使用率(留出 buffer) |
--max-model-len 4096 |
设置最大输入长度 |
--max-num-batched-tokens 4096 |
最大批处理 token 数,控制吞吐量 |
如果是单卡,请设置 tensor-parallel-size=1
下面脚本可以用来对推理服务进行图片添加请求,测试多模态理解能力
import os
import threading
import http.server
import socketserver
import time
import requests
# 配置部分
LOCAL_IMAGE_DIR = "/root/test" # 本地图片目录
IMAGE_FILENAME = "test2.jpg" # 图片文件名
VLLM_SERVER = "http://localhost:8000" # vllm服务地址
TEMPERATURE = 0.2 # 可调
# 获取宿主机 IP 地址 (Docker下需要宿主机IP)
HOST_IP = "172.17.0.1"
HTTP_PORT = 8888
def start_http_server():
"""在子线程中起一个本地HTTP服务器"""
os.chdir(LOCAL_IMAGE_DIR)
handler = http.server.SimpleHTTPRequestHandler
with socketserver.TCPServer(("", HTTP_PORT), handler) as httpd:
print(f"Serving HTTP at port {HTTP_PORT}")
httpd.serve_forever()
# 起HTTP服务器
threading.Thread(target=start_http_server, daemon=True).start()
# 等待服务器启动
time.sleep(2)
# 构造图片访问URL
image_url = f"http://{HOST_IP}:{HTTP_PORT}/{IMAGE_FILENAME}"
# 构造请求数据
payload = {
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "识别图中信息,按照json格式输出"},
{
"type": "image_url",
"image_url": {
"url": image_url
}
}
]
}
],
"temperature": TEMPERATURE
}
headers = {
"Content-Type": "application/json"
}
# 发送请求
print(f"Sending request with image URL: {image_url}")
response = requests.post(f"{VLLM_SERVER}/v1/chat/completions", headers=headers, json=payload)
# 输出结果
print("\nResponse:")
print(response.json())