Prhub

#25391 Support DeepSeek V4 DeepEP Waterfill

原始 PR 作者 xutizhou 合并时间 2026-05-26 12:04 文件变更 4 提交数 1 评论 10 代码增减 +58 / -16

执行摘要

DeepSeek V4 整合 DeepEP Waterfill 负载均衡

DeepEP Waterfill 通过将共享专家负载均衡到最空闲的 EP rank 上,可以减少通信瓶颈并提升吞吐。DeepSeek V4 原有的 shared-expert fusion 因 clamp 差异被禁用,但 Waterfill 需要保持 fusion 以利用共享专家分发。为此需要适配 DeepSeek V4 的 HashTopK 路由逻辑和 expert distribution 记录。

值得精读。本 PR 展示了如何将 DeepEP Waterfill 负载均衡集成到 DeepSeek V4 的 HashTopK 路由中,设计上保持了 shared-expert fusion 并扩展了 balancer 接口,对其他 MoE 模型的类似集成有参考价值。

讨论亮点
  • try-except 简化 (ch-wan 提问, xutizhou 建议): ch-wan 质疑 HashTopK 中是否需要 try-except,xutizhou 建议直接使用 num_fused_shared_experts > 0 and get_global_server_args().enable_deepep_waterfill 简化逻辑,最终采纳该方案。
  • 整数除法安全性 (gemini-code-assist[bot] 建议): 在 topk.py_remap_topk_for_deepep 中,将 n_routed_experts // ep_size 改为 num_physical_routed_experts // ep_size,但未添加整除断言;reviewer 建议添加断言以确保安全。

实现拆解

  1. HashTopK 增加 Waterfill 支持 (python/sglang/srt/layers/moe/hash_topk.py): 在 __init__ 中根据 num_fused_shared_experts > 0enable_deepep_waterfill 标志设置 enable_deepep_waterfill,并保留 balancer 属性;在 forwardempty_topk_output 末尾调用 _apply_deepep_waterfill 方法,通过 DeepEPWaterfillBalancer.expand_topk 将共享专家追加到 topk 输出中。
  2. DeepSeek V4 保留 shared-expert fusion (python/sglang/srt/models/deepseek_v4.py): 在 determine_num_fused_shared_experts 中,当 enable_deepep_waterfill 为 True 且 n_shared_experts==1 时,不禁用 fusion,而是保留 num_fused_shared_experts = 1,使 shared expert 可通过路由参与 Waterfill 均衡。
  3. ModelRunner 准备 HashTopK 的 Waterfill (python/sglang/srt/model_executor/model_runner.py): 在 _prepare_moe_topk 中新增对 HashTopK 实例的识别,统一提取 routed_scaling_factor(从 module.routed_scaling_factormodule.topk_config.routed_scaling_factor),并创建 DeepEPWaterfillBalancer 分配给模块。
  4. TopK 简化 Waterfill 判定 (python/sglang/srt/layers/moe/topk.py): 移除不必要的 try-except,直接使用 num_fused_shared_experts > 0 and get_global_server_args().enable_deepep_waterfill 设置标志。
文件 模块 状态 重要度
python/sglang/srt/layers/moe/hash_topk.py MoE 路由 modified 7.12
python/sglang/srt/models/deepseek_v4.py DeepSeek V4 modified 6.73
python/sglang/srt/model_executor/model_runner.py 模型运行 modified 6.46
python/sglang/srt/layers/moe/topk.py MoE 路由 modified 6.21

关键符号

_apply_deepep_waterfill determine_num_fused_shared_experts _prepare_moe_topk

关键源码片段

python/sglang/srt/layers/moe/hash_topk.py dependency-wiring

核心修改:新增 Waterfill 支持,包括初始化、_apply_deepep_waterfill 方法,以及 forward/empty_topk_output 的出口扩展。

# python/sglang/srt/layers/moe/hash_topk.py
# 在 __init__ 中根据配置开启 Waterfill 模式
class HashTopK(nn.Module):
    def __init__(self, topk, num_experts, num_fused_shared_experts, vocab_size, ...):
        super().__init__()
        self.layer_id = None
        from sglang.srt.server_args import get_global_server_args
​
        # 仅当存在 fused shared expert 且全局 waterfill 启用时生效
        self.enable_deepep_waterfill = (
            num_fused_shared_experts > 0
            and get_global_server_args().enable_deepep_waterfill
        )
        self.deepep_waterfill_balancer = None
​
        if self.enable_deepep_waterfill:
            # Waterfill 将 shared expert 作为额外路由专家,因此从 topk 中扣除
            topk -= num_fused_shared_experts
            num_fused_shared_experts = 0
        # ... 其余初始化
​
    # 在 empty_topk_output 和 forward 末尾调用此方法
    def _apply_deepep_waterfill(
        self, topk_output: StandardTopKOutput, num_tokens: int
    ) -> StandardTopKOutput:
        # 若启用但未在 ModelRunner 中准备 balancer,则报错
        if self.enable_deepep_waterfill and self.deepep_waterfill_balancer is None:
            raise RuntimeError(
                "DeepEP waterfill HashTopK must be prepared by ModelRunner before forward."
            )
        if self.deepep_waterfill_balancer is None:
            return topk_output
        # 通过 balancer 将 shared expert 追加到 topk 输出中
        return self.deepep_waterfill_balancer.expand_topk(topk_output, num_tokens)
python/sglang/srt/models/deepseek_v4.py data-contract

决策关键:在 determine_num_fused_shared_experts 中为 Waterfill 保留 shared-expert fusion,打破原有限制。

# python/sglang/srt/models/deepseek_v4.py
# 在 determine_num_fused_shared_experts 中增加 Waterfill 分支
    def determine_num_fused_shared_experts(self):
        self.num_fused_shared_experts = 0
        if get_global_server_args().disable_shared_experts_fusion:
            return
​
        # Waterfill 需要 shared-expert fusion 以将 shared expert 分发给空闲 EP
        if get_global_server_args().enable_deepep_waterfill:
            if self.config.n_shared_experts != 1:
                raise ValueError(
                    "DeepEP Waterfill for DeepSeek V4 expects exactly one shared "
                    f"expert, but got n_shared_experts={self.config.n_shared_experts}."
                )
            # 保留 fusion,设置 num_fused_shared_experts 为 1
            self.num_fused_shared_experts = self.config.n_shared_experts
            log_info_on_rank0(logger,
                "DeepSeek V4: --enable-deepep-waterfill set; KEEP shared-experts "
                "fusion enabled so waterfill can rebalance shared expert dispatch.")
            return
​
        # 默认行为:V4 因 clamp 差异禁用 fusion
        get_global_server_args().disable_shared_experts_fusion = True
        log_info_on_rank0(logger, "Shared experts fusion optimization is disabled.")

评论区精华

HashTopK 中 try-except 的简化 设计

ch-wan 质疑为什么需要 try-except 包裹 get_global_server_args(),xutizhou 建议直接使用 if-else 条件赋值。

结论:简化为 `self.enable_deepep_waterfill = (num_fused_shared_experts > 0 and get_global_server_args().enable_deepep_waterfill)`,移除了 try-except。 · 已解决

整数除法安全性与断言 正确性

gemini-code-assist[bot] 指出 `num_physical_routed_experts // ep_size` 可能不能整除,建议添加断言。

结论:已改为使用 `num_physical_routed_experts` 计算,但未添加断言;讨论未进一步处理。 · unresolved

风险与影响

  1. 异常路径风险: 若 n_shared_experts != 1 但启用了 waterfill,DeepSeek V4 会抛出 ValueError(已处理),但用户可能未预期此行为。
  2. 整数整除风险: 在 topk.py 的 _remap_topk_for_deepep 中,num_physical_routed_experts // ep_size 假设整除,当 redundant experts 导致不能整除时可能产生错误;review 建议添加断言但未落实。
  3. 性能影响: Waterfill 增加一次 balancer 调用(expand_topk),但吞吐测试显示正向收益 2-4%,风险可控。

-用户影响: 仅影响使用 --enable-deepep-waterfill 的 DeepSeek V4 用户,提供 2-4% 吞吐提升,正确性经过 MMLU 验证(分数一致)。

  • 系统影响: 修改 MoE 路由核心路径(HashTopK 和 TopK),需确保其他模型(如 DeepSeek V3、Qwen 等)不受影响,因为 enable_deepep_waterfill 仅在新参数下生效。
  • 团队协作: 依赖两个 bugfix PR(#25285, #25367),需依次合并。
核心 MoE 路由变更 缺少兼容性测试 整数整除假设

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论