Prhub

#25892 Fix/dsv4 flash eagle dummy ima

原始 PR 作者 mattteochen 合并时间 2026-05-21 06:41 文件变更 1 提交数 4 评论 7 代码增减 +18 / -0

执行摘要

为 dummy 权重初始化 hash topk 整数查找表

Issue #25767 报告了 sglang serve 使用 --load-format dummy 启动 DeepSeek-V4-Flash 时,在 CUDA graph capture 阶段出现 illegal memory access(IMA)。根本原因是 DummyModelLoader 只初始化浮点张量,而 HashTopK.tid2eid 是 int32 类型的查找表,未被填充,包含随机值导致越界。PR body 进一步说明:"Initialize HashTopK.tid2eid with a deterministic valid default mapping when the layer is constructed."

值得精读,特别是需要理解自定义初始化器与 checkpoint 加载顺序交互的场景。该 PR 展示了如何巧妙地在 dummy 模式下保障整数张量有效性的设计模式。

讨论亮点

Gemini code-assist bot 建议将中间张量(token_idsexpert_offsets)的 dtype 直接设为 self.tid2eid.dtype(int32)而非默认的 int64,以减少内存开销并消除最后的类型转换。该建议已被采纳(最终提交中已使用 dtype=self.tid2eid.dtype)。审核者 Fridge003 批准了该 PR。

实现拆解

  1. HashTopK.__init__self.tid2eid 创建后立即调用新增的 _init_default_tid2eid() 方法(hash_topk.py:44),确保构造后即包含有效数据。
  2. _init_default_tid2eid() 函数内部首先处理 topk==0 的边界情况直接返回。
  3. 生成形状为 (vocab_size, topk) 的 token ID 索引矩阵和 expert 偏移矩阵,通过 (token_ids + expert_offsets) % num_experts 计算一个周期性的合法 expert ID 映射,并在 torch.no_grad() 上下文中原地 copy_self.tid2eid
  4. 后续正常加载真实 checkpoint 时,权重仍会覆盖 tid2eid,因此不影响正常推理路径。
  5. 无配套测试、配置或部署变更。
文件 模块 状态 重要度
python/sglang/srt/layers/moe/hash_topk.py MoE modified 6.74

关键符号

HashTopK.__init__ HashTopK._init_default_tid2eid

关键源码片段

python/sglang/srt/layers/moe/hash_topk.py core-logic

唯一修改的文件,在 HashTopK 类中新增 `_init_default_tid2eid()` 方法,针对 dummy 加载初始化整数查找表 `tid2eid`。

def _init_default_tid2eid(self) -> None:
    topk = self.tid2eid.shape[1]
    if topk == 0:
        return
​
    # DummyModelLoader only initializes floating tensors, so keep this int
    # lookup table valid until real checkpoints overwrite it.
    token_ids = torch.arange(
        self.tid2eid.shape[0], dtype=self.tid2eid.dtype, device=self.tid2eid.device
    ).unsqueeze(1) # shape: (vocab_size, 1)
    expert_offsets = torch.arange(
        topk, dtype=self.tid2eid.dtype, device=self.tid2eid.device
    ).unsqueeze(0) # shape: (1, topk)
    # Cyclic mapping: expert_id = (token_id + offset) % num_experts
    tid2eid = (token_ids + expert_offsets) % self.num_experts
    with torch.no_grad():
        self.tid2eid.copy_(tid2eid.to(self.tid2eid.dtype))

评论区精华

中间张量 dtype 优化 性能

Gemini code-assist bot 建议将中间张量 `token_ids`, `expert_offsets` 的 dtype 设为 int32(与 `tid2eid` 一致),避免默认 int64 的内存浪费和类型转换。

结论:已采纳,最终代码使用 `dtype=self.tid2eid.dtype`。 · 已解决

风险与影响

  1. 仅影响 dummy 加载路径,正常加载 checkpoint 时 tid2eid 会被覆盖,无回归风险。
  2. 新增方法 _init_default_tid2eid 仅在 __init__ 中调用一次,影响极小。
  3. 边界情况 topk==0 已处理,不会触发除零或索引错误。
  1. 直接修复 DeepSeek-V4-Flash 在 dummy 权重模式下的启动崩溃(CUDA IMA),使开发测试和快速验证可用。
  2. 对其他模型或加载方式无影响(因真实 checkpoint 会覆盖默认值)。
  3. 代码量小(+18行),无外部依赖变更。

关联 Issue

#25767 [Bug] DSV4-Flash fails with dummy weights

完整报告

参与讨论