[diffusion] feat: support distilled vae generic (#14195)
Co-authored-by: BBuf <1182563586@qq.com> Co-authored-by: Mick <mickjagger19@icloud.com>
This commit is contained in:
@@ -4,10 +4,11 @@
|
||||
|
||||
import dataclasses
|
||||
import glob
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from abc import ABC, abstractmethod
|
||||
from abc import ABC
|
||||
from collections.abc import Generator, Iterable
|
||||
from copy import deepcopy
|
||||
from typing import Any, cast
|
||||
@@ -101,17 +102,13 @@ def load_native(library, component_module_path: str, server_args: ServerArgs):
|
||||
revision=server_args.revision,
|
||||
)
|
||||
elif library == "diffusers":
|
||||
import diffusers
|
||||
from diffusers import AutoModel
|
||||
|
||||
config = get_diffusers_component_config(model_path=component_module_path)
|
||||
class_name = config.pop("_class_name", None)
|
||||
if class_name:
|
||||
cls = getattr(diffusers, class_name)
|
||||
return cls.from_pretrained(
|
||||
component_module_path, revision=server_args.revision, **config
|
||||
)
|
||||
else:
|
||||
raise ValueError("Cannot determine class name for generic diffusers loader")
|
||||
return AutoModel.from_pretrained(
|
||||
component_module_path,
|
||||
revision=server_args.revision,
|
||||
trust_remote_code=server_args.trust_remote_code,
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"Unsupported library: {library}")
|
||||
|
||||
@@ -202,13 +199,6 @@ class ComponentLoader(ABC):
|
||||
f"load_customized not implemented for {self.__class__.__name__}"
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def load_customized(
|
||||
self, model_path: str, server_args: ServerArgs, module_name: str
|
||||
) -> Any:
|
||||
"""Implement the minimal core load logic in subclasses."""
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def for_module_type(
|
||||
cls, module_type: str, transformers_or_diffusers: str
|
||||
@@ -503,7 +493,6 @@ class ImageEncoderLoader(TextEncoderLoader):
|
||||
encoder_config.update_model_arch(model_config)
|
||||
|
||||
# Always start with local device; load_model will adjust for offload if needed
|
||||
should_offload = self.should_offload(server_args)
|
||||
# TODO(will): add support for other dtypes
|
||||
return self.load_model(
|
||||
component_model_path,
|
||||
@@ -555,7 +544,7 @@ class VAELoader(ComponentLoader):
|
||||
):
|
||||
"""Load the VAE based on the model path, and inference args."""
|
||||
config = get_diffusers_component_config(model_path=component_model_path)
|
||||
class_name = config.pop("_class_name")
|
||||
class_name = config.pop("_class_name", None)
|
||||
assert (
|
||||
class_name is not None
|
||||
), "Model config does not contain a _class_name attribute. Only diffusers format is supported."
|
||||
@@ -571,23 +560,42 @@ class VAELoader(ComponentLoader):
|
||||
|
||||
target_device = self.target_device(server_args.vae_cpu_offload)
|
||||
|
||||
with set_default_torch_dtype(
|
||||
PRECISION_TO_TYPE[server_args.pipeline_config.vae_precision]
|
||||
), skip_init_modules():
|
||||
# Check for auto_map first (custom VAE classes)
|
||||
auto_map = config.get("auto_map", {})
|
||||
auto_model_map = auto_map.get("AutoModel")
|
||||
if auto_model_map:
|
||||
module_path, cls_name = auto_model_map.rsplit(".", 1)
|
||||
custom_module_file = os.path.join(component_model_path, f"{module_path}.py")
|
||||
spec = importlib.util.spec_from_file_location("_custom", custom_module_file)
|
||||
custom_module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(custom_module)
|
||||
vae_cls = getattr(custom_module, cls_name)
|
||||
vae_dtype = PRECISION_TO_TYPE[server_args.pipeline_config.vae_precision]
|
||||
with set_default_torch_dtype(vae_dtype):
|
||||
vae = vae_cls.from_pretrained(
|
||||
component_model_path,
|
||||
revision=server_args.revision,
|
||||
trust_remote_code=server_args.trust_remote_code,
|
||||
)
|
||||
vae = vae.to(device=target_device, dtype=vae_dtype)
|
||||
return vae.eval()
|
||||
|
||||
# Load from ModelRegistry (standard VAE classes)
|
||||
with (
|
||||
set_default_torch_dtype(
|
||||
PRECISION_TO_TYPE[server_args.pipeline_config.vae_precision]
|
||||
),
|
||||
skip_init_modules(),
|
||||
):
|
||||
vae_cls, _ = ModelRegistry.resolve_model_cls(class_name)
|
||||
vae = vae_cls(vae_config).to(target_device)
|
||||
|
||||
# Find all safetensors files
|
||||
safetensors_list = _list_safetensors_files(component_model_path)
|
||||
# TODO(PY)
|
||||
assert (
|
||||
len(safetensors_list) == 1
|
||||
), f"Found {len(safetensors_list)} safetensors files in {component_model_path}"
|
||||
loaded = safetensors_load_file(safetensors_list[0])
|
||||
vae.load_state_dict(
|
||||
loaded, strict=False
|
||||
) # We might only load encoder or decoder
|
||||
|
||||
vae.load_state_dict(loaded, strict=False)
|
||||
return vae.eval()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user