From 101bb2327cdebf310d5261775f00eaef13a2e168 Mon Sep 17 00:00:00 2001 From: TobyMint <130973409+TobyMint@users.noreply.github.com> Date: Tue, 4 Aug 2026 14:03:35 +0800 Subject: [PATCH] [diffusion] fix: fix local-path detection for MiniMax-H3 and other non-diffusers models (#33365) Co-authored-by: Mick --- python/sglang/cli/utils.py | 27 ++++++------ python/sglang/multimodal_gen/registry.py | 42 +++++++++++++++---- .../test/unit/test_server_args.py | 14 +++++++ python/sglang/utils.py | 27 ------------ 4 files changed, 60 insertions(+), 50 deletions(-) diff --git a/python/sglang/cli/utils.py b/python/sglang/cli/utils.py index bc3f5b3e8..62127c818 100644 --- a/python/sglang/cli/utils.py +++ b/python/sglang/cli/utils.py @@ -9,7 +9,6 @@ from huggingface_hub import HfApi from sglang.srt.environ import envs from sglang.utils import ( has_diffusion_overlay_registry_match, - is_known_non_diffusers_diffusion_model, 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()) -def _is_registered_diffusion_model(model_path: str) -> bool: +def _is_diffusion_model_from_registry(model_path: str) -> bool: 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: # if diffusion dependencies are not installed 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: @@ -59,8 +58,9 @@ def _is_gated_diffusion_repo(repo_id: str) -> bool: def get_is_diffusion_model(model_path: str) -> bool: """Detect whether model_path points to a diffusion model. - For local directories, checks the filesystem directly. - For HF/ModelScope model IDs, attempts to fetch only model_index.json. + For registered models, consults the diffusion registry first. + 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 metadata (library_name == "diffusers"). 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) 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 _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 + return _is_diffusers_model_dir(model_path) try: if envs.SGLANG_USE_MODELSCOPE.get(): diff --git a/python/sglang/multimodal_gen/registry.py b/python/sglang/multimodal_gen/registry.py index bb90c805d..8537f29a0 100644 --- a/python/sglang/multimodal_gen/registry.py +++ b/python/sglang/multimodal_gen/registry.py @@ -182,7 +182,6 @@ from sglang.multimodal_gen.runtime.utils.hf_diffusers_utils import ( maybe_download_model_index, ) 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__) @@ -289,6 +288,22 @@ _MODEL_HF_PATH_TO_NAME: Dict[str, str] = {} # Detectors to identify model families from paths or class names _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( sampling_param_cls: Any, @@ -1163,17 +1178,28 @@ _register_configs() def is_known_non_diffusers_multimodal_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 - ) + return get_non_diffusers_pipeline_name(model_path) is not None def get_non_diffusers_pipeline_name(model_path: str) -> Optional[str]: """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(): - 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 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 + ) diff --git a/python/sglang/multimodal_gen/test/unit/test_server_args.py b/python/sglang/multimodal_gen/test/unit/test_server_args.py index 7a94c276f..a0e650bfc 100644 --- a/python/sglang/multimodal_gen/test/unit/test_server_args.py +++ b/python/sglang/multimodal_gen/test/unit/test_server_args.py @@ -6,6 +6,7 @@ import unittest from contextlib import contextmanager from unittest.mock import patch +from sglang.cli.utils import get_is_diffusion_model from sglang.multimodal_gen.configs.models.fsdp import ( is_module_list_entry, is_module_list_entry_in, @@ -697,7 +698,16 @@ class TestWarmupImageIsModelValid(unittest.TestCase): 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): + def test_semantic_variants_map_to_checkpoint_partitions(self): self.assertEqual( MiniMaxH3Pipeline.model_subfolder_for_variant("fl2va"), "FL2VA" @@ -718,6 +728,10 @@ class TestMiniMaxH3Routing(unittest.TestCase): get_non_diffusers_pipeline_name("MiniMax/MiniMax-H3"), "MiniMaxH3Pipeline", ) + self.assertEqual( + get_non_diffusers_pipeline_name("/models/MiniMax-H3"), + "MiniMaxH3Pipeline", + ) class TestOffloadDefaults(unittest.TestCase): diff --git a/python/sglang/utils.py b/python/sglang/utils.py index 9fb40b019..568026dd5 100644 --- a/python/sglang/utils.py +++ b/python/sglang/utils.py @@ -31,25 +31,6 @@ from sglang.srt.environ import envs 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]]: 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) -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): has_run = None