[diffusion] refactor: remove component loader capability switches (#36824)
This commit is contained in:
@@ -27,12 +27,14 @@ class BridgeLoader(PlainStateDictComponentLoader):
|
||||
|
||||
component_names = ["dual_tower_bridge"]
|
||||
expected_library = "diffusers"
|
||||
supports_fsdp_inference = True
|
||||
|
||||
def load_customized(
|
||||
self, component_model_path: str, server_args: ServerArgs, component_name: str
|
||||
):
|
||||
config = self.load_component_config(component_model_path, component_name)
|
||||
component_weights_path = self.resolve_component_weights_path(
|
||||
component_model_path, server_args, component_name
|
||||
)
|
||||
hf_config = deepcopy(config)
|
||||
class_name = config.pop("_class_name", None)
|
||||
if class_name is None:
|
||||
@@ -60,9 +62,9 @@ class BridgeLoader(PlainStateDictComponentLoader):
|
||||
model_cls, _ = ModelRegistry.resolve_model_cls(class_name)
|
||||
|
||||
# Find all safetensors files
|
||||
safetensors_list = _list_safetensors_files(component_model_path)
|
||||
safetensors_list = _list_safetensors_files(component_weights_path)
|
||||
if not safetensors_list:
|
||||
raise ValueError(f"No safetensors files found in {component_model_path}")
|
||||
raise ValueError(f"No safetensors files found in {component_weights_path}")
|
||||
|
||||
default_dtype = resolve_precision(
|
||||
server_args, component_name, precision_attr="dit_precision"
|
||||
@@ -82,10 +84,14 @@ class BridgeLoader(PlainStateDictComponentLoader):
|
||||
|
||||
# Use the FSDP loader when FSDP is requested or shard rules are declared.
|
||||
fsdp_shard_conditions = getattr(model_cls, "_fsdp_shard_conditions", None)
|
||||
if use_fsdp or (
|
||||
if (
|
||||
component_weights_path != component_model_path
|
||||
or use_fsdp
|
||||
or (
|
||||
server_args.residency_mode(component_name) == RESIDENT
|
||||
and server_args.hsdp_shard_dim is not None
|
||||
and fsdp_shard_conditions
|
||||
)
|
||||
):
|
||||
local_torch_device = get_local_torch_device()
|
||||
# Load with FSDP support
|
||||
|
||||
+136
-76
@@ -131,18 +131,6 @@ class ComponentLoader(ABC):
|
||||
# diffusers or transformers
|
||||
expected_library: str = ""
|
||||
|
||||
# --attention-backend primarily selects the DiT backend. Auxiliary
|
||||
# components may fall back when that global choice is incompatible; an
|
||||
# explicit --component-attention-backends entry remains strict.
|
||||
allow_global_attention_backend_fallback = True
|
||||
# Gates only --component-quantizations.<name>. Quantization declared by a
|
||||
# checkpoint is discovered and admitted by the component's normal loader.
|
||||
supports_online_quantization_override = False
|
||||
# Gates only --component-direct-gpu-weight-loading.<name>. The checkpoint
|
||||
# source stays component-specific because its streaming ABI is loader-owned.
|
||||
supports_direct_gpu_weight_loading = False
|
||||
supports_fsdp_inference = False
|
||||
|
||||
_loaders_registered = False
|
||||
|
||||
def __init_subclass__(cls, **kwargs):
|
||||
@@ -194,10 +182,56 @@ class ComponentLoader(ABC):
|
||||
)
|
||||
return None
|
||||
|
||||
def supports_direct_gpu_weight_loading_for_component(
|
||||
self, _component_name: str
|
||||
def resolve_component_weight_override(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
) -> str | None:
|
||||
"""Return the consumed weights-only override or reject it."""
|
||||
override = server_args.component_weights_paths.get(component_name)
|
||||
if override is not None:
|
||||
raise ComponentCheckpointUnsupportedError(
|
||||
f"{component_name!r} does not support a weights-only override; "
|
||||
f"use --component-paths.{component_name} to replace its config "
|
||||
"and weights together"
|
||||
)
|
||||
return None
|
||||
|
||||
def resolve_component_quantization_override(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
) -> str | None:
|
||||
"""Return the consumed online quantization override or reject it."""
|
||||
quantization = server_args.component_quantizations.get(component_name)
|
||||
if quantization is not None:
|
||||
raise ComponentCheckpointUnsupportedError(
|
||||
f"{component_name!r} does not support an explicit quantization "
|
||||
"override; use a self-describing quantized component checkpoint "
|
||||
"when supported"
|
||||
)
|
||||
return None
|
||||
|
||||
def resolve_component_direct_gpu_loading(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
) -> bool:
|
||||
return self.supports_direct_gpu_weight_loading
|
||||
"""Return whether this load consumes the exact direct-GPU request."""
|
||||
requested = server_args.should_direct_gpu_weight_load_component(component_name)
|
||||
if requested:
|
||||
raise ComponentCheckpointUnsupportedError(
|
||||
f"{component_name!r} does not support direct GPU weight loading"
|
||||
)
|
||||
return False
|
||||
|
||||
def component_attention_backend_context(
|
||||
self,
|
||||
attn_backend: Any,
|
||||
component_attn_name: str | None,
|
||||
require_backend_selection: bool,
|
||||
):
|
||||
"""Build the attention-selection context used by this loader."""
|
||||
return component_attn_backend_context_manager(
|
||||
attn_backend,
|
||||
component_name=component_attn_name,
|
||||
allow_global_backend_fallback=True,
|
||||
require_backend_selection=require_backend_selection,
|
||||
)
|
||||
|
||||
def is_native_only_component(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
@@ -223,15 +257,6 @@ class ComponentLoader(ABC):
|
||||
"""Validate that fallback preserves the exact component's runtime contract."""
|
||||
pass
|
||||
|
||||
def disable_unsupported_component_fsdp(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
) -> None:
|
||||
if (
|
||||
not self.supports_fsdp_inference
|
||||
and server_args.should_use_fsdp_for_component(component_name)
|
||||
):
|
||||
server_args.disable_fsdp_for_component(component_name)
|
||||
|
||||
def _load_customized_with_context(
|
||||
self,
|
||||
component_model_path: str,
|
||||
@@ -239,14 +264,12 @@ class ComponentLoader(ABC):
|
||||
component_name: str,
|
||||
attn_backend: Any,
|
||||
component_attn_name: str | None,
|
||||
allow_global_backend_fallback: bool,
|
||||
require_backend_selection: bool,
|
||||
) -> AutoModel:
|
||||
with component_attn_backend_context_manager(
|
||||
with self.component_attention_backend_context(
|
||||
attn_backend,
|
||||
component_name=component_attn_name,
|
||||
allow_global_backend_fallback=allow_global_backend_fallback,
|
||||
require_backend_selection=require_backend_selection,
|
||||
component_attn_name,
|
||||
require_backend_selection,
|
||||
):
|
||||
load_kwargs = self.customized_load_kwargs_for_component(
|
||||
server_args, component_name
|
||||
@@ -263,14 +286,12 @@ class ComponentLoader(ABC):
|
||||
transformers_or_diffusers: str,
|
||||
attn_backend: Any,
|
||||
component_attn_name: str | None,
|
||||
allow_global_backend_fallback: bool,
|
||||
require_backend_selection: bool,
|
||||
) -> AutoModel:
|
||||
with component_attn_backend_context_manager(
|
||||
with self.component_attention_backend_context(
|
||||
attn_backend,
|
||||
component_name=component_attn_name,
|
||||
allow_global_backend_fallback=allow_global_backend_fallback,
|
||||
require_backend_selection=require_backend_selection,
|
||||
component_attn_name,
|
||||
require_backend_selection,
|
||||
):
|
||||
component = self.load_native(
|
||||
component_model_path,
|
||||
@@ -300,23 +321,12 @@ class ComponentLoader(ABC):
|
||||
"""
|
||||
self._native_load_manages_placement = False
|
||||
self.component_load_precision(server_args, component_name)
|
||||
if server_args.should_direct_gpu_weight_load_component(
|
||||
component_name
|
||||
) and not self.supports_direct_gpu_weight_loading_for_component(component_name):
|
||||
raise ComponentCheckpointUnsupportedError(
|
||||
f"{component_name!r} does not support direct GPU weight loading"
|
||||
)
|
||||
self.disable_unsupported_component_fsdp(server_args, component_name)
|
||||
component_quantization = server_args.component_quantizations.get(component_name)
|
||||
if (
|
||||
component_quantization is not None
|
||||
and not self.supports_online_quantization_override
|
||||
):
|
||||
raise ValueError(
|
||||
f"{component_name!r} does not support an explicit quantization "
|
||||
"override; "
|
||||
"use a self-describing quantized component checkpoint when supported"
|
||||
component_weight_override = self.resolve_component_weight_override(
|
||||
server_args, component_name
|
||||
)
|
||||
self.resolve_component_quantization_override(server_args, component_name)
|
||||
self.resolve_component_direct_gpu_loading(server_args, component_name)
|
||||
fsdp_requested = server_args.should_use_fsdp_for_component(component_name)
|
||||
|
||||
gpu_mem_before_loading = current_platform.get_available_gpu_memory()
|
||||
logger.info(
|
||||
@@ -361,7 +371,6 @@ class ComponentLoader(ABC):
|
||||
component_name,
|
||||
component_attn_backend,
|
||||
component_attn_name,
|
||||
self.allow_global_attention_backend_fallback,
|
||||
require_backend_selection,
|
||||
)
|
||||
source = "sgl-diffusion"
|
||||
@@ -375,9 +384,26 @@ class ComponentLoader(ABC):
|
||||
if require_backend_selection:
|
||||
raise
|
||||
native_loader_required = isinstance(e, NativeComponentLoaderRequired)
|
||||
if self.should_raise_customized_load_error(server_args, component_name):
|
||||
if native_loader_required and component_weight_override is not None:
|
||||
raise ComponentCheckpointUnsupportedError(
|
||||
f"{component_name!r} requires its library loader, which cannot "
|
||||
"consume a weights-only override; use "
|
||||
f"--component-paths.{component_name} to replace its config "
|
||||
"and weights together"
|
||||
) from e
|
||||
if (
|
||||
component_weight_override is not None
|
||||
or self.should_raise_customized_load_error(server_args, component_name)
|
||||
):
|
||||
if native_loader_required:
|
||||
raise
|
||||
if component_weight_override is not None:
|
||||
raise RuntimeError(
|
||||
f"Failed to load the weights-only override for "
|
||||
f"{component_name!r}; fallback would ignore it. Use "
|
||||
f"--component-paths.{component_name} when the checkpoint "
|
||||
"also requires a different config or library loader."
|
||||
) from e
|
||||
traceback.print_exc()
|
||||
raise RuntimeError(
|
||||
f"Failed to load customized {component_name}; native fallback "
|
||||
@@ -403,7 +429,6 @@ class ComponentLoader(ABC):
|
||||
transformers_or_diffusers,
|
||||
component_attn_backend,
|
||||
component_attn_name,
|
||||
self.allow_global_attention_backend_fallback,
|
||||
require_backend_selection,
|
||||
)
|
||||
source = "native"
|
||||
@@ -417,6 +442,13 @@ class ComponentLoader(ABC):
|
||||
logger.error("Load %s failed", component_name)
|
||||
consumed = 0.0
|
||||
else:
|
||||
if fsdp_requested and (
|
||||
not isinstance(component, nn.Module)
|
||||
or not is_fsdp_managed_module(component)
|
||||
):
|
||||
# The returned module is the source of truth. Loaders do not need
|
||||
# a parallel capability declaration for FSDP support.
|
||||
server_args.disable_fsdp_for_component(component_name)
|
||||
if isinstance(component, nn.Module):
|
||||
component = component.eval()
|
||||
if (
|
||||
@@ -492,11 +524,6 @@ class ComponentLoader(ABC):
|
||||
resolved_component_name,
|
||||
feature_name="Transformers quantized component",
|
||||
)
|
||||
if server_args.should_use_fsdp_for_component(resolved_component_name):
|
||||
raise ComponentCheckpointUnsupportedError(
|
||||
"Transformers-managed quantized components do not support "
|
||||
"SGLang FSDP loading"
|
||||
)
|
||||
load_kwargs["device_map"] = {
|
||||
"": self.target_device(component_starts_on_cpu=False)
|
||||
}
|
||||
@@ -648,7 +675,42 @@ class ComponentLoader(ABC):
|
||||
return loader
|
||||
|
||||
|
||||
class PlainStateDictComponentLoader(ComponentLoader):
|
||||
class WeightOverrideComponentLoader(ComponentLoader):
|
||||
"""Base for loaders that consume an exact weights-only override."""
|
||||
|
||||
def resolve_component_weight_override(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
) -> str | None:
|
||||
return server_args.component_weights_paths.get(component_name)
|
||||
|
||||
def validate_component_weight_override(self, _override: str) -> None:
|
||||
pass
|
||||
|
||||
def resolve_component_weights_path(
|
||||
self,
|
||||
component_model_path: str,
|
||||
server_args: ServerArgs,
|
||||
component_name: str,
|
||||
) -> str:
|
||||
override = self.resolve_component_weight_override(server_args, component_name)
|
||||
if override is None:
|
||||
return component_model_path
|
||||
self.validate_component_weight_override(override)
|
||||
weights_path = materialize_weight(resolve_weight(override))
|
||||
logger.info("Using weight override for %s: %s", component_name, weights_path)
|
||||
return weights_path
|
||||
|
||||
|
||||
class OnlineQuantizationComponentLoader(WeightOverrideComponentLoader):
|
||||
"""Base for loaders that also consume an online quantization override."""
|
||||
|
||||
def resolve_component_quantization_override(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
) -> str | None:
|
||||
return server_args.component_quantizations.get(component_name)
|
||||
|
||||
|
||||
class PlainStateDictComponentLoader(WeightOverrideComponentLoader):
|
||||
"""Base for native loaders whose current materializer expects plain weights."""
|
||||
|
||||
def component_load_precision(
|
||||
@@ -682,19 +744,6 @@ class PlainStateDictComponentLoader(ComponentLoader):
|
||||
self.ensure_plain_state_dict_checkpoint(config, component_name)
|
||||
return config
|
||||
|
||||
def resolve_component_weights_path(
|
||||
self,
|
||||
component_model_path: str,
|
||||
server_args: ServerArgs,
|
||||
component_name: str,
|
||||
) -> str:
|
||||
override = server_args.component_weights_paths.get(component_name)
|
||||
if override is None:
|
||||
return component_model_path
|
||||
weights_path = materialize_weight(resolve_weight(override))
|
||||
logger.info("Using weight override for %s: %s", component_name, weights_path)
|
||||
return weights_path
|
||||
|
||||
|
||||
class ImageProcessorLoader(ComponentLoader):
|
||||
"""Loader for image processor."""
|
||||
@@ -769,10 +818,6 @@ class TokenizerLoader(ComponentLoader):
|
||||
class GenericComponentLoader(ComponentLoader):
|
||||
"""Generic loader for components that don't have a specific loader."""
|
||||
|
||||
# An unknown out-of-tree component may itself be the primary transformer.
|
||||
# Require it to opt into fallback through a registered component loader.
|
||||
allow_global_attention_backend_fallback = False
|
||||
|
||||
def __init__(
|
||||
self, library="transformers", component_architecture: str | None = None
|
||||
) -> None:
|
||||
@@ -780,6 +825,21 @@ class GenericComponentLoader(ComponentLoader):
|
||||
self.library = library
|
||||
self.component_architecture = component_architecture
|
||||
|
||||
def component_attention_backend_context(
|
||||
self,
|
||||
attn_backend: Any,
|
||||
component_attn_name: str | None,
|
||||
require_backend_selection: bool,
|
||||
):
|
||||
# An unknown out-of-tree component may itself be the primary transformer.
|
||||
# Require it to opt into fallback through a registered component loader.
|
||||
return component_attn_backend_context_manager(
|
||||
attn_backend,
|
||||
component_name=component_attn_name,
|
||||
allow_global_backend_fallback=False,
|
||||
require_backend_selection=require_backend_selection,
|
||||
)
|
||||
|
||||
|
||||
class PipelineComponentLoader:
|
||||
"""
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ class ImageEncoderLoader(TextEncoderLoader):
|
||||
component_name: str = "image_encoder",
|
||||
):
|
||||
"""Load the text encoders based on the model path, and inference args."""
|
||||
component_weights_path = self.resolve_model_weights_path(
|
||||
component_weights_path = self.resolve_component_weights_path(
|
||||
component_model_path,
|
||||
server_args,
|
||||
component_name,
|
||||
|
||||
+9
-31
@@ -56,8 +56,8 @@ from sglang.multimodal_gen.runtime.layers.quantization.quanto_int8 import (
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders.component_loader import (
|
||||
ComponentCheckpointUnsupportedError,
|
||||
ComponentLoader,
|
||||
NativeComponentLoaderRequired,
|
||||
OnlineQuantizationComponentLoader,
|
||||
uses_native_transformers_quantization,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.gguf_weights import (
|
||||
@@ -102,10 +102,6 @@ from sglang.multimodal_gen.runtime.utils.quantization_utils import (
|
||||
inspect_comfy_quant_markers,
|
||||
resolve_comfy_checkpoint_quantization,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.weights.source import (
|
||||
materialize_weight,
|
||||
resolve_weight,
|
||||
)
|
||||
from sglang.multimodal_gen.utils import PRECISION_TO_TYPE
|
||||
from sglang.srt.environ import envs
|
||||
from sglang.srt.layers.linear import LinearBase as SrtLinearBase
|
||||
@@ -265,7 +261,10 @@ def _configure_encoder_quantization(
|
||||
explicit_quantization: str | None = None,
|
||||
ignored_layers: list[str] | None = None,
|
||||
) -> None:
|
||||
if getattr(model_cls, "manages_checkpoint_quantization", False):
|
||||
if (
|
||||
issubclass(model_cls, EncoderTensorParallelMixin)
|
||||
and model_cls.checkpoint_quantization_backend == "model"
|
||||
):
|
||||
if explicit_quantization is not None:
|
||||
raise ComponentCheckpointUnsupportedError(
|
||||
f"{component_name!r} manages its own checkpoint quantization and "
|
||||
@@ -493,12 +492,11 @@ def _keep_this_checkpoint_mapped(model_path: str) -> bool:
|
||||
return True
|
||||
|
||||
|
||||
class TextEncoderLoader(ComponentLoader):
|
||||
class TextEncoderLoader(OnlineQuantizationComponentLoader):
|
||||
"""Loader for text encoders."""
|
||||
|
||||
component_names = ["text_encoder"]
|
||||
expected_library = "transformers"
|
||||
supports_online_quantization_override = True
|
||||
|
||||
def component_load_precision(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
@@ -518,33 +516,13 @@ class TextEncoderLoader(ComponentLoader):
|
||||
or component_name in server_args.component_quantizations
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def resolve_model_weights_path(
|
||||
component_model_path: str,
|
||||
server_args: ServerArgs,
|
||||
component_name: str,
|
||||
) -> str:
|
||||
weights_override = server_args.component_weights_paths.get(component_name)
|
||||
if weights_override is None:
|
||||
return component_model_path
|
||||
if names_gguf_checkpoint(weights_override):
|
||||
def validate_component_weight_override(self, override: str) -> None:
|
||||
if names_gguf_checkpoint(override):
|
||||
if not current_platform.is_cuda():
|
||||
raise ValueError(
|
||||
"GGUF encoder checkpoints require CUDA; the GGML kernels have "
|
||||
f"no {current_platform.device_type} implementation"
|
||||
)
|
||||
if server_args.should_use_fsdp_for_component(component_name):
|
||||
raise ValueError(
|
||||
f"GGUF encoder checkpoint {component_name!r} is incompatible "
|
||||
"with FSDP; select resident or layerwise placement"
|
||||
)
|
||||
model_weights_path = materialize_weight(resolve_weight(weights_override))
|
||||
logger.info(
|
||||
"Using weight-file override for %s: %s",
|
||||
component_name,
|
||||
model_weights_path,
|
||||
)
|
||||
return model_weights_path
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Source:
|
||||
@@ -731,7 +709,7 @@ class TextEncoderLoader(ComponentLoader):
|
||||
component_starts_on_cpu: bool | None = None,
|
||||
):
|
||||
"""Load the text encoders based on the model path, and inference args."""
|
||||
component_weights_path = self.resolve_model_weights_path(
|
||||
component_weights_path = self.resolve_component_weights_path(
|
||||
component_model_path,
|
||||
server_args,
|
||||
component_name,
|
||||
|
||||
+15
-6
@@ -13,7 +13,7 @@ from sglang.multimodal_gen.runtime.layers.attention.selector import (
|
||||
get_global_forced_attn_backend,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders.component_loader import (
|
||||
ComponentLoader,
|
||||
OnlineQuantizationComponentLoader,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.fsdp_load import maybe_load_fsdp_model
|
||||
from sglang.multimodal_gen.runtime.loader.gguf_weights import gguf_weights_iterator
|
||||
@@ -152,13 +152,9 @@ def _server_args_for_transformer_component(
|
||||
return component_server_args
|
||||
|
||||
|
||||
class TransformerLoader(ComponentLoader):
|
||||
class TransformerLoader(OnlineQuantizationComponentLoader):
|
||||
"""Shared loader for (video/audio) DiT transformers."""
|
||||
|
||||
allow_global_attention_backend_fallback = False
|
||||
supports_online_quantization_override = True
|
||||
supports_fsdp_inference = True
|
||||
|
||||
component_names = [
|
||||
"transformer",
|
||||
"unconditional_transformer",
|
||||
@@ -167,6 +163,19 @@ class TransformerLoader(ComponentLoader):
|
||||
]
|
||||
expected_library = "diffusers"
|
||||
|
||||
def component_attention_backend_context(
|
||||
self,
|
||||
attn_backend,
|
||||
component_attn_name: str | None,
|
||||
require_backend_selection: bool,
|
||||
):
|
||||
return component_attn_backend_context_manager(
|
||||
attn_backend,
|
||||
component_name=component_attn_name,
|
||||
allow_global_backend_fallback=False,
|
||||
require_backend_selection=require_backend_selection,
|
||||
)
|
||||
|
||||
def customized_load_kwargs_for_component(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
) -> dict[str, bool]:
|
||||
|
||||
@@ -198,7 +198,6 @@ def _load_explicit_config(
|
||||
class UpsamplerLoader(PlainStateDictComponentLoader):
|
||||
component_names = ["spatial_upsampler"]
|
||||
expected_library = "diffusers"
|
||||
supports_component_weight_override = True
|
||||
|
||||
def load_customized(
|
||||
self,
|
||||
|
||||
@@ -15,8 +15,8 @@ from sglang.multimodal_gen.configs.pipeline_configs.qwen_image import (
|
||||
from sglang.multimodal_gen.configs.pipeline_configs.wan import WanT2V480PConfig
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders.component_loader import (
|
||||
ComponentCheckpointUnsupportedError,
|
||||
ComponentLoader,
|
||||
NativeComponentLoaderRequired,
|
||||
WeightOverrideComponentLoader,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.utils import (
|
||||
_list_safetensors_files,
|
||||
@@ -42,10 +42,6 @@ from sglang.multimodal_gen.runtime.utils.precision import (
|
||||
resolve_component_precision,
|
||||
resolve_decode_precision,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.weights.source import (
|
||||
materialize_weight,
|
||||
resolve_weight,
|
||||
)
|
||||
from sglang.multimodal_gen.utils import PRECISION_TO_TYPE
|
||||
from sglang.srt.model_loader.checkpoint_quantization import (
|
||||
resolve_checkpoint_quant_spec,
|
||||
@@ -393,17 +389,21 @@ def _assign_direct_gpu_vae_state(
|
||||
)
|
||||
|
||||
|
||||
class VAELoader(ComponentLoader):
|
||||
class VAELoader(WeightOverrideComponentLoader):
|
||||
"""Shared loader for (video/audio) VAE modules."""
|
||||
|
||||
component_names = ["vae", "audio_vae", "video_vae"]
|
||||
expected_library = "diffusers"
|
||||
supports_direct_gpu_weight_loading = True
|
||||
|
||||
def supports_direct_gpu_weight_loading_for_component(
|
||||
self, component_name: str
|
||||
def resolve_component_direct_gpu_loading(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
) -> bool:
|
||||
return component_name in ("vae", "video_vae")
|
||||
requested = server_args.should_direct_gpu_weight_load_component(component_name)
|
||||
if requested and component_name not in ("vae", "video_vae"):
|
||||
raise ComponentCheckpointUnsupportedError(
|
||||
f"Direct GPU loading is not implemented for {component_name!r}"
|
||||
)
|
||||
return requested
|
||||
|
||||
def select_weight_files(
|
||||
self,
|
||||
@@ -425,25 +425,6 @@ class VAELoader(ComponentLoader):
|
||||
) -> str | None:
|
||||
return server_args.component_precisions.get(component_name)
|
||||
|
||||
@staticmethod
|
||||
def resolve_model_weights_path(
|
||||
component_model_path: str,
|
||||
server_args: ServerArgs,
|
||||
component_name: str,
|
||||
) -> str:
|
||||
weights_override = getattr(server_args, "component_weights_paths", {}).get(
|
||||
component_name
|
||||
)
|
||||
if weights_override is None:
|
||||
return component_model_path
|
||||
model_weights_path = materialize_weight(resolve_weight(weights_override))
|
||||
logger.info(
|
||||
"Using weight-file override for %s: %s",
|
||||
component_name,
|
||||
model_weights_path,
|
||||
)
|
||||
return model_weights_path
|
||||
|
||||
def customized_load_kwargs_for_component(
|
||||
self, server_args: ServerArgs, component_name: str
|
||||
) -> dict[str, bool]:
|
||||
@@ -467,14 +448,10 @@ class VAELoader(ComponentLoader):
|
||||
cpu_offload_flag: bool = False,
|
||||
):
|
||||
"""Load the VAE based on the model path, and inference args."""
|
||||
direct_gpu_weight_loading = server_args.should_direct_gpu_weight_load_component(
|
||||
component_name
|
||||
direct_gpu_weight_loading = self.resolve_component_direct_gpu_loading(
|
||||
server_args, component_name
|
||||
)
|
||||
if direct_gpu_weight_loading and component_name not in ("vae", "video_vae"):
|
||||
raise ComponentCheckpointUnsupportedError(
|
||||
f"Direct GPU loading is not implemented for {component_name!r}"
|
||||
)
|
||||
component_weights_path = self.resolve_model_weights_path(
|
||||
component_weights_path = self.resolve_component_weights_path(
|
||||
component_model_path,
|
||||
server_args,
|
||||
component_name,
|
||||
|
||||
@@ -160,9 +160,6 @@ class EncoderTensorParallelMixin:
|
||||
_encoder_tp_group: GroupCoordinator | None = None
|
||||
checkpoint_quantization_backend = "diffusion"
|
||||
packed_modules_mapping: dict[str, list[str]] = {}
|
||||
# Some encoders own checkpoint quantization end to end because their weight
|
||||
# states or sharding contract cannot use the generic loader lifecycle.
|
||||
manages_checkpoint_quantization = False
|
||||
|
||||
@staticmethod
|
||||
def should_materialize_checkpoint_weight(name: str) -> bool:
|
||||
@@ -196,9 +193,6 @@ class TextEncoder(
|
||||
# Qwen2_5_VLCausalLMOutputWithPast). Off by default so a new encoder is
|
||||
# replicated rather than silently broken; flip it once dp is verified there.
|
||||
supports_dp_encode = False
|
||||
# Some encoders own checkpoint quantization end to end because their weight
|
||||
# states or sharding contract cannot use the generic loader lifecycle.
|
||||
manages_checkpoint_quantization = False
|
||||
layerwise_offload_dit_group_enabled = False
|
||||
layer_names = [
|
||||
"layers",
|
||||
|
||||
@@ -25,7 +25,7 @@ from sglang.multimodal_gen.runtime.models.encoders.qwen3vl import Qwen3VLTextMod
|
||||
class IdeogramQwen3VLTextEncoder(TextEncoder):
|
||||
"""Language-only Qwen3-VL text encoder stored inside Ideogram checkpoints."""
|
||||
|
||||
manages_checkpoint_quantization = True
|
||||
checkpoint_quantization_backend = "model"
|
||||
_activation_layers = (0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 35)
|
||||
layer_names = ["language_model.layers"]
|
||||
|
||||
|
||||
@@ -1788,16 +1788,7 @@ class ServerArgs(DisaggServerArgsMixin):
|
||||
component_paths: dict[str, str] = {}
|
||||
component_weights_paths = dict(self.component_weights_paths)
|
||||
for component, path in self.component_paths.items():
|
||||
supports_weight_file_override = (
|
||||
is_dit_component_name(component)
|
||||
or is_text_encoder_component_name(component)
|
||||
or is_image_encoder_component_name(component)
|
||||
or is_vae_component_name(component)
|
||||
)
|
||||
if (
|
||||
not supports_weight_file_override
|
||||
or not is_explicit_weight_file_reference(path)
|
||||
):
|
||||
if not is_explicit_weight_file_reference(path):
|
||||
component_paths[component] = path
|
||||
continue
|
||||
existing = component_weights_paths.get(component)
|
||||
|
||||
@@ -332,9 +332,24 @@ class TestComponentAttentionBackendScope(unittest.TestCase):
|
||||
captured_context = get_component_attn_backend_context()
|
||||
return object()
|
||||
|
||||
def component_attention_backend_context(
|
||||
self,
|
||||
attn_backend,
|
||||
component_attn_name: str | None,
|
||||
require_backend_selection: bool,
|
||||
):
|
||||
return component_attn_backend_context_manager(
|
||||
attn_backend,
|
||||
component_name=component_attn_name,
|
||||
allow_global_backend_fallback=allow_global_backend_fallback,
|
||||
require_backend_selection=require_backend_selection,
|
||||
)
|
||||
|
||||
class _Args:
|
||||
component_precisions = {}
|
||||
component_quantizations = {}
|
||||
component_weights_paths = {}
|
||||
pipeline_config = SimpleNamespace(native_only_components=())
|
||||
|
||||
@staticmethod
|
||||
def requested_component_attention_backend(_component_name):
|
||||
@@ -348,7 +363,6 @@ class TestComponentAttentionBackendScope(unittest.TestCase):
|
||||
def should_use_fsdp_for_component(_component_name):
|
||||
return False
|
||||
|
||||
_Loader.allow_global_attention_backend_fallback = allow_global_backend_fallback
|
||||
with (
|
||||
patch.object(ComponentLoader, "for_component_type", return_value=_Loader()),
|
||||
patch(
|
||||
@@ -378,10 +392,22 @@ class TestComponentAttentionBackendScope(unittest.TestCase):
|
||||
self.assertFalse(context.allow_global_backend_fallback)
|
||||
|
||||
def test_builtin_loader_scopes(self):
|
||||
self.assertFalse(TransformerLoader.allow_global_attention_backend_fallback)
|
||||
self.assertFalse(GenericComponentLoader.allow_global_attention_backend_fallback)
|
||||
self.assertTrue(TextEncoderLoader.allow_global_attention_backend_fallback)
|
||||
self.assertTrue(VAELoader.allow_global_attention_backend_fallback)
|
||||
cases = (
|
||||
(TransformerLoader(), "transformer", False),
|
||||
(GenericComponentLoader(), "custom", False),
|
||||
(TextEncoderLoader(), "text_encoder", True),
|
||||
(VAELoader(), "vae", True),
|
||||
)
|
||||
for loader, component_name, expected_fallback in cases:
|
||||
with (
|
||||
self.subTest(loader=loader.__class__.__name__),
|
||||
loader.component_attention_backend_context(None, component_name, False),
|
||||
):
|
||||
context = get_component_attn_backend_context()
|
||||
self.assertIsNotNone(context)
|
||||
self.assertEqual(
|
||||
context.allow_global_backend_fallback, expected_fallback
|
||||
)
|
||||
|
||||
def test_explicit_backend_must_be_consumed(self):
|
||||
with self.assertRaisesRegex(
|
||||
@@ -414,6 +440,8 @@ class TestComponentAttentionBackendScope(unittest.TestCase):
|
||||
class _Args:
|
||||
component_precisions = {}
|
||||
component_quantizations = {}
|
||||
component_weights_paths = {}
|
||||
pipeline_config = SimpleNamespace(native_only_components=())
|
||||
|
||||
@staticmethod
|
||||
def requested_component_attention_backend(_component_name):
|
||||
@@ -479,6 +507,7 @@ class TestComponentAttentionBackendScope(unittest.TestCase):
|
||||
class _Args:
|
||||
component_precisions = {}
|
||||
component_quantizations = {}
|
||||
component_weights_paths = {}
|
||||
pipeline_config = SimpleNamespace(native_only_components=())
|
||||
|
||||
@staticmethod
|
||||
@@ -530,6 +559,7 @@ class TestComponentAttentionBackendScope(unittest.TestCase):
|
||||
class _Args:
|
||||
component_precisions = {}
|
||||
component_quantizations = {}
|
||||
component_weights_paths = {}
|
||||
pipeline_config = SimpleNamespace(native_only_components=())
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -5,6 +5,9 @@ import unittest
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
import torch
|
||||
from torch import nn
|
||||
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders.adapter_loader import (
|
||||
AdapterLoader,
|
||||
)
|
||||
@@ -14,6 +17,7 @@ from sglang.multimodal_gen.runtime.loader.component_loaders.bridge_loader import
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders.component_loader import (
|
||||
ComponentCheckpointUnsupportedError,
|
||||
ComponentLoader,
|
||||
NativeComponentLoaderRequired,
|
||||
PlainStateDictComponentLoader,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders.diffusion_decoder_loader import (
|
||||
@@ -38,6 +42,42 @@ class _TestLoader(PlainStateDictComponentLoader):
|
||||
pass
|
||||
|
||||
|
||||
class _WeightOverrideLoader(PlainStateDictComponentLoader):
|
||||
def __init__(self, error: Exception):
|
||||
super().__init__()
|
||||
self.error = error
|
||||
self.native_called = False
|
||||
|
||||
def load_customized(self, *args, **kwargs):
|
||||
raise self.error
|
||||
|
||||
def load_native(self, *args, **kwargs):
|
||||
self.native_called = True
|
||||
return object()
|
||||
|
||||
|
||||
class _ModuleLoader(ComponentLoader):
|
||||
def load_customized(self, *args, **kwargs):
|
||||
return nn.Linear(1, 1)
|
||||
|
||||
|
||||
def _loader_server_args(component_weights_paths, *, fsdp_requested=False):
|
||||
disabled_components = set()
|
||||
return SimpleNamespace(
|
||||
component_precisions={},
|
||||
component_quantizations={},
|
||||
component_weights_paths=component_weights_paths,
|
||||
pipeline_config=SimpleNamespace(native_only_components=()),
|
||||
resolve_component_attention_backend=lambda _name: (None, None),
|
||||
requested_component_attention_backend=lambda _name: None,
|
||||
should_direct_gpu_weight_load_component=lambda _name: False,
|
||||
should_start_component_on_cpu=lambda _name: True,
|
||||
should_use_fsdp_for_component=lambda _name: fsdp_requested,
|
||||
disable_fsdp_for_component=lambda name: disabled_components.add(name),
|
||||
disabled_components=disabled_components,
|
||||
)
|
||||
|
||||
|
||||
class TestComponentQuantizationAdmission(unittest.TestCase):
|
||||
def test_plain_loader_admits_its_exact_precision(self):
|
||||
server_args = SimpleNamespace(component_precisions={"vocoder": "fp16"})
|
||||
@@ -60,6 +100,7 @@ class TestComponentQuantizationAdmission(unittest.TestCase):
|
||||
server_args = SimpleNamespace(
|
||||
component_precisions={},
|
||||
component_quantizations={},
|
||||
component_weights_paths={},
|
||||
should_direct_gpu_weight_load_component=lambda component: component
|
||||
== "vocoder",
|
||||
)
|
||||
@@ -75,12 +116,14 @@ class TestComponentQuantizationAdmission(unittest.TestCase):
|
||||
server_args = SimpleNamespace(
|
||||
component_precisions={},
|
||||
component_quantizations={},
|
||||
component_weights_paths={},
|
||||
should_direct_gpu_weight_load_component=lambda component: component
|
||||
== "audio_vae",
|
||||
)
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
ComponentCheckpointUnsupportedError, "does not support direct GPU"
|
||||
ComponentCheckpointUnsupportedError,
|
||||
"Direct GPU loading is not implemented",
|
||||
):
|
||||
VAELoader().load("/model/audio_vae", server_args, "audio_vae", "diffusers")
|
||||
|
||||
@@ -107,6 +150,71 @@ class TestComponentQuantizationAdmission(unittest.TestCase):
|
||||
"/cache/vocoder.safetensors",
|
||||
)
|
||||
|
||||
def test_unsupported_loader_rejects_weight_override_before_loading(self):
|
||||
server_args = _loader_server_args({"pe": "/weights/model.safetensors"})
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
ComponentCheckpointUnsupportedError,
|
||||
r"--component-paths\.pe.*config and weights",
|
||||
):
|
||||
ComponentLoader().load("/base/pe", server_args, "pe", "transformers")
|
||||
|
||||
def test_weight_override_failure_never_falls_back_to_base_component(self):
|
||||
loader = _WeightOverrideLoader(ValueError("incompatible checkpoint"))
|
||||
server_args = _loader_server_args(
|
||||
{"text_encoder": "/weights/model.safetensors"}
|
||||
)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"sglang.multimodal_gen.runtime.loader.component_loaders."
|
||||
"component_loader.current_platform.get_available_gpu_memory",
|
||||
return_value=10.0,
|
||||
),
|
||||
self.assertRaisesRegex(RuntimeError, "fallback would ignore it"),
|
||||
):
|
||||
loader.load(
|
||||
"/base/text_encoder", server_args, "text_encoder", "transformers"
|
||||
)
|
||||
|
||||
self.assertFalse(loader.native_called)
|
||||
|
||||
def test_library_fallback_requires_a_complete_component_override(self):
|
||||
loader = _WeightOverrideLoader(
|
||||
NativeComponentLoaderRequired("delegate to Transformers")
|
||||
)
|
||||
server_args = _loader_server_args(
|
||||
{"text_encoder": "/weights/model.safetensors"}
|
||||
)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"sglang.multimodal_gen.runtime.loader.component_loaders."
|
||||
"component_loader.current_platform.get_available_gpu_memory",
|
||||
return_value=10.0,
|
||||
),
|
||||
self.assertRaisesRegex(
|
||||
ComponentCheckpointUnsupportedError,
|
||||
r"--component-paths\.text_encoder.*config and weights",
|
||||
),
|
||||
):
|
||||
loader.load(
|
||||
"/base/text_encoder", server_args, "text_encoder", "transformers"
|
||||
)
|
||||
|
||||
self.assertFalse(loader.native_called)
|
||||
|
||||
def test_materialized_module_decides_fsdp_support(self):
|
||||
server_args = _loader_server_args({}, fsdp_requested=True)
|
||||
with patch(
|
||||
"sglang.multimodal_gen.runtime.loader.component_loaders."
|
||||
"component_loader.current_platform.get_available_gpu_memory",
|
||||
side_effect=(10.0, 9.0),
|
||||
):
|
||||
_ModuleLoader().load("/base/module", server_args, "module", "diffusers")
|
||||
|
||||
self.assertEqual(server_args.disabled_components, {"module"})
|
||||
|
||||
def test_plain_checkpoint_config_is_accepted(self):
|
||||
config = {"_class_name": "TestModel"}
|
||||
|
||||
@@ -119,6 +227,76 @@ class TestComponentQuantizationAdmission(unittest.TestCase):
|
||||
|
||||
self.assertIs(loaded, config)
|
||||
|
||||
def test_bridge_consumes_exact_component_weight_override(self):
|
||||
loader = BridgeLoader()
|
||||
bridge_config = SimpleNamespace(update_model_arch=lambda _config: None)
|
||||
server_args = SimpleNamespace(
|
||||
component_weights_paths={
|
||||
"dual_tower_bridge": "owner/repo/bridge.safetensors"
|
||||
},
|
||||
model_paths={},
|
||||
pipeline_config=SimpleNamespace(bridge_config=bridge_config),
|
||||
should_use_fsdp_for_component=lambda _name: False,
|
||||
should_start_component_on_cpu=lambda _name: False,
|
||||
hsdp_replicate_dim=1,
|
||||
hsdp_shard_dim=1,
|
||||
pin_cpu_memory=False,
|
||||
)
|
||||
|
||||
with (
|
||||
patch.object(
|
||||
loader,
|
||||
"load_component_config",
|
||||
return_value={"_class_name": "MOVADualTowerModel"},
|
||||
),
|
||||
patch.object(
|
||||
loader,
|
||||
"resolve_component_weights_path",
|
||||
return_value="/cache/bridge.safetensors",
|
||||
) as resolve_weights,
|
||||
patch(
|
||||
"sglang.multimodal_gen.runtime.loader.component_loaders."
|
||||
"bridge_loader._list_safetensors_files",
|
||||
return_value=["/cache/bridge.safetensors"],
|
||||
) as list_weights,
|
||||
patch(
|
||||
"sglang.multimodal_gen.runtime.loader.component_loaders."
|
||||
"bridge_loader.ModelRegistry.resolve_model_cls",
|
||||
return_value=(nn.Linear, None),
|
||||
),
|
||||
patch(
|
||||
"sglang.multimodal_gen.runtime.loader.component_loaders."
|
||||
"bridge_loader.resolve_precision",
|
||||
return_value=torch.bfloat16,
|
||||
),
|
||||
patch(
|
||||
"sglang.multimodal_gen.runtime.loader.component_loaders."
|
||||
"bridge_loader.get_local_torch_device",
|
||||
return_value=torch.device("cpu"),
|
||||
),
|
||||
patch(
|
||||
"sglang.multimodal_gen.runtime.loader.component_loaders."
|
||||
"bridge_loader.maybe_load_fsdp_model",
|
||||
return_value=nn.Linear(1, 1),
|
||||
) as load_weights,
|
||||
):
|
||||
loaded = loader.load_customized(
|
||||
"/base/dual_tower_bridge",
|
||||
server_args,
|
||||
"dual_tower_bridge",
|
||||
)
|
||||
|
||||
self.assertIsInstance(loaded, nn.Linear)
|
||||
resolve_weights.assert_called_once_with(
|
||||
"/base/dual_tower_bridge", server_args, "dual_tower_bridge"
|
||||
)
|
||||
list_weights.assert_called_once_with("/cache/bridge.safetensors")
|
||||
self.assertEqual(
|
||||
load_weights.call_args.kwargs["weight_dir_list"],
|
||||
["/cache/bridge.safetensors"],
|
||||
)
|
||||
self.assertFalse(load_weights.call_args.kwargs["fsdp_inference"])
|
||||
|
||||
def test_all_quantization_metadata_layouts_fail_closed(self):
|
||||
configs = {
|
||||
"quantization_config": {
|
||||
@@ -217,7 +395,6 @@ class TestComponentQuantizationAdmission(unittest.TestCase):
|
||||
load_weights.assert_not_called()
|
||||
|
||||
def test_upsampler_uses_exact_component_weight_override(self):
|
||||
self.assertTrue(UpsamplerLoader.supports_component_weight_override)
|
||||
server_args = SimpleNamespace(
|
||||
component_weights_paths={"spatial_upsampler": "owner/repo/upsampler"}
|
||||
)
|
||||
|
||||
@@ -246,6 +246,7 @@ class TestImageEncoderNativeLoading(unittest.TestCase):
|
||||
from_pretrained=mock.Mock(return_value=loaded_encoder)
|
||||
)
|
||||
server_args = SimpleNamespace(
|
||||
component_weights_paths={},
|
||||
component_quantizations={},
|
||||
component_precisions={},
|
||||
pipeline_config=SimpleNamespace(
|
||||
|
||||
@@ -188,7 +188,7 @@ class TestServerArgsPathExpansion(unittest.TestCase):
|
||||
},
|
||||
)
|
||||
|
||||
def test_supplemental_weight_file_remains_a_component_path(self):
|
||||
def test_any_explicit_component_weight_file_keeps_base_config(self):
|
||||
args = self._from_dict_without_model_resolution(
|
||||
{
|
||||
"model_path": "/data/my-model",
|
||||
@@ -198,11 +198,11 @@ class TestServerArgsPathExpansion(unittest.TestCase):
|
||||
}
|
||||
)
|
||||
|
||||
self.assertEqual(args.component_paths, {})
|
||||
self.assertEqual(
|
||||
args.component_paths,
|
||||
args.component_weights_paths,
|
||||
{"conditioning_projection": "owner/repo/projection.safetensors"},
|
||||
)
|
||||
self.assertEqual(args.component_weights_paths, {})
|
||||
|
||||
def test_component_attention_backends_are_normalized(self):
|
||||
args = self._from_dict_without_model_resolution(
|
||||
|
||||
@@ -792,12 +792,12 @@ class TestTextEncoderQuantization(unittest.TestCase):
|
||||
"text_encoder",
|
||||
)
|
||||
|
||||
def test_model_managed_quantization_bypasses_generic_lifecycle(self):
|
||||
def test_model_quantization_backend_bypasses_generic_lifecycle(self):
|
||||
model_config = SimpleNamespace(quant_config=None)
|
||||
with mock.patch.object(
|
||||
TextEncoder,
|
||||
"manages_checkpoint_quantization",
|
||||
True,
|
||||
"checkpoint_quantization_backend",
|
||||
"model",
|
||||
):
|
||||
_configure_encoder_quantization(
|
||||
model_config,
|
||||
|
||||
@@ -3,20 +3,12 @@ import unittest
|
||||
from types import SimpleNamespace
|
||||
from unittest import mock
|
||||
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders.bridge_loader import (
|
||||
BridgeLoader,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders.component_loader import (
|
||||
ComponentLoader,
|
||||
NativeComponentLoaderRequired,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders.transformer_loader import (
|
||||
TransformerLoader,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.managers.memory_managers.component_residency import (
|
||||
RESIDENT,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.server_args import ServerArgs
|
||||
|
||||
|
||||
class TestTransformerLoaderFallbackAdmission(unittest.TestCase):
|
||||
@@ -94,7 +86,7 @@ class TestTransformerLoaderFallbackAdmission(unittest.TestCase):
|
||||
)
|
||||
|
||||
native.assert_not_called()
|
||||
server_args.should_use_fsdp_for_component.assert_called_once_with(
|
||||
server_args.should_use_fsdp_for_component.assert_called_with(
|
||||
"transformer_2"
|
||||
)
|
||||
|
||||
@@ -118,9 +110,7 @@ class TestTransformerLoaderFallbackAdmission(unittest.TestCase):
|
||||
self.assertIsNotNone(component)
|
||||
self.assertEqual(consumed, 0.0)
|
||||
native.assert_called_once()
|
||||
server_args.should_use_fsdp_for_component.assert_called_once_with(
|
||||
"transformer_2"
|
||||
)
|
||||
server_args.should_use_fsdp_for_component.assert_called_with("transformer_2")
|
||||
|
||||
def test_parallel_execution_rejects_native_fallback(self):
|
||||
cases = (
|
||||
@@ -146,26 +136,6 @@ class TestTransformerLoaderFallbackAdmission(unittest.TestCase):
|
||||
)
|
||||
)
|
||||
|
||||
def test_only_fsdp_materializers_keep_the_component_request(self):
|
||||
server_args = ServerArgs.__new__(ServerArgs)
|
||||
server_args.use_fsdp_inference = True
|
||||
server_args._fsdp_disabled_components = set()
|
||||
server_args.residency_mode = lambda _component: RESIDENT
|
||||
|
||||
ComponentLoader().disable_unsupported_component_fsdp(
|
||||
server_args, "text_encoder"
|
||||
)
|
||||
self.assertFalse(server_args.should_use_fsdp_for_component("text_encoder"))
|
||||
|
||||
TransformerLoader().disable_unsupported_component_fsdp(
|
||||
server_args, "transformer"
|
||||
)
|
||||
BridgeLoader().disable_unsupported_component_fsdp(
|
||||
server_args, "dual_tower_bridge"
|
||||
)
|
||||
self.assertTrue(server_args.should_use_fsdp_for_component("transformer"))
|
||||
self.assertTrue(server_args.should_use_fsdp_for_component("dual_tower_bridge"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -16,7 +16,10 @@ from sglang.multimodal_gen.configs.pipeline_configs.wan import (
|
||||
Wan2_2_I2V_A14B_Config,
|
||||
WanT2V480PConfig,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders import vae_loader
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders import (
|
||||
component_loader,
|
||||
vae_loader,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.loader.component_loaders.component_loader import (
|
||||
ComponentCheckpointUnsupportedError,
|
||||
)
|
||||
@@ -49,6 +52,7 @@ class _FakeServerArgs:
|
||||
self.revision = "test-revision"
|
||||
self.trust_remote_code = True
|
||||
self.layerwise_components = set()
|
||||
self.component_weights_paths = {}
|
||||
self.component_quantizations = {}
|
||||
self.component_precisions = {}
|
||||
self.component_direct_gpu_weight_loading = {}
|
||||
@@ -327,15 +331,15 @@ class TestVAELoader(unittest.TestCase):
|
||||
}
|
||||
|
||||
with (
|
||||
patch.object(vae_loader, "resolve_weight", return_value="resolved"),
|
||||
patch.object(component_loader, "resolve_weight", return_value="resolved"),
|
||||
patch.object(
|
||||
vae_loader,
|
||||
component_loader,
|
||||
"materialize_weight",
|
||||
return_value="/cache/audio.safetensors",
|
||||
),
|
||||
):
|
||||
self.assertEqual(
|
||||
loader.resolve_model_weights_path(
|
||||
loader.resolve_component_weights_path(
|
||||
"/base/audio_vae", server_args, "audio_vae"
|
||||
),
|
||||
"/cache/audio.safetensors",
|
||||
|
||||
Reference in New Issue
Block a user