执行摘要
- 一句话:NPU 平台新增 6 模型 GSM8K 精度回归测试与 CI 注册
- 推荐动作:值得关注的是 NPU CI 注册机制(register_npu_ci 与 workflow matrix 的双向注册)和精度测试基类 TestNpuAccuracyTestCaseBase 的模板化用法;对于需要在 NPU 上新增模型测试的工程师,本 PR 提供了可直接复用的范式。代码本身逻辑简单,无需精读推理路径。
功能与动机
PR body 明确提出目标:Add NPU GSM8K accuracy test cases under test/registered/ascend/accuracy/,覆盖 glm4_7_flash、qwen3_vl_30b_a3b、glm5_top64_pruned、moonshotai_moonlight_16b_a3b、qwen3_5_9b、qwen3_vl_8b 等模型。动机是补全 NPU 侧精度回归覆盖:ascend 注意力后端、采样后端等 NPU 特有实现与 CUDA 路径差异较大,缺少 GSM8K 基线会导致算子改动后精度回退难以被及时发现,需要为 NPU 推理栈建立可自动触发的精度基线。
实现拆解
- 模型路径常量(python/sglang/test/ascend/e2e/test_npu_performance_utils.py):新增 QWEN3_5_9B_MODEL_PATH、MOONLIGHT_16B_A3B_MODEL_PATH、GLM5_TOP64_PRUNED_GSM8K_MODEL_PATH 三个常量,统一采用 modelscope 本地缓存路径格式,与既有 GLM_4_7_FLASH_MODEL_PATH 等常量管理方式一致。
- 新增精度测试用例(test/registered/ascend/accuracy//):6 个测试文件均继承 TestNpuAccuracyTestCaseBase,通过类属性声明 model、envs、other_args、accuracy 阈值、datasets、few_shot_num、generation_config、eval_batch_size,test_gsm8k 调用 run_accuracy() 执行完整评估流程;再用 register_npu_ci(est_time=3600, nightly=True, disabled="accuracy testcase") 注册进夜间 CI 套件。多模态模型(Qwen3-VL-8B、Qwen3-VL-30B-A3B)额外配置 --enable-multimodal 与 ascend_attn 后端;GLM5-top64-pruned 使用 --tp-size 16 与 deepep a2a 后端,是规模最大的用例。
- CI 工作流注册(.github/workflows/pr-test-npu.yml):在测试矩阵中新增 6 个 test_type: 'accuracy' 条目,按模型规模分配 linux-aarch64-a3-2(双卡)、linux-aarch64-a3-4(四卡)、linux-aarch64-a3-16(十六卡)runner。
- 修正与精简:提交历史显示修复了基类导入名(TestAscendAccuracyTestCaseBase → TestNpuAccuracyTestCaseBase),更新精度阈值基线;按 review 意见删除 register_npu_ci 中重复的 full 套件注册,并移除 qwen3_vl_30b_a3b_thinking 工作流条目(该用例最终未合入)。qwen3_5_9b 与 glm5_top64_pruned 通过 limit = 100 限制评估样本数以控制 CI 时长。
关键文件:
test/registered/ascend/accuracy/qwen3_vl_8b/test_npu_qwen3_vl_8b_bf16_2p_gsm8k.py(模块 精度测试;类别 test;类型 test-coverage;符号 TestNPUQwen3_VL_8B_GSM8K, test_gsm8k): 最完整的模板化精度测试用例:配置多模态、ascend 注意力后端、tp-size 4 等参数,并注册到 stage-b 夜间套件,是其他 5 个用例的参照。
test/registered/ascend/accuracy/glm4_7_flash/test_npu_glm4_7_flash_1p_gsm8k.py(模块 精度测试;类别 test;类型 test-coverage;符号 TestNPUGlm4_7Flash_1P_GSM8K, test_gsm8k): GLM4.7-Flash 的 GSM8K 精度测试,配置 tp-size 2、chunked prefill 16384 与 glm47 工具调用解析器,覆盖 Dense 模型在 NPU 上的精度基线。
test/registered/ascend/accuracy/qwen3_5_9b/test_npu_qwen3_5_9b_bf16_1p_gsm8k.py(模块 精度测试;类别 test;类型 test-coverage;符号 TestNPUQwen3_5_9B_GSM8K, test_gsm8k): Qwen3.5-9B 的 GSM8K 精度测试,开启 dp-attention,并通过 limit = 100 限制评估样本数控制时长,展示大规模模型的降采样策略。
test/registered/ascend/accuracy/qwen3_vl_30b_a3b/test_npu_qwen3_vl_30b_a3b_bf16_2p_gsm8k.py(模块 精度测试;类别 test;类型 test-coverage;符号 TestNPUQwen3_VL_30B_A3B_GSM8K, test_gsm8k): Qwen3-VL-30B-A3B 多模态 MoE 模型的 GSM8K 精度测试,tp-size 4、max-prefill-tokens 102400,覆盖多模态大模型配置。
test/registered/ascend/accuracy/moonshotai_moonlight_16b_a3b/test_npu_moonlight_16b_a3b_bf16_1p_gsm8k.py(模块 精度测试;类别 test;类型 test-coverage;符号 TestNPUMoonlight16B_A3B_GSM8K, test_gsm8k): Moonlight-16B-A3B 的 GSM8K 精度测试,tp-size 2,为月之暗面 MoE 模型在 NPU 上建立精度基线。
test/registered/ascend/accuracy/glm5_top64_pruned/test_npu_glm5_top64_pruned_bf16_8p_gsm8k.py(模块 精度测试;类别 test;类型 test-coverage;符号 TestNPUGLM5_Top64_Pruned_GSM8K, test_gsm8k): GLM5-top64-pruned 的 GSM8K 精度测试,tp-size 16 并使用 deepep a2a 后端,是本次矩阵中规模最大、资源占用最高的用例。
python/sglang/test/ascend/e2e/test_npu_performance_utils.py(模块 测试工具;类别 test;类型 test-coverage): 集中管理 NPU 测试模型路径,本次新增 QWEN3_5_9B_MODEL_PATH、MOONLIGHT_16B_A3B_MODEL_PATH、GLM5_TOP64_PRUNED_GSM8K_MODEL_PATH,是测试用例引用的依赖入口。
.github/workflows/pr-test-npu.yml(模块 CI 配置;类别 infra;类型 infrastructure): NPU PR 测试矩阵入口,新增 6 个 accuracy 测试条目并按模型规模分配 runner,是 CI 实际执行的依据。
关键符号:test_gsm8k, run_accuracy, register_npu_ci
关键源码片段
test/registered/ascend/accuracy/qwen3_vl_8b/test_npu_qwen3_vl_8b_bf16_2p_gsm8k.py
最完整的模板化精度测试用例:配置多模态、ascend 注意力后端、tp-size 4 等参数,并注册到 stage-b 夜间套件,是其他 5 个用例的参照。
import unittest
# 复用 NPU 精度测试基类,统一负责服务启动、数据集评估与阈值比对
from sglang.test.ascend.e2e.test_npu_accuracy_utils import TestNpuAccuracyTestCaseBase
# 模型路径常量集中在 performance_utils 中,供多套测试复用
from sglang.test.ascend.e2e.test_npu_performance_utils import QWEN3_VL_8B_MODEL_PATH
from sglang.test.ci.ci_register import register_npu_ci
# 注册进夜间 CI 的 stage-b 套件,预计耗时 1 小时
register_npu_ci(
est_time=3600,
suite="stage-b-test-4-npu-a3",
nightly=True,
disabled="accuracy testcase",
)
# 环境变量:开启 CPU 亲和与 expandable segments,稳定 NPU 显存分配
QWEN3_VL_8B_ENVS = {
"SGLANG_SET_CPU_AFFINITY": "1",
"PYTORCH_NPU_ALLOC_CONF": "expandable_segments:True",
"STREAMS_PER_DEVICE": "32",
"HCCL_BUFFSIZE": "1536",
"HCCL_OP_EXPANSION_MODE": "AIV",
}
# 启动参数:多模态 + ascend 注意力后端,tp-size 4,bf16,关闭 radix cache
QWEN3_VL_8B_OTHER_ARGS = [
"--enable-multimodal",
"--mm-attention-backend", "ascend_attn",
"--attention-backend", "ascend",
"--device", "npu",
"--trust-remote-code",
"--tp-size", 4,
"--mem-fraction-static", 0.8,
"--disable-radix-cache",
"--chunked-prefill-size", -1,
"--sampling-backend", "ascend",
"--tool-call-parser", "qwen",
"--reasoning-parser", "qwen3",
"--cuda-graph-bs",
8, 16, 32, 64, 128, 256,
"--dtype", "bfloat16",
]
class TestNPUQwen3_VL_8B_GSM8K(TestNpuAccuracyTestCaseBase):
"""Qwen3-VL-8B 在 NPU 上的 GSM8K 精度回归测试。"""
model = QWEN3_VL_8B_MODEL_PATH
envs = QWEN3_VL_8B_ENVS
other_args = QWEN3_VL_8B_OTHER_ARGS
# 精度阈值来自基线数据,低于该值即判定回归
accuracy = 0.9553
datasets = ["gsm8k"]
few_shot_num = 5
# 关闭 thinking 的生成配置,与 GSM8K 评测约定对齐
generation_config = {
"max_tokens": 32768,
"temperature": 1.0,
"top_p": 1.0,
"top_k": 40,
"repetition_penalty": 1.0,
"presence_penalty": 2.0,
"extra_body": {"chat_template_kwargs": {"enable_thinking": False}},
}
eval_batch_size = 64
def test_gsm8k(self):
self.run_accuracy()
if __name__ == "__main__":
unittest.main()
评论区精华
review 全程由 cherryblo 给出,讨论非常简短:在 qwen3_vl_8b、qwen3_5_9b 测试文件的 register_npu_ci 块上分别评论 "delete",指向 full-4-npu-a3、full-2-npu-a3 的重复注册;在 pr-test-npu.yml 中同样对 qwen3_vl_30b_a3b_thinking_1p_gsm8k 条目评论 "delete"。核心诉求是避免同一用例在 full 套件与 stage-b 套件中重复执行,并移除最终未落地的 thinking 变体条目。提交 cleanup: delete gsm8k test, keep only stage-b registrations for dual-reg files 落实了清理。
- 删除测试文件内重复的 full 套件注册 (design): 提交 cleanup: delete gsm8k test, keep only stage-b registrations for dual-reg files 已删除重复注册,仅保留 stage-b 条目。
- pr-test-npu.yml 中移除 qwen3_vl_30b_a3b_thinking 条目 (design): 已删除该条目,最终矩阵不含 thinking 变体用例。
风险与影响
- 风险:精度阈值硬编码:accuracy 字段(如 0.9553、0.8370)是基线快照,模型权重更新、采样后端或 ascend kernel 实现变化都可能触发阈值误报。模型路径硬编码为 /root/.cache/modelscope/...,依赖 CI runner 镜像预置权重缓存,缓存缺失会导致用例直接失败。CI 资源开销:6 个用例各 est_time=3600(约 1 小时),其中 glm5_top64_pruned 占用 16 卡 runner,矩阵扩展明显增加 NPU CI 资源消耗与排队时间。覆盖局限:qwen3_5_9b、glm5_top64_pruned 通过 limit = 100 仅评估 100 条样本,统计功效有限;qwen3_vl_30b_a3b_thinking 未合入意味着带 thinking 推理路径暂无 GSM8K 基线。合入时 PR Test 状态为失败(:x:),需确认是否为资源或基线问题。
- 影响:对线上服务无运行时影响。影响集中在 NPU CI 维护者(矩阵资源、模型权重准备)与后续 NPU 算子/后端改动者(必须保持 6 条 GSM8K 精度基线)。对团队而言,NPU 平台首次建立覆盖多种规模(双卡到十六卡)与多种架构(Dense、MoE、多模态)的精度回归入口,后续 NPU 内核优化可用其作为回归闸门。
- 风险标记:CI 资源开销增加, 精度阈值硬编码, 模型路径硬编码, 样本数受限
关联脉络
参与讨论