[AMD] [GLM-5.3-Flash Day 0] Enable FP8 and Quark MXFP4 MoE on gfx950 (#38546)
Co-authored-by: Raiden-Makoto <Raiden-Makoto@users.noreply.github.com> Co-authored-by: Thomas Wang <thomawan@amd.com> Co-authored-by: andyluo7 <andy.luo@amd.com> Co-authored-by: Kevin Mi <mikevin920@yahoo.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Raiden-Makoto
Thomas Wang
andyluo7
Kevin Mi
Claude Opus 5
parent
15ba54bd5d
commit
b44e248682
@@ -282,10 +282,13 @@ class AiterRunnerCore(MoeRunnerCore):
|
||||
# `SGLANG_USE_AITER_MOE_GU_ITLV=0` to switch to SEPARATED, which
|
||||
# matches the layout produced by `Mxfp4MoEMethod` (gpt-oss
|
||||
# MXFP4) and the gptoss_fp4 tuned FlyDSL kernels.
|
||||
extra["gate_mode"] = (
|
||||
GateMode.INTERLEAVE.value
|
||||
if envs.SGLANG_USE_AITER_MOE_GU_ITLV.get()
|
||||
else GateMode.SEPARATED.value
|
||||
extra.setdefault(
|
||||
"gate_mode",
|
||||
(
|
||||
GateMode.INTERLEAVE.value
|
||||
if envs.SGLANG_USE_AITER_MOE_GU_ITLV.get()
|
||||
else GateMode.SEPARATED.value
|
||||
),
|
||||
)
|
||||
extra["swiglu_limit"] = quant_info.swiglu_limit
|
||||
if self.config.no_combine:
|
||||
|
||||
@@ -1886,6 +1886,7 @@ class Fp8MoEMethod(FusedMoEMethodBase):
|
||||
)
|
||||
layer.w13_weight.is_shuffled = True
|
||||
layer.w2_weight.is_shuffled = True
|
||||
layer._aiter_gate_up_interleaved = False
|
||||
return
|
||||
elif self.use_mxfp8 and get_moe_a2a_backend().is_flashinfer_megamoe():
|
||||
from sglang.srt.layers.moe.flashinfer_megamoe import (
|
||||
@@ -1933,6 +1934,7 @@ class Fp8MoEMethod(FusedMoEMethodBase):
|
||||
)
|
||||
layer.w13_weight.is_shuffled = True
|
||||
layer.w2_weight.is_shuffled = True
|
||||
layer._aiter_gate_up_interleaved = False
|
||||
elif _use_aiter:
|
||||
# Pre-shuffle weights
|
||||
t = shuffle_weight(layer.w13_weight, (16, 16))
|
||||
@@ -1943,6 +1945,7 @@ class Fp8MoEMethod(FusedMoEMethodBase):
|
||||
del t
|
||||
layer.w13_weight.is_shuffled = True
|
||||
layer.w2_weight.is_shuffled = True
|
||||
layer._aiter_gate_up_interleaved = False
|
||||
elif _is_cpu:
|
||||
assert _is_cpu_amx_available, (
|
||||
"Fp8MoEMethod on CPU requires that CPU has AMX support"
|
||||
@@ -2650,6 +2653,7 @@ class Fp8MoEMethod(FusedMoEMethodBase):
|
||||
requires_grad=False,
|
||||
)
|
||||
torch.cuda.empty_cache()
|
||||
layer._aiter_gate_up_interleaved = False
|
||||
|
||||
# ROCm (_use_aiter): using column-wise scaling
|
||||
layer.w13_weight_scale1 *= layer.w13_weight_scale.unsqueeze(-1)
|
||||
@@ -3158,6 +3162,23 @@ class Fp8MoEMethod(FusedMoEMethodBase):
|
||||
quant_type = AiterQuantType.PER_TOKEN
|
||||
w13_scale = layer.w13_weight_scale1
|
||||
w2_scale = layer.w2_weight_scale1
|
||||
|
||||
fused_moe_kwargs = None
|
||||
gate_up_interleaved = getattr(layer, "_aiter_gate_up_interleaved", None)
|
||||
if (
|
||||
gate_up_interleaved is not None
|
||||
and (self.moe_runner_config.swiglu_limit or 0.0) > 0
|
||||
):
|
||||
from aiter.ops.flydsl.moe_common import GateMode
|
||||
|
||||
fused_moe_kwargs = {
|
||||
"gate_mode": (
|
||||
GateMode.INTERLEAVE.value
|
||||
if gate_up_interleaved
|
||||
else GateMode.SEPARATED.value
|
||||
)
|
||||
}
|
||||
|
||||
return AiterMoeQuantInfo(
|
||||
w13_weight=w13_weight,
|
||||
w2_weight=w2_weight,
|
||||
@@ -3168,6 +3189,7 @@ class Fp8MoEMethod(FusedMoEMethodBase):
|
||||
swiglu_limit=self.moe_runner_config.swiglu_limit or 0.0,
|
||||
hidden_pad=getattr(layer, "hidden_pad", 0),
|
||||
intermediate_pad=getattr(layer, "intermediate_pad", 0),
|
||||
fused_moe_kwargs=fused_moe_kwargs,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,11 @@ from sglang.srt.layers.quantization.base_config import ( # noqa: E501
|
||||
QuantizationConfig,
|
||||
QuantizeMethodBase,
|
||||
)
|
||||
from sglang.srt.layers.quantization.fp8 import Fp8Config, Fp8LinearMethod
|
||||
from sglang.srt.layers.quantization.fp8 import (
|
||||
Fp8Config,
|
||||
Fp8LinearMethod,
|
||||
Fp8MoEMethod,
|
||||
)
|
||||
from sglang.srt.layers.quantization.kv_cache import BaseKVCacheMethod
|
||||
from sglang.srt.layers.quantization.quark.schemes import (
|
||||
QuarkLinearScheme,
|
||||
@@ -375,6 +379,46 @@ class QuarkConfig(QuantizationConfig):
|
||||
expanded.append(name.removeprefix("language_model."))
|
||||
self.exclude_layers = list(dict.fromkeys(expanded))
|
||||
|
||||
layer_quant_config = self.quant_config.get("layer_quant_config")
|
||||
if layer_quant_config:
|
||||
self.quant_config["layer_quant_config"] = hf_to_sglang_mapper.apply_dict(
|
||||
layer_quant_config
|
||||
)
|
||||
|
||||
if self.kv_cache_group:
|
||||
self.kv_cache_group = hf_to_sglang_mapper.apply_list(self.kv_cache_group)
|
||||
|
||||
@staticmethod
|
||||
def _get_block_fp8_config(
|
||||
layer_quant_config: Optional[dict[str, Any]],
|
||||
packed_modules_mapping: dict[str, list[str]],
|
||||
) -> Optional[Fp8Config]:
|
||||
if layer_quant_config is None:
|
||||
return None
|
||||
|
||||
weight_config = layer_quant_config.get("weight") or {}
|
||||
input_config = layer_quant_config.get("input_tensors") or {}
|
||||
block_size = weight_config.get("block_size")
|
||||
if not (
|
||||
not layer_quant_config.get("output_tensors")
|
||||
and not layer_quant_config.get("bias")
|
||||
and weight_config.get("dtype") in {"fp8_e4m3", "fp8_e4m3fn"}
|
||||
and weight_config.get("qscheme") == "per_block"
|
||||
and weight_config.get("is_dynamic") is False
|
||||
and isinstance(block_size, list)
|
||||
and len(block_size) == 2
|
||||
and input_config.get("dtype") in {"fp8_e4m3", "fp8_e4m3fn"}
|
||||
and input_config.get("is_dynamic") is True
|
||||
):
|
||||
return None
|
||||
|
||||
return Fp8Config(
|
||||
is_checkpoint_fp8_serialized=True,
|
||||
activation_scheme="dynamic",
|
||||
weight_block_size=block_size,
|
||||
packed_modules_mapping=packed_modules_mapping,
|
||||
)
|
||||
|
||||
def get_quant_method(
|
||||
self, layer: torch.nn.Module, prefix: str
|
||||
) -> Optional["QuantizeMethodBase"]:
|
||||
@@ -396,6 +440,17 @@ class QuarkConfig(QuantizationConfig):
|
||||
return QuarkKVCacheMethod(self)
|
||||
return None
|
||||
|
||||
from sglang.srt.layers.moe.fused_moe_triton.layer import FusedMoE
|
||||
|
||||
block_fp8_config = self._get_block_fp8_config(
|
||||
self._find_matched_config(prefix, layer), self.packed_modules_mapping
|
||||
)
|
||||
if block_fp8_config is not None:
|
||||
if isinstance(layer, LinearBase):
|
||||
return Fp8LinearMethod(block_fp8_config)
|
||||
if isinstance(layer, FusedMoE):
|
||||
return Fp8MoEMethod(block_fp8_config)
|
||||
|
||||
if isinstance(layer, LinearBase):
|
||||
scheme = self.get_linear_scheme(layer=layer, layer_name=prefix)
|
||||
layer.scheme = scheme
|
||||
@@ -406,8 +461,6 @@ class QuarkConfig(QuantizationConfig):
|
||||
self._online_quantized_layers.add(prefix)
|
||||
return QuarkKVCacheMethod(self)
|
||||
|
||||
from sglang.srt.layers.moe.fused_moe_triton.layer import FusedMoE
|
||||
|
||||
if isinstance(layer, FusedMoE):
|
||||
self._online_quantized_layers.add(prefix)
|
||||
layer.scheme = self.get_moe_scheme(layer, prefix)
|
||||
|
||||
@@ -38,12 +38,12 @@ if TYPE_CHECKING:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_is_shuffle_moe_mxfp4 = is_gfx95_supported()
|
||||
|
||||
__all__ = ["QuarkW4A4MXFp4MoE"]
|
||||
|
||||
_is_hip = is_hip()
|
||||
_use_aiter = get_bool_env_var("SGLANG_USE_AITER") and _is_hip
|
||||
_is_gfx95 = is_gfx95_supported()
|
||||
_is_shuffle_moe_mxfp4 = _use_aiter and _is_gfx95
|
||||
if _use_aiter:
|
||||
from aiter.ops.shuffle import moe_shuffle_scale, moe_shuffle_weight, shuffle_weight
|
||||
from aiter.utility.fp4_utils import e8m0_shuffle
|
||||
@@ -202,6 +202,8 @@ class QuarkW4A4MXFp4MoE(QuarkMoEScheme):
|
||||
is_concat=True,
|
||||
is_packed=True,
|
||||
)
|
||||
layer.hidden_pad = 0
|
||||
layer.intermediate_pad = w13_up_dim // 2 - intermediate_size_per_partition
|
||||
|
||||
# Add the quantization method used (per tensor/grouped/channel)
|
||||
# to ensure the weight scales are loaded in properly
|
||||
@@ -819,6 +821,11 @@ class QuarkW4A4MXFp4MoE(QuarkMoEScheme):
|
||||
layer.w2_weight = torch.nn.Parameter(qw2_weight, requires_grad=False)
|
||||
|
||||
def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
|
||||
if not getattr(self, "_owns_moe_runner", False):
|
||||
raise RuntimeError(
|
||||
"Quark MXFP4 weight preshuffling requires an owned AITER runner."
|
||||
)
|
||||
|
||||
if (
|
||||
not self.is_checkpoint_mxfp4_serialized
|
||||
or self.dequantization_config is not None
|
||||
@@ -889,15 +896,19 @@ class QuarkW4A4MXFp4MoE(QuarkMoEScheme):
|
||||
)
|
||||
|
||||
self.moe_runner_config = moe_runner_config
|
||||
self._owns_moe_runner = False
|
||||
moe_runner_backend = get_moe_runner_backend()
|
||||
if moe_runner_backend.is_auto() and get_moe_a2a_backend().supports_aiter():
|
||||
moe_runner_backend = MoeRunnerBackend.AITER
|
||||
|
||||
if moe_runner_backend.is_aiter():
|
||||
self.runner = MoeRunner(moe_runner_backend, moe_runner_config)
|
||||
self._owns_moe_runner = True
|
||||
else:
|
||||
# TODO(cwan): refactor other backends
|
||||
pass
|
||||
raise NotImplementedError(
|
||||
"Quark MXFP4 MoE currently requires the AITER runner; "
|
||||
f"got {moe_runner_backend.value!r}."
|
||||
)
|
||||
|
||||
def apply_weights(
|
||||
self,
|
||||
@@ -924,6 +935,12 @@ class QuarkW4A4MXFp4MoE(QuarkMoEScheme):
|
||||
from aiter.ops.flydsl.moe_common import GateMode
|
||||
|
||||
_fused_moe_kwargs = {"gate_mode": GateMode.INTERLEAVE.value}
|
||||
elif _is_gfx95:
|
||||
from aiter.ops.flydsl.moe_common import GateMode
|
||||
|
||||
# Quark checkpoints store gate and up projections as separate
|
||||
# contiguous row ranges. Keep that ordering for correctness.
|
||||
_fused_moe_kwargs = {"gate_mode": GateMode.SEPARATED.value}
|
||||
else:
|
||||
_fused_moe_kwargs = None
|
||||
|
||||
@@ -934,6 +951,9 @@ class QuarkW4A4MXFp4MoE(QuarkMoEScheme):
|
||||
w13_scale=layer.w13_weight_scale,
|
||||
w2_scale=layer.w2_weight_scale,
|
||||
expert_mask=layer.dispatcher.expert_mask_gpu,
|
||||
hidden_pad=getattr(layer, "hidden_pad", 0),
|
||||
intermediate_pad=getattr(layer, "intermediate_pad", 0),
|
||||
swiglu_limit=self.moe_runner_config.swiglu_limit or 0.0,
|
||||
fused_moe_kwargs=_fused_moe_kwargs,
|
||||
)
|
||||
return self.runner.run(dispatch_output, quant_info)
|
||||
|
||||
@@ -1233,11 +1233,13 @@ class Glm5NextModel(nn.Module):
|
||||
class Glm5NextForConditionalGeneration(nn.Module):
|
||||
hf_to_sglang_mapper = WeightsMapper(
|
||||
orig_to_new_substr={
|
||||
"model.language_model.": "model.",
|
||||
"model.visual": "visual",
|
||||
}
|
||||
},
|
||||
orig_to_new_prefix={
|
||||
"model.language_model.": "model.",
|
||||
},
|
||||
orig_to_new_suffix={".attn.qkv": ".attn.qkv_proj"},
|
||||
)
|
||||
|
||||
packed_modules_mapping = {
|
||||
"fused_qkv_a_proj_with_mqa": ["q_a_proj", "kv_a_proj_with_mqa"],
|
||||
**Glm5NextLinearAttention._PACKED_MODULES_MAPPING,
|
||||
@@ -1570,6 +1572,14 @@ class Glm5NextForConditionalGeneration(nn.Module):
|
||||
fused_cat_dim = 0
|
||||
|
||||
params_dict = dict(self.named_parameters())
|
||||
|
||||
def maybe_map_fp8_block_scale_name(name: str) -> str:
|
||||
if name.endswith("weight_scale"):
|
||||
candidate = name.removesuffix("weight_scale") + "weight_scale_inv"
|
||||
if candidate in params_dict:
|
||||
return candidate
|
||||
return name
|
||||
|
||||
weight_names = []
|
||||
for name, loaded_weight in weights:
|
||||
is_visual_weight = "visual" in name
|
||||
@@ -1633,6 +1643,7 @@ class Glm5NextForConditionalGeneration(nn.Module):
|
||||
if "mlp.experts" in name:
|
||||
continue
|
||||
candidate = name.replace(weight_name, param_name)
|
||||
candidate = maybe_map_fp8_block_scale_name(candidate)
|
||||
if (
|
||||
param_name
|
||||
in {
|
||||
@@ -1662,6 +1673,7 @@ class Glm5NextForConditionalGeneration(nn.Module):
|
||||
continue
|
||||
is_expert_weight = True
|
||||
name = name.replace(weight_name, param_name)
|
||||
name = maybe_map_fp8_block_scale_name(name)
|
||||
if name not in params_dict:
|
||||
continue
|
||||
param = params_dict[name]
|
||||
@@ -1713,6 +1725,7 @@ class Glm5NextForConditionalGeneration(nn.Module):
|
||||
"fused_qkv_a_proj_with_mqa",
|
||||
)
|
||||
)
|
||||
target = maybe_map_fp8_block_scale_name(target)
|
||||
if target in params_dict:
|
||||
param = params_dict[target]
|
||||
weight_loader = getattr(
|
||||
@@ -1723,6 +1736,7 @@ class Glm5NextForConditionalGeneration(nn.Module):
|
||||
cached_a_proj.pop(kv_a_proj_name, None)
|
||||
continue
|
||||
|
||||
name = maybe_map_fp8_block_scale_name(name)
|
||||
if name not in params_dict:
|
||||
continue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user