Prhub

#20736 [AMD] Enable share expert fusion with router experts for Qwen3.5 BF16 & FP8

sgl-project/sglang · 作者 zhentaocc · 合并时间 2026-04-15 09:52

分析状态 已生成
文件变更 2提交数 42 · 评论 18
代码增减 +218 / -8
amd feature performance run-ci moe

执行摘要

为 AMD 平台 Qwen3.5 MoE 模型启用共享专家融合,减少内核启动以提升推理效率。

PR body指出:Qwen2 MoE和Qwen3.5 MoE模型使用共享专家,当shared_expert_intermediate_size == moe_intermediate_size时,可将共享专家与路由专家融合(topk+1),从而减少内核启动次数并提升推理效率。

推荐工程师精读can_fuse_shared_expert条件判断和权重映射逻辑,理解AMD特定优化路径;关注FP8兼容性为待办事项,可参考讨论中的技术权衡。

讨论亮点
  • 变量名一致性:yichiche评论“Is there a specific reason for changing the name from router_logits to gate_logits? If not, we should keep it as is to avoid unnecessary changes.”,强调保持代码一致性以避免混淆。
  • 日志清理:yichiche多次指出“We should remove this logging code from the production environment.”,要求移除调试日志以提升代码整洁性。
  • DeepEP兼容性:yichiche建议“Add or get_moe_a2a_backend().is_deepep() to check if deepep is enable.”,防止融合逻辑与DeepEP后端冲突,已整合到can_fuse_shared_expert中。
  • 权重映射细节:yichiche询问“You may also need fused_expert_params_mapping here?”,zhentaocc解释共享专家通过现有逻辑映射,无需额外条目。
  • FP8问题与后续工作:zhentaocc提到“FP8 accuracy issue identified, will need aiter upgrade to fix split_k issue.”,指出当前PR限BF16,FP8支持需后续PR解决,并计划扩展共享gate融合。

实现拆解

  1. 环境检测与条件判断:在python/sglang/srt/models/qwen2_moe.py中添加can_fuse_shared_expert函数,检查服务器参数(--disable-shared-experts-fusion)、配置属性(shared_expert_intermediate_size)和后端兼容性(DeepEP),确保融合仅在HIP平台且SGLANG_USE_AITER=1时启用。
  2. 专家计数与初始化扩展Qwen2MoeSparseMoeBlock初始化时新增support_shared_expert_fusion参数,计算num_fused_shared_experts,并更新top_knum_experts以包含共享专家,影响后续MoE调度。
  3. 路由逻辑增强_forward_router_experts方法中,在top-k选择后调用_append_shared_to_topk_output将共享专家ID和权重追加到输出,实现单次调度中的融合前向。
  4. 权重加载适配:在python/sglang/srt/models/qwen3_5.py中,Qwen3_5MoeForConditionalGeneration.load_weights方法使用_get_num_fused_shared_experts获取融合专家数,调整expert_params_mappingfused_expert_params_mapping,将共享专家权重(如mlp.shared_expert.*)重映射到路由专家布局。
  5. 测试与配置配套:PR body包含准确性测试(GSM8K)和基准测试结果,但未直接修改测试文件;作者提及FP8精度问题需aiter升级,当前仅限BF16,后续PR将补全。
文件 模块 状态 重要度
python/sglang/srt/models/qwen2_moe.py 模型层 modified 8.36
python/sglang/srt/models/qwen3_5.py 模型层 modified 7.62
python/sglang/srt/models/qwen2_moe.py core-logic

核心实现文件,新增共享专家融合判断函数并扩展 MoE 块逻辑,直接影响路由调度和专家计数。

def can_fuse_shared_expert(
    config: PretrainedConfig,
) -> bool:
    """共享专家是否可作为额外MoE专家融合(Qwen3.5 + Aiter)。    调用方仍需基于`support_shared_expert_fusion`和`_use_aiter`门控。
    """
    if (
        get_global_server_args().disable_shared_experts_fusion is True # 服务器参数禁用融合
        or getattr(config, "shared_expert_intermediate_size", 0) <= 0 # 配置未定义共享专家尺寸
        or config.shared_expert_intermediate_size != config.moe_intermediate_size # 尺寸不匹配
        or get_moe_a2a_backend().is_deepep() # 后端为DeepEP时不兼容
    ):
        return False
    return True
​
​
def _append_shared_to_topk_output(
    self,
    topk_output: StandardTopKOutput,
    shared_expert_weights: torch.Tensor,
) -> StandardTopKOutput:
    """将共享专家追加到top-k输出,用于融合调度。    共享专家ID设为`self.num_experts`(即基础专家数),权重来自sigmoid(gate)。
    """
    shared_expert_ids = torch.full_like(
        topk_output.indices[:, :1],
        self.num_experts,
        device=topk_output.indices.device,
    )
    # 扩展indices和weights以包含共享专家
    new_indices = torch.cat([topk_output.indices, shared_expert_ids], dim=-1)
    new_weights = torch.cat([topk_output.weights, shared_expert_weights], dim=-1)
    return StandardTopKOutput(new_indices, new_weights)
python/sglang/srt/models/qwen3_5.py data-contract

权重加载适配文件,添加方法获取融合专家数量并更新映射逻辑,确保模型正确加载融合共享专家权重。

def _get_num_fused_shared_experts(self):
    """获取融合共享专家的数量,用于权重加载时调整专家计数。    通过检查首层MLP的`num_fused_shared_experts`属性实现;若未启用则返回0。
    """
    if not (
        hasattr(self.model, "layers")
        and len(self.model.layers) > 0
        and hasattr(self.model.layers[0].mlp, "num_fused_shared_experts")
    ):
        return 0
    return self.model.layers[0].mlp.num_fused_shared_experts
​
​
def load_weights(self, weights: Iterable[Tuple[str, torch.Tensor]]):
    """加载权重,适配融合共享专家布局。    当启用融合时,`num_experts`增加`num_fused_shared_experts`,并将共享专家权重映射到路由专家索引。
    """
    num_experts_base = self.config.num_experts
    num_fused_shared_experts = self._get_num_fused_shared_experts()
    num_experts = num_experts_base + num_fused_shared_experts # 调整总专家数
​
    # 构建专家参数映射,包含基础专家和融合共享专家
    expert_params_mapping = FusedMoE.make_expert_params_mapping(
        ckpt_gate_proj_name="gate_proj",
        ckpt_down_proj_name="down_proj",
        ckpt_up_proj_name="up_proj",
        num_experts=num_experts, # 使用调整后的专家数
    )
​
    # 处理共享专家权重重映射
    if self.enable_shared_expert_fusion:
        for name, loaded_weight in weights:
            if f"mlp.shared_expert.gate_up_proj" in name:
                # 将共享专家gate_up_proj拆分为gate和up,加载到对应专家索引
                loaded_weight = loaded_weight.chunk(2, dim=-2)
                weight_loader(param, loaded_weight[0], name_mapped, "w1", num_experts_base)
                weight_loader(param, loaded_weight[1], name_mapped, "w3", num_experts_base)
            elif f"mlp.shared_expert.down_proj" in name:
                weight_loader(param, loaded_weight, name_mapped, "w2", num_experts_base)

关键符号

can_fuse_shared_expert _get_shared_expert_weights _append_shared_to_topk_output _get_num_fused_shared_experts

评论区精华

变量名一致性与日志清理 style

yichiche 建议保持 router_logits 变量名而非改为 gate_logits,并多次指出应移除生产环境中的调试日志代码。

结论:作者可能已调整变量名,日志代码在后续提交中被移除,强调代码整洁性和一致性。 · 已解决

DeepEP 后端兼容性检查 正确性

yichiche 评论需添加 get_moe_a2a_backend().is_deepep() 检查,以防止融合逻辑与 DeepEP 后端冲突导致 self.shared_expert 被覆盖。

结论:检查已整合到 can_fuse_shared_expert 函数中,确保在 DeepEP 启用时禁用融合。 · 已解决

权重映射逻辑适配 设计

yichiche 询问 fused_expert_params_mapping 是否必要以处理共享专家融合,zhentaocc 解释共享专家通过现有权重加载逻辑映射,无需额外条目。

结论:权重加载已适配,共享专家权重被重映射到路由专家布局,设计决策基于现有架构扩展。 · 已解决

FP8 精度问题与后续工作 正确性

zhentaocc 指出 FP8 存在准确性问题,需 aiter 升级解决 split_k 问题,当前 PR 限 BF16;yichiche 确认问题并提及后续协作。

结论:FP8 支持被识别为待办事项,作者计划后续 PR 解决,不影响当前 BF16 功能。 · pending

风险与影响

  • 回归风险:融合条件依赖SGLANG_USE_AITER环境变量和HIP后端,若配置不当或平台不支持,可能导致MoE层行为异常或性能退化;权重加载改动涉及共享专家重映射,错误处理可能引发模型加载失败。
  • 性能风险:融合逻辑增加初始化复杂度,但在启用时减少内核启动,实测吞吐量提升;未启用时对性能无影响。
  • 兼容性风险:对FP8/MXFP4量化支持不完整,作者提及精度问题,需后续aiter升级,可能影响量化模型用户。
  • 安全风险:无直接安全漏洞,但新代码分支需验证边界条件,防止配置错误导致服务中断。
  • 用户影响:AMD ROCm用户通过设置SGLANG_USE_AITER=1可自动启用融合,获得约5%吞吐量提升(基准测试显示BF16下输出token吞吐量从767.82 tok/s增至802.79 tok/s),且准确性测试显示精度变化可忽略(GSM8K exact_match差异<0.003)。
  • 系统影响:优化MoE层调度,减少GPU内核启动次数,提升整体推理效率;权重加载逻辑扩展支持融合布局,增强模型兼容性。
  • 团队影响:需跟进FP8支持和共享gate融合等后续工作,可能推动AMD平台优化和MoE模块演进。
条件依赖环境变量 FP8 支持不完整 权重加载复杂化

关联 Issue

未识别关联 Issue

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

完整报告

执行摘要

  • 一句话:为AMD平台Qwen3.5 MoE模型启用共享专家融合,减少内核启动以提升推理效率。
  • 推荐动作:推荐工程师精读can_fuse_shared_expert条件判断和权重映射逻辑,理解AMD特定优化路径;关注FP8兼容性为待办事项,可参考讨论中的技术权衡。

功能与动机

PR body指出:Qwen2 MoE和Qwen3.5 MoE模型使用共享专家,当shared_expert_intermediate_size == moe_intermediate_size时,可将共享专家与路由专家融合(topk+1),从而减少内核启动次数并提升推理效率。

实现拆解

  1. 环境检测与条件判断:在python/sglang/srt/models/qwen2_moe.py中添加can_fuse_shared_expert函数,检查服务器参数(--disable-shared-experts-fusion)、配置属性(shared_expert_intermediate_size)和后端兼容性(DeepEP),确保融合仅在HIP平台且SGLANG_USE_AITER=1时启用。
  2. 专家计数与初始化扩展Qwen2MoeSparseMoeBlock初始化时新增support_shared_expert_fusion参数,计算num_fused_shared_experts,并更新top_knum_experts以包含共享专家,影响后续MoE调度。
  3. 路由逻辑增强_forward_router_experts方法中,在top-k选择后调用_append_shared_to_topk_output将共享专家ID和权重追加到输出,实现单次调度中的融合前向。
  4. 权重加载适配:在python/sglang/srt/models/qwen3_5.py中,Qwen3_5MoeForConditionalGeneration.load_weights方法使用_get_num_fused_shared_experts获取融合专家数,调整expert_params_mappingfused_expert_params_mapping,将共享专家权重(如mlp.shared_expert.*)重映射到路由专家布局。
  5. 测试与配置配套:PR body包含准确性测试(GSM8K)和基准测试结果,但未直接修改测试文件;作者提及FP8精度问题需aiter升级,当前仅限BF16,后续PR将补全。

关键文件:

  • python/sglang/srt/models/qwen2_moe.py(模块 模型层;类别 source;类型 core-logic;符号 can_fuse_shared_expert, _get_shared_expert_weights, _append_shared_to_topk_output): 核心实现文件,新增共享专家融合判断函数并扩展MoE块逻辑,直接影响路由调度和专家计数。
  • python/sglang/srt/models/qwen3_5.py(模块 模型层;类别 source;类型 data-contract;符号 _get_num_fused_shared_experts): 权重加载适配文件,添加方法获取融合专家数量并更新映射逻辑,确保模型正确加载融合共享专家权重。

关键符号:can_fuse_shared_expert, _get_shared_expert_weights, _append_shared_to_topk_output, _get_num_fused_shared_experts

关键源码片段

python/sglang/srt/models/qwen2_moe.py

核心实现文件,新增共享专家融合判断函数并扩展MoE块逻辑,直接影响路由调度和专家计数。

def can_fuse_shared_expert(
    config: PretrainedConfig,
) -> bool:
    """共享专家是否可作为额外MoE专家融合(Qwen3.5 + Aiter)。    调用方仍需基于`support_shared_expert_fusion`和`_use_aiter`门控。
    """
    if (
        get_global_server_args().disable_shared_experts_fusion is True # 服务器参数禁用融合
        or getattr(config, "shared_expert_intermediate_size", 0) <= 0 # 配置未定义共享专家尺寸
        or config.shared_expert_intermediate_size != config.moe_intermediate_size # 尺寸不匹配
        or get_moe_a2a_backend().is_deepep() # 后端为DeepEP时不兼容
    ):
        return False
    return True
​
​
def _append_shared_to_topk_output(
    self,
    topk_output: StandardTopKOutput,
    shared_expert_weights: torch.Tensor,
) -> StandardTopKOutput:
    """将共享专家追加到top-k输出,用于融合调度。    共享专家ID设为`self.num_experts`(即基础专家数),权重来自sigmoid(gate)。
    """
    shared_expert_ids = torch.full_like(
        topk_output.indices[:, :1],
        self.num_experts,
        device=topk_output.indices.device,
    )
    # 扩展indices和weights以包含共享专家
    new_indices = torch.cat([topk_output.indices, shared_expert_ids], dim=-1)
    new_weights = torch.cat([topk_output.weights, shared_expert_weights], dim=-1)
    return StandardTopKOutput(new_indices, new_weights)

python/sglang/srt/models/qwen3_5.py

权重加载适配文件,添加方法获取融合专家数量并更新映射逻辑,确保模型正确加载融合共享专家权重。

def _get_num_fused_shared_experts(self):
    """获取融合共享专家的数量,用于权重加载时调整专家计数。    通过检查首层MLP的`num_fused_shared_experts`属性实现;若未启用则返回0。
    """
    if not (
        hasattr(self.model, "layers")
        and len(self.model.layers) > 0
        and hasattr(self.model.layers[0].mlp, "num_fused_shared_experts")
    ):
        return 0
    return self.model.layers[0].mlp.num_fused_shared_experts
​
​
def load_weights(self, weights: Iterable[Tuple[str, torch.Tensor]]):
    """加载权重,适配融合共享专家布局。    当启用融合时,`num_experts`增加`num_fused_shared_experts`,并将共享专家权重映射到路由专家索引。
    """
    num_experts_base = self.config.num_experts
    num_fused_shared_experts = self._get_num_fused_shared_experts()
    num_experts = num_experts_base + num_fused_shared_experts # 调整总专家数
​
    # 构建专家参数映射,包含基础专家和融合共享专家
    expert_params_mapping = FusedMoE.make_expert_params_mapping(
        ckpt_gate_proj_name="gate_proj",
        ckpt_down_proj_name="down_proj",
        ckpt_up_proj_name="up_proj",
        num_experts=num_experts, # 使用调整后的专家数
    )
​
    # 处理共享专家权重重映射
    if self.enable_shared_expert_fusion:
        for name, loaded_weight in weights:
            if f"mlp.shared_expert.gate_up_proj" in name:
                # 将共享专家gate_up_proj拆分为gate和up,加载到对应专家索引
                loaded_weight = loaded_weight.chunk(2, dim=-2)
                weight_loader(param, loaded_weight[0], name_mapped, "w1", num_experts_base)
                weight_loader(param, loaded_weight[1], name_mapped, "w3", num_experts_base)
            elif f"mlp.shared_expert.down_proj" in name:
                weight_loader(param, loaded_weight, name_mapped, "w2", num_experts_base)

评论区精华

  • 变量名一致性:yichiche评论“Is there a specific reason for changing the name from router_logits to gate_logits? If not, we should keep it as is to avoid unnecessary changes.”,强调保持代码一致性以避免混淆。
  • 日志清理:yichiche多次指出“We should remove this logging code from the production environment.”,要求移除调试日志以提升代码整洁性。
  • DeepEP兼容性:yichiche建议“Add or get_moe_a2a_backend().is_deepep() to check if deepep is enable.”,防止融合逻辑与DeepEP后端冲突,已整合到can_fuse_shared_expert中。
  • 权重映射细节:yichiche询问“You may also need fused_expert_params_mapping here?”,zhentaocc解释共享专家通过现有逻辑映射,无需额外条目。
  • FP8问题与后续工作:zhentaocc提到“FP8 accuracy issue identified, will need aiter upgrade to fix split_k issue.”,指出当前PR限BF16,FP8支持需后续PR解决,并计划扩展共享gate融合。

  • 变量名一致性与日志清理 (style): 作者可能已调整变量名,日志代码在后续提交中被移除,强调代码整洁性和一致性。

  • DeepEP后端兼容性检查 (correctness): 检查已整合到can_fuse_shared_expert函数中,确保在DeepEP启用时禁用融合。
  • 权重映射逻辑适配 (design): 权重加载已适配,共享专家权重被重映射到路由专家布局,设计决策基于现有架构扩展。
  • FP8精度问题与后续工作 (correctness): FP8支持被识别为待办事项,作者计划后续PR解决,不影响当前BF16功能。

风险与影响

  • 风险:- 回归风险:融合条件依赖SGLANG_USE_AITER环境变量和HIP后端,若配置不当或平台不支持,可能导致MoE层行为异常或性能退化;权重加载改动涉及共享专家重映射,错误处理可能引发模型加载失败。
  • 性能风险:融合逻辑增加初始化复杂度,但在启用时减少内核启动,实测吞吐量提升;未启用时对性能无影响。
  • 兼容性风险:对FP8/MXFP4量化支持不完整,作者提及精度问题,需后续aiter升级,可能影响量化模型用户。
  • 安全风险:无直接安全漏洞,但新代码分支需验证边界条件,防止配置错误导致服务中断。
  • 影响:- 用户影响:AMD ROCm用户通过设置SGLANG_USE_AITER=1可自动启用融合,获得约5%吞吐量提升(基准测试显示BF16下输出token吞吐量从767.82 tok/s增至802.79 tok/s),且准确性测试显示精度变化可忽略(GSM8K exact_match差异<0.003)。
  • 系统影响:优化MoE层调度,减少GPU内核启动次数,提升整体推理效率;权重加载逻辑扩展支持融合布局,增强模型兼容性。
  • 团队影响:需跟进FP8支持和共享gate融合等后续工作,可能推动AMD平台优化和MoE模块演进。
  • 风险标记:条件依赖环境变量, FP8支持不完整, 权重加载复杂化

关联脉络

  • PR #21773 [AMD][CI] Add GLM-5-MXFP4 accuracy and perf nightly tests for MI35x: 同为AMD平台相关PR,涉及CI测试扩展,可辅助理解AMD环境验证背景。
  • PR #22606 [serving] replace O(n²) stream_buffer string concat with integer offset: 同为性能优化PR,共享减少计算开销的目标,可对比学习性能改进策略。
  • PR #21232 [sgl] perf optimization for eplb: 涉及算法性能优化,与本PR的MoE层效率提升主题相关,反映团队持续性能优化趋势。

参与讨论