Files
wehub-resource-sync 94057c3d3e
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:38:16 +08:00

365 lines
12 KiB
Python

# Copyright 2023-2024 SGLang Team
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Mega-MoE forward path and expert-weight prep shared by Deepseek V2/V4."""
from __future__ import annotations
import os
from contextlib import nullcontext
from typing import TYPE_CHECKING, Optional
import torch
from sglang.jit_kernel.dsv4 import mega_moe_pre_dispatch
from sglang.srt.environ import envs
from sglang.srt.eplb.expert_location_dispatch import ExpertLocationDispatchInfo
from sglang.srt.layers.dp_attention import get_dp_global_num_tokens
from sglang.srt.layers.moe.utils import get_moe_a2a_backend
from sglang.srt.model_executor.runner import get_is_capture_mode
if TYPE_CHECKING:
from deep_gemm import SymmBuffer
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
from sglang.srt.models.deepseek_v2 import DeepseekV2MoE
_MEGA_MOE_SYMM_BUFFER: dict = {}
_MEGA_MOE_DG_ENV_APPLIED = False
def _apply_mega_moe_dg_env() -> None:
"""Forward sglang's FP4/MXF4 opt-in flags to DeepGEMM via env vars.
DeepGEMM reads `DG_USE_FP4_ACTS` (and `DG_USE_MXF4_KIND`) at host-function
call time — both `get_symm_buffer_for_mega_moe` and `fp8_fp4_mega_moe`.
Forwarding once at first use is sufficient (these are static config
flags, not per-request state) and matches the `setdefault` pattern so
explicit `DG_USE_*` overrides from outside still win.
"""
global _MEGA_MOE_DG_ENV_APPLIED
if _MEGA_MOE_DG_ENV_APPLIED:
return
if envs.SGLANG_OPT_DEEPGEMM_MEGA_MOE_USE_FP4_ACTS.get():
os.environ.setdefault("DG_USE_FP4_ACTS", "1")
if envs.SGLANG_OPT_DEEPGEMM_MEGA_MOE_USE_MXF4_KIND.get():
os.environ.setdefault("DG_USE_MXF4_KIND", "1")
_MEGA_MOE_DG_ENV_APPLIED = True
def _get_mega_moe_symm_buffer(
group,
num_experts: int,
num_max_tokens_per_rank: int,
num_topk: int,
hidden: int,
intermediate_hidden: int,
) -> SymmBuffer:
import deep_gemm
_apply_mega_moe_dg_env()
key = (
id(group),
num_max_tokens_per_rank,
num_experts,
num_topk,
hidden,
intermediate_hidden,
)
buf = _MEGA_MOE_SYMM_BUFFER.get(key)
if buf is None:
buf = deep_gemm.get_symm_buffer_for_mega_moe(
group,
num_experts,
num_max_tokens_per_rank,
num_topk,
hidden,
intermediate_hidden,
use_fp8_dispatch=True,
activation="swiglu",
)
_MEGA_MOE_SYMM_BUFFER[key] = buf
return buf
def should_use_mega_moe(moe: DeepseekV2MoE, hidden_states: torch.Tensor) -> bool:
if not get_moe_a2a_backend().is_megamoe():
return False
if not getattr(moe.experts, "_mega_moe_weights_built", False):
return False
if get_is_capture_mode():
return True
global_num_tokens = get_dp_global_num_tokens()
if global_num_tokens:
max_tokens_per_rank = max(global_num_tokens)
else:
max_tokens_per_rank = hidden_states.shape[0]
cap = envs.SGLANG_OPT_DEEPGEMM_MEGA_MOE_NUM_MAX_TOKENS_PER_RANK.get()
return max_tokens_per_rank <= cap
def forward_mega_moe(
moe: DeepseekV2MoE,
hidden_states: torch.Tensor,
forward_batch: Optional[ForwardBatch] = None,
input_ids_global: Optional[torch.Tensor] = None,
) -> torch.Tensor:
num_tokens = hidden_states.shape[0]
sbo_overlap_flag = (
moe.alt_stream is not None
and moe.num_fused_shared_experts == 0
and num_tokens > 0
and get_is_capture_mode()
)
if sbo_overlap_flag:
current_stream = torch.cuda.current_stream()
moe.alt_stream.wait_stream(current_stream)
shared_output = moe._forward_shared_experts(hidden_states)
mega_stream_ctx = torch.cuda.stream(moe.alt_stream)
else:
shared_output = moe._forward_shared_experts(hidden_states)
mega_stream_ctx = nullcontext()
with mega_stream_ctx:
y = _run_mega_routed(
moe, hidden_states, forward_batch, input_ids_global, num_tokens
)
if sbo_overlap_flag:
current_stream.wait_stream(moe.alt_stream)
if shared_output is not None:
y.add_(shared_output)
return y
def _run_mega_routed(
moe: DeepseekV2MoE,
hidden_states: torch.Tensor,
forward_batch: Optional[ForwardBatch],
input_ids_global: Optional[torch.Tensor],
num_tokens: int,
) -> torch.Tensor:
import deep_gemm
from sglang.srt.distributed.parallel_state import get_moe_ep_group
hidden_size = moe.config.hidden_size
if num_tokens > 0:
router_logits = moe.gate(hidden_states, forward_batch=forward_batch)
topk_kwargs = {"input_ids": input_ids_global} if moe.is_hash else {}
topk_output = moe.topk(
hidden_states,
router_logits,
num_token_non_padded=(
forward_batch.num_token_non_padded
if forward_batch is not None
else None
),
expert_location_dispatch_info=ExpertLocationDispatchInfo.init_new(
layer_id=moe.layer_id,
),
**topk_kwargs,
)
topk_ids = topk_output.topk_ids
topk_weights = topk_output.topk_weights
else:
topk_ids = None
topk_weights = None
ep_group = get_moe_ep_group().device_group
num_experts = moe.experts.num_experts
top_k = moe.config.num_experts_per_tok + moe.num_fused_shared_experts
intermediate_size = moe.config.moe_intermediate_size
num_max_tokens_per_rank = (
envs.SGLANG_OPT_DEEPGEMM_MEGA_MOE_NUM_MAX_TOKENS_PER_RANK.get()
)
assert num_tokens <= num_max_tokens_per_rank, (
f"mega MoE: num_tokens={num_tokens} exceeds cap "
f"SGLANG_OPT_DEEPGEMM_MEGA_MOE_NUM_MAX_TOKENS_PER_RANK="
f"{num_max_tokens_per_rank}; raise the env var or shrink "
f"cuda_graph_max_bs / chunked_prefill_size accordingly"
)
buf = _get_mega_moe_symm_buffer(
ep_group,
num_experts=num_experts,
num_max_tokens_per_rank=num_max_tokens_per_rank,
num_topk=top_k,
hidden=hidden_size,
intermediate_hidden=intermediate_size,
)
if num_tokens > 0:
topk_ids_in = topk_ids.to(torch.int32)
topk_weights_in = topk_weights.to(torch.float32)
else:
topk_ids_in = hidden_states.new_empty((0, top_k), dtype=torch.int32)
topk_weights_in = hidden_states.new_empty((0, top_k), dtype=torch.float32)
use_fp4_acts = envs.SGLANG_OPT_DEEPGEMM_MEGA_MOE_USE_FP4_ACTS.get()
if use_fp4_acts:
# FP4 path goes through DeepGEMM's mega_moe_pre_dispatch which
# handles the E2M1 packing variant. The jit implementation
# only emits FP8.
deep_gemm.mega_moe_pre_dispatch(
hidden_states,
topk_ids_in,
topk_weights_in,
buf.x,
buf.x_sf,
buf.topk_idx,
buf.topk_weights,
num_tokens=num_tokens,
group_size=32,
use_fp4_acts=True,
)
else:
mega_moe_pre_dispatch(
hidden_states,
topk_ids_in,
topk_weights_in,
buf.x,
buf.x_sf,
buf.topk_idx,
buf.topk_weights,
quant_group_size=32,
)
# Allocate at least one row so y has a non-null CUDA data_ptr;
# the DeepGEMM tvm-ffi binding rejects nullptr in convert_to_torch_tensor().
y = torch.empty(
(max(num_tokens, 1), hidden_size),
dtype=torch.bfloat16,
device=hidden_states.device,
)
swiglu_limit = getattr(moe.config, "swiglu_limit", None)
deep_gemm.fp8_fp4_mega_moe(
y,
moe.experts.mega_l1_weights,
moe.experts.mega_l2_weights,
buf,
recipe=(1, 1, 32),
activation="swiglu",
activation_clamp=swiglu_limit,
fast_math=True,
)
y = y[:num_tokens]
if not moe.experts.should_fuse_routed_scaling_factor_in_topk:
y.mul_(moe.routed_scaling_factor)
return y
def _interleave_mega_moe_gate_up(t: torch.Tensor, gran: int = 8) -> torch.Tensor:
# Match DeepGEMM's L1 gate/up layout:
# [gate: 0..7, up: 0..7, gate: 8..15, up: 8..15, ...].
num_groups, n, *rest = t.shape
half = n // 2
gate = t[:, :half].reshape(num_groups, half // gran, gran, *rest)
up = t[:, half:].reshape(num_groups, half // gran, gran, *rest)
result = torch.stack([gate, up], dim=2).reshape(num_groups, n, *rest)
return torch.empty_like(t).copy_(result)
def _interleave_mega_moe_l1_weights(
l1_weights: tuple[torch.Tensor, torch.Tensor],
) -> tuple[torch.Tensor, torch.Tensor]:
return (
_interleave_mega_moe_gate_up(l1_weights[0]),
_interleave_mega_moe_gate_up(l1_weights[1]),
)
def _transpose_mega_moe_sf_for_utccp(sf: torch.Tensor) -> torch.Tensor:
num_groups, mn, packed_sf_k = sf.shape
assert sf.dtype == torch.int and mn % 128 == 0
result = (
sf.reshape(num_groups, -1, 4, 32, packed_sf_k)
.transpose(2, 3)
.reshape(num_groups, mn, packed_sf_k)
)
return torch.empty_like(sf).copy_(result)
def build_mega_moe_experts_weights(experts) -> None:
from deep_gemm import (
transform_sf_into_required_layout,
transform_weights_for_mega_moe,
)
if getattr(experts, "_mega_moe_weights_built", False):
return
w13 = experts.w13_weight.data
w13_sf_fp32 = experts.w13_weight_scale_inv.data
w2 = experts.w2_weight.data
w2_sf_fp32 = experts.w2_weight_scale_inv.data
num_groups, n1, half_k1 = w13.shape
k1 = half_k1 * 2
_, n2, half_k2 = w2.shape
k2 = half_k2 * 2
w13_sf = transform_sf_into_required_layout(
w13_sf_fp32,
mn=n1,
k=k1,
recipe=(1, 32),
num_groups=num_groups,
disable_ue8m0_cast=False,
)
w2_sf = transform_sf_into_required_layout(
w2_sf_fp32,
mn=n2,
k=k2,
recipe=(1, 32),
num_groups=num_groups,
disable_ue8m0_cast=False,
)
if envs.SGLANG_OPT_FIX_MEGA_MOE_MEMORY.get():
# Build the interleaved L1 weight + scale once; share the weight buffer
# between `w13_weight.data` (normal deep-ep path) and `mega_l1_weights[0]`
# (mega moe path). Mega moe additionally needs a UTCCP-transposed scale;
# the deep-ep path consumes the non-transposed interleaved scale and a
# swizzle-aware activation kernel. L2 weight is untouched by the mega
# transform, so the existing `w2_weight.data` is shared directly.
w13_interleaved, w13_sf_interleaved = _interleave_mega_moe_l1_weights(
(w13, w13_sf)
)
w13_sf_utccp = _transpose_mega_moe_sf_for_utccp(w13_sf_interleaved)
w2_sf_utccp = _transpose_mega_moe_sf_for_utccp(w2_sf)
experts.w13_weight.data = w13_interleaved
experts.w13_weight_scale_inv.data = w13_sf_interleaved
experts.w2_weight_scale_inv.data = w2_sf
experts.w13_weight_scale_inv.format_ue8m0 = True
experts.w2_weight_scale_inv.format_ue8m0 = True
experts.mega_l1_weights = (experts.w13_weight.data, w13_sf_utccp)
experts.mega_l2_weights = (experts.w2_weight.data, w2_sf_utccp)
else:
l1_pair, l2_pair = transform_weights_for_mega_moe((w13, w13_sf), (w2, w2_sf))
experts.mega_l1_weights = l1_pair
experts.mega_l2_weights = l2_pair
experts._mega_moe_weights_built = True