Qwen3-Dense(Qwen3-0.6B/8B/32B)#
简介#
Qwen3 是通义千问系列最新一代大语言模型,提供全面的稠密和混合专家(MoE)模型。基于大规模训练,Qwen3 在推理、指令遵循、智能体能力和多语言支持方面取得了突破性进展。
欢迎阅读在 vLLM-Ascend 环境中优化 Qwen Dense 模型的教程。本指南将帮助您为您的使用场景配置最有效的设置,并提供突出关键优化点的实际示例。我们还将探讨如何调整服务参数以在各种场景下最大化吞吐量性能。
本文档将展示模型的主要验证步骤,包括支持的特性、特性配置、环境准备、精度评估和性能评估。
Qwen3 Dense 模型从 v0.8.4rc2 版本开始首次支持。本示例需要 v0.11.0rc2 版本。较早版本可能缺少某些功能。
支持的特性#
请参阅支持的特性矩阵获取模型支持的特性列表。
请参阅特性指南获取特性的配置方法。
环境准备#
模型权重#
Qwen3-0.6B(BF16 版本):需要 1 张 Atlas 800 A3(64G × 2)卡或 1 张 Atlas 800I A2(64G × 1)卡。下载模型权重Qwen3-1.7B(BF16 版本):需要 1 张 Atlas 800 A3(64G × 2)卡或 1 张 Atlas 800I A2(64G × 1)卡。下载模型权重Qwen3-4B(BF16 版本):需要 1 张 Atlas 800 A3(64G × 2)卡或 1 张 Atlas 800I A2(64G × 1)卡。下载模型权重Qwen3-8B(BF16 版本):需要 1 张 Atlas 800 A3(64G × 2)卡或 1 张 Atlas 800I A2(64G × 1)卡。下载模型权重Qwen3-14B(BF16 版本):需要 1 张 Atlas 800 A3(64G × 2)卡或 2 张 Atlas 800I A2(64G × 1)卡。下载模型权重Qwen3-32B(BF16 版本):需要 2 张 Atlas 800 A3(64G × 4)卡或 4 张 Atlas 800I A2(64G × 4)卡。下载模型权重Qwen3-32B-W8A8(量化版本):需要 2 张 Atlas 800 A3(64G × 4)卡或 4 张 Atlas 800I A2(64G × 4)卡。下载模型权重
这些是推荐的卡数量,可以根据实际情况进行调整。
建议将模型权重下载到多节点共享目录,例如 /root/.cache/
验证多节点通信(可选)#
如果要部署多节点环境,需要按照验证多节点通信环境验证多节点通信。
安装#
您可以使用官方 Docker 镜像来支持 Qwen3 Dense 模型。目前,我们提供一体化镜像。下载镜像
Docker 拉取(按标签)#
docker pull quay.io/ascend/vllm-ascend:v0.20.2rc1
Docker 运行#
# Update --device according to your device (Atlas A2: /dev/davinci[0-7] Atlas A3:/dev/davinci[0-15]).
# Update the vllm-ascend image according to your environment.
# Note you should download the weight to /root/.cache in advance.
# For Atlas A2 machines:
# export IMAGE=quay.io/ascend/vllm-ascend:v0.20.2rc1
# For Atlas A3 machines:
export IMAGE=quay.io/ascend/vllm-ascend:v0.20.2rc1-a3
docker run --rm \
--name vllm-ascend-env \
--shm-size=1g \
--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/Ascend/driver/tools/hccn_tool:/usr/local/Ascend/driver/tools/hccn_tool \
-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 \
-it $IMAGE bash
默认工作目录为 /workspace,vLLM 和 vLLM Ascend 代码位于 /vllm-workspace,并以开发模式(pip install -e)安装,以帮助开发者无需重新安装即可立即应用更改。
在运行 Docker 容器中,通过具体示例提供了详细说明。
此外,如果您不想使用上述 Docker 镜像,也可以从源码构建:
从源码安装
vllm-ascend,请参考安装指南。
如果要部署多节点环境,需要在每个节点上设置环境。
部署#
在本节中,我们将演示在 vLLM-Ascend 中调整超参数以最大化推理吞吐量性能的最佳实践。通过针对不同使用场景定制服务级配置,您可以确保系统在各种场景下都能以最佳性能运行。我们将指导您如何根据观察到的现象(如 max_model_len、max_num_batched_tokens 和 cudagraph_capture_sizes)来微调超参数,以获得最佳性能。
具体示例场景如下:
机器环境为 Atlas 800 A3(64G*16)
LLM 为 Qwen3-32B-W8A8
数据场景为固定长度输入 3.5K,输出 1.5K。
并行配置要求为 DP=1&TP=4
如果机器环境为 Atlas 800I A2(64G*8),部署方法保持不变。
运行 Docker 容器#
备注
vllm-ascend/Qwen3-32B-W8A8 是默认模型路径,请将其替换为您的实际路径。
v0.11.0rc2-a3 是镜像标签,请将其替换为您的实际标签。
请将 '-p 8113:8113' 替换为您的实际端口。
请将 '--device /dev/davinci0' 替换为您的实际卡设备。
# Update the vllm-ascend image
export IMAGE=quay.io/ascend/vllm-ascend:v0.20.2rc1
docker run --rm \
--name vllm-ascend \
--shm-size=1g \
--privileged=true \
--device /dev/davinci0 \
--device /dev/davinci1 \
--device /dev/davinci2 \
--device /dev/davinci3 \
--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 \
-p 8113:8113 \
-it $IMAGE bash
多 NPU 在线推理#
运行以下脚本在多 NPU 上启动 vLLM 服务器。
此脚本配置为在上述特定示例场景下实现最佳性能,在两块 A3 卡上 batchsize = 72。
# set the NPU device number
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3
# Set the operator dispatch pipeline level to 1 and disable manual memory control in ACLGraph
export TASK_QUEUE_ENABLE=1
# [Optional] jemalloc
# jemalloc is for better performance, if `libjemalloc.so` is installed on your machine, you can turn it on.
# if os is Ubuntu
# export LD_PRELOAD=/usr/lib/aarch64-linux-gnu/libjemalloc.so.2:$LD_PRELOAD
# if os is openEuler
# export LD_PRELOAD=/usr/lib64/libjemalloc.so.2:$LD_PRELOAD
# Enable the AIVector core to directly schedule ROCE communication
export HCCL_OP_EXPANSION_MODE="AIV"
# Enable FlashComm_v1 optimization when tensor parallel is enabled.
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1
vllm serve vllm-ascend/Qwen3-32B-W8A8 \
--served-model-name qwen3 \
--trust-remote-code \
--quantization ascend \
--distributed-executor-backend mp \
--tensor-parallel-size 4 \
--max-model-len 5500 \
--max-num-batched-tokens 40960 \
--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY"}' \
--additional-config '{"pa_shape_list":[48,64,72,80], "weight_prefetch_config":{"enabled":true}}' \
--port 8113 \
--block-size 128 \
--gpu-memory-utilization 0.9
备注
vllm-ascend/Qwen3-32B-W8A8 是默认模型路径,请将其替换为您的实际路径。
如果模型不是量化模型,请移除
--quantization ascend参数。[可选]
--additional-config '{"pa_shape_list":[48,64,72,80]}':pa_shape_list指定要切换到 PA 算子的批次大小。这是一个临时调优参数。目前,注意力算子调度默认使用 FIA 算子。在某些批次大小(并发)设置下,FIA 可能性能不佳。通过设置pa_shape_list,当运行时批次大小与列表中的某个值匹配时,vLLM-Ascend 将使用 PA 算子替换 FIA 以防止性能下降。未来,FIA 将针对这些场景进行优化,此参数将被移除。如果需要最佳性能,可以启用 cudagraph_capture_sizes 参数,参考:关键优化点、优化亮点。以下是 batchsize 为 72 的示例:
--compilation-config '{"cudagraph_mode": "FULL_DECODE_ONLY", "cudagraph_capture_sizes":[1,8,24,48,60,64,72,76]}'。
服务器启动后,您可以使用输入提示词查询模型
curl http://localhost:8113/v1/chat/completions -H "Content-Type: application/json" -d '{
"model": "qwen3",
"messages": [
{"role": "user", "content": "Give me a short introduction to large language models."}
],
"temperature": 0.6,
"top_p": 0.95,
"top_k": 20,
"max_completion_tokens": 4096
}'
多 NPU 离线推理#
运行以下脚本在多 NPU 上执行离线推理。
备注
vllm-ascend/Qwen3-32B-W8A8 是默认模型路径,请将其替换为您的实际路径。
如果模型不是量化模型,请移除
quantization="ascend"参数。
import gc
import torch
from vllm import LLM, SamplingParams
from vllm.distributed.parallel_state import (destroy_distributed_environment,
destroy_model_parallel)
def clean_up():
destroy_model_parallel()
destroy_distributed_environment()
gc.collect()
torch.npu.empty_cache()
prompts = [
"Hello, my name is",
"The future of AI is",
]
sampling_params = SamplingParams(temperature=0.6, top_p=0.95, top_k=40)
llm = LLM(model="vllm-ascend/Qwen3-32B-W8A8",
tensor_parallel_size=4,
trust_remote_code=True,
distributed_executor_backend="mp",
max_model_len=5500,
max_num_batched_tokens=5500,
quantization="ascend",
compilation_config={"cudagraph_mode": "FULL_DECODE_ONLY"})
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}")
del llm
clean_up()
精度评估#
以下是一种精度评估方法。
使用 AISBench#
详细信息请参考使用 AISBench 进行精度评估。
执行后即可获得结果,以下是
Qwen3-32B-W8A8在vllm-ascend:0.11.0rc2上的结果,仅供参考。
数据集 |
版本 |
指标 |
模式 |
任务名称 |
vllm-api-general-chat |
|---|---|---|---|---|---|
gsm8k |
- |
准确率 |
生成 |
gsm8k_gen_0_shot_noncot_chat_prompt |
96.44 |
math500 |
- |
准确率 |
生成 |
math500_gen_0_shot_cot_chat_prompt |
97.60 |
aime |
- |
准确率 |
生成 |
aime2024_gen_0_shot_chat_prompt |
76.67 |
性能#
使用 AISBench#
详细信息请参考使用 AISBench 进行性能评估。
使用 vLLM 基准测试#
以 Qwen3-32B-W8A8 为例运行性能评估。
更多详细信息请参考 vLLM 基准测试。
有三个 vllm bench 子命令:
latency:基准测试单批次请求的延迟。serve:基准测试在线服务的吞吐量。throughput:基准测试离线推理的吞吐量。
以 serve 为例,运行如下代码。
备注
vllm-ascend/Qwen3-32B-W8A8 是默认模型路径,请将其替换为您的实际路径。
vllm bench serve --model vllm-ascend/Qwen3-32B-W8A8 --served-model-name qwen3 --port 8113 --dataset-name random --random-input 200 --num-prompts 200 --request-rate 1 --save-result --result-dir ./
大约几分钟后,即可获得性能评估结果。
关键优化点#
在本节中,我们将介绍可以显著提升 Qwen Dense 模型性能的关键优化点。这些技术旨在提高各种场景下的吞吐量和效率。
1.Rope 优化#
Rope 优化通过修改位置编码过程来提高模型效率。具体来说,它确保 cos_sin_cache 和相关索引选择操作仅在前向传播的第一层执行。对于后续层,位置编码被直接复用,消除了冗余计算,并显著加快了解码阶段的推理速度。
此优化默认启用,无需设置任何额外的环境变量。
2.AddRMSNormQuant 融合#
AddRMSNormQuant 融合将逐地址多尺度归一化和量化操作合并,实现更高效的内存访问和计算,从而提升吞吐量。
此优化默认启用,无需设置任何额外的环境变量。
3.FlashComm_v1#
FlashComm_v1 通过将传统的 allreduce 集合通信分解为 reduce-scatter 和 all-gather,显著提高了大批次场景下的性能。这种分解有助于减少 RMSNorm token 维度的计算,从而实现更高效的处理。在量化场景中,FlashComm_v1 还通过减少位级数据传输来降低通信开销,从而进一步最小化预填充阶段的端到端延迟。
需要注意的是,将 allreduce 通信分解为 reduce-scatter 和 all-gather 操作仅在高并发场景下有益,在这些场景中通信不会显著退化。在其他情况下,这种分解可能会导致明显的性能下降。为了解决这个问题,当前实现采用了基于阈值的方法,只有当每次推理调度的实际 token 数量超过阈值时才启用 FlashComm_v1。这确保了该特性仅在能够提升性能的场景下被激活,避免了低并发情况下的潜在性能下降。
此优化需要设置环境变量 VLLM_ASCEND_ENABLE_FLASHCOMM1 = 1 才能启用。
4.Matmul 与 ReduceScatter 融合#
一旦启用了 FlashComm_v1,就可以应用额外的优化。此优化将矩阵乘法和 ReduceScatter 操作融合,并配合分块优化。Matmul 计算作为一个流水线处理,而 ReduceScatter 和反量化操作在另一个流水线中处理。这种方法显著减少了通信步骤,提高了计算效率,并实现了更好的资源利用率,从而提升了吞吐量,特别是在大规模分布式环境中。
一旦 FlashComm_v1 被激活,此优化会自动启用。然而,由于融合后在小并发场景下会出现性能下降的问题,目前采用基于阈值的方法来缓解此问题。只有当 token 数量超过阈值时才应用该优化,确保在可能对性能产生负面影响的场景下不会启用。
5.权重预取#
权重预取通过在需要之前将权重预加载到缓存中来优化内存使用,最小化模型执行期间内存访问引起的延迟。
在稠密模型场景中,MLP 的 gate_up_proj 和 down_proj 线性层通常表现出较高的 MTE 利用率。为了解决这个问题,我们创建了一个专门用于权重预取的独立流水线,它与原始向量计算流水线(如 RMSNorm 和 SiLU)并行运行,位于 MLP 之前。这种方法允许权重提前预加载到 L2 缓存中,减少了 MLP 计算期间的 MTE 利用率,并通过最小化资源争用和优化数据流间接提高了 Cube 计算效率。
以前,用于启用 MLP 权重预取的环境变量 VLLM_ASCEND_ENABLE_PREFETCH_MLP,以及用于设置 MLP gate_up_proj 和 down_proj 权重预取大小的 VLLM_ASCEND_MLP_GATE_UP_PREFETCH_SIZE 和 VLLM_ASCEND_MLP_DOWN_PREFETCH_SIZE 已被弃用。请改用以下配置:"weight_prefetch_config": { "enabled": true, "prefetch_ratio": { "mlp": { "gate_up": 1.0, "down": 1.0}}}。详细信息请参见用户指南->特性指南->权重预取指南。
6.Zerolike 消除#
此消除操作移除了 Attention 前向传播中与零张量相关的不必要操作,提高了矩阵运算的效率并减少了内存使用。
此优化默认启用,无需设置任何额外的环境变量。
7.FullGraph 优化#
ACLGraph 提供了多项关键优化来提升模型执行效率。通过一次性回放整个模型执行图,与多次较小的回放相比,我们显著降低了调度延迟。这种方法还稳定了多设备性能,因为将模型捕获为单个静态图可以缓解设备间的调度波动。此外,合并图捕获可以释放流资源,允许捕获更多的图并优化资源使用,最终提高系统效率并降低开销。
启动服务时使用配置 compilation_config = { "cudagraph_mode": "FULL_DECODE_ONLY"}。此设置对于启用 aclgraph 的完整纯解码模式是必要的。
8.异步调度#
异步调度是一种用于优化推理效率的技术。它允许非阻塞的任务调度以提高并发性和吞吐量,尤其是在处理大规模模型时。
优化亮点#
基于前面概述的具体示例场景,本节重点介绍了在实现最佳性能中起关键作用的调优点。通过关注对超参数和优化最有影响的调整,我们将强调可用于最大化吞吐量、最小化延迟并确保在各种环境中高效利用资源的策略。这些见解将帮助指导您微调自己的配置以获得最佳结果。
1.预取缓冲区大小#
设置合适的预取缓冲区大小对于优化权重加载至关重要,预取缓冲区的大小与向量计算可以隐藏的时间直接相关。为了实现预取流和计算流之间的近乎完美的重叠,您可以通过性能分析并观察不同缓冲区大小下的重叠程度来灵活调整缓冲区大小。
例如,在上面提到的实际场景中,我将 MLP 中 gate_up_proj 和 down_proj 的预取缓冲区大小设置为 18MB。这样做的原因是,在此值下,RMSNorm 和 SiLU 的向量计算可以有效地隐藏预取流,从而加速两个线性层的 Matmul 计算。
2.Max-num-batched-tokens#
max-num-batched-tokens 参数决定单个批次中可以处理的最大 token 数量。调整该值有助于平衡吞吐量和内存使用。将该值设置得过小可能会对端到端性能产生负面影响,因为每批处理的 token 较少,可能导致效率低下。相反,设置得过大则会因内存消耗过多而增加内存不足(OOM)错误的风险。
在上述实际场景中,我们不仅进行了大量测试以确定最具性价比的值,还考虑了启用分块预填充时解码 token 的累积。如果该值设置得过小,单个请求可能被多次分块,并且在推理的早期阶段,批次中可能只包含少量解码 token。这可能导致端到端吞吐量达不到预期。
3.Cudagraph_capture_sizes#
cudagraph_capture_sizes 参数控制推理过程中图捕获的粒度。调整该值决定了一次捕获多少计算图,这会对性能和内存使用产生重大影响。
如果未手动指定此列表,它将填充一系列均匀分布的值,这通常能确保良好的性能。然而,如果您想进一步微调,手动指定值将产生更好的结果。这是因为如果批次大小落在两个值之间,框架会自动将 token 数量填充到较大的值。这通常会导致实际性能偏离预期甚至下降。
因此,与上述实际场景一样,在调整基准测试请求并发数时,我们始终确保并发数实际包含在 cudagraph_capture_sizes 列表中。这样,在解码阶段,基本上可以避免填充操作,确保实验数据的可靠性。
需要注意的是,如果启用了 FlashComm_v1,此列表中的值必须是 TP 大小的整数倍。任何不满足此条件的值将被自动过滤掉。因此,我建议在启用 FlashComm_v1 后,根据 TP 大小逐步增加并发数。