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

567 lines
19 KiB
Python

from __future__ import annotations
import logging
import os
from contextlib import contextmanager
from enum import Enum, IntEnum
from typing import TYPE_CHECKING
import torch
from sglang.srt.environ import envs
from sglang.srt.layers.dp_attention import (
is_dp_attention_enabled,
)
from sglang.srt.runtime_context import get_flags, get_forward, get_parallel
from sglang.srt.utils import is_cuda, is_npu
_is_npu = is_npu()
if TYPE_CHECKING:
from sglang.srt.server_args import ServerArgs
from sglang.srt.runtime_context import get_server_args
logger = logging.getLogger(__name__)
class MoeA2ABackend(Enum):
NONE = "none"
DEEPEP = "deepep"
MOONCAKE = "mooncake"
NIXL = "nixl"
MORI = "mori"
ASCEND_FUSEEP = "ascend_fuseep"
FLASHINFER = "flashinfer"
MEGAMOE = "megamoe"
CUSTOMIZED = "customized"
@classmethod
def _missing_(cls, value):
if value is None:
return cls.NONE
for member in cls:
if value == member.value:
return member
raise ValueError(f"No {cls.__name__} member for value {value}")
def is_none(self):
return self == MoeA2ABackend.NONE
def is_deepep(self):
return self == MoeA2ABackend.DEEPEP
def is_mooncake(self):
return self == MoeA2ABackend.MOONCAKE
def is_nixl(self):
return self == MoeA2ABackend.NIXL
def is_flashinfer(self):
return self == MoeA2ABackend.FLASHINFER
def is_ascend_fuseep(self):
return self == MoeA2ABackend.ASCEND_FUSEEP
def is_mori(self):
return self == MoeA2ABackend.MORI
def is_megamoe(self):
return self == MoeA2ABackend.MEGAMOE
def is_customized(self):
return self == MoeA2ABackend.CUSTOMIZED
def supports_aiter(self) -> bool:
return self in (
MoeA2ABackend.NONE,
MoeA2ABackend.DEEPEP,
MoeA2ABackend.MOONCAKE,
MoeA2ABackend.NIXL,
MoeA2ABackend.MORI,
)
class MoeRunnerBackend(Enum):
AUTO = "auto"
DEEP_GEMM = "deep_gemm"
TRITON = "triton"
TRITON_KERNELS = "triton_kernel"
FLASHINFER_TRTLLM = "flashinfer_trtllm"
EXPERIMENTAL_SGL_TRTLLM = "experimental_sgl_trtllm"
FLASHINFER_TRTLLM_ROUTED = "flashinfer_trtllm_routed"
FLASHINFER_CUTLASS = "flashinfer_cutlass"
FLASHINFER_MXFP4 = "flashinfer_mxfp4"
FLASHINFER_CUTEDSL = "flashinfer_cutedsl"
CUTLASS = "cutlass"
MARLIN = "marlin"
AITER = "aiter"
def is_auto(self):
return self == MoeRunnerBackend.AUTO
def is_deep_gemm(self):
return self == MoeRunnerBackend.DEEP_GEMM
def is_triton(self):
return self == MoeRunnerBackend.TRITON
def is_triton_kernels(self):
return self == MoeRunnerBackend.TRITON_KERNELS
def is_flashinfer_trtllm(self):
# experimental_sgl_trtllm shares the TRT-LLM FP8 kernels + layout, so it inherits
# trtllm weight-prep here; divergent sites check is_experimental_sgl_trtllm() first.
return self in (
MoeRunnerBackend.FLASHINFER_TRTLLM,
MoeRunnerBackend.EXPERIMENTAL_SGL_TRTLLM,
)
def is_experimental_sgl_trtllm(self):
return self == MoeRunnerBackend.EXPERIMENTAL_SGL_TRTLLM
def is_flashinfer_trtllm_routed(self):
return self == MoeRunnerBackend.FLASHINFER_TRTLLM_ROUTED
def is_flashinfer_cutlass(self):
return self == MoeRunnerBackend.FLASHINFER_CUTLASS
def is_flashinfer_cutedsl(self):
return self == MoeRunnerBackend.FLASHINFER_CUTEDSL
def is_flashinfer_mxfp4(self):
return self == MoeRunnerBackend.FLASHINFER_MXFP4
def is_cutlass(self):
return self == MoeRunnerBackend.CUTLASS
def is_marlin(self):
return self == MoeRunnerBackend.MARLIN
def is_aiter(self):
return self == MoeRunnerBackend.AITER
class DeepEPMode(Enum):
NORMAL = "normal"
LOW_LATENCY = "low_latency"
AUTO = "auto"
def enable_normal(self) -> bool:
return self in [DeepEPMode.NORMAL, DeepEPMode.AUTO]
def enable_low_latency(self) -> bool:
return self in [DeepEPMode.LOW_LATENCY, DeepEPMode.AUTO]
def resolve(self, is_extend_in_batch: bool) -> DeepEPMode:
if self != DeepEPMode.AUTO:
return self
if is_extend_in_batch:
return DeepEPMode.NORMAL
else:
return DeepEPMode.LOW_LATENCY
def is_normal(self) -> bool:
return self == DeepEPMode.NORMAL
def is_low_latency(self) -> bool:
return self == DeepEPMode.LOW_LATENCY
def is_auto(self) -> bool:
return self == DeepEPMode.AUTO
class DeepEPOutputDtype(Enum):
"""
Describes the dispatch output data type for DeepEP.
- BF16: dispatch hidden states in bf16
- FP8: dispatch hidden states in fp8
- INT8: dispatch hidden states in int8
- NVFP4: dispatch hidden states in nvfp4
"""
BF16 = "bf16"
FP8 = "fp8"
INT8 = "int8"
NVFP4 = "nvfp4"
def get_deepep_output_dtype(self) -> DeepEPOutputDtype:
"""
Automatically choose the dispatch output dtype for DeepEP.
The decision follows several checks in priority order:
0. Parse server argument.
1. Parse deprecated environment variables.
2. If quant_config contains input_global_scale → NVFP4 path.
3. Parse quant config
4. If flashinfer_cutedsl or is_cutlass backend is active → BF16 (it quantizes hidden_states internally).
5. Otherwise default for NPU → BF16 (the default for NPU).
6. Otherwise → FP8 (the default for most models like DeepSeek-V3).
"""
# 0. Parse server argument.
server_args = get_server_args()
if server_args and server_args.deepep_dispatcher_output_dtype != "auto":
return DeepEPOutputDtype(server_args.deepep_dispatcher_output_dtype)
# 1. Parse deprecated environment variables.
if envs.SGLANG_DEEPEP_BF16_DISPATCH.get():
logger.warning_once(
"Warning: The env variable SGLANG_DEEPEP_BF16_DISPATCH deprecated "
"and will be removed in future releases. Please use a new "
"`--deepep-dispatcher-output-dtype bf16` argument instead."
)
return DeepEPOutputDtype.BF16
# 2. NVFP4 is detected inside dispatch_a / _dispatch_core via quant_config; no need to infer here.
if self.quant_config is not None:
input_global_scale = self.quant_config.get("input_global_scale", None)
if input_global_scale is not None:
return DeepEPOutputDtype.NVFP4
# 3. Parse quant config to determine the output dtype of dispatcher
dispatcher_output_dtype = self.quant_config.get("dispatcher_output_dtype", None)
if dispatcher_output_dtype is not None:
return DeepEPOutputDtype(dispatcher_output_dtype)
# 4. flashinfer_cutedsl and is_cutlass expects BF16 dispatch
if (
get_moe_runner_backend().is_flashinfer_cutedsl()
or get_moe_runner_backend().is_cutlass()
):
return DeepEPOutputDtype.BF16
# 5. Default on NPU → BF16
if _is_npu:
return DeepEPOutputDtype.BF16
# 6. Default → FP8
return DeepEPOutputDtype.FP8
def initialize_moe_config(server_args: ServerArgs):
moe = get_flags().moe
moe.a2a_backend = MoeA2ABackend(server_args.moe_a2a_backend)
moe.runner_backend = MoeRunnerBackend(server_args.moe_runner_backend)
moe.speculative_runner_backend = (
MoeRunnerBackend(server_args.speculative_moe_runner_backend)
if server_args.speculative_moe_runner_backend is not None
else moe.runner_backend
)
moe.speculative_a2a_backend = (
MoeA2ABackend(server_args.speculative_moe_a2a_backend)
if server_args.speculative_moe_a2a_backend is not None
else moe.a2a_backend
)
moe.deepep_mode = DeepEPMode(server_args.deepep_mode)
moe.deepep_config = server_args.deepep_config or ""
moe.tbo_enabled = server_args.enable_two_batch_overlap
moe.sbo_enabled = server_args.enable_single_batch_overlap
if moe.sbo_enabled and is_cuda():
if torch.cuda.get_device_capability()[0] == 9:
raise ValueError(
"SBO (single batch overlap) is not supported on SM90 GPUs with latest sgl-deep-gemm wheel. Please try removing --enable-single-batch-overlap argument."
)
moe.tbo_token_distribution_threshold = server_args.tbo_token_distribution_threshold
moe.disable_fp4_allgather = server_args.disable_flashinfer_cutlass_moe_fp4_allgather
moe.quantization = server_args.quantization
def get_moe_a2a_backend() -> MoeA2ABackend:
moe = get_flags().moe
if moe.a2a_backend is None:
moe.a2a_backend = MoeA2ABackend.NONE
return moe.a2a_backend
def get_moe_runner_backend() -> MoeRunnerBackend:
moe = get_flags().moe
if moe.runner_backend is None:
moe.runner_backend = MoeRunnerBackend.AUTO
return moe.runner_backend
def get_speculative_moe_runner_backend() -> MoeRunnerBackend:
moe = get_flags().moe
if moe.speculative_runner_backend is None:
logger.warning(
"SPECULATIVE_MOE_RUNNER_BACKEND is not initialized, using auto backend"
)
moe.speculative_runner_backend = MoeRunnerBackend.AUTO
return moe.speculative_runner_backend
def get_speculative_moe_a2a_backend() -> MoeA2ABackend:
moe = get_flags().moe
if moe.speculative_a2a_backend is None:
logger.warning(
"SPECULATIVE_MOE_A2A_BACKEND is not initialized, using none backend"
)
moe.speculative_a2a_backend = MoeA2ABackend.NONE
return moe.speculative_a2a_backend
def get_deepep_mode() -> DeepEPMode:
moe = get_flags().moe
if moe.deepep_mode is None:
logger.warning("DEEPEP_MODE is not initialized, using auto mode")
moe.deepep_mode = DeepEPMode.AUTO
return moe.deepep_mode
def get_deepep_config() -> str:
moe = get_flags().moe
if moe.deepep_config is None:
logger.warning("DEEPEP_CONFIG is not initialized, using default config")
moe.deepep_config = ""
return moe.deepep_config
def is_tbo_enabled() -> bool:
moe = get_flags().moe
if moe.tbo_enabled is None:
moe.tbo_enabled = False
return moe.tbo_enabled
def is_sbo_enabled() -> bool:
moe = get_flags().moe
if moe.sbo_enabled is None:
moe.sbo_enabled = False
return moe.sbo_enabled
def is_deepep_class_backend() -> bool:
"""Check if the MoE backend is DeepEP-family (DeepEP, Mooncake, or Mori)."""
b = get_moe_a2a_backend()
return b.is_deepep() or b.is_mooncake() or b.is_mori()
def uses_per_rank_fused_shared_slots() -> bool:
"""Check whether fused shared experts use per-rank physical slots."""
return is_deepep_class_backend() or get_moe_a2a_backend().is_megamoe()
def has_per_rank_fused_shared_slots(num_fused_shared_experts: int) -> bool:
"""Check whether this layer has fused shared experts in per-rank slots."""
return num_fused_shared_experts > 0 and uses_per_rank_fused_shared_slots()
def is_flashinfer_cutedsl_v1_path() -> bool:
"""CuteDSL v1 + DeepEP low-latency path (no MoeRunner, no autotune)."""
return (
get_moe_runner_backend().is_flashinfer_cutedsl()
and get_moe_a2a_backend().is_deepep()
)
def get_tbo_token_distribution_threshold() -> float:
moe = get_flags().moe
if moe.tbo_token_distribution_threshold is None:
logger.warning(
"TBO_TOKEN_DISTRIBUTION_THRESHOLD is not initialized, using 0.48"
)
moe.tbo_token_distribution_threshold = 0.48
return moe.tbo_token_distribution_threshold
def filter_moe_weight_param_global_expert(name, x, num_local_experts):
"""
Filter out for MoE expert parameters that requires global expert.
"""
return (
not getattr(x, "_sglang_require_global_experts", False)
and x.data.ndim > 0
and x.data.shape[0] == num_local_experts
)
def should_use_flashinfer_cutlass_moe_fp4_allgather():
"""
Perform FP4 quantize before all-gather for flashinfer cutlass moe to reduce communication cost for high-throughput serving.
"""
return (
not get_flags().moe.disable_fp4_allgather
and get_moe_a2a_backend().is_none()
and get_moe_runner_backend().is_flashinfer_cutlass()
and is_dp_attention_enabled()
and get_flags().moe.quantization == "modelopt_fp4"
and get_parallel().moe_ep_size == get_parallel().attn_dp_size
)
def should_use_dp_reduce_scatterv():
"""
Use reduce_scatterv in the standard dispatcher's combine() for DP attention
with EP, replacing the default all-reduce + dp_scatter path.
Only changes the combine (post-kernel) communication; dispatch is unchanged.
"""
return (
not should_use_flashinfer_cutlass_moe_fp4_allgather()
and get_moe_a2a_backend().is_none()
and is_dp_attention_enabled()
and get_parallel().attn_dp_size > 1
and get_parallel().moe_ep_size == get_parallel().attn_dp_size
)
def should_skip_mlp_all_reduce() -> bool:
"""Whether dense MLP / row-parallel projections should skip their all-reduce.
True when the decoder published ``fuse_mlp_allreduce`` (next residual+LN
absorbs the AR) or ``mlp_reduce_scatter`` (postprocess will reduce-scatter)
on ``get_forward()``.
"""
f = get_forward()
return f.fuse_mlp_allreduce or f.mlp_reduce_scatter
def should_skip_post_experts_all_reduce(*, is_tp_path: bool) -> bool:
"""Whether to skip the post-experts all-reduce (EP or TP) because a
downstream component will fuse, replace, or absorb it.
Skip reasons, in order:
- ``get_forward().fuse_mlp_allreduce``: LayerCommunicator will fuse the
all-reduce with the next layer's residual all-reduce.
- ``get_forward().mlp_reduce_scatter``: LayerCommunicator's post-attention
scatter will do reduce-scatter, which would double-reduce on top of
an all-reduce.
- ``should_use_dp_reduce_scatterv()``: the standard dispatcher's combine
path replaces the all-reduce with a reduce-scatterv.
- ``should_use_flashinfer_cutlass_moe_fp4_allgather()`` (TP path only):
the flashinfer cutlass FP4 kernel performs an all-gather that absorbs
the post-experts TP all-reduce. Not relevant to the EP all-reduce.
- ``get_moe_a2a_backend().is_flashinfer()``: the flashinfer A2A
dispatcher's ``MoeAlltoAll.combine`` already alltoall-reduces partial
MoE outputs back to the source rank, so any further EP/TP all-reduce
would double-count and overflow BF16. Mirrors TRTLLM's
``not enable_alltoall`` gate
(``tensorrt_llm/_torch/modules/fused_moe/interface.py:879``).
The first two reasons come from per-layer ``ForwardFlags`` published by
the decoder via ``get_forward().scoped(...)``. Pass ``is_tp_path=True``
for the post-experts TP all-reduce, ``False`` for the EP all-reduce.
"""
if should_skip_mlp_all_reduce():
return True
if should_use_dp_reduce_scatterv():
return True
if is_tp_path and should_use_flashinfer_cutlass_moe_fp4_allgather():
return True
if get_moe_a2a_backend().is_flashinfer():
return True
return False
@contextmanager
def speculative_moe_backend_context():
"""
Context manager to temporarily use the speculative MoE backend for draft model operations.
This ensures that draft models in speculative decoding use the configured speculative backend.
"""
moe = get_flags().moe
original_backend = moe.runner_backend
try:
moe.runner_backend = get_speculative_moe_runner_backend()
yield
finally:
moe.runner_backend = original_backend
@contextmanager
def speculative_moe_a2a_backend_context():
"""
Context manager to temporarily use the speculative MoE A2A backend for draft model operations.
This ensures that draft models in speculative decoding use the configured speculative A2A backend.
"""
moe = get_flags().moe
original_backend = moe.a2a_backend
original_disable_fp4_allgather = moe.disable_fp4_allgather
try:
moe.a2a_backend = get_speculative_moe_a2a_backend()
# Disable FP4 allgather for spec decode since MTP layers are unquantized
moe.disable_fp4_allgather = True
yield
finally:
moe.a2a_backend = original_backend
moe.disable_fp4_allgather = original_disable_fp4_allgather
# The type of method in top-K routing, for use in torch custom op
# Please keep this in sync with the counterpart defined in https://github.com/flashinfer-ai/flashinfer/blob/main/include/flashinfer/trtllm/fused_moe/runner.h
class RoutingMethodType(IntEnum):
# Default: Softmax -> TopK
Default = (0,)
# Renormalize: TopK -> Softmax
Renormalize = (1,)
# DeepSeekV3: Sigmoid -> RoutingBiasAdd -> Top2 in group -> Top4 groups -> Top8 experts from the Top4 groups
DeepSeekV3 = (2,)
# Llama4: Top1 -> Sigmoid
Llama4 = (3,)
# Qwen3: Softmax -> TopK -> Renormalize
RenormalizeNaive = (4,)
# TopK only (no softmax)
TopK = (5,)
# SigmoidRenorm: Sigmoid -> TopK -> Renormalize
SigmoidRenorm = (6,)
# MiniMax2
MiniMax2 = (7,)
# Sigmoid: Sigmoid -> TopK (no renormalize)
Sigmoid = (8,)
# Unspecified
Unspecified = 9
AITER_PADDING_SIZE = 128
TRITON_PADDING_SIZE = 128
# Unit of padding - context dependent
def get_moe_padding_size(is_aiter_moe):
if is_aiter_moe:
return AITER_PADDING_SIZE
else:
return (
TRITON_PADDING_SIZE
if bool(int(os.getenv("SGLANG_MOE_PADDING", "0")))
else 0
)
def get_moe_weight_sizes(inter_dim, is_concat, is_packed, is_aiter_moe):
"""
Calculate dimensions for MoE weight tensors.
Args:
inter_dim: Base intermediate dimension.
is_concat: If True, fusions W1 (gate) and W3 (up) projections.
is_packed: If True, uses 4-bit quantization (two FP4 elements per byte).
is_aiter_moe: If True, applies Aiter-specific kernel padding alignment.
"""
# w2_down_dim is the packing rank, but w13_up_dim not (of matrix to matmul)
w13_up_dim = 2 * inter_dim if is_concat else inter_dim
w2_down_dim = inter_dim // 2 if is_packed else inter_dim
if is_aiter_moe:
padding_size = get_moe_padding_size(True)
align_aiter = lambda n: ((n + padding_size - 1) // padding_size) * padding_size
is_padded = (w2_down_dim % padding_size) > 0
if is_padded:
# w2_down_dim, padding & aligned, unit: parameter dtype
w2_down_dim = align_aiter(w2_down_dim)
# up proj + gate fusion : 2x
if is_concat:
w13_up_dim = w2_down_dim * 2
# packed
if hasattr(torch, "float4_e2m1fn_x2") and is_packed:
# w13_up_dim (row rank of matmul matrix) is not packing dim, *2 to recover
w13_up_dim *= 2
return (w13_up_dim, w2_down_dim, False if not is_aiter_moe else is_padded)