Qwen3-Dense (Qwen3-0.6B/8B/32B)#

简介#

Qwen3 是通义千问(Qwen)系列的最新一代大语言模型,提供了一系列完整的密集(Dense)和混合专家(MoE)模型。基于大规模训练,Qwen3 在推理、指令遵循、Agent 能力和多语言支持方面取得了突破性的进展。

欢迎阅读在 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 模型。目前,我们提供全功能一体化(all-in-one)镜像。下载镜像

Docker 拉取(按标签)#

docker pull quay.io/ascend/vllm-ascend:v0.13.0

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.13.0
# For Atlas A3 machines:
export IMAGE=quay.io/ascend/vllm-ascend:v0.13.0-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 中调整超参数以最大化推理吞吐量性能的最佳实践。通过针对不同用例定制服务级配置,您可以确保系统在各种场景下都能以最佳状态运行。我们将指导您如何根据观察到的现象微调超参数(如 max_model_len、max_num_batched_tokens 和 cudagraph_capture_sizes),从而获得最佳性能。

具体示例场景如下:

  • 机器环境为 Atlas 800 A3 (64G*16)

  • 大语言模型为 Qwen3-32B-W8A8

  • 数据场景为固定长度输入 3.5K,输出 1.5K。

  • 并行配置要求为 DP=1 & TP=4

  • 如果机器环境是 Atlas 800I A2 (64G*8),部署方法完全相同。

运行 Docker 容器:#

注意#

  • /model/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.13.0
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 /model/Qwen3-32B-W8A8:/model/Qwen3-32B-W8A8 \
-p 8113:8113 \
-it $IMAGE bash

多 NPU 在线推理#

运行以下脚本以在多 NPU 上启动 vLLM 服务器。

该脚本经过配置,可在上述特定示例场景下(两张 A3 卡,Batch Size = 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 install 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 MLP prefetch for better performance.
export VLLM_ASCEND_ENABLE_PREFETCH_MLP=1

# Enable FlashComm_v1 optimization when tensor parallel is enabled.
export VLLM_ASCEND_ENABLE_FLASHCOMM1=1

vllm serve /model/Qwen3-32B-W8A8 \
  --served-model-name qwen3 \
  --trust-remote-code \
  --async-scheduling \
  --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]}' \
  --port 8113 \
  --block-size 128 \
  --gpu-memory-utilization 0.9

注意#

  • /model/Qwen3-32B-W8A8 是模型路径,请替换为您实际的路径。

  • 如果模型不是量化模型,请移除 --quantization ascend 参数。

  • [可选] --additional-config '{"pa_shape_list":[48,64,72,80]}'pa_shape_list 指定了您希望切换到 PA 算子的 Batch Size 列表。这是一个临时的调优参数。目前,Attention 算子默认调度为 FIA 算子。在某些 Batch Size(并发)设置下,FIA 的性能可能不是最优。通过设置 pa_shape_list,当运行时 Batch Size 匹配列表中任意值时,vLLM-Ascend 将使用 PA 算子替换 FIA,以防止性能下降。未来 FIA 将针对这些场景进行优化,届时此参数将被移除。

  • 如果追求极致性能,可以启用 cudagraph_capture_sizes 参数,参考:关键优化点优化亮点。以下是 Batch Size 为 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_tokens": 4096
}'

多 NPU 离线推理#

运行以下脚本以在多 NPU 上执行离线推理。

注意#

  • /model/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="/model/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#

  1. 详见 使用 AISBench

  2. 执行后可获取结果,以下为 vllm-ascend:0.11.0rc2Qwen3-32B-W8A8 的测试结果,仅供参考。

数据集

版本

指标

模式

任务名称

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 基准测试 (Benchmark)#

Qwen3-32B-W8A8 的性能评估为例。

更多细节请参考 vLLM Benchmark

共有三个 vllm bench 子命令:

  • latency:测试单批次请求的延迟。

  • serve:测试在线服务的吞吐量。

  • throughput:测试离线推理的吞吐量。

serve 模式为例,运行如下代码。

注意#

  • /model/Qwen3-32B-W8A8 是模型路径,请替换为您实际的路径。

vllm bench serve --model /model/Qwen3-32B-W8A8 --served-model-name qwen3 --port 8113 --dataset-name random --random-input 200 --num-prompt 200 --request-rate 1 --save-result --result-dir ./

大约几分钟后,您即可获得性能评估结果。

关键优化点#

在本节中,我们将介绍可以显著提高 Qwen Dense 模型性能的关键优化点。这些技术旨在增强各种场景下的吞吐量和效率。

1.RoPE 优化#

RoPE(旋转位置编码)优化通过改进位置编码过程来提高模型效率。具体而言,它确保 cos_sin_cache 及其相关的索引选择操作仅在正向传播的第一层执行。对于后续层,直接复用该位置编码,从而消除了冗余计算,显著加快了解码阶段的推理速度。

此优化默认启用,不需要设置任何额外的环境变量。

2.AddRMSNormQuant 融合算子#

AddRMSNormQuant 融合算子合并了加法、RMSNorm 归一化和量化操作,实现了更高效的内存访问和计算,从而提升了吞吐量。

此优化默认启用,不需要设置任何额外的环境变量。

3.FlashComm_v1(闪速通信)#

FlashComm_v1 通过将传统的 AllReduce 集合通信分解为 ReduceScatter 和 AllGather,显著提高了大 Batch 场景下的性能。这种分解有助于减少 RMSNorm 在 Token 维度上的计算量,从而实现更高效的处理。在量化场景中,FlashComm_v1 还通过减少位级数据传输来降低通信开销,进一步缩短了 Prefill 阶段的端到端延迟。

需要注意的是,将 AllReduce 通信分解为 ReduceScatter 和 AllGather 仅在没有显著通信退化的高并发场景下才有收益。在其他情况下,这种分解可能会导致明显的性能下降。为了缓解这一问题,目前的实现采用了基于阈值的方法:仅当每次推理调度的实际 Token 数量超过阈值时,才会启用 FlashComm_v1。这确保了该功能仅在能提升性能的场景下激活,避免了低并发情况下的潜在性能退化。

此优化需要设置环境变量 VLLM_ASCEND_ENABLE_FLASHCOMM1 = 1 才能启用。

4.Matmul 与 ReduceScatter 融合#

启用 FlashComm_v1 后,可以应用进一步的优化。该优化融合了矩阵乘法(Matmul)和 ReduceScatter 操作,并结合了 Tiling 优化。Matmul 计算被视为一个流水线,而 ReduceScatter 和反量化(Dequant)操作则在另一个独立的流水线中处理。这种方法显著减少了通信步骤,提高了计算效率,并实现了更好的资源利用率,从而提升了吞吐量,尤其是在大规模分布式环境中。

一旦激活 FlashComm_v1,此优化将自动开启。然而,由于该融合在小并发场景下存在性能下降的问题,目前采用基于阈值的方法来缓解。仅当 Token 数量超过阈值时才应用该优化,以确保不会在可能产生负面影响的情况下启用。

5.权重预取#

权重预取通过在需要之前将权重预加载到缓存中来优化内存使用,从而最大限度地减少模型执行期间由内存访问引起的延迟。

在密集模型场景中,MLP 的 gate_up_proj 和 down_proj 线性层通常表现出较高的 MTE(内存传输引擎)利用率。为了解决这个问题,我们创建了一个专门用于权重预取的独立流水线,它与 MLP 之前的原始向量计算流水线(如 RMSNorm 和 SiLU)并行运行。这种方法允许权重提前预加载到 L2 缓存中,降低了 MLP 计算期间的 MTE 利用率,并通过减少资源竞争和优化数据流间接提高了 Cube 计算效率。

需要强调的是,由于我们利用向量计算来隐藏权重预取流水线的时间,预取缓冲区大小(prefetch buffer size)的设置至关重要。如果缓冲区太小,优化收益无法充分体现;如果太大,则可能导致资源竞争,导致性能下降。为了适应不同场景,我们暴露了两个环境变量 VLLM_ASCEND_MLP_GATE_UP_PREFETCH_SIZEVLLM_ASCEND_MLP_DOWN_PREFETCH_SIZE,以便根据具体工作负载灵活配置缓冲区大小。

此优化需要设置环境变量 VLLM_ASCEND_ENABLE_PREFETCH_MLP = 1 才能启用。

6.Zerolike 消除#

该优化消除了 Attention 正向传播中与类零张量(zero-like tensors)相关的非必要操作,提高了矩阵运算效率并减少了内存使用。

此优化默认启用,不需要设置任何额外的环境变量。

7.全图(FullGraph)优化#

ACLGraph 提供了多项关键优化以提升模型执行效率。通过一次性回放整个模型执行图,与多次回放零散的小图相比,我们显著降低了调度(dispatch)延迟。由于将模型捕获为单个静态图可以缓解跨设备的调度波动,这种方法还稳定了多设备性能。此外,整合图捕获释放了 Stream 资源,允许捕获更多图并优化资源利用,最终提高系统效率并减少开销。

启动服务时使用配置 compilation_config = { "cudagraph_mode": "FULL_DECODE_ONLY"}。此设置对于启用 ACLGraph 的 Full Decode-only 模式是必需的。

8.异步调度#

异步调度是一种优化推理效率的技术。它允许非阻塞的任务调度,从而提高并发量和吞吐量,尤其是在处理大规模模型时。

通过设置 --async-scheduling 参数来启用此优化。

调优亮点#

基于前文概述的特定示例场景,本节重点介绍了对实现最佳性能起关键作用的调优要点。通过关注对超参数和优化最具影响力的调整,我们将强调那些可用于最大化吞吐量、最小化延迟并确保在各种环境中高效利用资源的策略。这些见解将指导您微调自己的配置,以获得最佳结果。

1.预取缓冲区大小 (Prefetch Buffer Size)#

设置正确的预取缓冲区大小对于优化权重加载至关重要,且该缓冲区的大小直接关系到能被向量计算“隐藏”的时间。为了实现预取流和计算流之间近乎完美的重叠(overlap),您可以通过 Profiling(性能分析)并观察不同缓冲区大小下的重叠程度,灵活调整缓冲区大小。

例如,在上述实际场景中,我将 MLP 的 gate_up_proj 和 down_proj 的预取缓冲区大小设置为 18MB。原因是,在此取值下,RMSNorm 和 SiLU 的向量计算可以有效地隐藏预取流,从而加速这两个线性层的 Matmul 计算。

2.最大批处理 Token 数 (Max-num-batched-tokens)#

max-num-batched-tokens 参数决定了单次批处理中处理的最大 Token 数量。调整此值有助于平衡吞吐量和内存使用。设置过小可能会对端到端性能产生负面影响,因为每批处理的 Token 较少,可能导致效率低下。相反,设置过大则会因为内存消耗过多而增加显存溢出(OOM)的风险。

在上述实际场景中,我们不仅通过大量测试确定了最具性价比的取值,还考虑了启用分块预填充(Chunked Prefill)时解码 Token 的累积情况。如果设置得太小,单个请求可能会被多次分块,且在推理初期,一个 Batch 可能仅包含极少量的解码 Token,这会导致端到端吞吐量低于预期。

3.Cudagraph 捕获尺寸 (Cudagraph_capture_sizes)#

cudagraph_capture_sizes 参数控制推理过程中图捕获的粒度。调整此值决定了一次性捕获多少计算图,这会对性能和内存使用产生显著影响。

如果未手动指定此列表,系统将使用一系列均匀分布的值填充,通常能保证较好的性能。但是,如果您想进一步微调,手动指定取值将获得更好的效果。这是因为如果 Batch Size 落在两个捕获尺寸之间,框架会自动将 Token 数量补齐(Pad)到较大的尺寸,这往往会导致实际性能偏离预期甚至下降。

因此,在上述实际场景中,在调整基准测试请求并发量时,我们始终确保该并发量包含在 cudagraph_capture_sizes 列表中。这样在解码阶段,补齐操作基本上被避免了,确保了实验数据的可靠性。

需要特别注意的是,如果您启用了 FlashComm_v1,此列表中的值必须是 TP(张量并行)大小的整数倍。任何不满足此条件的数值都将被自动过滤。因此,我建议在启用 FlashComm_v1 后,基于 TP 大小来递增添加并发量。