最近由于项目原因,拿到了 95 万元的华为云代金券。项目需要进行大规模的大模型推理生成任务,为了利用好华为云的资源,于是我研究了下如何在华为云的昇腾 910B 平台部署大模型。尽管没有成熟的 CUDA 平台方便,但实际上整个流程也没有太过于困难,本篇文章便简单分享一下部署经验吧。
注意:国产平台还在高速发展期,本文的操作流程只对当前版本负责,后续版本如果出现变化可能本文就不适用了。
1 本文内容
在华为国产计算平台,完成大模型多机多卡的高性能分布式推理:张量并行(Tensor Parallel)+流水线并行(Pipeline Parallel)+专家并行(Expert Parallel)。文章以 910B4 32G 为例(理论上所有昇腾 NPU 都可用),以 Qwen3 模型为例(理论上所有 vLLM 支持的模型都可用)。
2025/10/22 UPD: 已验证 2*8 卡 910B2 总计 1024GB 显存配置同样可成功部署。
项目使用华为云的 ModelArts 轻量算力集群产品,购买了 2 台 8 卡昇腾 910B4 进行分布式推理,单台配置如下:
| 类型 | 规格 |
|---|---|
| CPU | 4*鲲鹏 920 48核=192核 |
| 内存 | 24*64GB=1.5TB |
| NPU | 8*昇腾 910B4 32G |
| 磁盘 | 3*7.68TB NVMe |
| 网络 | 2*100GE标准网卡+8*200GE卡间互联 |
| 系统 | EulerOS 2.0 (SP10) |
| 驱动 | 7.5.0.5.220-24.1.0.3 |
如果你要参照本文进行部署,请确保你使用的 CPU 为鲲鹏 920 且 NPU 为昇腾系列,且昇腾 NPU 配置了 RoCE 的高速互联网络。
本文主要参考文档:https://vllm-ascend.readthedocs.io/en/latest/quick_start.html。这个文档写得真的很不错,属于国产平台文档里写得很详尽的一档了,跟着走基本没出现什么问题。
2 环境配置
如果你要进行分布式多机多卡推理,那么每台节点都需要完成下面的环境配置操作。
2.1 安装 Docker
本文使用 Docker 进行部署,原因是 vLLM Ascend 提供了官方的 Docker 镜像,免去了繁琐的依赖库配置步骤,因此首先需要安装 Docker。
我购买服务器时直接选择了 Docker 作为容器引擎(默认是 contained),因此服务器初始化好后直接自带了 Docker。如果你的服务器还没有 Docker,可以使用软件包管理器安装:yum install docker
安装后查看 Docker 版本:docker -v ,本文使用的版本为 Docker version 18.09.0, build ca986cf。
2.2 拉取 vLLM-Ascend 镜像
vLLM 是一款高性能的大模型推理框架,而 vLLM-Ascend 是 vLLM 的插件,用于支持昇腾平台。本文撰写时,最新的镜像是 quay.io/ascend/vllm-ascend:v0.11.0rc0,大家拉取时可以在文档中查找最新的版本拉取。
使用指令 docker pull quay.io/ascend/vllm-ascend:v0.11.0rc0 进行镜像拉取,镜像大小有 15GB ,可能得自行配置一下镜像站来加速拉取。
2.3 准备模型
自行下载需要运行的模型到节点中,模型格式为标准 Transformers 库的格式即可。如果你需要使用量化模型,请注意你并不能使用网上为 CUDA 平台量化的版本,下文会有说明。(最方便的还是使用原始精度)
本文使用 2*8 卡昇腾 910B4 总计 512GB 显存,为了测试方便,选择了 Qwen3-VL-30B-A3B-Instruct 这个参数量很小的模型。实际上该配置可以运行 235B 的量化版本了。
3 运行模型
3.1 单机多卡
3.1.1 启动 vLLM-Ascend 容器
使用以下指令启动 vLLM-Ascend 容器:
docker run --rm \
--name vllm-ascend-env \
--net=host \
--device /dev/davinci0 \
--device /dev/davinci1 \
--device /dev/davinci2 \
--device /dev/davinci3 \
--device /dev/davinci4 \
--device /dev/davinci5 \
--device /dev/davinci6 \
--device /dev/davinci7 \
--device /dev/davinci_manager \
--device /dev/devmm_svm \
--device /dev/hisi_hdc \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
-v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /root/.cache:/root/.cache \
-v /data:/data \
-it quay.io/ascend/vllm-ascend:v0.11.0rc0 bash
如果要控制使用哪几个 NPU,可以修改 --device 参数,这里选择将 8 张 NPU 全部传入容器。另外注意将下好模型的目录挂载到容器中,我的模型储存在 /data 目录下,因此使用 -v /data:/data 将整个 /data 目录挂载到容器内,这样容器就可以读取下好的模型了。
容器启动需要一段时间,运行该指令后,稍作等待应该就能进入容器内的命令行了(可以发现用户变成容器里的 root 了)。
如果要退出容器,则使用 exit 退出命令行即可。需要注意的是,除了挂载到容器内的目录,对其他目录的修改在退出容器后均不会保存。
3.1.2 升级 transformers 库(可选)
如果你使用的模型架构很新,有可能容器里的 transformers 库还没有支持,这种情况就需要升级 transformers 库的版本了。模型所需的最低 transformers 库版本一般在官方的模型仓库中会注明,可以自行检查是否兼容。
本文的容器版本中包含的 transformers 库版本为 4.56.2,而 Qwen3-VL 的模型架构在 4.57.0 版本才引入,因此没法直接运行,得用以下指令升级库版本:
pip install transformers==4.57.0 -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
注意,上文提到了除了挂载到容器内的目录,对其他目录的修改在退出容器后均不会保存,因此本次升级也不会保存。再退出容器后,下次启动还需要重新升级。
3.1.3 运行模型
完成了一切准备操作,终于可以开始运行模型了!使用以下指令启动 vllm:
vllm serve /data/Qwen3-VL-30B-A3B-Instruct \ --served-model-name qwen3-vl \ --disable-uvicorn-access-log \ --disable-log-requests \ --tensor-parallel-size 8 \ --enable-expert-parallel \ --max-model-len 32768 \ --gpu-memory-utilization 0.9
第一行的模型路径需要修改为自己保存模型的路径,请确保该路径已经挂载到容器内,第二行设定了模型的名称。--tensor-parallel-size 参数指定了张量并行大小,服务器有 8 张 NPU 因此设定为 8。
另外,如果你使用的是混合专家模型(MoE),那么你还可以使用专家并行。向启动参数中添加 --enable-expert-parallel 即可开启该功能,例如:
出现以下消息时,就说明模型启动成功了。
如果你需要使用量化模型,请注意:你并不能直接使用网上为 CUDA 平台量化的版本,而是需要下载专为昇腾平台量化的 W8A8 版本,或是参考文档自行完成原始精度模型的量化,启动量化模型时,还需要在指令中添加 --quantization ascend 参数。
3.1.4 测试模型
启动后,vLLM 服务将在本地 8000 端口提供,http://localhost:8000/v1 便是 base_url,编写代码或者用大模型客户端即可进行连接了。这里提供一份我写的测试代码,用 Python 运行就可以快速测试模型效果了。
import argparse
from openai import OpenAI
def main():
client = OpenAI(api_key=args.token, base_url=args.base_url)
response = client.chat.completions.create(
model=args.model,
messages=[{"role": "user", "content": args.prompt}],
max_completion_tokens=args.max_completion_tokens,
temperature=args.temperature,
stream=True
)
is_thinking = False
for chunk in response:
response_delta = chunk.choices[0].delta
if hasattr(response_delta, 'content') and response_delta.content is not None:
if is_thinking:
is_thinking = False
print("</think>")
print(response_delta.content, end='', flush=True)
if hasattr(response_delta, 'reasoning_content') and response_delta.reasoning_content is not None:
if not is_thinking:
is_thinking = True
print("<think>")
print(response_delta.reasoning_content, end='', flush=True)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--base-url', type=str, default='http://localhost:8000/v1')
parser.add_argument('--token', type=str, default='')
parser.add_argument('--model', type=str, default='qwen3-vl')
parser.add_argument('--max-completion-tokens', type=int, default=1024 * 8)
parser.add_argument('--temperature', type=float, default=0.6)
parser.add_argument('--prompt', type=str, default='介绍一下大语言模型是什么。')
args = parser.parse_args()
main()
3.2 多机多卡
3.2.1 测试互联网络
多级多卡分布式推理需要用到标准以太网络来进行进程交互,也需要用到 RoCE 网络完成高速卡间互联。
(1)测试标准以太网络
使用 ifconfig 指令查询节点的 IP 地址,本文两台节点的内网 IP 分别是 192.168.0.147 和 192.168.0.35,互相 Ping 一下确认连通性就行了:
# 在 node 0 运行 ping 192.168.0.35 # 在 node 1 运行 ping 192.168.0.147
(2)测试 RoCE 网络
测试 RoCE 网络配置是否正常,使用以下指令测试,确保输出没有报错即可:
# Check the remote switch ports
for i in {0..7}; do hccn_tool -i $i -lldp -g | grep Ifname; done
# Get the link status of the Ethernet ports (UP or DOWN)
for i in {0..7}; do hccn_tool -i $i -link -g ; done
# Check the network health status
for i in {0..7}; do hccn_tool -i $i -net_health -g ; done
# View the network detected IP configuration
for i in {0..7}; do hccn_tool -i $i -netdetect -g ; done
# View gateway configuration
for i in {0..7}; do hccn_tool -i $i -gateway -g ; done
# View NPU network configuration
cat /etc/hccn.conf
接下来查看节点的 RoCE 网卡 IP 地址,使用以下指令:
for i in {0..7}; do hccn_tool -i $i -ip -g | grep ipaddr; done
我的输出如下,每个节点的 8 个 IP 分别对应着 8 张 NPU:
# node 0 输出 ipaddr:29.74.153.181 ipaddr:29.74.161.19 ipaddr:29.74.191.70 ipaddr:29.74.135.46 ipaddr:29.74.13.110 ipaddr:29.74.159.60 ipaddr:29.74.11.174 ipaddr:29.74.138.7 # node 1 输出 ipaddr:29.74.42.211 ipaddr:29.74.80.82 ipaddr:29.74.66.31 ipaddr:29.74.137.124 ipaddr:29.74.123.170 ipaddr:29.74.159.58 ipaddr:29.74.62.133 ipaddr:29.74.28.3
接下来就可以测试一下连通性了,随便挑一个节点,向另一个节点的 IP 发送 Ping 就行了,用以下指令:
# node 0 -> node 1 hccn_tool -i 0 -ping -g address 29.74.42.211 # node 1 -> node 0 hccn_tool -i 0 -ping -g address 29.74.153.181
3.2.2 启动 vLLM-Ascend 容器
同 3.1.1 中的内容,注意每台节点均需要启动。
3.2.3 升级 transformers 库(可选)
同 3.1.2 中的内容,注意每台节点均需要操作。
3.2.4 启动 Ray
Ray 是一款机器学习分布式框架,vLLM 使用该框架完成分布式推理,在启动 vLLM 之前需要先在每个节点上启动 Ray。
Ray 节点分为两种:
- Head Node:提供计算资源,负责完成分布式任务,同时负责整个分布式任务的调度。
- Worker Node:仅提供计算资源,负责完成分布式任务。
本文一共两台节点,因此一台作为 Head,一台作为 Worker。如果你要部署更大规模的并行推理,那么只需要一台作为 Head,其他作为 Worker 即可。
(1)启动 Head 节点
vLLM-Ascend 容器已经配置好了 Ray 环境,在容器中运行以下命令启动 Ray:
# Head node export HCCL_IF_IP=【本地IP地址】 export GLOO_SOCKET_IFNAME=【网卡名】 export TP_SOCKET_IFNAME=【网卡名】 export RAY_EXPERIMENTAL_NOSET_ASCEND_RT_VISIBLE_DEVICES=1 export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 ray start --head
注意将本地 IP 地址和网卡名替换为该节点的真实值,可以使用 ifconfig 命令查看。
Ray 是后台进程,运行完后就会退出,没有报错就是成功运行:
(2)启动 Worker 节点
在另一个节点的 vLLM-Ascend 容器中运行以下命令启动 Ray:
# Worker node export HCCL_IF_IP=【本地IP地址】 export GLOO_SOCKET_IFNAME=【网卡名】 export TP_SOCKET_IFNAME=【网卡名】 export RAY_EXPERIMENTAL_NOSET_ASCEND_RT_VISIBLE_DEVICES=1 export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 ray start --address='【Head节点的IP地址】:6379' --node-ip-address=【本地IP地址】
注意将本地 IP 地址、网卡名、Head节点的 IP 地址替换为真实值。
Ray 是后台进程,运行完后就会退出,没有报错就是成功运行:
3.2.5 运行模型(TP张量并行)
如果你选择无论节点内和节点间,均使用张量并行策略,则使用以下指令启动 vllm:(该指令只需要在 Head 节点的容器内运行,Worker 节点会自动收到任务调度)
vllm serve /data/Qwen3-VL-30B-A3B-Instruct \ --served-model-name qwen3-vl \ --disable-uvicorn-access-log \ --disable-log-requests \ --distributed-executor-backend ray \ --tensor-parallel-size 16 \ --max-model-len 32768 \ --gpu-memory-utilization 0.9
第一行的模型路径需要修改为自己保存模型的路径,请确保该路径已经挂载到容器内,第二行设定了模型的名称。--tensor-parallel-size 参数指定了张量并行大小,每个节点有 8 张 NPU,一共 2 个节点,因此设定为 16.
模型成功启动后,可以看到两台节点的 NPU 均有显存占用:
如果你需要使用量化模型,请注意:你并不能直接使用网上为 CUDA 平台量化的版本,而是需要下载专为昇腾平台量化的 W8A8 版本,或是参考文档自行完成原始精度模型的量化,启动量化模型时,还需要在指令中添加 --quantization ascend 参数。
3.2.6 运行模型(TP张量并行+PP流水线并行)
如果你选择在节点内使用张量并行策略,在节点间使用流水线并行策略,则使用以下指令启动 vllm:(该指令只需要在 Head 节点的容器内运行,Worker 节点会自动收到任务调度)
vllm serve /data/Qwen3-VL-30B-A3B-Instruct \ --served-model-name qwen3-vl \ --disable-uvicorn-access-log \ --disable-log-requests \ --distributed-executor-backend ray \ --pipeline-parallel-size 2 \ --tensor-parallel-size 8 \ --max-model-len 32768 \ --gpu-memory-utilization 0.9
第一行的模型路径需要修改为自己保存模型的路径,请确保该路径已经挂载到容器内,第二行设定了模型的名称。--pipeline-parallel-size 参数指定了流水线并行大小,一共 2 个节点,因此设定为 2,--tensor-parallel-size 参数指定了张量并行大小,每个节点有 8 张 NPU,因此设定为 8.
如果你需要使用量化模型,请注意:你并不能直接使用网上为 CUDA 平台量化的版本,而是需要下载专为昇腾平台量化的 W8A8 版本,或是参考文档自行完成原始精度模型的量化,启动量化模型时,还需要在指令中添加 --quantization ascend 参数。
3.2.7 运行模型(EP专家并行)
如果你使用的是混合专家模型(MoE),那么你还可以使用专家并行。向启动参数中添加 --enable-expert-parallel 即可开启该功能,例如:
vllm serve /data/Qwen3-VL-30B-A3B-Instruct \ --served-model-name qwen3-vl \ --disable-uvicorn-access-log \ --disable-log-requests \ --distributed-executor-backend ray \ --tensor-parallel-size 16 \ --enable-expert-parallel \ --max-model-len 32768 \ --gpu-memory-utilization 0.9
不过需要注意的是,目前的版本如果将流水线并行和专家并行一起使用,模型无法正常启动,这有可能是 bug。
3.2.8 测试模型
同 3.1.4 中的内容,注意模型服务是在 Head 节点提供的,因此需要在 Head 节点连接模型。
4 效率测试
接下来评估不同并行方式的模型推理效率差异,评估不算严谨,仅供参考。以下评估均使用代码 256 线程请求模型进行压力测试,查看 vLLM 界面的吞吐量日志,模型均为 Qwen3-VL-30B-A3B-Instruct。
(1)单机多卡 TP:输出速度大约为 2500 token/s.

(2)单机多卡 TP+EP:输出速度大约为 2500 token/s.
(3)多机多卡 TP:输出速度大约为 2200 token/s,较单机下降了大约 12%.
(4)多机多卡 TP+PP:输出速度大约为 1800 token/s,较单机下降了大约 28%.
(5)多机多卡 TP+EP:输出速度大约为 2100 token/s,较单机下降了大约 16%.
综上,可以看到由于节点间的通信延迟,只要是使用了多机分布式推理,都会产生 10% 以上的性能下降,最高甚至下降了 28%。因此如果模型能够在单机容纳,则不要使用分布式推理(不过可以使用本文没提到的 DP 分布式,这种不存在多机损耗)。











![[滑稽]](https://static.zouht.com/wp-content/plugins/WP-Alu2Button/static/img/%5B滑稽%5D.png)
发表回复