执行摘要
- 一句话:NPU 测试代码去重与重构,使用 Mixin 消除重复 GSM8K 测试逻辑
- 推荐动作:值得精读,展示了如何通过 Mixin 模式重构大型测试套件中的重复代码,是测试基础设施优化的良好实践。需特别关注 Review 中尚未完全解决的属性名不匹配问题,以及权重路径是否使用缓存。
功能与动机
来自 PR Body:'There is a lot of duplicated code because, instead of using a GSM8KAscendMixin common class, the GSM8K model tests were added by copy-pasting.' 目标是消除重复代码,统一测试配置方式,并在 CI 中输出测试摘要。
实现拆解
-
创建 Mixin 基类:在 python/sglang/test/ascend/gsm8k_ascend_mixin.py 中定义 GSM8KAscendMixin,封装 GSM8K 评估的公共逻辑(启动服务、执行评估、断言)。在 python/sglang/test/ascend/test_mmlu.py 中定义 TestMMLU 基类,封装 MMLU 评估逻辑。基类通过读取子类的类属性(model、other_args、env、accuracy 等)自动完成服务启动和测试执行。
-
重构各测试类:修改 6 个 DeepEP 和注意力并行测试文件,使其继承 GSM8KAscendMixin 和 TestMMLU(部分类多重继承)。将原来的 setUpClass/tearDownClass 方法替换为声明式类属性,移除了大量重复的 popen_launch_server 调用和 kill_process_tree 逻辑。测试方法(如 test_gsm8k、test_mmlu)由基类统一实现。
-
添加 GitHub Summary 输出:在基类和部分测试中集成 GitHub Actions Step Summary,将准确率结果以 JSON 格式输出,方便 CI 流水线解析。
-
更新权重路径:在 test_ascend_utils.py 中添加新的模型权重常量 REDHATAI_QWEN2_5_0_5B_INSTRUCT_QUANTIZED_W8A8_WEIGHTS_PATH,用于量化测试。
-
修复配置问题:根据 Review 反馈,修正了 other_args 误定义为元组的问题、属性名不匹配问题(accuracy_mmlu → accuracy_mmlu_threshold),以及权重路径缺少 MODEL_WEIGHTS_DIR 前缀的问题。
-
更新 CODEOWNERS:修改 .github/CODEOWNERS,将 Ascend 测试的维护者指向新团队。
关键文件:
test/registered/ascend/llm_models/test_npu_qwen3_30b_attn_cp.py(模块 注意力并行;类别 test;类型 test-coverage;符号 TestQwen330BAttnCP, setUpClass, tearDownClass, test_gsm8k_accuracy): 核心测试文件,重构后使用 GSM8KAscendMixin,减少约 70 行重复代码,展示了从 setUpClass 到声明式配置的转变。
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_auto_qwen3_480b.py(模块 专家并行;类别 test;类型 test-coverage;符号 TestDeepEpQwen, setUpClass, tearDownClass, test_mmlu): 典型的 DeepEP 自动模式测试文件,重构后同时使用 GSM8KAscendMixin 和 TestMMLU,显著减少重复代码。
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_low_latency_qwen3_480b.py(模块 专家并行;类别 test;类型 test-coverage;符号 TestDeepEpQwen, setUpClass, tearDownClass, test_mmlu): DeepEP 低延迟模式测试,重构后同样减少约 100 行重复代码。
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_low_latency_qwen3_next.py(模块 专家并行;类别 test;类型 test-coverage;符号 TestQwen3Next, setUpClass, tearDownClass, test_mmlu): Qwen3-Next 低延迟模式测试,重构后减少约 100 行重复代码。
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_auto_qwen3_next.py(模块 专家并行;类别 test;类型 test-coverage;符号 TestQwen3Next, setUpClass, tearDownClass, test_mmlu): Qwen3-Next 自动模式测试,重构后减少约 96 行重复代码。
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_low_latency_deepseek_v3_2_w8a8.py(模块 专家并行;类别 test;类型 test-coverage;符号 TestDeepEpDeepseekV32, setUpClass, tearDownClass, test_mmlu): DeepSeek V3.2 低延迟模式测试,重构后减少约 87 行重复代码。
test/registered/ascend/basic_function/quant/test_npu_w4a4_quantization.py(模块 量化测试;类别 test;类型 test-coverage;符号 TestAscendW4A4, setUpClass, tearDownClass, test_gsm8k): 量化测试文件,同样引入 GSM8KAscendMixin 以消除重复的 setUpClass 和 test_gsm8k。
test/registered/ascend/basic_function/quant/test_npu_w8a8_quantization.py(模块 量化测试;类别 test;类型 test-coverage;符号 TestAscendW8A8CompressedTensors, setUpClass, tearDownClass, test_gsm8k): W8A8 量化测试,同样采用 Mixin 去掉重复样板代码。
python/sglang/test/ascend/test_ascend_utils.py(模块 测试工具;类别 test;类型 test-coverage): 工具文件,新增模型权重路径常量,并修复了路径前缀问题。
python/sglang/test/ascend/test_mmlu.py(模块 测试基类;类别 test;类型 test-coverage): MMLU 测试基类,引入 TestMMLU 供其他测试继承,并在此 PR 中调整了 Summary 输出格式。
python/sglang/test/ascend/gsm8k_ascend_mixin.py(模块 测试基类;类别 test;类型 test-coverage): 核心 Mixin 文件,定义了 GSM8KAscendMixin,封装了服务启动、评估执行和 Summary 输出逻辑。
.github/CODEOWNERS(模块 仓库配置;类别 infra;类型 infrastructure): 更新 Ascend 测试目录的负责人,将维护者指向新团队。
关键符号:GSM8KAscendMixin, TestMMLU, setUpClass, test_gsm8k, test_mmlu
关键源码片段
test/registered/ascend/llm_models/test_npu_qwen3_30b_attn_cp.py
核心测试文件,重构后使用 GSM8KAscendMixin,减少约 70 行重复代码,展示了从 setUpClass 到声明式配置的转变。
# test/registered/ascend/llm_models/test_npu_qwen3_30b_attn_cp.py
# 重构后:使用 Mixin + 类属性,无需重复编写服务启动和测试方法
import os
import unittest
from sglang.test.ascend.gsm8k_ascend_mixin import GSM8KAscendMixin # 引入共享 Mixin
from sglang.test.ascend.test_ascend_utils import QWEN3_30B_A3B_WEIGHTS_PATH
from sglang.test.ci.ci_register import register_npu_ci
from sglang.test.test_utils import CustomTestCase
register_npu_ci(est_time=500, suite="nightly-4-npu-a3", nightly=True)
class TestQwen330BAttnCP(GSM8KAscendMixin, CustomTestCase):
"""GSM8K accuracy test for Qwen3-30B-A3B mixed deployment on 4 NPUs."""
model = QWEN3_30B_A3B_WEIGHTS_PATH # 类属性:模型路径
other_args = [ # 类属性:额外启动参数
"--trust-remote-code",
"--mem-fraction-static", "0.7",
"--max-running-requests", "32",
"--attention-backend", "ascend",
"--tp-size", "4",
"--moe-dp-size", "2",
"--attn-cp-size", "2",
"--cuda-graph-max-bs", "32",
"--enable-prefill-context-parallel",
]
env = {**os.environ, "ASCEND_USE_FIA": "1"} # 类属性:环境变量
accuracy = 0.92 # GSM8K 最低准确率
gsm8k_parallel = 32
num_questions = 100
gsm8k_num_shots = 5
if __name__ == "__main__":
unittest.main()
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_auto_qwen3_480b.py
典型的 DeepEP 自动模式测试文件,重构后同时使用 GSM8KAscendMixin 和 TestMMLU,显著减少重复代码。
# test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_auto_qwen3_480b.py
# 重构后:多重继承 Mixin,同时获得 GSM8K 和 MMLU 测试能力
import os
import unittest
from sglang.test.ascend.gsm8k_ascend_mixin import GSM8KAscendMixin
from sglang.test.ascend.test_ascend_utils import QWEN3_CODER_480B_A35B_INSTRUCT_W8A8_QUAROT_WEIGHTS_PATH
from sglang.test.ascend.test_mmlu import TestMMLU # 引入 MMLU 测试基类
from sglang.test.ci.ci_register import register_npu_ci
from sglang.test.test_utils import CustomTestCase
register_npu_ci(est_time=200, suite="nightly-16-npu-a3", nightly=True)
class TestDeepEpQwen(GSM8KAscendMixin, TestMMLU, CustomTestCase):
"""Test with DeepEP auto mode"""
model = QWEN3_CODER_480B_A35B_INSTRUCT_W8A8_QUAROT_WEIGHTS_PATH
other_args = [
"--trust-remote-code", "--nnodes", "1", "--node-rank", "0",
"--attention-backend", "ascend", "--device", "npu",
"--quantization", "modelslim", "--max-running-requests", 96,
"--context-length", 8192, "--dtype", "bfloat16",
"--chunked-prefill-size", 28672, "--max-prefill-tokens", 458880,
"--disable-radix-cache", "--moe-a2a-backend", "deepep",
"--deepep-mode", "auto", "--tp-size", 16, "--dp-size", 4,
"--enable-dp-attention", "--enable-dp-lm-head",
"--mem-fraction-static", 0.7, "--cuda-graph-bs", 16, 20, 24,
]
env = {
"PYTORCH_NPU_ALLOC_CONF": "expandable_segments:True",
"SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT": "600",
"HCCL_BUFFSIZE": "2100", "HCCL_OP_EXPANSION_MODE": "AIV",
"TRANSFORMERS_VERBOSITY": "error", **os.environ,
}
mmlu_num_examples = 8
accuracy_mmlu_threshold = 0.61 # MMLU 准确性阈值
accuracy = 0.91 # GSM8K 准确性阈值
num_questions = 200
gsm8k_num_shots = 8
if __name__ == "__main__":
unittest.main()
评论区精华
Review 主要指出三个问题:
- 属性名不匹配:
test_mmlu.py 中 getattr(self, 'accuracy_mmlu') 与子类定义的 accuracy_mmlu_threshold 不一致,会导致 Summary 显示 'N/A'。
- 权重路径缺少前缀:新增的
REDHATAI_QWEN2_5_0_5B_INSTRUCT_QUANTIZED_W8A8_WEIGHTS_PATH 未使用 os.path.join(MODEL_WEIGHTS_DIR, ...),可能导致文件未找到。作者回应:“Since the test did not specify an absolute path, I copied it here the same way.” 后改为使用缓存。
- other_args 类型错误:多个文件将
other_args 定义为 ([...]) 即元组包裹列表,应改为纯列表。
最终 reviewer ping1jing2 批准了 PR,但部分评论指出问题可能未完全修复(如 accuracy_mmlu 仍残留),需注意。
- 属性名不匹配导致 Summary 显示 N/A (correctness): 作者未明确回复,但后续提交可能已修复。最终需验证。
- 新权重路径缺少 MODEL_WEIGHTS_DIR 前缀 (correctness): 作者在后续提交中修复,使用了缓存路径。
- other_args 定义为元组而非列表 (correctness): 作者应已修复(相关文件最终版本显示为列表格式)。
风险与影响
关联脉络
- PR #24689 [NPU] Add GitHub test summary and deduplicate test code. Part 2: 自身,作为上下文参考。
参与讨论