[diffusion] fix: fix local-path detection for MiniMax-H3 and other non-diffusers models (#33365)
Co-authored-by: Mick <mickjagger19@icloud.com>
This commit is contained in:
+12
-15
@@ -9,7 +9,6 @@ from huggingface_hub import HfApi
|
|||||||
from sglang.srt.environ import envs
|
from sglang.srt.environ import envs
|
||||||
from sglang.utils import (
|
from sglang.utils import (
|
||||||
has_diffusion_overlay_registry_match,
|
has_diffusion_overlay_registry_match,
|
||||||
is_known_non_diffusers_diffusion_model,
|
|
||||||
load_diffusion_overlay_registry_from_env,
|
load_diffusion_overlay_registry_from_env,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,14 +24,14 @@ def _is_overlay_diffusion_model(model_path: str) -> bool:
|
|||||||
return has_diffusion_overlay_registry_match(model_path, _load_overlay_registry())
|
return has_diffusion_overlay_registry_match(model_path, _load_overlay_registry())
|
||||||
|
|
||||||
|
|
||||||
def _is_registered_diffusion_model(model_path: str) -> bool:
|
def _is_diffusion_model_from_registry(model_path: str) -> bool:
|
||||||
try:
|
try:
|
||||||
from sglang.multimodal_gen.registry import has_registered_diffusion_model_path
|
from sglang.multimodal_gen.registry import is_registered_diffusion_model_path
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# if diffusion dependencies are not installed
|
# if diffusion dependencies are not installed
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return has_registered_diffusion_model_path(model_path)
|
return is_registered_diffusion_model_path(model_path)
|
||||||
|
|
||||||
|
|
||||||
def _is_diffusers_model_dir(model_dir: str) -> bool:
|
def _is_diffusers_model_dir(model_dir: str) -> bool:
|
||||||
@@ -59,8 +58,9 @@ def _is_gated_diffusion_repo(repo_id: str) -> bool:
|
|||||||
def get_is_diffusion_model(model_path: str) -> bool:
|
def get_is_diffusion_model(model_path: str) -> bool:
|
||||||
"""Detect whether model_path points to a diffusion model.
|
"""Detect whether model_path points to a diffusion model.
|
||||||
|
|
||||||
For local directories, checks the filesystem directly.
|
For registered models, consults the diffusion registry first.
|
||||||
For HF/ModelScope model IDs, attempts to fetch only model_index.json.
|
For other local directories, checks the filesystem directly.
|
||||||
|
For other HF/ModelScope model IDs, attempts to fetch only model_index.json.
|
||||||
For gated repos where file download fails, falls back to HF model card
|
For gated repos where file download fails, falls back to HF model card
|
||||||
metadata (library_name == "diffusers").
|
metadata (library_name == "diffusers").
|
||||||
Returns False on any failure (network error, 404, offline mode, etc.)
|
Returns False on any failure (network error, 404, offline mode, etc.)
|
||||||
@@ -70,16 +70,13 @@ def get_is_diffusion_model(model_path: str) -> bool:
|
|||||||
# short-circuit, if applicable for the overlay mechanism (diffusion-only)
|
# short-circuit, if applicable for the overlay mechanism (diffusion-only)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# the diffusion registry is authoritative for native models, including
|
||||||
|
# local directories without a top-level model_index.json
|
||||||
|
if _is_diffusion_model_from_registry(model_path):
|
||||||
|
return True
|
||||||
|
|
||||||
if os.path.isdir(model_path):
|
if os.path.isdir(model_path):
|
||||||
if _is_diffusers_model_dir(model_path):
|
return _is_diffusers_model_dir(model_path)
|
||||||
return True
|
|
||||||
return is_known_non_diffusers_diffusion_model(model_path)
|
|
||||||
|
|
||||||
if is_known_non_diffusers_diffusion_model(model_path):
|
|
||||||
return True
|
|
||||||
|
|
||||||
if _is_registered_diffusion_model(model_path):
|
|
||||||
return True
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if envs.SGLANG_USE_MODELSCOPE.get():
|
if envs.SGLANG_USE_MODELSCOPE.get():
|
||||||
|
|||||||
@@ -182,7 +182,6 @@ from sglang.multimodal_gen.runtime.utils.hf_diffusers_utils import (
|
|||||||
maybe_download_model_index,
|
maybe_download_model_index,
|
||||||
)
|
)
|
||||||
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
|
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
|
||||||
from sglang.utils import KNOWN_NON_DIFFUSERS_DIFFUSION_MODEL_PATTERNS
|
|
||||||
|
|
||||||
logger = init_logger(__name__)
|
logger = init_logger(__name__)
|
||||||
|
|
||||||
@@ -289,6 +288,22 @@ _MODEL_HF_PATH_TO_NAME: Dict[str, str] = {}
|
|||||||
# Detectors to identify model families from paths or class names
|
# Detectors to identify model families from paths or class names
|
||||||
_MODEL_NAME_DETECTORS: List[Tuple[str, Callable[[str], bool]]] = []
|
_MODEL_NAME_DETECTORS: List[Tuple[str, Callable[[str], bool]]] = []
|
||||||
|
|
||||||
|
# native pipelines do not have a diffusers model_index.json. Keep their path
|
||||||
|
# aliases next to the resolver that consumes them so CLI detection and
|
||||||
|
# pipeline selection cannot drift apart
|
||||||
|
KNOWN_NON_DIFFUSERS_DIFFUSION_MODEL_PATTERNS: Dict[str, str] = {
|
||||||
|
"minimaxai/minimax-h3": "MiniMaxH3Pipeline",
|
||||||
|
"minimax/minimax-h3": "MiniMaxH3Pipeline",
|
||||||
|
"lerobot/pi05": "Pi05Pipeline",
|
||||||
|
"pi05": "Pi05Pipeline",
|
||||||
|
"pi0.5": "Pi05Pipeline",
|
||||||
|
"hunyuan3d": "Hunyuan3D2Pipeline",
|
||||||
|
"flux.2-dev-nvfp4": "Flux2NvfpPipeline",
|
||||||
|
"fal/ideogram-v4-fast": "Ideogram4FastPipeline",
|
||||||
|
"fal/ideogram-v4-instant": "Ideogram4InstantPipeline",
|
||||||
|
"comfy-org/ideogram-4": "Ideogram4Nvfp4Pipeline",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def register_configs(
|
def register_configs(
|
||||||
sampling_param_cls: Any,
|
sampling_param_cls: Any,
|
||||||
@@ -1163,17 +1178,28 @@ _register_configs()
|
|||||||
|
|
||||||
|
|
||||||
def is_known_non_diffusers_multimodal_model(model_path: str) -> bool:
|
def is_known_non_diffusers_multimodal_model(model_path: str) -> bool:
|
||||||
model_path_lower = model_path.lower()
|
return get_non_diffusers_pipeline_name(model_path) is not None
|
||||||
return any(
|
|
||||||
pattern in model_path_lower
|
|
||||||
for pattern in KNOWN_NON_DIFFUSERS_DIFFUSION_MODEL_PATTERNS
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_non_diffusers_pipeline_name(model_path: str) -> Optional[str]:
|
def get_non_diffusers_pipeline_name(model_path: str) -> Optional[str]:
|
||||||
"""Get the pipeline name for a known non-diffusers model."""
|
"""Get the pipeline name for a known non-diffusers model."""
|
||||||
model_path_lower = model_path.lower()
|
normalized_model_path = _normalize_hf_cache_path(model_path)
|
||||||
|
model_short_name = get_model_short_name(normalized_model_path)
|
||||||
for pattern, pipeline_name in KNOWN_NON_DIFFUSERS_DIFFUSION_MODEL_PATTERNS.items():
|
for pattern, pipeline_name in KNOWN_NON_DIFFUSERS_DIFFUSION_MODEL_PATTERNS.items():
|
||||||
if pattern in model_path_lower:
|
pattern = pattern.lower()
|
||||||
|
if "/" not in pattern and pattern in normalized_model_path:
|
||||||
|
return pipeline_name
|
||||||
|
if "/" in pattern and (
|
||||||
|
normalized_model_path == pattern
|
||||||
|
or model_short_name == get_model_short_name(pattern)
|
||||||
|
or f"models--{pattern.replace('/', '--')}" in normalized_model_path
|
||||||
|
):
|
||||||
return pipeline_name
|
return pipeline_name
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def is_registered_diffusion_model_path(model_path: str) -> bool:
|
||||||
|
"""Return whether the diffusion registry recognizes a model path."""
|
||||||
|
return has_registered_diffusion_model_path(model_path) or (
|
||||||
|
get_non_diffusers_pipeline_name(model_path) is not None
|
||||||
|
)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import unittest
|
|||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from sglang.cli.utils import get_is_diffusion_model
|
||||||
from sglang.multimodal_gen.configs.models.fsdp import (
|
from sglang.multimodal_gen.configs.models.fsdp import (
|
||||||
is_module_list_entry,
|
is_module_list_entry,
|
||||||
is_module_list_entry_in,
|
is_module_list_entry_in,
|
||||||
@@ -697,7 +698,16 @@ class TestWarmupImageIsModelValid(unittest.TestCase):
|
|||||||
self.assertGreaterEqual(height, 64)
|
self.assertGreaterEqual(height, 64)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDiffusionModelDetection(unittest.TestCase):
|
||||||
|
def test_registered_local_model_path_is_detected_as_diffusion(self):
|
||||||
|
with tempfile.TemporaryDirectory() as root:
|
||||||
|
model_path = os.path.join(root, "Z-Image-Turbo")
|
||||||
|
os.mkdir(model_path)
|
||||||
|
self.assertTrue(get_is_diffusion_model(model_path))
|
||||||
|
|
||||||
|
|
||||||
class TestMiniMaxH3Routing(unittest.TestCase):
|
class TestMiniMaxH3Routing(unittest.TestCase):
|
||||||
|
|
||||||
def test_semantic_variants_map_to_checkpoint_partitions(self):
|
def test_semantic_variants_map_to_checkpoint_partitions(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
MiniMaxH3Pipeline.model_subfolder_for_variant("fl2va"), "FL2VA"
|
MiniMaxH3Pipeline.model_subfolder_for_variant("fl2va"), "FL2VA"
|
||||||
@@ -718,6 +728,10 @@ class TestMiniMaxH3Routing(unittest.TestCase):
|
|||||||
get_non_diffusers_pipeline_name("MiniMax/MiniMax-H3"),
|
get_non_diffusers_pipeline_name("MiniMax/MiniMax-H3"),
|
||||||
"MiniMaxH3Pipeline",
|
"MiniMaxH3Pipeline",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
get_non_diffusers_pipeline_name("/models/MiniMax-H3"),
|
||||||
|
"MiniMaxH3Pipeline",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestOffloadDefaults(unittest.TestCase):
|
class TestOffloadDefaults(unittest.TestCase):
|
||||||
|
|||||||
@@ -31,25 +31,6 @@ from sglang.srt.environ import envs
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
KNOWN_NON_DIFFUSERS_DIFFUSION_MODEL_PATTERNS: dict[str, str] = {
|
|
||||||
"minimaxai/minimax-h3": "MiniMaxH3Pipeline",
|
|
||||||
"minimaxai--minimax-h3": "MiniMaxH3Pipeline",
|
|
||||||
"minimax/minimax-h3": "MiniMaxH3Pipeline",
|
|
||||||
"minimax--minimax-h3": "MiniMaxH3Pipeline",
|
|
||||||
"lerobot/pi05": "Pi05Pipeline",
|
|
||||||
"lerobot--pi05": "Pi05Pipeline",
|
|
||||||
"pi05": "Pi05Pipeline",
|
|
||||||
"pi0.5": "Pi05Pipeline",
|
|
||||||
"hunyuan3d": "Hunyuan3D2Pipeline",
|
|
||||||
"flux.2-dev-nvfp4": "Flux2NvfpPipeline",
|
|
||||||
"fal/ideogram-v4-fast": "Ideogram4FastPipeline",
|
|
||||||
"fal--ideogram-v4-fast": "Ideogram4FastPipeline",
|
|
||||||
"fal/ideogram-v4-instant": "Ideogram4InstantPipeline",
|
|
||||||
"fal--ideogram-v4-instant": "Ideogram4InstantPipeline",
|
|
||||||
"comfy-org/ideogram-4": "Ideogram4Nvfp4Pipeline",
|
|
||||||
"comfy-org--ideogram-4": "Ideogram4Nvfp4Pipeline",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def load_diffusion_overlay_registry_from_env() -> dict[str, dict[str, Any]]:
|
def load_diffusion_overlay_registry_from_env() -> dict[str, dict[str, Any]]:
|
||||||
raw_value = os.getenv("SGLANG_DIFFUSION_MODEL_OVERLAY_REGISTRY", "").strip()
|
raw_value = os.getenv("SGLANG_DIFFUSION_MODEL_OVERLAY_REGISTRY", "").strip()
|
||||||
@@ -88,14 +69,6 @@ def has_diffusion_overlay_registry_match(
|
|||||||
return any(base_name == key.rsplit("/", 1)[-1] for key in registry)
|
return any(base_name == key.rsplit("/", 1)[-1] for key in registry)
|
||||||
|
|
||||||
|
|
||||||
def is_known_non_diffusers_diffusion_model(model_path: str) -> bool:
|
|
||||||
model_path_lower = model_path.lower()
|
|
||||||
return any(
|
|
||||||
pattern in model_path_lower
|
|
||||||
for pattern in KNOWN_NON_DIFFUSERS_DIFFUSION_MODEL_PATTERNS
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def execute_once(func):
|
def execute_once(func):
|
||||||
has_run = None
|
has_run = None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user