Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 11 additions & 19 deletions python/sglang/srt/layers/moe/moe_runner/flashinfer_trtllm.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
per_token_group_quant_fp8,
scaled_fp8_quant,
)
from sglang.srt.layers.utils import copy_or_rebind_param
from sglang.srt.utils.common import (
is_cuda_alike,
is_flashinfer_available,
Expand Down Expand Up @@ -151,34 +152,25 @@ def align_fp4_moe_weights_for_flashinfer_trtllm(layer: Module) -> None:
)

# Set flashinfer parameters
layer.gemm1_weights_fp4_shuffled = Parameter(
gemm1_weights_fp4_shuffled, requires_grad=False
copy_or_rebind_param(
layer, "gemm1_weights_fp4_shuffled", gemm1_weights_fp4_shuffled
)
layer.gemm2_weights_fp4_shuffled = Parameter(
gemm2_weights_fp4_shuffled, requires_grad=False
)
layer.gemm1_scales_fp4_shuffled = Parameter(
gemm1_scales_fp4_shuffled, requires_grad=False
)
layer.gemm2_scales_fp4_shuffled = Parameter(
gemm2_scales_fp4_shuffled, requires_grad=False
copy_or_rebind_param(
layer, "gemm2_weights_fp4_shuffled", gemm2_weights_fp4_shuffled
)
copy_or_rebind_param(layer, "gemm1_scales_fp4_shuffled", gemm1_scales_fp4_shuffled)
copy_or_rebind_param(layer, "gemm2_scales_fp4_shuffled", gemm2_scales_fp4_shuffled)

# Compute additional scaling factor needed for TRT-LLM
w2_input_scale_quant = cast(torch.Tensor, layer.w2_input_scale_quant)
g1_alphas = cast(torch.Tensor, layer.g1_alphas)
layer.g1_scale_c = Parameter(
copy_or_rebind_param(
layer,
"g1_scale_c",
(w2_input_scale_quant * g1_alphas).to(torch.float32),
requires_grad=False,
)

# Clean up weights that won't be used by TRT-LLM
del (
layer.w2_weight,
layer.w2_weight_scale,
layer.w13_weight,
layer.w13_weight_scale,
)
# Keep original weights/scales to support update_weights_from_disk.
Comment thread
b8zhong marked this conversation as resolved.
Outdated


@dataclass
Expand Down
122 changes: 72 additions & 50 deletions python/sglang/srt/layers/quantization/modelopt_quant.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
swizzle_blockscale,
)
from sglang.srt.layers.radix_attention import RadixAttention
from sglang.srt.layers.utils import copy_or_rebind_param
from sglang.srt.utils.common import (
get_bool_env_var,
is_cuda,
Expand Down Expand Up @@ -1180,13 +1181,13 @@ def create_weights(
def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
input_scale_2 = layer.input_scale.max().to(torch.float32)
weight_scale_2 = layer.weight_scale_2.max().to(torch.float32)
layer.input_scale = Parameter(input_scale_2, requires_grad=False)
layer.weight_scale_2 = Parameter(weight_scale_2, requires_grad=False)
layer.alpha = Parameter(
layer.input_scale * layer.weight_scale_2, requires_grad=False

# Keep per-shard scales intact for hot reload; derive scalar params below.
copy_or_rebind_param(
layer, "alpha", (input_scale_2 * weight_scale_2).to(torch.float32)
)
layer.input_scale_inv = Parameter(
(1 / input_scale_2).to(torch.float32), requires_grad=False
copy_or_rebind_param(
layer, "input_scale_inv", (1 / input_scale_2).to(torch.float32)
)

# Store original output size before any padding
Expand Down Expand Up @@ -1238,15 +1239,15 @@ def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
.view(torch.float8_e4m3fn)
)

layer.weight_scale_interleaved = Parameter(scale, requires_grad=False)
layer.weight = Parameter(weight, requires_grad=False)
copy_or_rebind_param(layer, "weight_scale_interleaved", scale)
copy_or_rebind_param(layer, "weight", weight)
layer.weights_padding_cols = weights_padding_cols
return

# Pad weights for CUTLASS/FlashInfer kernel alignment (K and N divisible by 32)
weight, weights_padding_cols = pad_nvfp4_weight(layer.weight.data)
layer.weights_padding_cols = weights_padding_cols
layer.weight = Parameter(weight, requires_grad=False)
copy_or_rebind_param(layer, "weight", weight)

# Pad and blockwise interleave weight_scale
scales = layer.weight_scale
Expand All @@ -1270,7 +1271,7 @@ def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
if scale_ndim == 2
else padded_scales.reshape(B, M_padded, K_padded)
)
layer.weight_scale_interleaved = Parameter(padded_scales, requires_grad=False)
copy_or_rebind_param(layer, "weight_scale_interleaved", padded_scales)

def apply(
self,
Expand Down Expand Up @@ -1496,18 +1497,22 @@ def process_weights_after_loading(self, layer: torch.nn.Module) -> None:

# GEMM 1 scale processing
if layer.moe_runner_config.is_gated:
if not torch.allclose(
layer.w13_weight_scale_2[:, 0], layer.w13_weight_scale_2[:, 1]
):
logger.warning_once(
"w1_weight_scale_2 must match w3_weight_scale_2. "
"Accuracy may be affected."
)
if layer.w13_weight_scale_2.dim() == 1:
# Some checkpoints store a shared scale for w1/w3.
w13_weight_scale_2 = layer.w13_weight_scale_2
else:
if layer.w13_weight_scale_2.shape[1] >= 2 and not torch.allclose(
layer.w13_weight_scale_2[:, 0],
layer.w13_weight_scale_2[:, 1],
):
logger.warning_once(
"w1_weight_scale_2 must match w3_weight_scale_2. "
"Accuracy may be affected."
)

w13_weight_scale_2 = layer.w13_weight_scale_2[:, 0]
w13_weight_scale_2 = layer.w13_weight_scale_2[:, 0]
else:
w13_weight_scale_2 = layer.w13_weight_scale_2[:]
layer.w13_weight_scale_2 = Parameter(w13_weight_scale_2, requires_grad=False)

# Calculate input scales based on strategy
if self.enable_flashinfer_cutlass_moe or self.enable_flashinfer_trtllm_moe:
Expand Down Expand Up @@ -1549,19 +1554,25 @@ def _slice_scale(w):
w2_input_scale = layer.w2_input_scale

# Create shared parameters
layer.g1_alphas = Parameter(
copy_or_rebind_param(
layer,
"g1_alphas",
(w13_input_scale * w13_weight_scale_2).to(torch.float32),
requires_grad=False,
)
layer.g2_alphas = Parameter(
copy_or_rebind_param(
layer,
"g2_alphas",
(w2_input_scale * layer.w2_weight_scale_2).to(torch.float32),
requires_grad=False,
)
layer.w13_input_scale_quant = Parameter(
(1 / w13_input_scale).to(torch.float32), requires_grad=False
copy_or_rebind_param(
layer,
"w13_input_scale_quant",
(1 / w13_input_scale).to(torch.float32),
)
layer.w2_input_scale_quant = Parameter(
(1 / w2_input_scale).to(torch.float32), requires_grad=False
copy_or_rebind_param(
layer,
"w2_input_scale_quant",
(1 / w2_input_scale).to(torch.float32),
)

# TODO: for flashinfer always do MOE_NVFP4_DISPATCH
Expand Down Expand Up @@ -1621,8 +1632,9 @@ def _slice_scale(w):

# Process w13 weights
w13_blockscale_swizzled = swizzle_blockscale(layer.w13_weight_scale)
del layer.w13_weight_scale
layer.w13_blockscale_swizzled.data.copy_(w13_blockscale_swizzled)
copy_or_rebind_param(
layer, "w13_blockscale_swizzled", w13_blockscale_swizzled
)

w13_weight = layer.w13_weight
intermediate_size_pad = w13_blockscale_swizzled.size(1) - w13_weight.size(1)
Expand All @@ -1634,46 +1646,56 @@ def _slice_scale(w):
"but padding is also implemented for gated activations"
)

layer.w13_weight = Parameter(
copy_or_rebind_param(
layer,
"w13_weight",
torch.nn.functional.pad(
w13_weight, (0, 0, 0, intermediate_size_pad)
),
requires_grad=False,
)
layer.w2_weight = Parameter(
copy_or_rebind_param(
layer,
"w2_weight",
torch.nn.functional.pad(
layer.w2_weight, (0, intermediate_size_pad // 2, 0, 0)
),
requires_grad=False,
)
layer.w2_weight_scale = Parameter(
copy_or_rebind_param(
layer,
"w2_weight_scale",
torch.nn.functional.pad(
layer.w2_weight_scale, (0, intermediate_size_pad // 16)
),
requires_grad=False,
)
layer.w2_blockscale_swizzled = Parameter(
swizzle_blockscale(layer.w2_weight_scale), requires_grad=False
)

layer.w13_weight = Parameter(layer.w13_weight.data, requires_grad=False)

# Process w2 weights
w2_blockscale_swizzled = swizzle_blockscale(layer.w2_weight_scale)
del layer.w2_weight_scale
layer.w2_blockscale_swizzled.data.copy_(w2_blockscale_swizzled)
copy_or_rebind_param(
layer, "w2_blockscale_swizzled", w2_blockscale_swizzled
)

# Both flashinfer cutlass and regular cutlass use same processing for w2

# Set up CUTLASS MoE parameters
# Set up CUTLASS MoE parameters (reuse to keep CUDA graph stable)
Comment thread
Fridge003 marked this conversation as resolved.
device = layer.w13_weight.device
layer.cutlass_moe_params = CutlassMoEParams(
CutlassMoEType.BlockscaledFP4,
device,
num_experts=layer.num_experts, # global num experts
intermediate_size_per_partition=layer.w2_weight.shape[2] * 2, # n
hidden_size=layer.w13_weight.shape[2] * 2,
) # k
inter_size = layer.w2_weight.shape[2] * 2
hidden_size = layer.w13_weight.shape[2] * 2
existing_params = getattr(layer, "cutlass_moe_params", None)
if (
existing_params is None
or existing_params.cutlass_moe_type != CutlassMoEType.BlockscaledFP4
or existing_params.num_experts != layer.num_experts
or existing_params.intermediate_size_per_partition != inter_size
or existing_params.hidden_size != hidden_size
or existing_params.device != device
):
layer.cutlass_moe_params = CutlassMoEParams(
CutlassMoEType.BlockscaledFP4,
device,
num_experts=layer.num_experts, # global num experts
intermediate_size_per_partition=inter_size, # n
hidden_size=hidden_size,
) # k

@property
def load_up_proj_weight_first(self) -> bool:
Expand Down
17 changes: 17 additions & 0 deletions python/sglang/srt/layers/utils/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import re

import torch
from torch.nn.parameter import Parameter

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -37,6 +38,22 @@ def pad_or_narrow_weight(
)


def copy_or_rebind_param(
module: torch.nn.Module, name: str, new_value: torch.Tensor
) -> None:
"""Keep parameter identities stable for CUDA graph reuse and hot reload."""
new_value = new_value.detach()
param = getattr(module, name, None)
if isinstance(param, Parameter):
if param.data.shape == new_value.shape and param.data.dtype == new_value.dtype:
param.data.copy_(new_value)
else:
param.data = new_value
param.requires_grad_(False)
else:
setattr(module, name, Parameter(new_value, requires_grad=False))


class PPMissingLayer(torch.nn.Identity):
# Adapted from
# https://github.com/vllm-project/vllm/blob/18ed3132d2bfe1df9a74729457b69243955221e8/vllm/model_executor/models/utils.py#L468C1-L486C1
Expand Down
Loading