笔记:Ubuntu环境下AMD AI MAX 395+ 使用ROCm加速并本地部署千问Qwen模型
目录
前言
一、ROCm7.0驱动安装
二、Docker环境准备(vLLM)
1. 安装并配置docker
2. 拉取vLLM镜像
2.1 将镜像文件打包进U盘
2.2 加载镜像
三、千问模型部署
1. Qwen3-32B
1.1 下载模型
1.2 启动模型
1.3 验证模型
2. Qwen3-Embedding
2.1 下载模型
2.2 启动模型
2.3 验证模型
3. Qwen3-Reranker
3.1 下载模型
3.2 配置启动脚本与uv管理
3.3 启动镜像
3.4 检验模型
前言
刚刚学习、感谢支持
环境:Ubuntu22.04、Python3.1+…
一、ROCm7.0驱动安装
官方安装指南:https://rocm.docs.amd.com/projects/install-on-linux/en/latest/install/quick-start.htmlx
选择好对应系统版本的ROCm进行安装,如果需要安装其他版本的ROCm可以在如下文档中查找相应的版本号进行替换:https://repo.radeon.com/amdgpu-install/
# 更新apt缓存
sudo apt update
sudo apt install wget -y
# 选做:如果之前安装过旧驱动,需要卸载
sudo apt autoremove amdgpu-dkms
sudo rm /etc/apt/sources.list.d/amdgpu.list
sudo rm -rf /var/cache/apt/*
sudo apt clean all
sudo apt update
# 此处我选择了7.0.3版本的ROCm,
wget https://repo.radeon.com/amdgpu-install/7.0.3/ubuntu/jammy/amdgpu-install_7.0.3.70003-1_all.deb
sudo apt install ./amdgpu-install_7.0.3.70003-1_all.deb
sudo apt install python3-setuptools python3-wheel
sudo usermod -a -G render,video $LOGNAME # Add the current user to the render and video groups
sudo apt install rocm
# 安装驱动
sudo apt update
sudo apt install "linux-headers-$(uname -r)" "linux-modules-extra-$(uname -r)"
sudo apt install amdgpu-dkms
# 下载完成后当前的用户加入到 render 和 video 用户组
sudo usermod -aG render $USER
sudo usermod -aG video $USER
# 重启
reboot
# 出现Agent2 GPU即可
rocminfo
# 最后可以再确认一下GPU代号对不对,我这里是gfx1151
rocminfo | grep gfx
二、Docker环境准备(vLLM)
1.安装并配置docker
# 1. 更新Ubuntu系统软件源
sudo apt update -y
# 2. 安装Docker依赖的基础软件包(解决证书、传输等依赖问题)
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common lrzsz -y
# 3. 添加阿里云Docker GPG密钥(验证软件源合法性)
sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# 4. 添加阿里云Docker软件源(替换官方源,提升下载速度)
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# 5. 再次更新软件源(使新增的Docker源生效)
sudo apt update -y
# 6. 安装Docker CE(社区版)
sudo apt-get install docker-ce -y
# 7. 验证Docker版本(确认安装成功)
docker version
# 8. 创建/编辑Docker镜像加速器配置文件(解决拉取镜像慢的问题)
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://docker.1panel.live",
"https://hub.rat.dev"
]
}
EOF
# 9. 重新加载Docker配置并重启服务(使镜像源配置生效)
sudo systemctl daemon-reload
sudo systemctl restart docker
2.拉取vLLM镜像
为了方便满足客户主机无法联网的需求进行了打包,用别的主机上使用了一个U盘保存了这个需要的镜像文件,如果没有此需求可以直接在需要部署的电脑上直接拉取,pul成功之后,验证存在性即可。
2.1 将镜像文件打包进U盘
# 准备一个有docker可以正常拉取外网镜像的主机,可以调整一下docker保存镜像的文件,方便后续拷贝
# 1.拉取(版本可选)
docker pull rocm/vllm:rocm7.0.0_vllm_0.11.2
# 2.这会在当前目录下生成一个名为 vllm_rocm7.tar 的大文件
docker save -o vllm_rocm7.tar rocm/vllm:rocm7.0.0_vllm_0.11.2
# 3.复制/剪切文件到U盘里(确保你的 U 盘格式是 exFAT 或 NTFS)
2.2 加载镜像
# 1. 找到U盘路径
# 通常在 /media/你的用户名/U盘名称 下
# 你可以在文件管理器里右键空白处,选择 "Open in Terminal" (在终端打开),这样最方便。
# 2. 或者手动拷贝(根据你实际情况修改路径)
cp /media/iristar/MyUSB/vllm_rocm7.tar ~/
# 3.导入镜像,可以不下载到Ubuntu本地直接在U盘里加载
docker load -i vllm_rocm7.tar
# 4.验证,出现TAG: rocm7.0.0_vllm_0.11.2
docker images
三、千问模型部署
1.Qwen3-32B
1.1 下载模型
# 1.按需创建文件
mkdir -p /home/iristar/models/Qwen-32B-AWQ
export MODEL_DIR=/home/iristar/models/Qwen-32B-AWQ
# 2. 安装/升级modelscope依赖(确保能正常下载模型)
pip3 install modelscope
# 3. 下载Qwen-32B-AWQ模型
python3 -c """
import os
from modelscope.hub.snapshot_download import snapshot_download
# 魔搭社区Qwen-32B-AWQ的正确模型ID(匹配你要的模型)
model_id = 'qwen/Qwen-32B-AWQ'
# 正确读取Shell环境变量,避免路径错误
snapshot_download(
model_id=model_id,
cache_dir=os.environ.get('MODEL_DIR'),
revision='master'
)
"""
1.2 启动模型
# 启动模型
# 其中:
# -v /home/iristar/models/Qwen3-32B:/model :请把冒号前面的 /home/iristar/models/Qwen3-32B
# 换成你真实的模型路径
# -e HSA_OVERRIDE_GFX_VERSION=11.0.0: 强行告诉程序“我是 RX 7900 XTX”,从而骗过程序,让它在
# Ryzen AI Max 395+ 上运行,说是ROCm7.1.0支持这个了,但是官方文档中我好像没看到gfx1151
# --quantization awq :下载的是 AWQ 版。
# --dtype float16 : 配合 AWQ 使用。
# --max-model-len 8192: 限制上下文长度。
docker run -it
--network=host
--group-add=video
--ipc=host
--cap-add=SYS_PTRACE
--security-opt seccomp=unconfined
--device /dev/kfd
--device /dev/dri
-v /home/iristar/models/Qwen3-32B-AWQ/qwen/Qwen3-32B-AWQ:/model
-e HSA_OVERRIDE_GFX_VERSION=11.0.0
rocm/vllm:rocm7.0.0_vllm_0.11.2_20251210
vllm serve /model
--quantization awq
--dtype float16
--served-model-name Qwen3-32B-AWQ
--trust-remote-code
--max-model-len 8192
1.3 验证模型
# 新开一个终端,拿到返回值就成功了,
curl http://localhost:8000/v1/completions
-H "Content-Type: application/json"
-d '{
"model": "Qwen3-32B-AWQ",
"prompt": "你是谁?",
"max_tokens": 2000,
"temperature": 0.7
}''
2. Qwen3-Embedding
2.1 下载模型
python3 -c """
from modelscope import snapshot_download
# 模型ID保证与社区一致
snapshot_download('Qwen/Qwen3-Embedding-8B', cache_dir='/home/iristar/models')
"""
2.2 启动模型
# 注意更改模型地址与端口号,两个名字也可以自行设置
docker run -d
--name vllm-embedding
--restart=always
--network=host
--group-add=video
--ipc=host
--cap-add=SYS_PTRACE
--security-opt seccomp=unconfined
--device /dev/kfd
--device /dev/dri
-v /home/iristar/models/Qwen3-Embedding-8B:/model
-e HSA_OVERRIDE_GFX_VERSION=11.0.0
rocm/vllm:rocm7.0.0_vllm_0.11.2_20251210
vllm serve /model
--port 8001
--task embed
--dtype float16
--max-model-len 8192
--gpu-memory-utilization 0.4
--trust-remote-code
--served-model-name qwen-embedding
2.3 验证模型
# 看容器是否存在
docker ps
# 查看日志是否有问题报错,用自己的name或container ID的前几位
docker logs vllm-embedding
# 发个测试
curl http://localhost:8001/v1/embeddings
-H "Content-Type: application/json"
-d '{
"model": "qwen-embedding",
"input": "你好,测试一下向量化服务"
}'
拿到一大堆乱七八糟的数字就可以了
3. Qwen3-Reranker
3.1 下载模型
python3 -c """
from modelscope import snapshot_download
# 模型ID保证与社区一致
snapshot_download('Qwen/Qwen3-Reranker-8B', cache_dir='/home/iristar/models')
"""
3.2 配置启动脚本与uv管理
因为vLLM现在还不支持起Qwen3的Rerank模型,所以这里选择用脚本手动起,魔塔社区有相应的示例与要求:https://www.modelscope.cn/models/Qwen/Qwen3-Reranker-8B
# 创建文件目录
mkdir -p /home/iristar/qwen_project
cd /home/iristar/qwen_project
# 找一个位置 创建一个python文件
sudo nano rerank_service.py
Python文件中写入脚本:
import torch
import uvicorn
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
from transformers import AutoModelForCausalLM, AutoTokenizer
# === 配置区域 ===
MODEL_PATH = "/model"
PORT = 8002
# =============
app = FastAPI()
print(f"Loading model from {MODEL_PATH} ...")
# 1. 加载 Tokenizer
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, padding_side='left', trust_remote_code=True)
# 2. 加载模型
model = AutoModelForCausalLM.from_pretrained(
MODEL_PATH,
trust_remote_code=True,
device_map="auto",
torch_dtype=torch.float16,
attn_implementation="flash_attention_2"
).eval()
# 3. 准备 Token IDs
token_false_id = tokenizer.convert_tokens_to_ids("no")
token_true_id = tokenizer.convert_tokens_to_ids("yes")
# 4. 准备前后缀
prefix = "<|im_start|>systemnJudge whether the Document meets the requirements based on the Query and the Instruct provided. Note that the answer can only be "yes" or "no".<|im_end|>n<|im_start|>usern"
suffix = "<|im_end|>n<|im_start|>assistantn<think>nn</think>nn"
prefix_tokens = tokenizer.encode(prefix, add_special_tokens=False)
suffix_tokens = tokenizer.encode(suffix, add_special_tokens=False)
max_length = 8192
print("Model loaded successfully!")
# === 核心处理逻辑 ===
def format_instruction(instruction, query, doc):
# 注意这里的缩进
if instruction is None or instruction == "":
instruction = 'Given a web search query, retrieve relevant passages that answer the query'
return "<Instruct>: {instruction}n<Query>: {query}n<Document>: {doc}".format(instruction=instruction, query=query, doc=doc)
def process_inputs(pairs):
inputs = tokenizer(
pairs, padding=False, truncation='longest_first',
return_attention_mask=False, max_length=max_length - len(prefix_tokens) - len(suffix_tokens)
)
for i, ele in enumerate(inputs['input_ids']):
inputs['input_ids'][i] = prefix_tokens + ele + suffix_tokens
inputs = tokenizer.pad(inputs, padding=True, return_tensors="pt", max_length=max_length)
for key in inputs:
inputs[key] = inputs[key].to(model.device)
return inputs
@torch.no_grad()
def compute_scores(inputs):
batch_scores = model(**inputs).logits[:, -1, :]
true_vector = batch_scores[:, token_true_id]
false_vector = batch_scores[:, token_false_id]
batch_scores = torch.stack([false_vector, true_vector], dim=1)
batch_scores = torch.nn.functional.log_softmax(batch_scores, dim=1)
scores = batch_scores[:, 1].exp().tolist()
return scores
# === API 定义 ===
class RerankRequest(BaseModel):
model: str = "qwen-reranker"
query: str
documents: List[str]
top_n: Optional[int] = None
instruction: Optional[str] = None
@app.post("/v1/rerank")
async def rerank(request: RerankRequest):
try:
query = request.query
documents = request.documents
instruction = request.instruction
if not documents:
return {"results": []}
pairs = [format_instruction(instruction, query, doc) for doc in documents]
inputs = process_inputs(pairs)
scores = compute_scores(inputs)
results = []
for i, score in enumerate(scores):
results.append({
"index": i,
"relevance_score": float(score),
"document": documents[i]
})
results.sort(key=lambda x: x["relevance_score"], reverse=True)
if request.top_n:
results = results[:request.top_n]
return {
"model": request.model,
"results": results,
"usage": {"total_tokens": inputs.input_ids.numel()}
}
except Exception as e:
print(f"Error: {e}")
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=PORT)
为了更好的管理与迁移,我们可以考虑使用uv来帮助管理,在同一目录下创建pyproject.toml文件,并写入相关依赖,不把 torch 写在这里,用系统自带的AMD版本
sudo nano pyproject.toml
# 写入相关资料
[project]
name = "qwen3-reranker-service"
version = "0.1.0"
description = "Rerank service using Qwen3 and ROCm"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
"transformers>=4.51.0",
"fastapi",
"uvicorn",
"modelscope",
"accelerate",
"pydantic"
]
# 注意:我们故意不把 torch 写在这里,因为我们要用系统自带的 AMD 版本
3.3 启动镜像
为了让镜像在迁移后可以直接使用,我们需要将依赖环境和业务代码全部打包进镜像中。这里我们利用临时容器来完成构建。
先创建一个镜像做一下尝试
# 启动一个临时容器
# 这里我们将项目目录挂载到临时目录 /tmp_build,目的是为了把代码拷贝进去。
docker run -it --name builder
--network=host
-v /home/iristar/qwen_project:/tmp_build
rocm/vllm:rocm7.0.0_vllm_0.11.2_20251210
bash
# 进入容器后进行下面操作
# 1. 安装uv(极速包管理器)
pip install uv -i https://pypi.tuna.tsinghua.edu.cn/simple
# 2. 创建应用目录(这是镜像内部永久存放代码的地方)
mkdir -p /app
# 3. 将代码和配置从挂载点“复制”到容器内部
# 只有复制进去了,commit的时候才会保存代码
cp /tmp_build/rerank_service.py /app/
cp /tmp_build/pyproject.toml /app/
# 4. 进入应用目录
cd /app
# 5. 使用 uv 安装依赖
# --system: 安装到系统环境,配合 Docker 使用
uv pip install --system -r pyproject.toml -i https://pypi.tuna.tsinghua.edu.cn/simple
# 6. 验证
pip list | grep transformers # 版本号大于4.51.0
ls /app # 确保能看到 python 脚本
# 7. 退出
exit
没问题的话,就可以将他固定下来
# 提交为新镜像
docker commit builder qwen-rerank:v1
# 删除临时构建容器
docker rm builder
#后续如果有需要,即可直接导出镜像文件
docker save -o qwen-rerank-v1.tar qwen-rerank:v1
现在就可以启动最终服务了
# 只需要调整挂载模型路径
# 注意/home/iristar/models/Qwen3-Reranker-8B为自己模型所在位置
docker run -d
--name final_reranker
--restart=always
--network=host
--group-add=video
--ipc=host
--cap-add=SYS_PTRACE
--security-opt seccomp=unconfined
--device /dev/kfd
--device /dev/dri
-v /home/iristar/models/Qwen3-Reranker-8B:/model
-e HSA_OVERRIDE_GFX_VERSION=11.0.0
qwen-rerank:v1
python3 /app/rerank_service.py
3.4 检验模型
# 看容器是否存在
docker ps
# 查看日志是否有问题报错,用自己的name或container ID的前几位
docker logs final_reranker
# 通过访问http://localhost:8002/docs,可以看到FastAPI的绿色POST
# 终端发送请求等
curl http://localhost:8002/v1/rerank
-H "Content-Type: application/json"
-d '{
"model": "qwen-reranker",
"query": "中国的首都在哪里?",
"documents": [
"重力是万有引力。",
"中国的首都是北京。",
"香蕉很好吃。"
]
}'