执行摘要
- 一句话:MI35x 新增 Kimi-K3 精度 nightly,替换 K2.6
- 推荐动作:值得精读,尤其是 6 个 commit 的演进过程。这个 PR 虽无源码逻辑,但展示了高质量的 CI 工程判断:精度先于性能、用硬件 ISA 约束校验"替换"决策、不 pin 废弃镜像、用 completion harness 规避 chat 模板陷阱。对想了解 sglang AMD nightly 编排(register_amd_ci、run_suite.py、job_select 联动)的读者是很好的范本。
功能与动机
PR body 明确指出:Kimi-K3 cookbook 虽然发布了 MI350X/MI355X 1×8 部署配方,AMD Day-0 跟踪 issue #32548 也报告了吞吐,但两者都没有提供自动化端到端精度信号——cookbook 该 cell 仍标记为 verified: false,#32548 只测速度。测试文件 docstring 进一步说明:"That issue reports throughput on MI355 TP8 but no accuracy, and the cookbook cell for this topology is still published as verified: false. So the recipe is known to run at speed; what is missing, and what this test supplies, is evidence that it produces correct tokens." 即配方能跑多快已知,缺的是"跑得对不对"的证据。
实现拆解
实现分四步完成,核心是新增一个端到端精度测试并接入 AMD nightly 编排:
-
新增 MI35x 精度测试文件 test/registered/amd/accuracy/mi35x/test_kimi_k3_eval_mi35x.py(+163 行)。文件顶部调用 register_amd_ci(est_time=9000, suite="nightly-amd-accuracy-8-gpu-mi35x-kimi-k3", nightly=True) 完成 suite 注册;TestKimiK3EvalMI35x.setUpClass 通过环境变量 GSM8K_NUM_QUESTIONS、GSM8K_MAX_NEW_TOKENS 提供可调入口;test_kimi_k3_gsm8k_accuracy 用 popen_launch_server 拉起 TP8 服务,参数完全对齐 #32548 的非投机配方(Triton attention、bfloat16、--mem-fraction-static 0.85、--disable-radix-cache),并设置 --reasoning-parser kimi_k3、--tool-call-parser kimi_k3。关键设计是选用 few-shot completion 评估而不是 chat 路径:K3 的 thinking 永久开启,答案走 reasoning_content,chat 路径的 message.content 为空会得 0 分;completion 路径直接对原始输出打分,并与既有 Kimi 兄弟测试(K2/K2.5/K2.6)保持一致。环境方面设置了 4 个 AITER 相关变量(SGLANG_USE_AITER、SGLANG_AITER_K3_OPT、AITER_FLYDSL_FORCE、AITER_SITUV2_A8W4),其中前两个在 sglang 内被读取,后两个由 AITER 自身消费。评估完成后按 ACCURACY_THRESHOLD = 0.92 断言(与 AMD Kimi 精度家族一致),CI 下将结果写入 GitHub step summary,finally 中 kill_process_tree 确保 server 进程被回收。
-
工作流替换 .github/workflows/nightly-test-amd-rocm720.yml(+21/-10)。将 nightly-8-gpu-mi35x-kimi-k26-rocm720 替换为 nightly-8-gpu-mi35x-kimi-k3-rocm720,同步更新 job_select 与 check-all-jobs 两处条目;MI30x 的 nightly-8-gpu-kimi-k26-rocm720 保留,注释从 "MI30x + MI35x" 改为 "MI30x"。由于 2.8T 权重的 MXFP4 checkpoint 约 1.56 TB,加载耗时占大头,job 超时从 180 分钟提升到 300 分钟,--timeout-per-file 从 7200 升到 14400。
-
suite 注册 test/run_suite.py(+1/-0)。在 NIGHTLY_SUITES[HWBackend.AMD] 列表中插入 nightly-amd-accuracy-8-gpu-mi35x-kimi-k3,使 run_suite.py --hw amd --suite ... 能发现该测试。
-
提交演进中的范围收敛(来自 6 个 commit)。初始版本同时包含 accuracy 与 perf 两个 job,且 perf 通过 needs: 依赖 accuracy 通过后才运行;但 perf job 在唯一一次分派中 23 秒即死于 setUpClass(基于 #33832 之前的 NightlyBenchmarkRunner API 编写),因此被拆出推迟到 #34985。随后恢复 MI300 的 K2.6 任务、保留 ROCm 7.0 工作流不动,最终只替换 7.2 lane 的 MI35x 槽位。
关键文件:
test/registered/amd/accuracy/mi35x/test_kimi_k3_eval_mi35x.py(模块 测试用例;类别 test;类型 test-coverage;符号 TestKimiK3EvalMI35x, setUpClass, test_kimi_k3_gsm8k_accuracy): 核心新增文件,定义了 Kimi-K3 在 MI35x 8 卡上的 GSM8K 精度测试:服务器参数、AITER 环境变量、评估断言与 CI summary 输出全部集中于此。
.github/workflows/nightly-test-amd-rocm720.yml(模块 CI 工作流;类别 infra;类型 infrastructure): 工作流编排的替换点:将 MI35x 8 卡槽位从 K2.6 换成 K3,并调整超时、job_select、check-all-jobs 等配套条目。
test/run_suite.py(模块 测试编排;类别 test;类型 test-coverage): suite 注册入口,将新测试接入 NIGHTLY_SUITES[AMD],使 run_suite.py 能按 suite 名发现并运行该 test。
关键符号:TestKimiK3EvalMI35x.setUpClass, TestKimiK3EvalMI35x.test_kimi_k3_gsm8k_accuracy
关键源码片段
test/registered/amd/accuracy/mi35x/test_kimi_k3_eval_mi35x.py
核心新增文件,定义了 Kimi-K3 在 MI35x 8 卡上的 GSM8K 精度测试:服务器参数、AITER 环境变量、评估断言与 CI summary 输出全部集中于此。
class TestKimiK3EvalMI35x(CustomTestCase):
"""Kimi-K3 GSM8K 精度评估测试,运行在 AMD MI35x 8 卡(TP8)上。"""
@classmethod
def setUpClass(cls):
cls.base_url = DEFAULT_URL_FOR_TEST
# 允许通过环境变量覆盖题目数与生成长度,便于本地快速调试
cls.num_questions = int(os.environ.get("GSM8K_NUM_QUESTIONS", "1319"))
cls.max_new_tokens = int(os.environ.get("GSM8K_MAX_NEW_TOKENS", "512"))
def test_kimi_k3_gsm8k_accuracy(self):
# 服务器参数对齐 #32548 非投机配方:TP8 + Triton attention +
# bfloat16 + 静态内存占比 0.85,并关闭 radix cache
other_args = [
"--tp", str(TP_SIZE),
"--attention-backend", "triton",
"--dtype", "bfloat16",
"--mem-fraction-static", "0.85",
"--disable-radix-cache",
# 并发上限与 decode graph 捕获上限保持一致:1319 题一次性
# 全量提交,必须显式限流,避免突破权重之后仅剩的约 53 GB/ 卡
# 显存预算;捕获超过并发上限的 decode graph 没有收益
"--cuda-graph-max-bs-decode", str(MAX_RUNNING_REQUESTS),
"--max-running-requests", str(MAX_RUNNING_REQUESTS),
# K3 的 thinking 永远开启,需用专用 parser 解析输出
"--reasoning-parser", "kimi_k3",
"--tool-call-parser", "kimi_k3",
"--trust-remote-code",
'--model-loader-extra-config', '{"enable_multithread_load": true}',
"--watchdog-timeout", "1200",
]
env = os.environ.copy()
# K3 的 MoE 在 ROCm 上由 AITER 提供,四个环境变量缺一不可:
# SGLANG_USE_AITER 是总开关;SGLANG_AITER_K3_OPT 在 mxfp4.py 与
# models/kimi_k3.py 中被读取;AITER_SITUV2_A8W4 选择 W4A8 SiTU
# expert 内核;AITER_FLYDSL_FORCE 由 AITER 自身消费,仓库内不 grep
env["SGLANG_USE_AITER"] = "1"
env["SGLANG_AITER_K3_OPT"] = "1"
env["AITER_FLYDSL_FORCE"] = "1"
env["AITER_SITUV2_A8W4"] = "1"
process = popen_launch_server(
KIMI_K3_MODEL_PATH, self.base_url,
timeout=SERVER_LAUNCH_TIMEOUT, other_args=other_args, env=env,
)
try:
requests.get(self.base_url + "/flush_cache")
args = SimpleNamespace(
num_shots=8, data_path=None,
num_questions=self.num_questions,
parallel=self.num_questions,
max_new_tokens=self.max_new_tokens,
host="http://127.0.0.1",
port=int(self.base_url.split(":")[-1]),
)
metrics = run_eval_few_shot_gsm8k(args)
acc = metrics["accuracy"]
passed = acc >= ACCURACY_THRESHOLD
status = "✅ PASS" if passed else "❌ FAIL"
print(f" accuracy={acc:.3f} threshold={ACCURACY_THRESHOLD} {status}")
if is_in_ci():
# 在 GitHub Actions 中把结果写入 step summary 表格
summary = "### Kimi-K3 Model (MI35x)
"
summary += "| Model | TP | Accuracy | Threshold | Status |\n"
summary += "| ----- | -- | -------- | --------- | ------ |\n"
summary += f"| {KIMI_K3_MODEL_PATH} | {TP_SIZE} | {acc:.3f} | {ACCURACY_THRESHOLD} | {status} |\n"
write_github_step_summary(summary)
self.assertGreaterEqual(
acc, ACCURACY_THRESHOLD,
f"Kimi-K3 accuracy {acc:.3f} below threshold {ACCURACY_THRESHOLD}",
)
finally:
# 无论成败都确保销毁 server 进程,避免污染后续测试
kill_process_tree(process.pid)
评论区精华
Review 层面没有实质交锋:HaiShaw 直接 APPROVED(body 为空)。真正的设计争论体现在 6 个 commit 的演进消息里,作者在提交说明中给出了清晰的工程论证:
- perf 与 accuracy 的先后关系(commit
4d4d1a8):"Throughput on a checkpoint that spends most of an hour loading is not worth an 8-GPU MI35x slot until the kernels are known to emit correct tokens, and that runner is contended enough that a wasted slot costs real time."——在确认内核输出正确 token 之前,不值得为性能占一个稀缺的 8 卡槽位。
- K2.6 不应被整体退役(commit
dfc6954):"K3's native MXFP4 weights need gfx95x and mxfp4 does not register on gfx942 ... dropping those jobs would have left MI30x with no Kimi accuracy signal rather than moving it to a new one."——这是对"新模型取代旧模型"直觉的纠偏,硬件 ISA 约束使覆盖无法迁移。
-
不 pin 镜像的决定(PR body):"Pinning the abandoned rocm720-mi35x-k3-* image line would make a nightly rot over time."——作者选择信任标准 unpinned 镜像,避免废弃镜像线导致 nightly 逐渐腐烂。
-
perf nightly 是否应与 accuracy 一起落地 (design): 将 perf 部分拆出推迟到 #34985 跟踪,本 PR 只落 accuracy,避免在精度未经证实前占用稀缺的 8 卡 MI35x 槽位。
- MI300 的 Kimi-K2.6 nightly 是否应退役 (design): 恢复 nightly-8-gpu-kimi-k26 与 nightly-8-gpu-kimi-k26-rocm720,仅替换 MI35x 槽位。
- ROCm 7.0 lane 是否要改动 (design): 7.0 workflow 原样保留,本 PR 只改 7.2 工作流。
- codespell 单字命中导致全 CI 中止 (bugfix): 改为树内一致拼写 unparsable,而非向 .codespellrc 加入 ignore-words-list。
风险与影响
-
风险:本 PR 无源码主路径改动,但作为硬件精度门禁仍有以下风险:
-
外部资源依赖:测试默认从 HuggingFace 拉取 moonshotai/Kimi-K3,MXFP4 权重约 1.5 TB,下载失败或 HF 波动会直接导致 nightly 失败,且浪费 8 卡 MI35x 槽位(job 超时已调至 300 分钟)。
- AITER 内核耦合:测试依赖
SGLANG_AITER_K3_OPT、AITER_SITUV2_A8W4 等 AITER 行为,AITER 升级或改名会导致测试静默失效或误报;AITER_FLYDSL_FORCE 由 AITER 自身消费,仓库内无法 grep 验证,存在黑盒依赖。
- CI 门禁单点敏感:commit
bb70e1f 显示一个 codespell 单词(unparsable)就能让 check-pr-test-health 快速失败全部 21 个 base-b-* job,说明门禁链路对微小问题极度敏感。
- 阈值样本量小:0.92 阈值基于一次 0.956 的 green run(0.2% unparsable),统计样本有限,后续硬件或内核抖动可能造成偶发失败。
- 覆盖盲区:MI30x(gfx942)没有 K3 精度覆盖,这是硬件能力限制而非测试遗漏,但值得在文档中持续标注。
-
影响:影响范围集中在 AMD CI 基础设施,不涉及运行时行为:
-
对 AMD 团队:首次获得 Kimi-K3 在 MI355X 上自动化端到端精度信号,避免依赖手动验证;GSM8K 0.92 阈值与既有 Kimi 精度家族对齐,口径统一。
- 对 nightly 资源:ROCm 7.2 lane 的 MI35x 8 卡槽位从 K2.6 迁移到 K3,单 job 时长从约 74 分钟(精度跑完)拉长到包含约 1.5 TB 权重加载的全流程,占用时间显著增加。
- 对覆盖矩阵:MI30x 的 K2.6 精度覆盖保留,ROCm 7.0 lane 不变,总体覆盖不降反升(MI35x 精度从 K2.6 换成新模型 K3)。
- 后续演进:perf 覆盖拆到 #34985 单独跟踪,未来 K3 性能 nightly 会以本 PR 的精度门禁为前提合入。
- 风险标记:外部权重依赖(约 1.5 TB 下载), 长耗时 job(超时 300 分钟), CI 门禁对 lint 单词级敏感, 仅 MI35x 覆盖(gfx95x 限制), AITER 内核耦合
关联脉络
- PR #32548 AMD Day-0 tracking issue(Kimi-K3 MI355X 吞吐): PR body 与测试 docstring 反复引用其非投机部署配方,本测试的服务器参数完全对齐该 recipe。
- PR #34985 Kimi-K3 performance coverage 跟踪: 本 PR 将 K3 性能 nightly 拆出推迟到该 issue 单独跟踪,commit 4e61bbc 明确说明。
- PR #33832 NightlyBenchmarkRunner API 变更(推断): commit 4e61bbc 指出 perf 测试基于 #33832 之前的 API 编写导致 setUpClass 崩溃,是范围收缩的直接原因。
- PR #35168 docs: add NVFP4 quantization option to Kimi-K3 deploy panel: 同属 Kimi-K3 支持线,一个补部署文档与量化选项,一个补 ROCm 精度验证,共同完善 K3 在 AMD/Blackwell 上的发布矩阵。
参与讨论