Prhub

#26382 Enable Kimi-K2.5 piecewise CUDA graph

原始 PR 作者 BBuf 合并时间 2026-05-28 13:51 文件变更 2 提交数 2 评论 7 代码增减 +14 / -0

执行摘要

为 Kimi-K2.5 启用分段 CUDA Graph

Kimi-K2.5 多模态包装器中的语言模型存储在 language_model 属性下,而分段 CUDA Graph 设置检查通用的 .model 包装路径,导致 CUDA Graph 无法启用,预填充性能下降。

值得精读,尤其是分段 CUDA Graph 启用模式的通用设计(model 属性别名 + __setattr__ 保护)。这是个典型的性能优化与框架限制博弈的案例。

讨论亮点
  1. __setattr__ vs property setter 的权衡:gemini-code-assist[bot] 指出覆盖 nn.Module__setattr__ 有风险,建议改用 @model.setter 空实现。作者最终保留了 __setattr__ 方案,并在 PR body 中说明已验证 @model.setter 仍会导致 state dict 重复注册,因此 __setattr__ 是刻意的。
  2. 注释精简:Oasis-Git 建议缩短 __setattr__ 的注释,作者已采纳。
  3. max_token_num 下限:gemini-code-assist[bot] 建议使用 max(x.shape[0], 2048) 避免频繁 workspace 重分配,已被采纳。

实现拆解

  1. kimi_k25.py 中添加 model 属性别名:在 KimiK25ForConditionalGeneration 类中定义 @property model,返回 self.language_model,使分段 CUDA Graph 设置能够识别该包装器为语言模型。
  2. 自定义 __setattr__ 忽略重复赋值:重写 __setattr__ 方法,当属性名为 model 时直接返回,阻止 ModelRunner 在分段 CUDA Graph 设置中注册重复的 nn.Module 别名,避免 state dict / 加载路径污染。
  3. layernorm.py 中传递 max_token_num:在 _forward_with_allreduce_fusion 函数中调用 flashinfer_allreduce_residual_rmsnorm 时,传入 max_token_num=max(x.shape[0], 2048),避免因批次大小波动导致昂贵的 workspace 重分配。
文件 模块 状态 重要度
python/sglang/srt/models/kimi_k25.py 模型定义 modified 7.24
python/sglang/srt/layers/layernorm.py 归一化层 modified 4.75

关键符号

KimiK25ForConditionalGeneration.model KimiK25ForConditionalGeneration.__setattr__ _forward_with_allreduce_fusion

关键源码片段

python/sglang/srt/models/kimi_k25.py data-contract

核心变更文件:添加 `model` 属性别名和 `__setattr__` 方法以启用分段 CUDA Graph。

# python/sglang/srt/models/kimi_k25.py
# ... 在 __init__ 方法之后添加以下代码@property
def model(self):
    """ 为分段 CUDA Graph 设置提供 .model 别名,
    使其能够将此类识别为语言模型。 """
    return self.language_modeldef __setattr__(self, name, value):
    # 跳过 runner 中对 self.model.model 的重复赋值,
    # 以避免重复注册 nn.Module 导致 state dict 键重复。
    if name == "model":
        return
    super().__setattr__(name, value)
python/sglang/srt/layers/layernorm.py core-logic

传递 `max_token_num` 参数以优化 FlashInfer 融合 allreduce 和 RMSNorm 的性能。

# python/sglang/srt/layers/layernorm.py
# 在 _forward_with_allreduce_fusion 函数的 fused_result 调用处# ... 其他条件分支 ...
else:
    fused_result = flashinfer_allreduce_residual_rmsnorm(
        input_tensor=x,
        residual=residual,
        weight=weight,
        eps=norm_module.variance_epsilon,
        max_token_num=max(x.shape[0], 2048), # 避免因批次大小波动导致 workspace 频繁重分配
        use_attn_tp_group=use_attn_tp_group,
    )
    if fused_result[0] is not None:
        return fused_result
# ...

评论区精华

覆盖 `__setattr__` 的风险与替代方案 设计

gemini-code-assist[bot] 指出覆盖 `nn.Module.__setattr__` 有风险,建议改用 `@model.setter` 空实现。作者验证 `@model.setter` 仍会导致 state dict 重复,故保留 `__setattr__`。

结论:保留 `__setattr__` 方案,因为 `@model.setter` 无法阻止 state dict 重复注册。 · 已解决

`max_token_num` 参数添加 性能

gemini-code-assist[bot] 建议使用 `max(x.shape[0], 2048)` 避免 workspace 频繁重分配导致的性能抖动。该建议被采纳。

结论:采用 `max_token_num=max(x.shape[0], 2048)`。 · 已解决

注释精简建议 style

Oasis-Git 建议缩短 `__setattr__` 的注释,作者回复“OK.”并已修改。

结论:注释被精简为更简洁的版本。 · 已解决

风险与影响

  1. __setattr__ 的副作用风险:覆盖 nn.Module.__setattr__ 可能干扰参数/缓冲区注册(尽管已针对 model 属性做了处理)。但作者已通过测试验证不影响 state dict。
  2. max_token_num 影响:增加 2048 下限可能略微增加内存占用,但避免 workspace 频繁重分配带来的性能抖动。

性能提升显著:TTFT 均值降低约 69%(从 0.479s 到 0.147s),TPOT 略有上升(12.5ms 到 17.7ms),但整体 E2E 延迟从 0.722s 降至 0.488s。影响范围限于 Kimi-K2.5 模型用户。

核心路径变更 缺少测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论