海光GPU上部署VLM模型Qwen2.5-VL-32B-Instruct

前言

相关网站

ModelScope

ModelScope 魔搭社区

海光开发者社区

光源-光合开发者社区

准备工作

环境测试代码

验证 PyTorch 是否识别海光 GPU

/data/aitest/ai-server-qwen-vl/cuda_test.py

1
2
3
4
5
import torch
print(torch.__version__)
print(torch.cuda.is_available())
print(torch.cuda.device_count())
print(torch.cuda.get_device_name(0))

注意:

在 ROCm 中,torch.cuda 接口仍然可用(AMD/海光做了 CUDA API 兼容层),所以代码无需修改。

代码路径为

1
/data/aitest/ai-server-qwen-vl

下载模型

Qwen2.5-VL-32B-Instruct

千问2.5-VL-32B-Instruct · 模型库

下载模型

1
modelscope download --model Qwen/Qwen2.5-VL-32B-Instruct

模型下载位置为

1
/data/tools/modelscope

步骤

vLLM镜像启动

注意:

这个模型没法用vllm直接运行,这里使用该镜像是因为它也满足了运行该模型的环境的其他依赖。

下载vllm镜像

1
docker pull image.sourcefind.cn:5000/dcu/admin/base/vllm:0.8.5-ubuntu22.04-dtk25.04.1-rc5-das1.6-py3.10-20250724

运行容器

我这里下载镜像的 IMAGE ID是efc1a5d819c4

1
docker run -it --shm-size 64g --network=host --name vllm_085 --privileged --device=/dev/kfd --device=/dev/dri --device=/dev/mkfd --group-add video --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -u root -v /opt/hyhal/:/opt/hyhal/:ro -v /data/tools/modelscope/:/data/tools/modelscope/ -v /data/aitest/ai-server-qwen-vl/:/data/aitest/ai-server-qwen-vl/ efc1a5d819c4 bash

参数说明:

  • -it:以交互模式运行容器,并分配一个伪终端(TTY)。
  • --shm-size 64g:将容器的共享内存(/dev/shm)大小设为 64GB,供 vLLM 等大模型推理使用。
  • --network=host:让容器直接使用宿主机的网络命名空间(端口无需映射)。
  • --name vllm_085:给容器指定名称为 vllm_085
  • --privileged:赋予容器几乎全部系统权限(用于访问硬件设备,但有安全风险)。
  • --device=/dev/kfd:将海光/AMD 的 KFD(Kernel Fusion Driver)计算设备挂载进容器。
  • --device=/dev/dri:挂载 DRI 图形/计算设备节点,用于 GPU/DCU 访问。
  • --device=/dev/mkfd:挂载海光特有的多卡管理设备(如 Multi-KFD)。
  • --group-add video:将容器内用户加入 video 用户组,获得设备访问权限。
  • --cap-add=SYS_PTRACE:授予容器进程跟踪(ptrace)能力,用于调试或性能分析。
  • --security-opt seccomp=unconfined:禁用 seccomp 安全限制,避免 DCU 驱动调用被拦截。
  • -u root:以 root 用户身份在容器内运行。
  • -v /opt/hyhal/:/opt/hyhal/:ro:将宿主机的海光 HAL 驱动库以只读方式挂载到容器内。
  • -v /data/tools/modelscope/:/data/tools/modelscope/:挂载 ModelScope 模型缓存目录,供容器内使用。
  • -v /data/aitest/ai-server-qwen-vl/:/data/aitest/ai-server-qwen-vl/:挂载自定义测试数据或代码目录。
  • efc1a5d819c4:要运行的 Docker 镜像 ID(或可替换为完整镜像名)。
  • bash:容器启动后执行的命令(进入 bash shell)。

如果已经运行可以这样进入

1
docker exec -it vllm_085 bash

安装依赖

推理相关

查看容器内是否有所需依赖

1
2
3
4
5
pip list | grep transformers
pip list | grep accelerate

# 或者
pip list | grep -E 'transformers|accelerate'

这里是都安装了

1
2
accelerate                               1.9.0
transformers 4.51.1

API相关

服务启动依赖

1
pip list | grep -E 'fastapi|uvicorn|pydantic'

modelscope

安装

1
pip install modelscope

环境变量

创建目录

1
2
mkdir -p /data/tools/modelscope
chmod 755 /data/tools/modelscope

添加环境变量

添加

1
echo 'export MODELSCOPE_CACHE="/data/tools/modelscope"' >> ~/.bashrc

重新加载配置

1
source ~/.bashrc

验证

1
2
echo $MODELSCOPE_CACHE
# 输出应为:/data/tools/modelscope

查看

1
vim ~/.bashrc

图片处理工具包

它可以更方便地处理各种类型的视觉输入,就像使用API一样。这包括base64、URL以及混合的图片和视频。

您可以使用以下命令安装它:

1
pip install qwen-vl-utils[decord]==0.0.8

运行模型

/data/aitest/ai-server-qwen-vl/run_qwen_vl.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import torch
from modelscope import AutoProcessor, AutoTokenizer, Qwen2_5_VLForConditionalGeneration
from qwen_vl_utils import process_vision_info

# default: Load the model on the available device(s)
model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
"Qwen/Qwen2.5-VL-32B-Instruct",
torch_dtype=torch.bfloat16,
attn_implementation="flash_attention_2",
device_map="auto",
)

# 我们现在要推理,不是训练!
model.eval()
# 可选,进一步节省显存和计算
torch.set_grad_enabled(False)

# default processer
processor = AutoProcessor.from_pretrained("Qwen/Qwen2.5-VL-32B-Instruct", use_fast=True)


messages = [
{
"role": "user",
"content": [
{
"type": "image",
"image": "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-VL/assets/demo.jpeg",
},
{"type": "text", "text": "描述该图片."},
],
}
]

# Preparation for inference
text = processor.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
image_inputs, video_inputs = process_vision_info(messages)
inputs = processor(
text=[text],
images=image_inputs,
videos=video_inputs,
padding=True,
return_tensors="pt",
)
inputs = inputs.to("cuda")

# Inference: Generation of the output
generated_ids = model.generate(**inputs, max_new_tokens=512)
generated_ids_trimmed = [
out_ids[len(in_ids) :] for in_ids, out_ids in zip(inputs.input_ids, generated_ids)
]
output_text = processor.batch_decode(
generated_ids_trimmed,
skip_special_tokens=True,
clean_up_tokenization_spaces=False,
)
print(output_text)

运行

1
2
cd /data/aitest/ai-server-qwen-vl
python ./run_qwen_vl.py

添加服务

我们需要开发接口服务,这里就不提供接口服务的代码了。

服务启动脚本

/data/aitest/ai-server-qwen-vl/run.sh

1
2
export PYTHONPYCACHEPREFIX=".cache/pycache"
python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8002

Docker

Dockerfile

/data/aitest/ai-server-qwen-vl/Dockerfile

1
2
3
4
5
6
7
8
FROM image.sourcefind.cn:5000/dcu/admin/base/vllm:0.8.5-ubuntu22.04-dtk25.04.1-rc5-das1.6-py3.10-20250724

RUN pip install modelscope
ENV MODELSCOPE_CACHE="/data/tools/modelscope"

RUN pip install qwen-vl-utils[decord]==0.0.8

EXPOSE 8002

Docker Compose

/data/aitest/ai-server-qwen-vl/docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
version: '3.8'

services:
qwen25vl:
build:
context: ./
dockerfile: Dockerfile
image: qwen25vl
container_name: qwen25vl_01
privileged: true
network_mode: host
user: root
shm_size: '64g'
cap_add:
- SYS_PTRACE
security_opt:
- seccomp:unconfined
group_add:
- video
devices:
- /dev/kfd
- /dev/dri
- /dev/mkfd
volumes:
- /opt/hyhal/:/opt/hyhal/:ro
- /data/tools/modelscope/:/data/tools/modelscope/
- /data/aitest/ai-server-qwen-vl/:/data/aitest/ai-server-qwen-vl/
working_dir: /data/aitest/ai-server-qwen-vl/
command: [ "sh", "run.sh" ]

启动

1
docker-compose up -d

停止并删除

1
docker-compose down

模型加载封装

要将模型和 processor 放在全局,以便在 FastAPI(或其他 Web 框架)的多个路由或模块中复用

核心原则是:只加载一次,全局可访问,避免重复加载

使用 单例模块(Singleton Module)

这是最清晰、可维护性最好的方式。

步骤 1

创建一个独立的模型加载模块(如 model_loader.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# model_loader.py
from modelscope import Qwen2_5_VLForConditionalGeneration, AutoProcessor
import torch

# 全局变量(模块级)
_model = None
_processor = None

def get_model():
global _model
if _model is None:
print("Loading Qwen2.5-VL model...")
_model = Qwen2_5_VLForConditionalGeneration.from_pretrained(
"Qwen/Qwen2.5-VL-32B-Instruct",
torch_dtype="auto",
device_map="auto"
)
_model.eval()
torch.set_grad_enabled(False)
print("Model loaded.")
return _model

def get_processor():
global _processor
if _processor is None:
print("Loading processor...")
_processor = AutoProcessor.from_pretrained("Qwen/Qwen2.5-VL-32B-Instruct")
print("Processor loaded.")
return _processor

TIP

利用 Python 模块的单次导入机制_model_processor 只会被初始化一次。

步骤 2

在任意路由或业务逻辑中调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# api/v1/chat.py 或 main.py
from fastapi import APIRouter
from model_loader import get_model, get_processor
from qwen_vl_utils import process_vision_info

router = APIRouter()

@router.post("/chat")
async def chat(...):
model = get_model()
processor = get_processor()

# 后续推理逻辑...
# ...

或者在主应用中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# main.py
from fastapi import FastAPI
from model_loader import get_model, get_processor

app = FastAPI()

@app.on_event("startup")
async def startup_event():
# 可选:预热模型(提前加载,避免首次请求卡顿)
get_model()
get_processor()

@app.post("/chat")
async def chat(...):
model = get_model()
processor = get_processor()
# ...

常用速查

查看驱动是否安装

1
lsmod | grep hycu

查看显卡型号

1
clinfo | grep -A 2 "Device Type"

可以看到 Board name

1
2
3
Device Type:                                   CL_DEVICE_TYPE_GPU
Vendor ID: 1d94h
Board name: K100_AI

GPU使用情况

功能类似于 NVIDIA 的 nvidia-smi 或 AMD 的 rocm-smi,用于监控和管理海光 GPU 的状态。

输入

1
hy-smi

查看剩余显存

1
hy-smi --showmemavailable

显示总显存和已用显存

1
hy-smi --showmeminfo vram

查看是否有进程在使用 GPU

1
hy-smi --showpids

查看显存是否启用 ECC(关键用于稳定性)

1
hy-smi --showmemeccinfo

判断是否在容器内

执行

1
systemd-detect-virt
  • 容器内可能返回:dockerpodmanlxcprivate-users
  • 宿主机通常返回:nonekvm/vmware(如果是虚拟机)

安装(如未安装):

1
2
apt-get install -y systemd-container  # Debian/Ubuntu
yum install -y systemd # CentOS/RHEL