[diffusion] fix: reject unsupported modelopt checkpoint algorithms (#35182)
This commit is contained in:
@@ -13,6 +13,7 @@ from sglang.multimodal_gen.runtime.layers.quantization import (
|
||||
get_quantization_config,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
|
||||
from sglang.srt.layers.modelopt_utils import canonicalize_modelopt_quant_algo
|
||||
from sglang.srt.model_loader.checkpoint_quantization import (
|
||||
resolve_checkpoint_quant_spec,
|
||||
)
|
||||
@@ -106,7 +107,8 @@ def _resolve_quant_method_name(quant_cfg: dict) -> str:
|
||||
quant_method = quant_cfg.get("quant_method")
|
||||
if quant_method == "bitsandbytes":
|
||||
return "bitsandbytes"
|
||||
if quant_method != "modelopt":
|
||||
modelopt_methods = {"modelopt", "modelopt_fp8", "modelopt_fp4"}
|
||||
if quant_method not in modelopt_methods:
|
||||
return quant_method
|
||||
|
||||
quant_algo = (
|
||||
@@ -114,14 +116,37 @@ def _resolve_quant_method_name(quant_cfg: dict) -> str:
|
||||
or quant_cfg.get("quantization", {}).get("quant_algo")
|
||||
or ""
|
||||
).upper()
|
||||
if quant_method != "modelopt" and not quant_algo:
|
||||
# Preserve explicit legacy configs that select the backend directly.
|
||||
# When an algorithm is present below, validate that it agrees.
|
||||
return quant_method
|
||||
if quant_algo == "MIXED_PRECISION":
|
||||
raise ValueError(
|
||||
"ModelOpt mixed precision is not supported by the current SGLang diffusion runtime."
|
||||
)
|
||||
if "FP8" in quant_algo:
|
||||
return "modelopt_fp8"
|
||||
if "FP4" in quant_algo or "NVFP4" in quant_algo:
|
||||
return "modelopt_fp4"
|
||||
canonical_method = canonicalize_modelopt_quant_algo(quant_algo)
|
||||
if (
|
||||
quant_method != "modelopt"
|
||||
and canonical_method is not None
|
||||
and quant_method != canonical_method
|
||||
):
|
||||
raise ValueError(
|
||||
f"ModelOpt config declares quant_method={quant_method!r}, but "
|
||||
f"quant_algo={quant_algo!r} maps to {canonical_method!r}."
|
||||
)
|
||||
supported_algorithms = {
|
||||
"FP8": "modelopt_fp8",
|
||||
"NVFP4": "modelopt_fp4",
|
||||
}
|
||||
runtime_method = supported_algorithms.get(quant_algo)
|
||||
if runtime_method is not None:
|
||||
return runtime_method
|
||||
if canonical_method is not None:
|
||||
raise ValueError(
|
||||
f"ModelOpt quant_algo={quant_algo!r} maps to {canonical_method!r}, but "
|
||||
"that checkpoint algorithm is not supported by the SGLang diffusion runtime. "
|
||||
"Supported ModelOpt checkpoint algorithms are FP8 and NVFP4."
|
||||
)
|
||||
raise ValueError(f"Unsupported ModelOpt quant_algo for diffusion: {quant_algo}")
|
||||
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ from sglang.multimodal_gen.runtime.models.dits.flux import FluxSingleTransformer
|
||||
from sglang.multimodal_gen.runtime.platforms import AttentionBackendEnum
|
||||
from sglang.multimodal_gen.runtime.platforms.interface import DeviceCapability
|
||||
from sglang.multimodal_gen.runtime.utils.quantization_utils import (
|
||||
_resolve_quant_method_name,
|
||||
build_nvfp4_config_from_safetensors_list,
|
||||
get_quant_config,
|
||||
)
|
||||
@@ -647,6 +648,91 @@ class TestTransformerQuantHelpers(unittest.TestCase):
|
||||
self.assertIsInstance(config, ModelOptFp8Config)
|
||||
self.assertEqual(config.exclude_modules, ["proj_out"])
|
||||
|
||||
def test_modelopt_checkpoint_algorithm_admission(self):
|
||||
cases = [
|
||||
("modelopt", "FP8", {"ignore": []}, ModelOptFp8Config, None),
|
||||
("modelopt_fp8", "FP8", {"ignore": []}, ModelOptFp8Config, None),
|
||||
(
|
||||
"modelopt",
|
||||
"NVFP4",
|
||||
{"group_size": 16, "ignore": []},
|
||||
ModelOptFp4Config,
|
||||
None,
|
||||
),
|
||||
(
|
||||
"modelopt_fp4",
|
||||
"NVFP4",
|
||||
{"group_size": 16, "ignore": []},
|
||||
ModelOptFp4Config,
|
||||
None,
|
||||
),
|
||||
("modelopt", "MXFP8", {}, None, "maps to 'mxfp8'"),
|
||||
("modelopt", "FP4", {}, None, "maps to 'modelopt_fp4'"),
|
||||
("modelopt", "NVFP4_AWQ", {}, None, "maps to 'modelopt_fp4'"),
|
||||
("modelopt", "W4A16_NVFP4", {}, None, "maps to 'modelopt_fp4'"),
|
||||
(
|
||||
"modelopt",
|
||||
"MIXED_PRECISION",
|
||||
{},
|
||||
None,
|
||||
"mixed precision is not supported",
|
||||
),
|
||||
(
|
||||
"modelopt",
|
||||
"FP8_FAKE",
|
||||
{},
|
||||
None,
|
||||
"Unsupported ModelOpt quant_algo for diffusion: FP8_FAKE",
|
||||
),
|
||||
(
|
||||
"modelopt_fp8",
|
||||
"MXFP8",
|
||||
{},
|
||||
None,
|
||||
"declares quant_method='modelopt_fp8'.*maps to 'mxfp8'",
|
||||
),
|
||||
(
|
||||
"modelopt_fp4",
|
||||
"FP8",
|
||||
{},
|
||||
None,
|
||||
"declares quant_method='modelopt_fp4'.*maps to 'modelopt_fp8'",
|
||||
),
|
||||
]
|
||||
for (
|
||||
quant_method,
|
||||
quant_algo,
|
||||
extra_metadata,
|
||||
expected_type,
|
||||
expected_error,
|
||||
) in cases:
|
||||
with self.subTest(quant_algo=quant_algo):
|
||||
metadata = {
|
||||
"quant_method": quant_method,
|
||||
"quant_algo": quant_algo,
|
||||
**extra_metadata,
|
||||
}
|
||||
if expected_error is not None:
|
||||
with self.assertRaisesRegex(ValueError, expected_error):
|
||||
get_quant_config(
|
||||
{"quantization_config": metadata},
|
||||
"/unused/component/path",
|
||||
)
|
||||
else:
|
||||
config = get_quant_config(
|
||||
{"quantization_config": metadata},
|
||||
"/unused/component/path",
|
||||
)
|
||||
self.assertIsInstance(config, expected_type)
|
||||
|
||||
def test_explicit_modelopt_method_without_algorithm_is_preserved(self):
|
||||
for quant_method in ("modelopt_fp8", "modelopt_fp4"):
|
||||
with self.subTest(quant_method=quant_method):
|
||||
self.assertEqual(
|
||||
_resolve_quant_method_name({"quant_method": quant_method}),
|
||||
quant_method,
|
||||
)
|
||||
|
||||
@patch("sglang.multimodal_gen.runtime.layers.linear.get_group_rank", return_value=0)
|
||||
@patch("sglang.multimodal_gen.runtime.layers.linear.get_group_size", return_value=1)
|
||||
@patch(
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
ModelOpt related constants
|
||||
"""
|
||||
|
||||
from typing import Literal, TypeAlias
|
||||
|
||||
QUANT_CFG_CHOICES = {
|
||||
"fp8": "FP8_DEFAULT_CFG",
|
||||
"int4_awq": "INT4_AWQ_CFG", # TODO: add support for int4_awq
|
||||
@@ -9,3 +11,35 @@ QUANT_CFG_CHOICES = {
|
||||
"nvfp4": "NVFP4_DEFAULT_CFG",
|
||||
"nvfp4_awq": "NVFP4_AWQ_LITE_CFG", # TODO: add support for nvfp4_awq
|
||||
}
|
||||
|
||||
|
||||
ModelOptQuantMethod: TypeAlias = Literal[
|
||||
"modelopt_fp8",
|
||||
"modelopt_fp4",
|
||||
"mxfp8",
|
||||
]
|
||||
|
||||
|
||||
_MODELOPT_QUANT_ALGO_TO_METHOD: dict[str, ModelOptQuantMethod] = {
|
||||
"FP8": "modelopt_fp8",
|
||||
"MXFP8": "mxfp8",
|
||||
"FP4": "modelopt_fp4",
|
||||
"NVFP4": "modelopt_fp4",
|
||||
"NVFP4_AWQ": "modelopt_fp4",
|
||||
"W4A16_NVFP4": "modelopt_fp4",
|
||||
}
|
||||
|
||||
|
||||
def canonicalize_modelopt_quant_algo(
|
||||
quant_algo: object,
|
||||
) -> ModelOptQuantMethod | None:
|
||||
"""Map a known ModelOpt algorithm name to its SGLang runtime family.
|
||||
|
||||
This is intentionally an exact allowlist. In particular, ``MXFP8`` must not
|
||||
be mistaken for ordinary ``FP8`` merely because its name contains that
|
||||
substring. Runtime-specific capability checks remain with each consumer.
|
||||
"""
|
||||
|
||||
if not isinstance(quant_algo, str):
|
||||
return None
|
||||
return _MODELOPT_QUANT_ALGO_TO_METHOD.get(quant_algo.upper())
|
||||
|
||||
@@ -10,6 +10,8 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type
|
||||
import torch
|
||||
from torch import nn
|
||||
|
||||
from sglang.srt.layers.modelopt_utils import canonicalize_modelopt_quant_algo
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sglang.srt.layers.moe.moe_runner import MoeRunnerConfig
|
||||
from sglang.srt.layers.moe.moe_runner.triton import TritonMoeQuantInfo
|
||||
@@ -198,12 +200,9 @@ class QuantizationConfig(ABC):
|
||||
|
||||
# If user specified generic "modelopt", auto-detect the specific method
|
||||
if user_quant == "modelopt":
|
||||
if quant_algo == "MXFP8":
|
||||
return "mxfp8"
|
||||
elif quant_algo == "FP8":
|
||||
return "modelopt_fp8"
|
||||
elif "NVFP4" in quant_algo or "FP4" in quant_algo:
|
||||
return "modelopt_fp4"
|
||||
canonical_method = canonicalize_modelopt_quant_algo(quant_algo)
|
||||
if canonical_method is not None:
|
||||
return canonical_method
|
||||
|
||||
# The hf_quant_config may be a parsed quant config, so we need to check the
|
||||
# quant_method.
|
||||
|
||||
Reference in New Issue
Block a user