Prhub

#24689 [NPU] Add GitHub test summary and deduplicate test code. Part 2

原始 PR 作者 e-martirosian 合并时间 2026-06-08 23:08 文件变更 12 提交数 16 评论 12 代码增减 +390 / -688

执行摘要

NPU 测试代码去重与重构,使用 Mixin 消除重复 GSM8K 测试逻辑

来自 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 模式重构大型测试套件中的重复代码,是测试基础设施优化的良好实践。需特别关注 Review 中尚未完全解决的属性名不匹配问题,以及权重路径是否使用缓存。

讨论亮点

Review 主要指出三个问题:

  • 属性名不匹配test_mmlu.pygetattr(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 仍残留),需注意。

实现拆解

  1. 创建 Mixin 基类:在 python/sglang/test/ascend/gsm8k_ascend_mixin.py 中定义 GSM8KAscendMixin,封装 GSM8K 评估的公共逻辑(启动服务、执行评估、断言)。在 python/sglang/test/ascend/test_mmlu.py 中定义 TestMMLU 基类,封装 MMLU 评估逻辑。基类通过读取子类的类属性(modelother_argsenvaccuracy 等)自动完成服务启动和测试执行。

  2. 重构各测试类:修改 6 个 DeepEP 和注意力并行测试文件,使其继承 GSM8KAscendMixinTestMMLU(部分类多重继承)。将原来的 setUpClass/tearDownClass 方法替换为声明式类属性,移除了大量重复的 popen_launch_server 调用和 kill_process_tree 逻辑。测试方法(如 test_gsm8ktest_mmlu)由基类统一实现。

  3. 添加 GitHub Summary 输出:在基类和部分测试中集成 GitHub Actions Step Summary,将准确率结果以 JSON 格式输出,方便 CI 流水线解析。

  4. 更新权重路径:在 test_ascend_utils.py 中添加新的模型权重常量 REDHATAI_QWEN2_5_0_5B_INSTRUCT_QUANTIZED_W8A8_WEIGHTS_PATH,用于量化测试。

  5. 修复配置问题:根据 Review 反馈,修正了 other_args 误定义为元组的问题、属性名不匹配问题(accuracy_mmluaccuracy_mmlu_threshold),以及权重路径缺少 MODEL_WEIGHTS_DIR 前缀的问题。

  6. 更新 CODEOWNERS:修改 .github/CODEOWNERS,将 Ascend 测试的维护者指向新团队。

文件 模块 状态 重要度
test/registered/ascend/llm_models/test_npu_qwen3_30b_attn_cp.py 注意力并行 modified 7.42
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_auto_qwen3_480b.py 专家并行 modified 7.38
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_low_latency_qwen3_480b.py 专家并行 modified 7.09
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_low_latency_qwen3_next.py 专家并行 modified 7.09
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_auto_qwen3_next.py 专家并行 modified 7.07
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_low_latency_deepseek_v3_2_w8a8.py 专家并行 modified 7.02
test/registered/ascend/basic_function/quant/test_npu_w4a4_quantization.py 量化测试 modified 6.92
test/registered/ascend/basic_function/quant/test_npu_w8a8_quantization.py 量化测试 modified 6.88
python/sglang/test/ascend/test_ascend_utils.py 测试工具 modified 4.16
python/sglang/test/ascend/test_mmlu.py 测试基类 modified 4.51
python/sglang/test/ascend/gsm8k_ascend_mixin.py 测试基类 modified 4.39
.github/CODEOWNERS 仓库配置 modified 2.48

关键符号

GSM8KAscendMixin TestMMLU setUpClass test_gsm8k test_mmlu

关键源码片段

test/registered/ascend/llm_models/test_npu_qwen3_30b_attn_cp.py test-coverage

核心测试文件,重构后使用 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 CustomTestCaseregister_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 = 5if __name__ == "__main__":
    unittest.main()
test/registered/ascend/basic_function/parallel_strategy/expert_parallelism/test_npu_deepep_auto_qwen3_480b.py test-coverage

典型的 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 CustomTestCaseregister_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 = 8if __name__ == "__main__":
    unittest.main()

评论区精华

属性名不匹配导致 Summary 显示 N/A 正确性

Reviewer 指出 `getattr(self, 'accuracy_mmlu')` 应匹配子类定义的 `accuracy_mmlu_threshold`,否则阈值显示为 N/A。

结论:作者未明确回复,但后续提交可能已修复。最终需验证。 · 已解决

新权重路径缺少 MODEL_WEIGHTS_DIR 前缀 正确性

Reviewer 指出 `REDHATAI_QWEN2_5_0_5B_INSTRUCT_QUANTIZED_W8A8_WEIGHTS_PATH` 缺少 `os.path.join(MODEL_WEIGHTS_DIR, ...)`。作者先回应按原方式复制,后改为使用缓存。

结论:作者在后续提交中修复,使用了缓存路径。 · 已解决

other_args 定义为元组而非列表 正确性

多个文件中 `other_args = ([...])` 导致类型为元组,可能与启动工具不兼容。Reviewer 建议改为纯列表。

结论:作者应已修复(相关文件最终版本显示为列表格式)。 · 已解决

风险与影响

  1. 基类兼容性风险GSM8KAscendMixinTestMMLU 的多重继承 MRO 可能导致预期外的行为,例如若两个基类都定义了 setUpClass,子类调用 super() 时顺序可能非预期。但当前实现中 Mixin 只提供类属性,不重写 setUpClass,风险较低。
  2. 配置遗漏风险:声明式类属性可能遗漏某些测试类特定的配置(如超时时间、环境变量),例如 test_npu_deepep_low_latency_deepseek_v3_2_w8a8.py 中增加了 timeout_for_server_launch = 6000,但其他测试未显式设置,可能使用基类默认值,需确认基类是否妥善处理。
  3. 属性名不一致:Review 指出的 accuracy_mmluaccuracy_mmlu_threshold 不匹配问题,在最终代码中可能仍存在,若未修复会导致 Summary 中 MMLU 阈值显示异常,但不影响测试执行。
  4. 回归风险:修改涉及 12 个文件,删除约 600 行代码,若基类实现有缺陷可能影响所有 NPU 测试,需依赖 CI 验证。

范围:仅影响 NPU 测试套件(Ascend 平台),不涉及任何生产代码。
程度:显著降低测试代码重复度,提升可维护性。新增的 GitHub Summary 输出便于 CI 结果查看。未来新增类似测试只需继承 Mixin 并配置少量属性。对用户和推理服务无影响。

属性名不一致残留 多重继承 MRO 可能非预期 基类默认配置可能不适合所有测试

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论