执行摘要
- 一句话:合并 tokenizer 测试、删冗余 e2e,H100 CI 减时约 13 分钟
- 推荐动作:值得精读 PR body 的覆盖等价性论证与 test_int8_linear_methods.py 的实现模式:真实层 + weight_loader_v2 + 手写 dequant oracle,这种"e2e 冗余 → 层 UT 下沉"的方法对后续量化/后端测试设计有借鉴价值。建议关注合并后 base-b/base-c 套件的稳定性,并考虑为 triton/flashinfer 的端到端精度阈值补充轻量替代或文档说明。
功能与动机
PR body 明确指出目标:'Trims on the per-commit H100 suites (base-b 1-gpu ~ -548s, base-c 4-gpu -220s), replacing redundant e2e matrices with existing or new layer-level coverage'。作者逐条论证了各被删用例的覆盖等价性:detokenizer 的 ttft 测试与 tokenizer 仅差一个 flag;triton attention 数值已由 attention/unittests 覆盖;gpt-oss bf16 与 mxfp4 版本字节级相同;MLA per-backend 数值已由 attention/unittests/mla 覆盖。此外删除了本就 skipIf(is_in_ci()) 的 block-int8 死代码,把量化轴回归信号下沉到新的层 UT。
实现拆解
- 合并分词器测试:test/registered/tokenizer/test_multi_tokenizer.py 的
setUpClass 追加 --detokenizer-worker-num 4,与原有 --tokenizer-worker-num 8 并跑;删除 test_multi_detokenizer.py。两个 flag 正交,单次 server 启动即可同时覆盖两条 worker 池路径,节省约 211s,MMLU 阈值与 ttft/ITL 断言保持不变。
- 删除 triton attention e2e:test_triton_attention_backend.py 整体删除;mmlu 端到端精度断言由 attention/unittests/{dense,swa,gdn}/test_triton.py 的数值测试替代,offline throughput > 153 断言由 perf/test_bench_serving_1gpu_part1.py::test_offline_throughput_with_triton_attention_backend 承担,节省约 177s。
- 删除 gpt-oss bf16 双胞胎:test_gpt_oss_4gpu_bf16.py 与 mxfp4 版本仅
quantization="bf16" 不同;保留 mxfp4 的 h100/b200 e2e 及 test_mxfp4_sm90_cutlass.py 层 UT,bf16 upcast 路径改为人工 triage 时使用,节省约 220s。
- MLA e2e 收敛 + INT8 单测补位:删除 test_flashmla.py 与 test_mla_flashinfer.py(per-backend MLA 数值已由 attention/unittests/mla/test_{flashmla,flashinfer}.py 覆盖);test_mla_int8_deepseek_v3.py 保留为 channel-int8 + MTP 默认后端 smoke 并移除 skipIf(is_in_ci()) 的
TestDeepseekV3MTPBlockInt8 死代码;新增 test_int8_linear_methods.py,通过真实 ColumnParallelLinear + weight_loader_v2 加载手写量化权重,对比反量化参考矩阵,覆盖 W8A8Int8LinearMethod 与 BlockInt8LinearMethod 两种方法,约 +60s。
- CI 配套:新 UT 注册 stage base-b、1-gpu-large、est_time 60s;pr-test-extra 曾失败一次(Run #30990840598),作者 rerun 三个关键测试后通过,确认新矩阵在 H100 上稳定。
关键文件:
test/registered/unit/layers/quantization/test_int8_linear_methods.py(模块 量化单测;类别 test;类型 test-coverage;符号 _quantize_int8_channel, _quantize_int8_block, _Int8LinearCheck, _check): 本次唯一新写入的测试资产,用真实 ColumnParallelLinear + weight_loader_v2 覆盖 channel W8A8 与 blockwise int8 两种量化方法,并替代了原先在 CI 中被 skip 的 block-int8 死代码。
test/registered/mla/test_flashmla.py(模块 注意力测试;类别 test;类型 deletion;符号 TestFlashMLAMTP, setUpClass, tearDownClass, test_gsm8k): 删除的 FlashMLA + EAGLE MTP e2e,作者认为其 per-backend 数值已由 attention/unittests/mla/test_flashmla.py 覆盖,节省约 160s。
test/registered/mla/test_mla_flashinfer.py(模块 注意力测试;类别 test;类型 deletion;符号 TestFlashinferMLAMTP, test_gsm8k): 删除的 FlashInfer MLA + EAGLE MTP e2e,与 flashmla 版本同为 per-backend 数值覆盖,由 attention/unittests/mla/test_flashinfer.py 承接。
test/registered/tokenizer/test_multi_detokenizer.py(模块 分词器测试;类别 test;类型 deletion;符号 TestMultiDetokenizer, setUpClass, tearDownClass, test_multi_detokenizer_ttft): 删除;其 ttft 测试与 test_multi_tokenizer.py 仅差 --detokenizer-worker-num 参数,合并后由同一 server 覆盖,节省约 211s。
test/registered/attention/test_triton_attention_backend.py(模块 注意力测试;类别 test;类型 deletion;符号 TestTritonAttnBackend, test_latency, test_mmlu): 删除的 triton attention e2e;数值由 attention/unittests 承接,吞吐断言由 perf 套件承接,节省约 177s。
test/registered/mla/test_mla_int8_deepseek_v3.py(模块 量化冒烟;类别 test;类型 test-coverage;符号 TestDeepseekV3MTPChannelInt8, TestDeepseekV3MTPBlockInt8, test_gsm8k): 修改;删除 skipIf(is_in_ci()) 的 TestDeepseekV3MTPBlockInt8 死代码,保留 channel-int8 + MTP 默认后端 smoke,作为 MLA e2e 收敛后的唯一服务级回归。
test/registered/models_e2e/test_gpt_oss_4gpu_bf16.py(模块 多卡测试;类别 test;类型 deletion;符号 TestGptOss4GpuBf16, test_bf16_120b): 删除的 gpt-oss 120b bf16 4-GPU e2e;与 mxfp4 版本字节级相同,保留原生格式覆盖,节省约 220s。
test/registered/tokenizer/test_multi_tokenizer.py(模块 分词器测试;类别 test;类型 test-coverage;符号 TestMultiTokenizer, setUpClass): 修改;合并多 detokenizer 覆盖,server 启动同时带两个 worker flag。
关键符号:_quantize_int8_channel, _quantize_int8_block, _Int8LinearCheck._check, TestW8A8Int8Linear.test_channel, TestBlockInt8Linear.test_block, TestMultiTokenizer.setUpClass, TestDeepseekV3MTPChannelInt8.test_gsm8k, TestGptOss4GpuBf16.test_bf16_120b, TestFlashMLAMTP.test_gsm8k, TestFlashinferMLAMTP.test_gsm8k
关键源码片段
test/registered/unit/layers/quantization/test_int8_linear_methods.py
本次唯一新写入的测试资产,用真实 ColumnParallelLinear + weight_loader_v2 覆盖 channel W8A8 与 blockwise int8 两种量化方法,并替代了原先在 CI 中被 skip 的 block-int8 死代码。
# 量化辅助函数:把随机浮点权重转为 checkpoint 格式的 int8 + scale,
# 同时返回反量化参考矩阵,作为后续数值校验的 oracle。
def _quantize_int8_channel(w: torch.Tensor):
# per-output-channel 对称量化,scale 形状为 [N, 1]
amax = w.float().abs().amax(dim=1, keepdim=True).clamp(min=1e-12)
scale = amax / INT8_MAX
w_int8 = torch.round(w.float() / scale).clamp(-INT8_MAX, INT8_MAX).to(torch.int8)
w_dequant = w_int8.float() * scale
return w_int8, scale, w_dequant
def _quantize_int8_block(w: torch.Tensor, block: int = 128):
# per (128, 128) tile 对称量化,scale 形状为 [N / block, K / block]
n, k = w.shape
tiles = w.float().reshape(n // block, block, k // block, block)
amax = tiles.abs().amax(dim=(1, 3)).clamp(min=1e-12)
scale = amax / INT8_MAX
w_int8 = (
torch.round(tiles / scale[:, None, :, None])
.clamp(-INT8_MAX, INT8_MAX)
.to(torch.int8)
)
w_dequant = (w_int8.float() * scale[:, None, :, None]).reshape(n, k)
return w_int8.reshape(n, k), scale, w_dequant
class _Int8LinearCheck(CustomTestCase):
@classmethod
def setUpClass(cls):
# 初始化单进程分布式环境,供真实层加载使用
init_single_process_dist()
def _check(self, shapes, build_layer):
torch.manual_seed(7)
for m, n, k in shapes:
with self.subTest(shape=(m, n, k)):
# 走真实 ColumnParallelLinear + weight_loader_v2 路径,
# 而不是直接调用 kernel,以覆盖权重加载与量化方法装配。
layer, w_dequant = build_layer(n, k)
layer.quant_method.process_weights_after_loading(layer)
x = torch.randn((m, k), device="cuda", dtype=torch.bfloat16) / 10
out, _ = layer(x)
ref = x.float() @ w_dequant.T
# atol 吸收动态 per-token activation 量化引入的误差
assert_output_close(self, out, ref, rtol=5e-2, atol=1e-1)
@unittest.skipIf(
get_device_sm() >= 100, "sgl-kernel int8_scaled_mm has no SM100+ kernel"
)
class TestW8A8Int8Linear(_Int8LinearCheck):
@staticmethod
def _build_layer(n: int, k: int):
layer = make_tp1_column_parallel_linear(W8A8Int8Config({}), n, k)
w = torch.randn((n, k), device="cuda", dtype=torch.bfloat16) / 10
w_int8, scale, w_dequant = _quantize_int8_channel(w)
load_linear_weights(layer, weight=w_int8, weight_scale=scale)
return layer, w_dequant
def test_channel(self):
self._check(CHANNEL_SHAPES, self._build_layer)
评论区精华
本 PR 没有产生实质 review 评论,核心论证都在 PR body 中:
triton attention numerics are covered by attention/unittests/{dense,swa,gdn}/test_triton.py on the same runner... the offline-throughput assertion is covered by perf/test_bench_serving_1gpu_part1.py::test_offline_throughput_with_triton_attention_backend
test_gpt_oss_4gpu_bf16.py ... byte-identical to test_gpt_oss_4gpu_mxfp4.py except quantization="bf16"
Drop TestDeepseekV3MTPBlockInt8 from test_mla_int8_deepseek_v3.py: it was already skipIf(is_in_ci()) dead code
唯一的交互是作者发起的 /rerun-test,bot 返回:"🚀 1-gpu-h100 (3 tests): ✅"。未解决的疑虑:triton e2e 中 mmlu > 0.65 的端到端精度断言没有在 PR 内展开讨论是否有直接替代。
- 覆盖等价性论证:e2e 冗余如何下沉到 layer 级测试 (design): 作者认为等价覆盖成立,合并后无需保留这些 e2e;未收到 reviewer 反对意见。
- 合并后新矩阵的 rerun 验证 (testing): bot 返回 1-gpu-h100 三个测试全部通过,新矩阵在 H100 上稳定。
风险与影响
- 风险:覆盖缺口:triton e2e 中 mmlu > 0.65 的端到端精度断言没有明确替代(perf 套件只验吞吐);flashinfer + EAGLE 组合的
avg_spec_accept_length > 2.5 断言消失,组合级回归可能延迟暴露;gpt-oss bf16 upcast 路径失去 CI 覆盖,只能手动 triage。新 UT 局限:test_int8_linear_methods.py 在 SM100+ 上整体 skip(sgl-kernel int8_scaled_mm 无 SM100+ kernel),Blackwell 后续架构缺少 INT8 GEMM 数值回归;断言较宽松(rtol=5e-2、atol=1e-1),对 kernel 系统性偏差的敏感度有限。本 PR 无运行时源码改动,因此不引入生产代码回归风险。
- 影响:用户无感知,不涉及任何 sglang 运行时/API 变更。团队侧:base-b 1-gpu 套件减时约 548s(约 9 分钟)、base-c 4-gpu 减时约 220s(约 3.7 分钟),tokenizer 测试的 server 启动次数从 2 次降为 1 次。新增 INT8 层 UT(约 60s)为 channel/block int8 提供快速回归信号,替代原先在 CI 中被 skip 的死代码。影响范围主要限于 test/ 目录下的 CI 注册与测试资产。
- 风险标记:e2e 精度断言下沉后无直接替代, flashinfer+EAGLE 组合覆盖移除, SM100+ 跳过 INT8 单测, bf16 upcast 路径无 CI 覆盖, 纯测试改动、无运行时风险
关联脉络
- PR #33615 [Test] Route GEMM backend UTs through real layer modules and weight loaders: 本 PR 新增的 test_int8_linear_methods.py 完全沿用其"真实层 + 权重加载器 + oracle 对比"模式(make_tp1_column_parallel_linear、load_linear_weights、assert_output_close、test_fp8_blockwise_linear_backends.py),是同一测试基础设施演进线的下一环。
- PR #33619 [CI] Speed up dependency install: dual-ABI Rust ext cache and prevalidation pruning: 与本 PR 同属"削减 H100 per-commit CI 耗时"系列(head_ref lsyin/trim-h100-ci),一个优化依赖安装,一个裁剪测试矩阵。
- PR #33654 [CI] Move CPU-only unit tests to the CPU suite and trim dead 5090 registrations: 同为 CI 测试资产瘦身与注册整理,与本 PR 在 ci_register 套件调整上同脉络。
参与讨论