Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b59c02fb66 | |||
| fbff43acc9 | |||
| 3279751bf9 | |||
| 4a4afd5ece | |||
| aa79d7da46 |
@@ -83,7 +83,7 @@ jobs:
|
|||||||
python utils/print_env.py
|
python utils/print_env.py
|
||||||
- name: PyTorch CUDA checkpoint tests on Ubuntu
|
- name: PyTorch CUDA checkpoint tests on Ubuntu
|
||||||
env:
|
env:
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
HF_TOKEN: ${{ secrets.DIFFUSERS_HF_HUB_READ_TOKEN }}
|
||||||
# https://pytorch.org/docs/stable/notes/randomness.html#avoiding-nondeterministic-algorithms
|
# https://pytorch.org/docs/stable/notes/randomness.html#avoiding-nondeterministic-algorithms
|
||||||
CUBLAS_WORKSPACE_CONFIG: :16:8
|
CUBLAS_WORKSPACE_CONFIG: :16:8
|
||||||
run: |
|
run: |
|
||||||
@@ -137,7 +137,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Run PyTorch CUDA tests
|
- name: Run PyTorch CUDA tests
|
||||||
env:
|
env:
|
||||||
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
HF_TOKEN: ${{ secrets.DIFFUSERS_HF_HUB_READ_TOKEN }}
|
||||||
# https://pytorch.org/docs/stable/notes/randomness.html#avoiding-nondeterministic-algorithms
|
# https://pytorch.org/docs/stable/notes/randomness.html#avoiding-nondeterministic-algorithms
|
||||||
CUBLAS_WORKSPACE_CONFIG: :16:8
|
CUBLAS_WORKSPACE_CONFIG: :16:8
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -240,6 +240,46 @@ Benefits of using a single-file layout include:
|
|||||||
1. Easy compatibility with diffusion interfaces such as [ComfyUI](https://github.com/comfyanonymous/ComfyUI) or [Automatic1111](https://github.com/AUTOMATIC1111/stable-diffusion-webui) which commonly use a single-file layout.
|
1. Easy compatibility with diffusion interfaces such as [ComfyUI](https://github.com/comfyanonymous/ComfyUI) or [Automatic1111](https://github.com/AUTOMATIC1111/stable-diffusion-webui) which commonly use a single-file layout.
|
||||||
2. Easier to manage (download and share) a single file.
|
2. Easier to manage (download and share) a single file.
|
||||||
|
|
||||||
|
### DDUF
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> DDUF is an experimental file format and APIs related to it can change in the future.
|
||||||
|
|
||||||
|
DDUF (**D**DUF **D**iffusion **U**nified **F**ormat) is a file format designed to make storing, distributing, and using diffusion models much easier. Built on the ZIP file format, DDUF offers a standardized, efficient, and flexible way to package all parts of a diffusion model into a single, easy-to-manage file. It provides a balance between Diffusers multi-folder format and the widely popular single-file format.
|
||||||
|
|
||||||
|
Learn more details about DDUF on the Hugging Face Hub [documentation](https://huggingface.co/docs/hub/dduf).
|
||||||
|
|
||||||
|
Pass a checkpoint to the `dduf_file` parameter to load it in [`DiffusionPipeline`].
|
||||||
|
|
||||||
|
```py
|
||||||
|
from diffusers import DiffusionPipeline
|
||||||
|
import torch
|
||||||
|
|
||||||
|
pipe = DiffusionPipeline.from_pretrained(
|
||||||
|
"DDUF/FLUX.1-dev-DDUF", dduf_file="FLUX.1-dev.dduf", torch_dtype=torch.bfloat16
|
||||||
|
).to("cuda")
|
||||||
|
image = pipe(
|
||||||
|
"photo a cat holding a sign that says Diffusers", num_inference_steps=50, guidance_scale=3.5
|
||||||
|
).images[0]
|
||||||
|
image.save("cat.png")
|
||||||
|
```
|
||||||
|
|
||||||
|
To save a pipeline as a `.dduf` checkpoint, use the [`~huggingface_hub.export_folder_as_dduf`] utility, which takes care of all the necessary file-level validations.
|
||||||
|
|
||||||
|
```py
|
||||||
|
from huggingface_hub import export_folder_as_dduf
|
||||||
|
from diffusers import DiffusionPipeline
|
||||||
|
import torch
|
||||||
|
|
||||||
|
pipe = DiffusionPipeline.from_pretrained("black-forest-labs/FLUX.1-dev", torch_dtype=torch.bfloat16)
|
||||||
|
|
||||||
|
save_folder = "flux-dev"
|
||||||
|
pipe.save_pretrained("flux-dev")
|
||||||
|
export_folder_as_dduf("flux-dev.dduf", folder_path=save_folder)
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Packaging and loading quantized checkpoints in the DDUF format is supported as long as they respect the multi-folder structure.
|
||||||
|
|
||||||
## Convert layout and files
|
## Convert layout and files
|
||||||
|
|
||||||
Diffusers provides many scripts and methods to convert storage layouts and file formats to enable broader support across the diffusion ecosystem.
|
Diffusers provides many scripts and methods to convert storage layouts and file formats to enable broader support across the diffusion ecosystem.
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ _deps = [
|
|||||||
"filelock",
|
"filelock",
|
||||||
"flax>=0.4.1",
|
"flax>=0.4.1",
|
||||||
"hf-doc-builder>=0.3.0",
|
"hf-doc-builder>=0.3.0",
|
||||||
"huggingface-hub>=0.23.2",
|
"huggingface-hub>=0.27.0",
|
||||||
"requests-mock==1.10.0",
|
"requests-mock==1.10.0",
|
||||||
"importlib_metadata",
|
"importlib_metadata",
|
||||||
"invisible-watermark>=0.2.0",
|
"invisible-watermark>=0.2.0",
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ import os
|
|||||||
import re
|
import re
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Tuple, Union
|
from typing import Any, Dict, Optional, Tuple, Union
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from huggingface_hub import create_repo, hf_hub_download
|
from huggingface_hub import DDUFEntry, create_repo, hf_hub_download
|
||||||
from huggingface_hub.utils import (
|
from huggingface_hub.utils import (
|
||||||
EntryNotFoundError,
|
EntryNotFoundError,
|
||||||
RepositoryNotFoundError,
|
RepositoryNotFoundError,
|
||||||
@@ -347,6 +347,7 @@ class ConfigMixin:
|
|||||||
_ = kwargs.pop("mirror", None)
|
_ = kwargs.pop("mirror", None)
|
||||||
subfolder = kwargs.pop("subfolder", None)
|
subfolder = kwargs.pop("subfolder", None)
|
||||||
user_agent = kwargs.pop("user_agent", {})
|
user_agent = kwargs.pop("user_agent", {})
|
||||||
|
dduf_entries: Optional[Dict[str, DDUFEntry]] = kwargs.pop("dduf_entries", None)
|
||||||
|
|
||||||
user_agent = {**user_agent, "file_type": "config"}
|
user_agent = {**user_agent, "file_type": "config"}
|
||||||
user_agent = http_user_agent(user_agent)
|
user_agent = http_user_agent(user_agent)
|
||||||
@@ -358,8 +359,15 @@ class ConfigMixin:
|
|||||||
"`self.config_name` is not defined. Note that one should not load a config from "
|
"`self.config_name` is not defined. Note that one should not load a config from "
|
||||||
"`ConfigMixin`. Please make sure to define `config_name` in a class inheriting from `ConfigMixin`"
|
"`ConfigMixin`. Please make sure to define `config_name` in a class inheriting from `ConfigMixin`"
|
||||||
)
|
)
|
||||||
|
# Custom path for now
|
||||||
if os.path.isfile(pretrained_model_name_or_path):
|
if dduf_entries:
|
||||||
|
if subfolder is not None:
|
||||||
|
raise ValueError(
|
||||||
|
"DDUF file only allow for 1 level of directory (e.g transformer/model1/model.safetentors is not allowed). "
|
||||||
|
"Please check the DDUF structure"
|
||||||
|
)
|
||||||
|
config_file = cls._get_config_file_from_dduf(pretrained_model_name_or_path, dduf_entries)
|
||||||
|
elif os.path.isfile(pretrained_model_name_or_path):
|
||||||
config_file = pretrained_model_name_or_path
|
config_file = pretrained_model_name_or_path
|
||||||
elif os.path.isdir(pretrained_model_name_or_path):
|
elif os.path.isdir(pretrained_model_name_or_path):
|
||||||
if subfolder is not None and os.path.isfile(
|
if subfolder is not None and os.path.isfile(
|
||||||
@@ -426,10 +434,8 @@ class ConfigMixin:
|
|||||||
f"Otherwise, make sure '{pretrained_model_name_or_path}' is the correct path to a directory "
|
f"Otherwise, make sure '{pretrained_model_name_or_path}' is the correct path to a directory "
|
||||||
f"containing a {cls.config_name} file"
|
f"containing a {cls.config_name} file"
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Load config dict
|
config_dict = cls._dict_from_json_file(config_file, dduf_entries=dduf_entries)
|
||||||
config_dict = cls._dict_from_json_file(config_file)
|
|
||||||
|
|
||||||
commit_hash = extract_commit_hash(config_file)
|
commit_hash = extract_commit_hash(config_file)
|
||||||
except (json.JSONDecodeError, UnicodeDecodeError):
|
except (json.JSONDecodeError, UnicodeDecodeError):
|
||||||
@@ -552,9 +558,14 @@ class ConfigMixin:
|
|||||||
return init_dict, unused_kwargs, hidden_config_dict
|
return init_dict, unused_kwargs, hidden_config_dict
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _dict_from_json_file(cls, json_file: Union[str, os.PathLike]):
|
def _dict_from_json_file(
|
||||||
with open(json_file, "r", encoding="utf-8") as reader:
|
cls, json_file: Union[str, os.PathLike], dduf_entries: Optional[Dict[str, DDUFEntry]] = None
|
||||||
text = reader.read()
|
):
|
||||||
|
if dduf_entries:
|
||||||
|
text = dduf_entries[json_file].read_text()
|
||||||
|
else:
|
||||||
|
with open(json_file, "r", encoding="utf-8") as reader:
|
||||||
|
text = reader.read()
|
||||||
return json.loads(text)
|
return json.loads(text)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@@ -616,6 +627,20 @@ class ConfigMixin:
|
|||||||
with open(json_file_path, "w", encoding="utf-8") as writer:
|
with open(json_file_path, "w", encoding="utf-8") as writer:
|
||||||
writer.write(self.to_json_string())
|
writer.write(self.to_json_string())
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_config_file_from_dduf(cls, pretrained_model_name_or_path: str, dduf_entries: Dict[str, DDUFEntry]):
|
||||||
|
# paths inside a DDUF file must always be "/"
|
||||||
|
config_file = (
|
||||||
|
cls.config_name
|
||||||
|
if pretrained_model_name_or_path == ""
|
||||||
|
else "/".join([pretrained_model_name_or_path, cls.config_name])
|
||||||
|
)
|
||||||
|
if config_file not in dduf_entries:
|
||||||
|
raise ValueError(
|
||||||
|
f"We did not manage to find the file {config_file} in the dduf file. We only have the following files {dduf_entries.keys()}"
|
||||||
|
)
|
||||||
|
return config_file
|
||||||
|
|
||||||
|
|
||||||
def register_to_config(init):
|
def register_to_config(init):
|
||||||
r"""
|
r"""
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ deps = {
|
|||||||
"filelock": "filelock",
|
"filelock": "filelock",
|
||||||
"flax": "flax>=0.4.1",
|
"flax": "flax>=0.4.1",
|
||||||
"hf-doc-builder": "hf-doc-builder>=0.3.0",
|
"hf-doc-builder": "hf-doc-builder>=0.3.0",
|
||||||
"huggingface-hub": "huggingface-hub>=0.23.2",
|
"huggingface-hub": "huggingface-hub>=0.27.0",
|
||||||
"requests-mock": "requests-mock==1.10.0",
|
"requests-mock": "requests-mock==1.10.0",
|
||||||
"importlib_metadata": "importlib_metadata",
|
"importlib_metadata": "importlib_metadata",
|
||||||
"invisible-watermark": "invisible-watermark>=0.2.0",
|
"invisible-watermark": "invisible-watermark>=0.2.0",
|
||||||
|
|||||||
@@ -20,10 +20,11 @@ import os
|
|||||||
from array import array
|
from array import array
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Union
|
from typing import Dict, List, Optional, Union
|
||||||
|
|
||||||
import safetensors
|
import safetensors
|
||||||
import torch
|
import torch
|
||||||
|
from huggingface_hub import DDUFEntry
|
||||||
from huggingface_hub.utils import EntryNotFoundError
|
from huggingface_hub.utils import EntryNotFoundError
|
||||||
|
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
@@ -132,7 +133,10 @@ def _fetch_remapped_cls_from_config(config, old_class):
|
|||||||
|
|
||||||
|
|
||||||
def load_state_dict(
|
def load_state_dict(
|
||||||
checkpoint_file: Union[str, os.PathLike], variant: Optional[str] = None, disable_mmap: bool = False
|
checkpoint_file: Union[str, os.PathLike],
|
||||||
|
variant: Optional[str] = None,
|
||||||
|
dduf_entries: Optional[Dict[str, DDUFEntry]] = None,
|
||||||
|
disable_mmap: bool = False,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Reads a checkpoint file, returning properly formatted errors if they arise.
|
Reads a checkpoint file, returning properly formatted errors if they arise.
|
||||||
@@ -144,6 +148,10 @@ def load_state_dict(
|
|||||||
try:
|
try:
|
||||||
file_extension = os.path.basename(checkpoint_file).split(".")[-1]
|
file_extension = os.path.basename(checkpoint_file).split(".")[-1]
|
||||||
if file_extension == SAFETENSORS_FILE_EXTENSION:
|
if file_extension == SAFETENSORS_FILE_EXTENSION:
|
||||||
|
if dduf_entries:
|
||||||
|
# tensors are loaded on cpu
|
||||||
|
with dduf_entries[checkpoint_file].as_mmap() as mm:
|
||||||
|
return safetensors.torch.load(mm)
|
||||||
if disable_mmap:
|
if disable_mmap:
|
||||||
return safetensors.torch.load(open(checkpoint_file, "rb").read())
|
return safetensors.torch.load(open(checkpoint_file, "rb").read())
|
||||||
else:
|
else:
|
||||||
@@ -284,6 +292,7 @@ def _fetch_index_file(
|
|||||||
revision,
|
revision,
|
||||||
user_agent,
|
user_agent,
|
||||||
commit_hash,
|
commit_hash,
|
||||||
|
dduf_entries: Optional[Dict[str, DDUFEntry]] = None,
|
||||||
):
|
):
|
||||||
if is_local:
|
if is_local:
|
||||||
index_file = Path(
|
index_file = Path(
|
||||||
@@ -309,8 +318,10 @@ def _fetch_index_file(
|
|||||||
subfolder=None,
|
subfolder=None,
|
||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
commit_hash=commit_hash,
|
commit_hash=commit_hash,
|
||||||
|
dduf_entries=dduf_entries,
|
||||||
)
|
)
|
||||||
index_file = Path(index_file)
|
if not dduf_entries:
|
||||||
|
index_file = Path(index_file)
|
||||||
except (EntryNotFoundError, EnvironmentError):
|
except (EntryNotFoundError, EnvironmentError):
|
||||||
index_file = None
|
index_file = None
|
||||||
|
|
||||||
@@ -319,7 +330,9 @@ def _fetch_index_file(
|
|||||||
|
|
||||||
# Adapted from
|
# Adapted from
|
||||||
# https://github.com/bghira/SimpleTuner/blob/cea2457ab063f6dedb9e697830ae68a96be90641/helpers/training/save_hooks.py#L64
|
# https://github.com/bghira/SimpleTuner/blob/cea2457ab063f6dedb9e697830ae68a96be90641/helpers/training/save_hooks.py#L64
|
||||||
def _merge_sharded_checkpoints(sharded_ckpt_cached_folder, sharded_metadata):
|
def _merge_sharded_checkpoints(
|
||||||
|
sharded_ckpt_cached_folder, sharded_metadata, dduf_entries: Optional[Dict[str, DDUFEntry]] = None
|
||||||
|
):
|
||||||
weight_map = sharded_metadata.get("weight_map", None)
|
weight_map = sharded_metadata.get("weight_map", None)
|
||||||
if weight_map is None:
|
if weight_map is None:
|
||||||
raise KeyError("'weight_map' key not found in the shard index file.")
|
raise KeyError("'weight_map' key not found in the shard index file.")
|
||||||
@@ -332,14 +345,23 @@ def _merge_sharded_checkpoints(sharded_ckpt_cached_folder, sharded_metadata):
|
|||||||
# Load tensors from each unique file
|
# Load tensors from each unique file
|
||||||
for file_name in files_to_load:
|
for file_name in files_to_load:
|
||||||
part_file_path = os.path.join(sharded_ckpt_cached_folder, file_name)
|
part_file_path = os.path.join(sharded_ckpt_cached_folder, file_name)
|
||||||
if not os.path.exists(part_file_path):
|
if dduf_entries:
|
||||||
raise FileNotFoundError(f"Part file {file_name} not found.")
|
if part_file_path not in dduf_entries:
|
||||||
|
raise FileNotFoundError(f"Part file {file_name} not found.")
|
||||||
|
else:
|
||||||
|
if not os.path.exists(part_file_path):
|
||||||
|
raise FileNotFoundError(f"Part file {file_name} not found.")
|
||||||
|
|
||||||
if is_safetensors:
|
if is_safetensors:
|
||||||
with safetensors.safe_open(part_file_path, framework="pt", device="cpu") as f:
|
if dduf_entries:
|
||||||
for tensor_key in f.keys():
|
with dduf_entries[part_file_path].as_mmap() as mm:
|
||||||
if tensor_key in weight_map:
|
tensors = safetensors.torch.load(mm)
|
||||||
merged_state_dict[tensor_key] = f.get_tensor(tensor_key)
|
merged_state_dict.update(tensors)
|
||||||
|
else:
|
||||||
|
with safetensors.safe_open(part_file_path, framework="pt", device="cpu") as f:
|
||||||
|
for tensor_key in f.keys():
|
||||||
|
if tensor_key in weight_map:
|
||||||
|
merged_state_dict[tensor_key] = f.get_tensor(tensor_key)
|
||||||
else:
|
else:
|
||||||
merged_state_dict.update(torch.load(part_file_path, weights_only=True, map_location="cpu"))
|
merged_state_dict.update(torch.load(part_file_path, weights_only=True, map_location="cpu"))
|
||||||
|
|
||||||
@@ -360,6 +382,7 @@ def _fetch_index_file_legacy(
|
|||||||
revision,
|
revision,
|
||||||
user_agent,
|
user_agent,
|
||||||
commit_hash,
|
commit_hash,
|
||||||
|
dduf_entries: Optional[Dict[str, DDUFEntry]] = None,
|
||||||
):
|
):
|
||||||
if is_local:
|
if is_local:
|
||||||
index_file = Path(
|
index_file = Path(
|
||||||
@@ -400,6 +423,7 @@ def _fetch_index_file_legacy(
|
|||||||
subfolder=None,
|
subfolder=None,
|
||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
commit_hash=commit_hash,
|
commit_hash=commit_hash,
|
||||||
|
dduf_entries=dduf_entries,
|
||||||
)
|
)
|
||||||
index_file = Path(index_file)
|
index_file = Path(index_file)
|
||||||
deprecation_message = f"This serialization format is now deprecated to standardize the serialization format between `transformers` and `diffusers`. We recommend you to remove the existing files associated with the current variant ({variant}) and re-obtain them by running a `save_pretrained()`."
|
deprecation_message = f"This serialization format is now deprecated to standardize the serialization format between `transformers` and `diffusers`. We recommend you to remove the existing files associated with the current variant ({variant}) and re-obtain them by running a `save_pretrained()`."
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ import re
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from functools import partial, wraps
|
from functools import partial, wraps
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Callable, List, Optional, Tuple, Union
|
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
||||||
|
|
||||||
import safetensors
|
import safetensors
|
||||||
import torch
|
import torch
|
||||||
from huggingface_hub import create_repo, split_torch_state_dict_into_shards
|
from huggingface_hub import DDUFEntry, create_repo, split_torch_state_dict_into_shards
|
||||||
from huggingface_hub.utils import validate_hf_hub_args
|
from huggingface_hub.utils import validate_hf_hub_args
|
||||||
from torch import Tensor, nn
|
from torch import Tensor, nn
|
||||||
|
|
||||||
@@ -607,6 +607,7 @@ class ModelMixin(torch.nn.Module, PushToHubMixin):
|
|||||||
variant = kwargs.pop("variant", None)
|
variant = kwargs.pop("variant", None)
|
||||||
use_safetensors = kwargs.pop("use_safetensors", None)
|
use_safetensors = kwargs.pop("use_safetensors", None)
|
||||||
quantization_config = kwargs.pop("quantization_config", None)
|
quantization_config = kwargs.pop("quantization_config", None)
|
||||||
|
dduf_entries: Optional[Dict[str, DDUFEntry]] = kwargs.pop("dduf_entries", None)
|
||||||
disable_mmap = kwargs.pop("disable_mmap", False)
|
disable_mmap = kwargs.pop("disable_mmap", False)
|
||||||
|
|
||||||
allow_pickle = False
|
allow_pickle = False
|
||||||
@@ -700,6 +701,7 @@ class ModelMixin(torch.nn.Module, PushToHubMixin):
|
|||||||
revision=revision,
|
revision=revision,
|
||||||
subfolder=subfolder,
|
subfolder=subfolder,
|
||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
|
dduf_entries=dduf_entries,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
# no in-place modification of the original config.
|
# no in-place modification of the original config.
|
||||||
@@ -776,13 +778,14 @@ class ModelMixin(torch.nn.Module, PushToHubMixin):
|
|||||||
"revision": revision,
|
"revision": revision,
|
||||||
"user_agent": user_agent,
|
"user_agent": user_agent,
|
||||||
"commit_hash": commit_hash,
|
"commit_hash": commit_hash,
|
||||||
|
"dduf_entries": dduf_entries,
|
||||||
}
|
}
|
||||||
index_file = _fetch_index_file(**index_file_kwargs)
|
index_file = _fetch_index_file(**index_file_kwargs)
|
||||||
# In case the index file was not found we still have to consider the legacy format.
|
# In case the index file was not found we still have to consider the legacy format.
|
||||||
# this becomes applicable when the variant is not None.
|
# this becomes applicable when the variant is not None.
|
||||||
if variant is not None and (index_file is None or not os.path.exists(index_file)):
|
if variant is not None and (index_file is None or not os.path.exists(index_file)):
|
||||||
index_file = _fetch_index_file_legacy(**index_file_kwargs)
|
index_file = _fetch_index_file_legacy(**index_file_kwargs)
|
||||||
if index_file is not None and index_file.is_file():
|
if index_file is not None and (dduf_entries or index_file.is_file()):
|
||||||
is_sharded = True
|
is_sharded = True
|
||||||
|
|
||||||
if is_sharded and from_flax:
|
if is_sharded and from_flax:
|
||||||
@@ -811,6 +814,7 @@ class ModelMixin(torch.nn.Module, PushToHubMixin):
|
|||||||
|
|
||||||
model = load_flax_checkpoint_in_pytorch_model(model, model_file)
|
model = load_flax_checkpoint_in_pytorch_model(model, model_file)
|
||||||
else:
|
else:
|
||||||
|
# in the case it is sharded, we have already the index
|
||||||
if is_sharded:
|
if is_sharded:
|
||||||
sharded_ckpt_cached_folder, sharded_metadata = _get_checkpoint_shard_files(
|
sharded_ckpt_cached_folder, sharded_metadata = _get_checkpoint_shard_files(
|
||||||
pretrained_model_name_or_path,
|
pretrained_model_name_or_path,
|
||||||
@@ -822,10 +826,13 @@ class ModelMixin(torch.nn.Module, PushToHubMixin):
|
|||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
revision=revision,
|
revision=revision,
|
||||||
subfolder=subfolder or "",
|
subfolder=subfolder or "",
|
||||||
|
dduf_entries=dduf_entries,
|
||||||
)
|
)
|
||||||
# TODO: https://github.com/huggingface/diffusers/issues/10013
|
# TODO: https://github.com/huggingface/diffusers/issues/10013
|
||||||
if hf_quantizer is not None:
|
if hf_quantizer is not None or dduf_entries:
|
||||||
model_file = _merge_sharded_checkpoints(sharded_ckpt_cached_folder, sharded_metadata)
|
model_file = _merge_sharded_checkpoints(
|
||||||
|
sharded_ckpt_cached_folder, sharded_metadata, dduf_entries=dduf_entries
|
||||||
|
)
|
||||||
logger.info("Merged sharded checkpoints as `hf_quantizer` is not None.")
|
logger.info("Merged sharded checkpoints as `hf_quantizer` is not None.")
|
||||||
is_sharded = False
|
is_sharded = False
|
||||||
|
|
||||||
@@ -843,6 +850,7 @@ class ModelMixin(torch.nn.Module, PushToHubMixin):
|
|||||||
subfolder=subfolder,
|
subfolder=subfolder,
|
||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
commit_hash=commit_hash,
|
commit_hash=commit_hash,
|
||||||
|
dduf_entries=dduf_entries,
|
||||||
)
|
)
|
||||||
|
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
@@ -866,6 +874,7 @@ class ModelMixin(torch.nn.Module, PushToHubMixin):
|
|||||||
subfolder=subfolder,
|
subfolder=subfolder,
|
||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
commit_hash=commit_hash,
|
commit_hash=commit_hash,
|
||||||
|
dduf_entries=dduf_entries,
|
||||||
)
|
)
|
||||||
|
|
||||||
if low_cpu_mem_usage:
|
if low_cpu_mem_usage:
|
||||||
@@ -887,7 +896,9 @@ class ModelMixin(torch.nn.Module, PushToHubMixin):
|
|||||||
# TODO (sayakpaul, SunMarc): remove this after model loading refactor
|
# TODO (sayakpaul, SunMarc): remove this after model loading refactor
|
||||||
else:
|
else:
|
||||||
param_device = torch.device(torch.cuda.current_device())
|
param_device = torch.device(torch.cuda.current_device())
|
||||||
state_dict = load_state_dict(model_file, variant=variant, disable_mmap=disable_mmap)
|
state_dict = load_state_dict(
|
||||||
|
model_file, variant=variant, dduf_entries=dduf_entries, disable_mmap=disable_mmap
|
||||||
|
)
|
||||||
model._convert_deprecated_attention_blocks(state_dict)
|
model._convert_deprecated_attention_blocks(state_dict)
|
||||||
|
|
||||||
# move the params from meta device to cpu
|
# move the params from meta device to cpu
|
||||||
@@ -983,7 +994,9 @@ class ModelMixin(torch.nn.Module, PushToHubMixin):
|
|||||||
else:
|
else:
|
||||||
model = cls.from_config(config, **unused_kwargs)
|
model = cls.from_config(config, **unused_kwargs)
|
||||||
|
|
||||||
state_dict = load_state_dict(model_file, variant=variant, disable_mmap=disable_mmap)
|
state_dict = load_state_dict(
|
||||||
|
model_file, variant=variant, dduf_entries=dduf_entries, disable_mmap=disable_mmap
|
||||||
|
)
|
||||||
model._convert_deprecated_attention_blocks(state_dict)
|
model._convert_deprecated_attention_blocks(state_dict)
|
||||||
|
|
||||||
model, missing_keys, unexpected_keys, mismatched_keys, error_msgs = cls._load_pretrained_model(
|
model, missing_keys, unexpected_keys, mismatched_keys, error_msgs = cls._load_pretrained_model(
|
||||||
|
|||||||
@@ -727,7 +727,8 @@ class HunyuanVideoTransformer3DModel(ModelMixin, ConfigMixin, PeftAdapterMixin,
|
|||||||
|
|
||||||
for i in range(batch_size):
|
for i in range(batch_size):
|
||||||
attention_mask[i, : effective_sequence_length[i]] = True
|
attention_mask[i, : effective_sequence_length[i]] = True
|
||||||
attention_mask = attention_mask.unsqueeze(1) # [B, 1, N], for broadcasting across attention heads
|
# [B, 1, 1, N], for broadcasting across attention heads
|
||||||
|
attention_mask = attention_mask.unsqueeze(1).unsqueeze(1)
|
||||||
|
|
||||||
# 4. Transformer blocks
|
# 4. Transformer blocks
|
||||||
if torch.is_grad_enabled() and self.gradient_checkpointing:
|
if torch.is_grad_enabled() and self.gradient_checkpointing:
|
||||||
|
|||||||
@@ -1,365 +0,0 @@
|
|||||||
# Copyright 2024 The HuggingFace Team. All rights reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
from itertools import combinations
|
|
||||||
from typing import List, Optional, Union
|
|
||||||
|
|
||||||
import torch
|
|
||||||
|
|
||||||
from ..utils import (
|
|
||||||
is_accelerate_available,
|
|
||||||
logging,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if is_accelerate_available():
|
|
||||||
from accelerate.hooks import ModelHook, add_hook_to_module, remove_hook_from_module
|
|
||||||
from accelerate.state import PartialState
|
|
||||||
from accelerate.utils import send_to_device
|
|
||||||
from accelerate.utils.memory import clear_device_cache
|
|
||||||
from accelerate.utils.modeling import convert_file_size_to_int
|
|
||||||
|
|
||||||
logger = logging.get_logger(__name__) # pylint: disable=invalid-name
|
|
||||||
|
|
||||||
|
|
||||||
# YiYi Notes: copied from modeling_utils.py (decide later where to put this)
|
|
||||||
def get_memory_footprint(self, return_buffers=True):
|
|
||||||
r"""
|
|
||||||
Get the memory footprint of a model. This will return the memory footprint of the current model in bytes. Useful to
|
|
||||||
benchmark the memory footprint of the current model and design some tests. Solution inspired from the PyTorch
|
|
||||||
discussions: https://discuss.pytorch.org/t/gpu-memory-that-model-uses/56822/2
|
|
||||||
|
|
||||||
Arguments:
|
|
||||||
return_buffers (`bool`, *optional*, defaults to `True`):
|
|
||||||
Whether to return the size of the buffer tensors in the computation of the memory footprint. Buffers are
|
|
||||||
tensors that do not require gradients and not registered as parameters. E.g. mean and std in batch norm
|
|
||||||
layers. Please see: https://discuss.pytorch.org/t/what-pytorch-means-by-buffers/120266/2
|
|
||||||
"""
|
|
||||||
mem = sum([param.nelement() * param.element_size() for param in self.parameters()])
|
|
||||||
if return_buffers:
|
|
||||||
mem_bufs = sum([buf.nelement() * buf.element_size() for buf in self.buffers()])
|
|
||||||
mem = mem + mem_bufs
|
|
||||||
return mem
|
|
||||||
|
|
||||||
|
|
||||||
class CustomOffloadHook(ModelHook):
|
|
||||||
"""
|
|
||||||
A hook that offloads a model on the CPU until its forward pass is called. It ensures the model and its inputs are
|
|
||||||
on the given device. Optionally offloads other models to the CPU before the forward pass is called.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
execution_device(`str`, `int` or `torch.device`, *optional*):
|
|
||||||
The device on which the model should be executed. Will default to the MPS device if it's available, then
|
|
||||||
GPU 0 if there is a GPU, and finally to the CPU.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
execution_device: Optional[Union[str, int, torch.device]] = None,
|
|
||||||
other_hooks: Optional[List["UserCustomOffloadHook"]] = None,
|
|
||||||
offload_strategy: Optional["AutoOffloadStrategy"] = None,
|
|
||||||
):
|
|
||||||
self.execution_device = execution_device if execution_device is not None else PartialState().default_device
|
|
||||||
self.other_hooks = other_hooks
|
|
||||||
self.offload_strategy = offload_strategy
|
|
||||||
self.model_id = None
|
|
||||||
|
|
||||||
def set_strategy(self, offload_strategy: "AutoOffloadStrategy"):
|
|
||||||
self.offload_strategy = offload_strategy
|
|
||||||
|
|
||||||
def add_other_hook(self, hook: "UserCustomOffloadHook"):
|
|
||||||
"""
|
|
||||||
Add a hook to the list of hooks to consider for offloading.
|
|
||||||
"""
|
|
||||||
if self.other_hooks is None:
|
|
||||||
self.other_hooks = []
|
|
||||||
self.other_hooks.append(hook)
|
|
||||||
|
|
||||||
def init_hook(self, module):
|
|
||||||
return module.to("cpu")
|
|
||||||
|
|
||||||
def pre_forward(self, module, *args, **kwargs):
|
|
||||||
if module.device != self.execution_device:
|
|
||||||
if self.other_hooks is not None:
|
|
||||||
hooks_to_offload = [hook for hook in self.other_hooks if hook.model.device == self.execution_device]
|
|
||||||
# offload all other hooks
|
|
||||||
import time
|
|
||||||
|
|
||||||
# YiYi Notes: only logging time for now to monitor the overhead of offloading strategy (remove later)
|
|
||||||
start_time = time.perf_counter()
|
|
||||||
if self.offload_strategy is not None:
|
|
||||||
hooks_to_offload = self.offload_strategy(
|
|
||||||
hooks=hooks_to_offload,
|
|
||||||
model_id=self.model_id,
|
|
||||||
model=module,
|
|
||||||
execution_device=self.execution_device,
|
|
||||||
)
|
|
||||||
end_time = time.perf_counter()
|
|
||||||
logger.info(
|
|
||||||
f" time taken to apply offload strategy for {self.model_id}: {(end_time - start_time):.2f} seconds"
|
|
||||||
)
|
|
||||||
|
|
||||||
for hook in hooks_to_offload:
|
|
||||||
logger.info(
|
|
||||||
f"moving {self.model_id} to {self.execution_device}, offloading {hook.model_id} to cpu"
|
|
||||||
)
|
|
||||||
hook.offload()
|
|
||||||
|
|
||||||
if hooks_to_offload:
|
|
||||||
clear_device_cache()
|
|
||||||
module.to(self.execution_device)
|
|
||||||
return send_to_device(args, self.execution_device), send_to_device(kwargs, self.execution_device)
|
|
||||||
|
|
||||||
|
|
||||||
class UserCustomOffloadHook:
|
|
||||||
"""
|
|
||||||
A simple hook grouping a model and a `CustomOffloadHook`, which provides easy APIs for to call the init method of
|
|
||||||
the hook or remove it entirely.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, model_id, model, hook):
|
|
||||||
self.model_id = model_id
|
|
||||||
self.model = model
|
|
||||||
self.hook = hook
|
|
||||||
|
|
||||||
def offload(self):
|
|
||||||
self.hook.init_hook(self.model)
|
|
||||||
|
|
||||||
def attach(self):
|
|
||||||
add_hook_to_module(self.model, self.hook)
|
|
||||||
self.hook.model_id = self.model_id
|
|
||||||
|
|
||||||
def remove(self):
|
|
||||||
remove_hook_from_module(self.model)
|
|
||||||
self.hook.model_id = None
|
|
||||||
|
|
||||||
def add_other_hook(self, hook: "UserCustomOffloadHook"):
|
|
||||||
self.hook.add_other_hook(hook)
|
|
||||||
|
|
||||||
|
|
||||||
def custom_offload_with_hook(
|
|
||||||
model_id: str,
|
|
||||||
model: torch.nn.Module,
|
|
||||||
execution_device: Union[str, int, torch.device] = None,
|
|
||||||
offload_strategy: Optional["AutoOffloadStrategy"] = None,
|
|
||||||
):
|
|
||||||
hook = CustomOffloadHook(execution_device=execution_device, offload_strategy=offload_strategy)
|
|
||||||
user_hook = UserCustomOffloadHook(model_id=model_id, model=model, hook=hook)
|
|
||||||
user_hook.attach()
|
|
||||||
return user_hook
|
|
||||||
|
|
||||||
|
|
||||||
class AutoOffloadStrategy:
|
|
||||||
"""
|
|
||||||
Offload strategy that should be used with `CustomOffloadHook` to automatically offload models to the CPU based on
|
|
||||||
the available memory on the device.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, memory_reserve_margin="3GB"):
|
|
||||||
self.memory_reserve_margin = convert_file_size_to_int(memory_reserve_margin)
|
|
||||||
|
|
||||||
def __call__(self, hooks, model_id, model, execution_device):
|
|
||||||
if len(hooks) == 0:
|
|
||||||
return []
|
|
||||||
|
|
||||||
current_module_size = get_memory_footprint(model)
|
|
||||||
|
|
||||||
mem_on_device = torch.cuda.mem_get_info(execution_device.index)[0]
|
|
||||||
mem_on_device = mem_on_device - self.memory_reserve_margin
|
|
||||||
if current_module_size < mem_on_device:
|
|
||||||
return []
|
|
||||||
|
|
||||||
min_memory_offload = current_module_size - mem_on_device
|
|
||||||
logger.info(f" search for models to offload in order to free up {min_memory_offload / 1024**3:.2f} GB memory")
|
|
||||||
|
|
||||||
# exlucde models that's not currently loaded on the device
|
|
||||||
module_sizes = dict(
|
|
||||||
sorted(
|
|
||||||
{hook.model_id: get_memory_footprint(hook.model) for hook in hooks}.items(),
|
|
||||||
key=lambda x: x[1],
|
|
||||||
reverse=True,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def search_best_candidate(module_sizes, min_memory_offload):
|
|
||||||
"""
|
|
||||||
search the optimal combination of models to offload to cpu, given a dictionary of module sizes and a
|
|
||||||
minimum memory offload size. the combination of models should add up to the smallest modulesize that is
|
|
||||||
larger than `min_memory_offload`
|
|
||||||
"""
|
|
||||||
model_ids = list(module_sizes.keys())
|
|
||||||
best_candidate = None
|
|
||||||
best_size = float("inf")
|
|
||||||
for r in range(1, len(model_ids) + 1):
|
|
||||||
for candidate_model_ids in combinations(model_ids, r):
|
|
||||||
candidate_size = sum(
|
|
||||||
module_sizes[candidate_model_id] for candidate_model_id in candidate_model_ids
|
|
||||||
)
|
|
||||||
if candidate_size < min_memory_offload:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
if best_candidate is None or candidate_size < best_size:
|
|
||||||
best_candidate = candidate_model_ids
|
|
||||||
best_size = candidate_size
|
|
||||||
|
|
||||||
return best_candidate
|
|
||||||
|
|
||||||
best_offload_model_ids = search_best_candidate(module_sizes, min_memory_offload)
|
|
||||||
|
|
||||||
if best_offload_model_ids is None:
|
|
||||||
# if no combination is found, meaning that we cannot meet the memory requirement, offload all models
|
|
||||||
logger.warning("no combination of models to offload to cpu is found, offloading all models")
|
|
||||||
hooks_to_offload = hooks
|
|
||||||
else:
|
|
||||||
hooks_to_offload = [hook for hook in hooks if hook.model_id in best_offload_model_ids]
|
|
||||||
|
|
||||||
return hooks_to_offload
|
|
||||||
|
|
||||||
|
|
||||||
class ComponentsManager:
|
|
||||||
def __init__(self):
|
|
||||||
self.components = OrderedDict()
|
|
||||||
self.model_hooks = None
|
|
||||||
self._auto_offload_enabled = False
|
|
||||||
|
|
||||||
def add(self, name, component):
|
|
||||||
if name not in self.components:
|
|
||||||
self.components[name] = component
|
|
||||||
if self._auto_offload_enabled:
|
|
||||||
self.enable_auto_cpu_offload(self._auto_offload_device)
|
|
||||||
|
|
||||||
def remove(self, name):
|
|
||||||
self.components.pop(name)
|
|
||||||
if self._auto_offload_enabled:
|
|
||||||
self.enable_auto_cpu_offload(self._auto_offload_device)
|
|
||||||
|
|
||||||
def get(self, names: Union[str, List[str]]):
|
|
||||||
if isinstance(names, str):
|
|
||||||
if names not in self.components:
|
|
||||||
raise ValueError(f"Component '{names}' not found in ComponentsManager")
|
|
||||||
return self.components[names]
|
|
||||||
elif isinstance(names, list):
|
|
||||||
return {n: self.components[n] for n in names}
|
|
||||||
else:
|
|
||||||
raise ValueError(f"Invalid type for names: {type(names)}")
|
|
||||||
|
|
||||||
def enable_auto_cpu_offload(self, device, memory_reserve_margin="3GB"):
|
|
||||||
for name, component in self.components.items():
|
|
||||||
if isinstance(component, torch.nn.Module) and hasattr(component, "_hf_hook"):
|
|
||||||
remove_hook_from_module(component, recurse=True)
|
|
||||||
|
|
||||||
self.disable_auto_cpu_offload()
|
|
||||||
offload_strategy = AutoOffloadStrategy(memory_reserve_margin=memory_reserve_margin)
|
|
||||||
device = torch.device(device)
|
|
||||||
if device.index is None:
|
|
||||||
device = torch.device(f"{device.type}:{0}")
|
|
||||||
all_hooks = []
|
|
||||||
for name, component in self.components.items():
|
|
||||||
if isinstance(component, torch.nn.Module):
|
|
||||||
hook = custom_offload_with_hook(name, component, device, offload_strategy=offload_strategy)
|
|
||||||
all_hooks.append(hook)
|
|
||||||
|
|
||||||
for hook in all_hooks:
|
|
||||||
other_hooks = [h for h in all_hooks if h is not hook]
|
|
||||||
for other_hook in other_hooks:
|
|
||||||
if other_hook.hook.execution_device == hook.hook.execution_device:
|
|
||||||
hook.add_other_hook(other_hook)
|
|
||||||
|
|
||||||
self.model_hooks = all_hooks
|
|
||||||
self._auto_offload_enabled = True
|
|
||||||
self._auto_offload_device = device
|
|
||||||
|
|
||||||
def disable_auto_cpu_offload(self):
|
|
||||||
if self.model_hooks is None:
|
|
||||||
self._auto_offload_enabled = False
|
|
||||||
return
|
|
||||||
|
|
||||||
for hook in self.model_hooks:
|
|
||||||
hook.offload()
|
|
||||||
hook.remove()
|
|
||||||
if self.model_hooks:
|
|
||||||
clear_device_cache()
|
|
||||||
self.model_hooks = None
|
|
||||||
self._auto_offload_enabled = False
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
col_widths = {
|
|
||||||
"id": max(15, max(len(id) for id in self.components.keys())),
|
|
||||||
"class": max(25, max(len(component.__class__.__name__) for component in self.components.values())),
|
|
||||||
"device": 10,
|
|
||||||
"dtype": 15,
|
|
||||||
"size": 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create the header lines
|
|
||||||
sep_line = "=" * (sum(col_widths.values()) + len(col_widths) * 3 - 1) + "\n"
|
|
||||||
dash_line = "-" * (sum(col_widths.values()) + len(col_widths) * 3 - 1) + "\n"
|
|
||||||
|
|
||||||
output = "Components:\n" + sep_line
|
|
||||||
|
|
||||||
# Separate components into models and others
|
|
||||||
models = {k: v for k, v in self.components.items() if isinstance(v, torch.nn.Module)}
|
|
||||||
others = {k: v for k, v in self.components.items() if not isinstance(v, torch.nn.Module)}
|
|
||||||
|
|
||||||
# Models section
|
|
||||||
if models:
|
|
||||||
output += "Models:\n" + dash_line
|
|
||||||
# Column headers
|
|
||||||
output += f"{'Model ID':<{col_widths['id']}} | {'Class':<{col_widths['class']}} | "
|
|
||||||
output += f"{'Device':<{col_widths['device']}} | {'Dtype':<{col_widths['dtype']}} | Size (GB) \n"
|
|
||||||
output += dash_line
|
|
||||||
|
|
||||||
# Model entries
|
|
||||||
for name, component in models.items():
|
|
||||||
device = component.device
|
|
||||||
dtype = component.dtype
|
|
||||||
size_bytes = get_memory_footprint(component)
|
|
||||||
size_gb = size_bytes / (1024**3)
|
|
||||||
|
|
||||||
output += f"{name:<{col_widths['id']}} | {component.__class__.__name__:<{col_widths['class']}} | "
|
|
||||||
output += (
|
|
||||||
f"{str(device):<{col_widths['device']}} | {str(dtype):<{col_widths['dtype']}} | {size_gb:.2f}\n"
|
|
||||||
)
|
|
||||||
output += dash_line
|
|
||||||
|
|
||||||
# Other components section
|
|
||||||
if others:
|
|
||||||
if models: # Add extra newline if we had models section
|
|
||||||
output += "\n"
|
|
||||||
output += "Other Components:\n" + dash_line
|
|
||||||
# Column headers for other components
|
|
||||||
output += f"{'Component ID':<{col_widths['id']}} | {'Class':<{col_widths['class']}}\n"
|
|
||||||
output += dash_line
|
|
||||||
|
|
||||||
# Other component entries
|
|
||||||
for name, component in others.items():
|
|
||||||
output += f"{name:<{col_widths['id']}} | {component.__class__.__name__:<{col_widths['class']}}\n"
|
|
||||||
output += dash_line
|
|
||||||
|
|
||||||
return output
|
|
||||||
|
|
||||||
def add_from_pretrained(self, pretrained_model_name_or_path, **kwargs):
|
|
||||||
from ..pipelines.pipeline_utils import DiffusionPipeline
|
|
||||||
|
|
||||||
pipe = DiffusionPipeline.from_pretrained(pretrained_model_name_or_path, **kwargs)
|
|
||||||
for name, component in pipe.components.items():
|
|
||||||
if name not in self.components and component is not None:
|
|
||||||
self.add(name, component)
|
|
||||||
elif name in self.components:
|
|
||||||
logger.warning(
|
|
||||||
f"Component '{name}' already exists in ComponentsManager and will not be added. To add it, either:\n"
|
|
||||||
f"1. remove the existing component with remove('{name}')\n"
|
|
||||||
f"2. Use a different name: add('{name}_2', component)"
|
|
||||||
)
|
|
||||||
@@ -12,19 +12,19 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import warnings
|
import warnings
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Union
|
from typing import Any, Callable, Dict, List, Optional, Union
|
||||||
|
|
||||||
|
import requests
|
||||||
import torch
|
import torch
|
||||||
from huggingface_hub import ModelCard, model_info
|
from huggingface_hub import DDUFEntry, ModelCard, model_info, snapshot_download
|
||||||
from huggingface_hub.utils import validate_hf_hub_args
|
from huggingface_hub.utils import OfflineModeIsEnabled, validate_hf_hub_args
|
||||||
from packaging import version
|
from packaging import version
|
||||||
|
from requests.exceptions import HTTPError
|
||||||
|
|
||||||
from .. import __version__
|
from .. import __version__
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
@@ -38,14 +38,16 @@ from ..utils import (
|
|||||||
is_accelerate_available,
|
is_accelerate_available,
|
||||||
is_peft_available,
|
is_peft_available,
|
||||||
is_transformers_available,
|
is_transformers_available,
|
||||||
|
is_transformers_version,
|
||||||
logging,
|
logging,
|
||||||
)
|
)
|
||||||
from ..utils.torch_utils import is_compiled_module
|
from ..utils.torch_utils import is_compiled_module
|
||||||
|
from .transformers_loading_utils import _load_tokenizer_from_dduf, _load_transformers_model_from_dduf
|
||||||
|
|
||||||
|
|
||||||
if is_transformers_available():
|
if is_transformers_available():
|
||||||
import transformers
|
import transformers
|
||||||
from transformers import PreTrainedModel
|
from transformers import PreTrainedModel, PreTrainedTokenizerBase
|
||||||
from transformers.utils import FLAX_WEIGHTS_NAME as TRANSFORMERS_FLAX_WEIGHTS_NAME
|
from transformers.utils import FLAX_WEIGHTS_NAME as TRANSFORMERS_FLAX_WEIGHTS_NAME
|
||||||
from transformers.utils import SAFE_WEIGHTS_NAME as TRANSFORMERS_SAFE_WEIGHTS_NAME
|
from transformers.utils import SAFE_WEIGHTS_NAME as TRANSFORMERS_SAFE_WEIGHTS_NAME
|
||||||
from transformers.utils import WEIGHTS_NAME as TRANSFORMERS_WEIGHTS_NAME
|
from transformers.utils import WEIGHTS_NAME as TRANSFORMERS_WEIGHTS_NAME
|
||||||
@@ -627,6 +629,7 @@ def load_sub_model(
|
|||||||
low_cpu_mem_usage: bool,
|
low_cpu_mem_usage: bool,
|
||||||
cached_folder: Union[str, os.PathLike],
|
cached_folder: Union[str, os.PathLike],
|
||||||
use_safetensors: bool,
|
use_safetensors: bool,
|
||||||
|
dduf_entries: Optional[Dict[str, DDUFEntry]],
|
||||||
):
|
):
|
||||||
"""Helper method to load the module `name` from `library_name` and `class_name`"""
|
"""Helper method to load the module `name` from `library_name` and `class_name`"""
|
||||||
|
|
||||||
@@ -663,7 +666,7 @@ def load_sub_model(
|
|||||||
f" any of the loading methods defined in {ALL_IMPORTABLE_CLASSES}."
|
f" any of the loading methods defined in {ALL_IMPORTABLE_CLASSES}."
|
||||||
)
|
)
|
||||||
|
|
||||||
load_method = getattr(class_obj, load_method_name)
|
load_method = _get_load_method(class_obj, load_method_name, is_dduf=dduf_entries is not None)
|
||||||
|
|
||||||
# add kwargs to loading method
|
# add kwargs to loading method
|
||||||
diffusers_module = importlib.import_module(__name__.split(".")[0])
|
diffusers_module = importlib.import_module(__name__.split(".")[0])
|
||||||
@@ -721,7 +724,10 @@ def load_sub_model(
|
|||||||
loading_kwargs["low_cpu_mem_usage"] = False
|
loading_kwargs["low_cpu_mem_usage"] = False
|
||||||
|
|
||||||
# check if the module is in a subdirectory
|
# check if the module is in a subdirectory
|
||||||
if os.path.isdir(os.path.join(cached_folder, name)):
|
if dduf_entries:
|
||||||
|
loading_kwargs["dduf_entries"] = dduf_entries
|
||||||
|
loaded_sub_model = load_method(name, **loading_kwargs)
|
||||||
|
elif os.path.isdir(os.path.join(cached_folder, name)):
|
||||||
loaded_sub_model = load_method(os.path.join(cached_folder, name), **loading_kwargs)
|
loaded_sub_model = load_method(os.path.join(cached_folder, name), **loading_kwargs)
|
||||||
else:
|
else:
|
||||||
# else load from the root directory
|
# else load from the root directory
|
||||||
@@ -746,6 +752,22 @@ def load_sub_model(
|
|||||||
return loaded_sub_model
|
return loaded_sub_model
|
||||||
|
|
||||||
|
|
||||||
|
def _get_load_method(class_obj: object, load_method_name: str, is_dduf: bool) -> Callable:
|
||||||
|
"""
|
||||||
|
Return the method to load the sub model.
|
||||||
|
|
||||||
|
In practice, this method will return the `"from_pretrained"` (or `load_method_name`) method of the class object
|
||||||
|
except if loading from a DDUF checkpoint. In that case, transformers models and tokenizers have a specific loading
|
||||||
|
method that we need to use.
|
||||||
|
"""
|
||||||
|
if is_dduf:
|
||||||
|
if issubclass(class_obj, PreTrainedTokenizerBase):
|
||||||
|
return lambda *args, **kwargs: _load_tokenizer_from_dduf(class_obj, *args, **kwargs)
|
||||||
|
if issubclass(class_obj, PreTrainedModel):
|
||||||
|
return lambda *args, **kwargs: _load_transformers_model_from_dduf(class_obj, *args, **kwargs)
|
||||||
|
return getattr(class_obj, load_method_name)
|
||||||
|
|
||||||
|
|
||||||
def _fetch_class_library_tuple(module):
|
def _fetch_class_library_tuple(module):
|
||||||
# import it here to avoid circular import
|
# import it here to avoid circular import
|
||||||
diffusers_module = importlib.import_module(__name__.split(".")[0])
|
diffusers_module = importlib.import_module(__name__.split(".")[0])
|
||||||
@@ -968,3 +990,70 @@ def _get_ignore_patterns(
|
|||||||
)
|
)
|
||||||
|
|
||||||
return ignore_patterns
|
return ignore_patterns
|
||||||
|
|
||||||
|
|
||||||
|
def _download_dduf_file(
|
||||||
|
pretrained_model_name: str,
|
||||||
|
dduf_file: str,
|
||||||
|
pipeline_class_name: str,
|
||||||
|
cache_dir: str,
|
||||||
|
proxies: str,
|
||||||
|
local_files_only: bool,
|
||||||
|
token: str,
|
||||||
|
revision: str,
|
||||||
|
):
|
||||||
|
model_info_call_error = None
|
||||||
|
if not local_files_only:
|
||||||
|
try:
|
||||||
|
info = model_info(pretrained_model_name, token=token, revision=revision)
|
||||||
|
except (HTTPError, OfflineModeIsEnabled, requests.ConnectionError) as e:
|
||||||
|
logger.warning(f"Couldn't connect to the Hub: {e}.\nWill try to load from local cache.")
|
||||||
|
local_files_only = True
|
||||||
|
model_info_call_error = e # save error to reraise it if model is not cached locally
|
||||||
|
|
||||||
|
if (
|
||||||
|
not local_files_only
|
||||||
|
and dduf_file is not None
|
||||||
|
and dduf_file not in (sibling.rfilename for sibling in info.siblings)
|
||||||
|
):
|
||||||
|
raise ValueError(f"Requested {dduf_file} file is not available in {pretrained_model_name}.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
user_agent = {"pipeline_class": pipeline_class_name, "dduf": True}
|
||||||
|
cached_folder = snapshot_download(
|
||||||
|
pretrained_model_name,
|
||||||
|
cache_dir=cache_dir,
|
||||||
|
proxies=proxies,
|
||||||
|
local_files_only=local_files_only,
|
||||||
|
token=token,
|
||||||
|
revision=revision,
|
||||||
|
allow_patterns=[dduf_file],
|
||||||
|
user_agent=user_agent,
|
||||||
|
)
|
||||||
|
return cached_folder
|
||||||
|
except FileNotFoundError:
|
||||||
|
# Means we tried to load pipeline with `local_files_only=True` but the files have not been found in local cache.
|
||||||
|
# This can happen in two cases:
|
||||||
|
# 1. If the user passed `local_files_only=True` => we raise the error directly
|
||||||
|
# 2. If we forced `local_files_only=True` when `model_info` failed => we raise the initial error
|
||||||
|
if model_info_call_error is None:
|
||||||
|
# 1. user passed `local_files_only=True`
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
# 2. we forced `local_files_only=True` when `model_info` failed
|
||||||
|
raise EnvironmentError(
|
||||||
|
f"Cannot load model {pretrained_model_name}: model is not cached locally and an error occurred"
|
||||||
|
" while trying to fetch metadata from the Hub. Please check out the root cause in the stacktrace"
|
||||||
|
" above."
|
||||||
|
) from model_info_call_error
|
||||||
|
|
||||||
|
|
||||||
|
def _maybe_raise_error_for_incorrect_transformers(config_dict):
|
||||||
|
has_transformers_component = False
|
||||||
|
for k in config_dict:
|
||||||
|
if isinstance(config_dict[k], list):
|
||||||
|
has_transformers_component = config_dict[k][0] == "transformers"
|
||||||
|
if has_transformers_component:
|
||||||
|
break
|
||||||
|
if has_transformers_component and not is_transformers_version(">", "4.47.1"):
|
||||||
|
raise ValueError("Please upgrade your `transformers` installation to the latest version to use DDUF.")
|
||||||
|
|||||||
@@ -29,10 +29,12 @@ import PIL.Image
|
|||||||
import requests
|
import requests
|
||||||
import torch
|
import torch
|
||||||
from huggingface_hub import (
|
from huggingface_hub import (
|
||||||
|
DDUFEntry,
|
||||||
ModelCard,
|
ModelCard,
|
||||||
create_repo,
|
create_repo,
|
||||||
hf_hub_download,
|
hf_hub_download,
|
||||||
model_info,
|
model_info,
|
||||||
|
read_dduf_file,
|
||||||
snapshot_download,
|
snapshot_download,
|
||||||
)
|
)
|
||||||
from huggingface_hub.utils import OfflineModeIsEnabled, validate_hf_hub_args
|
from huggingface_hub.utils import OfflineModeIsEnabled, validate_hf_hub_args
|
||||||
@@ -72,6 +74,7 @@ from .pipeline_loading_utils import (
|
|||||||
CONNECTED_PIPES_KEYS,
|
CONNECTED_PIPES_KEYS,
|
||||||
CUSTOM_PIPELINE_FILE_NAME,
|
CUSTOM_PIPELINE_FILE_NAME,
|
||||||
LOADABLE_CLASSES,
|
LOADABLE_CLASSES,
|
||||||
|
_download_dduf_file,
|
||||||
_fetch_class_library_tuple,
|
_fetch_class_library_tuple,
|
||||||
_get_custom_components_and_folders,
|
_get_custom_components_and_folders,
|
||||||
_get_custom_pipeline_class,
|
_get_custom_pipeline_class,
|
||||||
@@ -79,6 +82,7 @@ from .pipeline_loading_utils import (
|
|||||||
_get_ignore_patterns,
|
_get_ignore_patterns,
|
||||||
_get_pipeline_class,
|
_get_pipeline_class,
|
||||||
_identify_model_variants,
|
_identify_model_variants,
|
||||||
|
_maybe_raise_error_for_incorrect_transformers,
|
||||||
_maybe_raise_warning_for_inpainting,
|
_maybe_raise_warning_for_inpainting,
|
||||||
_resolve_custom_pipeline_and_cls,
|
_resolve_custom_pipeline_and_cls,
|
||||||
_unwrap_model,
|
_unwrap_model,
|
||||||
@@ -218,6 +222,7 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
Whether or not to push your model to the Hugging Face model hub after saving it. You can specify the
|
Whether or not to push your model to the Hugging Face model hub after saving it. You can specify the
|
||||||
repository you want to push to with `repo_id` (will default to the name of `save_directory` in your
|
repository you want to push to with `repo_id` (will default to the name of `save_directory` in your
|
||||||
namespace).
|
namespace).
|
||||||
|
|
||||||
kwargs (`Dict[str, Any]`, *optional*):
|
kwargs (`Dict[str, Any]`, *optional*):
|
||||||
Additional keyword arguments passed along to the [`~utils.PushToHubMixin.push_to_hub`] method.
|
Additional keyword arguments passed along to the [`~utils.PushToHubMixin.push_to_hub`] method.
|
||||||
"""
|
"""
|
||||||
@@ -531,6 +536,7 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
- A path to a *directory* (for example `./my_pipeline_directory/`) containing pipeline weights
|
- A path to a *directory* (for example `./my_pipeline_directory/`) containing pipeline weights
|
||||||
saved using
|
saved using
|
||||||
[`~DiffusionPipeline.save_pretrained`].
|
[`~DiffusionPipeline.save_pretrained`].
|
||||||
|
- A path to a *directory* (for example `./my_pipeline_directory/`) containing a dduf file
|
||||||
torch_dtype (`str` or `torch.dtype`, *optional*):
|
torch_dtype (`str` or `torch.dtype`, *optional*):
|
||||||
Override the default `torch.dtype` and load the model with another dtype. If "auto" is passed, the
|
Override the default `torch.dtype` and load the model with another dtype. If "auto" is passed, the
|
||||||
dtype is automatically derived from the model's weights.
|
dtype is automatically derived from the model's weights.
|
||||||
@@ -625,6 +631,8 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
variant (`str`, *optional*):
|
variant (`str`, *optional*):
|
||||||
Load weights from a specified variant filename such as `"fp16"` or `"ema"`. This is ignored when
|
Load weights from a specified variant filename such as `"fp16"` or `"ema"`. This is ignored when
|
||||||
loading `from_flax`.
|
loading `from_flax`.
|
||||||
|
dduf_file(`str`, *optional*):
|
||||||
|
Load weights from the specified dduf file.
|
||||||
|
|
||||||
<Tip>
|
<Tip>
|
||||||
|
|
||||||
@@ -674,6 +682,7 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
offload_state_dict = kwargs.pop("offload_state_dict", False)
|
offload_state_dict = kwargs.pop("offload_state_dict", False)
|
||||||
low_cpu_mem_usage = kwargs.pop("low_cpu_mem_usage", _LOW_CPU_MEM_USAGE_DEFAULT)
|
low_cpu_mem_usage = kwargs.pop("low_cpu_mem_usage", _LOW_CPU_MEM_USAGE_DEFAULT)
|
||||||
variant = kwargs.pop("variant", None)
|
variant = kwargs.pop("variant", None)
|
||||||
|
dduf_file = kwargs.pop("dduf_file", None)
|
||||||
use_safetensors = kwargs.pop("use_safetensors", None)
|
use_safetensors = kwargs.pop("use_safetensors", None)
|
||||||
use_onnx = kwargs.pop("use_onnx", None)
|
use_onnx = kwargs.pop("use_onnx", None)
|
||||||
load_connected_pipeline = kwargs.pop("load_connected_pipeline", False)
|
load_connected_pipeline = kwargs.pop("load_connected_pipeline", False)
|
||||||
@@ -722,6 +731,12 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
" dispatching. Please make sure to set `low_cpu_mem_usage=True`."
|
" dispatching. Please make sure to set `low_cpu_mem_usage=True`."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if dduf_file:
|
||||||
|
if custom_pipeline:
|
||||||
|
raise NotImplementedError("Custom pipelines are not supported with DDUF at the moment.")
|
||||||
|
if load_connected_pipeline:
|
||||||
|
raise NotImplementedError("Connected pipelines are not supported with DDUF at the moment.")
|
||||||
|
|
||||||
# 1. Download the checkpoints and configs
|
# 1. Download the checkpoints and configs
|
||||||
# use snapshot download here to get it working from from_pretrained
|
# use snapshot download here to get it working from from_pretrained
|
||||||
if not os.path.isdir(pretrained_model_name_or_path):
|
if not os.path.isdir(pretrained_model_name_or_path):
|
||||||
@@ -744,6 +759,7 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
custom_pipeline=custom_pipeline,
|
custom_pipeline=custom_pipeline,
|
||||||
custom_revision=custom_revision,
|
custom_revision=custom_revision,
|
||||||
variant=variant,
|
variant=variant,
|
||||||
|
dduf_file=dduf_file,
|
||||||
load_connected_pipeline=load_connected_pipeline,
|
load_connected_pipeline=load_connected_pipeline,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
@@ -765,7 +781,17 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
)
|
)
|
||||||
logger.warning(warn_msg)
|
logger.warning(warn_msg)
|
||||||
|
|
||||||
config_dict = cls.load_config(cached_folder)
|
dduf_entries = None
|
||||||
|
if dduf_file:
|
||||||
|
dduf_file_path = os.path.join(cached_folder, dduf_file)
|
||||||
|
dduf_entries = read_dduf_file(dduf_file_path)
|
||||||
|
# The reader contains already all the files needed, no need to check it again
|
||||||
|
cached_folder = ""
|
||||||
|
|
||||||
|
config_dict = cls.load_config(cached_folder, dduf_entries=dduf_entries)
|
||||||
|
|
||||||
|
if dduf_file:
|
||||||
|
_maybe_raise_error_for_incorrect_transformers(config_dict)
|
||||||
|
|
||||||
# pop out "_ignore_files" as it is only needed for download
|
# pop out "_ignore_files" as it is only needed for download
|
||||||
config_dict.pop("_ignore_files", None)
|
config_dict.pop("_ignore_files", None)
|
||||||
@@ -943,6 +969,7 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
low_cpu_mem_usage=low_cpu_mem_usage,
|
low_cpu_mem_usage=low_cpu_mem_usage,
|
||||||
cached_folder=cached_folder,
|
cached_folder=cached_folder,
|
||||||
use_safetensors=use_safetensors,
|
use_safetensors=use_safetensors,
|
||||||
|
dduf_entries=dduf_entries,
|
||||||
)
|
)
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Loaded {name} as {class_name} from `{name}` subfolder of {pretrained_model_name_or_path}."
|
f"Loaded {name} as {class_name} from `{name}` subfolder of {pretrained_model_name_or_path}."
|
||||||
@@ -1256,6 +1283,8 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
variant (`str`, *optional*):
|
variant (`str`, *optional*):
|
||||||
Load weights from a specified variant filename such as `"fp16"` or `"ema"`. This is ignored when
|
Load weights from a specified variant filename such as `"fp16"` or `"ema"`. This is ignored when
|
||||||
loading `from_flax`.
|
loading `from_flax`.
|
||||||
|
dduf_file(`str`, *optional*):
|
||||||
|
Load weights from the specified DDUF file.
|
||||||
use_safetensors (`bool`, *optional*, defaults to `None`):
|
use_safetensors (`bool`, *optional*, defaults to `None`):
|
||||||
If set to `None`, the safetensors weights are downloaded if they're available **and** if the
|
If set to `None`, the safetensors weights are downloaded if they're available **and** if the
|
||||||
safetensors library is installed. If set to `True`, the model is forcibly loaded from safetensors
|
safetensors library is installed. If set to `True`, the model is forcibly loaded from safetensors
|
||||||
@@ -1296,6 +1325,23 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
use_onnx = kwargs.pop("use_onnx", None)
|
use_onnx = kwargs.pop("use_onnx", None)
|
||||||
load_connected_pipeline = kwargs.pop("load_connected_pipeline", False)
|
load_connected_pipeline = kwargs.pop("load_connected_pipeline", False)
|
||||||
trust_remote_code = kwargs.pop("trust_remote_code", False)
|
trust_remote_code = kwargs.pop("trust_remote_code", False)
|
||||||
|
dduf_file: Optional[Dict[str, DDUFEntry]] = kwargs.pop("dduf_file", None)
|
||||||
|
|
||||||
|
if dduf_file:
|
||||||
|
if custom_pipeline:
|
||||||
|
raise NotImplementedError("Custom pipelines are not supported with DDUF at the moment.")
|
||||||
|
if load_connected_pipeline:
|
||||||
|
raise NotImplementedError("Connected pipelines are not supported with DDUF at the moment.")
|
||||||
|
return _download_dduf_file(
|
||||||
|
pretrained_model_name=pretrained_model_name,
|
||||||
|
dduf_file=dduf_file,
|
||||||
|
pipeline_class_name=cls.__name__,
|
||||||
|
cache_dir=cache_dir,
|
||||||
|
proxies=proxies,
|
||||||
|
local_files_only=local_files_only,
|
||||||
|
token=token,
|
||||||
|
revision=revision,
|
||||||
|
)
|
||||||
|
|
||||||
allow_pickle = False
|
allow_pickle = False
|
||||||
if use_safetensors is None:
|
if use_safetensors is None:
|
||||||
@@ -1375,7 +1421,6 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
allow_patterns += [f"{custom_pipeline}.py"] if f"{custom_pipeline}.py" in filenames else []
|
allow_patterns += [f"{custom_pipeline}.py"] if f"{custom_pipeline}.py" in filenames else []
|
||||||
# also allow downloading config.json files with the model
|
# also allow downloading config.json files with the model
|
||||||
allow_patterns += [os.path.join(k, "config.json") for k in model_folder_names]
|
allow_patterns += [os.path.join(k, "config.json") for k in model_folder_names]
|
||||||
|
|
||||||
allow_patterns += [
|
allow_patterns += [
|
||||||
SCHEDULER_CONFIG_NAME,
|
SCHEDULER_CONFIG_NAME,
|
||||||
CONFIG_NAME,
|
CONFIG_NAME,
|
||||||
@@ -1471,7 +1516,6 @@ class DiffusionPipeline(ConfigMixin, PushToHubMixin):
|
|||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
)
|
)
|
||||||
|
|
||||||
# retrieve pipeline class from local file
|
|
||||||
cls_name = cls.load_config(os.path.join(cached_folder, "model_index.json")).get("_class_name", None)
|
cls_name = cls.load_config(os.path.join(cached_folder, "model_index.json")).get("_class_name", None)
|
||||||
cls_name = cls_name[4:] if isinstance(cls_name, str) and cls_name.startswith("Flax") else cls_name
|
cls_name = cls_name[4:] if isinstance(cls_name, str) and cls_name.startswith("Flax") else cls_name
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
# Copyright 2024 The HuggingFace Inc. team.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
import contextlib
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
from typing import TYPE_CHECKING, Dict
|
||||||
|
|
||||||
|
from huggingface_hub import DDUFEntry
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
from ..utils import is_safetensors_available, is_transformers_available, is_transformers_version
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from transformers import PreTrainedModel, PreTrainedTokenizer
|
||||||
|
|
||||||
|
if is_transformers_available():
|
||||||
|
from transformers import PreTrainedModel, PreTrainedTokenizer
|
||||||
|
|
||||||
|
if is_safetensors_available():
|
||||||
|
import safetensors.torch
|
||||||
|
|
||||||
|
|
||||||
|
def _load_tokenizer_from_dduf(
|
||||||
|
cls: "PreTrainedTokenizer", name: str, dduf_entries: Dict[str, DDUFEntry], **kwargs
|
||||||
|
) -> "PreTrainedTokenizer":
|
||||||
|
"""
|
||||||
|
Load a tokenizer from a DDUF archive.
|
||||||
|
|
||||||
|
In practice, `transformers` do not provide a way to load a tokenizer from a DDUF archive. This function is a
|
||||||
|
workaround by extracting the tokenizer files from the DDUF archive and loading the tokenizer from the extracted
|
||||||
|
files. There is an extra cost of extracting the files, but of limited impact as the tokenizer files are usually
|
||||||
|
small-ish.
|
||||||
|
"""
|
||||||
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||||
|
for entry_name, entry in dduf_entries.items():
|
||||||
|
if entry_name.startswith(name + "/"):
|
||||||
|
tmp_entry_path = os.path.join(tmp_dir, *entry_name.split("/"))
|
||||||
|
# need to create intermediary directory if they don't exist
|
||||||
|
os.makedirs(os.path.dirname(tmp_entry_path), exist_ok=True)
|
||||||
|
with open(tmp_entry_path, "wb") as f:
|
||||||
|
with entry.as_mmap() as mm:
|
||||||
|
f.write(mm)
|
||||||
|
return cls.from_pretrained(os.path.dirname(tmp_entry_path), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def _load_transformers_model_from_dduf(
|
||||||
|
cls: "PreTrainedModel", name: str, dduf_entries: Dict[str, DDUFEntry], **kwargs
|
||||||
|
) -> "PreTrainedModel":
|
||||||
|
"""
|
||||||
|
Load a transformers model from a DDUF archive.
|
||||||
|
|
||||||
|
In practice, `transformers` do not provide a way to load a model from a DDUF archive. This function is a workaround
|
||||||
|
by instantiating a model from the config file and loading the weights from the DDUF archive directly.
|
||||||
|
"""
|
||||||
|
config_file = dduf_entries.get(f"{name}/config.json")
|
||||||
|
if config_file is None:
|
||||||
|
raise EnvironmentError(
|
||||||
|
f"Could not find a config.json file for component {name} in DDUF file (contains {dduf_entries.keys()})."
|
||||||
|
)
|
||||||
|
generation_config = dduf_entries.get(f"{name}/generation_config.json", None)
|
||||||
|
|
||||||
|
weight_files = [
|
||||||
|
entry
|
||||||
|
for entry_name, entry in dduf_entries.items()
|
||||||
|
if entry_name.startswith(f"{name}/") and entry_name.endswith(".safetensors")
|
||||||
|
]
|
||||||
|
if not weight_files:
|
||||||
|
raise EnvironmentError(
|
||||||
|
f"Could not find any weight file for component {name} in DDUF file (contains {dduf_entries.keys()})."
|
||||||
|
)
|
||||||
|
if not is_safetensors_available():
|
||||||
|
raise EnvironmentError(
|
||||||
|
"Safetensors is not available, cannot load model from DDUF. Please `pip install safetensors`."
|
||||||
|
)
|
||||||
|
if is_transformers_version("<", "4.47.0"):
|
||||||
|
raise ImportError(
|
||||||
|
"You need to install `transformers>4.47.0` in order to load a transformers model from a DDUF file. "
|
||||||
|
"You can install it with: `pip install --upgrade transformers`"
|
||||||
|
)
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||||
|
from transformers import AutoConfig, GenerationConfig
|
||||||
|
|
||||||
|
tmp_config_file = os.path.join(tmp_dir, "config.json")
|
||||||
|
with open(tmp_config_file, "w") as f:
|
||||||
|
f.write(config_file.read_text())
|
||||||
|
config = AutoConfig.from_pretrained(tmp_config_file)
|
||||||
|
if generation_config is not None:
|
||||||
|
tmp_generation_config_file = os.path.join(tmp_dir, "generation_config.json")
|
||||||
|
with open(tmp_generation_config_file, "w") as f:
|
||||||
|
f.write(generation_config.read_text())
|
||||||
|
generation_config = GenerationConfig.from_pretrained(tmp_generation_config_file)
|
||||||
|
state_dict = {}
|
||||||
|
with contextlib.ExitStack() as stack:
|
||||||
|
for entry in tqdm(weight_files, desc="Loading state_dict"): # Loop over safetensors files
|
||||||
|
# Memory-map the safetensors file
|
||||||
|
mmap = stack.enter_context(entry.as_mmap())
|
||||||
|
# Load tensors from the memory-mapped file
|
||||||
|
tensors = safetensors.torch.load(mmap)
|
||||||
|
# Update the state dictionary with tensors
|
||||||
|
state_dict.update(tensors)
|
||||||
|
return cls.from_pretrained(
|
||||||
|
pretrained_model_name_or_path=None,
|
||||||
|
config=config,
|
||||||
|
generation_config=generation_config,
|
||||||
|
state_dict=state_dict,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
@@ -70,6 +70,7 @@ from .import_utils import (
|
|||||||
is_gguf_available,
|
is_gguf_available,
|
||||||
is_gguf_version,
|
is_gguf_version,
|
||||||
is_google_colab,
|
is_google_colab,
|
||||||
|
is_hf_hub_version,
|
||||||
is_inflect_available,
|
is_inflect_available,
|
||||||
is_invisible_watermark_available,
|
is_invisible_watermark_available,
|
||||||
is_k_diffusion_available,
|
is_k_diffusion_available,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from typing import Dict, List, Optional, Union
|
|||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from huggingface_hub import (
|
from huggingface_hub import (
|
||||||
|
DDUFEntry,
|
||||||
ModelCard,
|
ModelCard,
|
||||||
ModelCardData,
|
ModelCardData,
|
||||||
create_repo,
|
create_repo,
|
||||||
@@ -291,9 +292,26 @@ def _get_model_file(
|
|||||||
user_agent: Optional[Union[Dict, str]] = None,
|
user_agent: Optional[Union[Dict, str]] = None,
|
||||||
revision: Optional[str] = None,
|
revision: Optional[str] = None,
|
||||||
commit_hash: Optional[str] = None,
|
commit_hash: Optional[str] = None,
|
||||||
|
dduf_entries: Optional[Dict[str, DDUFEntry]] = None,
|
||||||
):
|
):
|
||||||
pretrained_model_name_or_path = str(pretrained_model_name_or_path)
|
pretrained_model_name_or_path = str(pretrained_model_name_or_path)
|
||||||
if os.path.isfile(pretrained_model_name_or_path):
|
|
||||||
|
if dduf_entries:
|
||||||
|
if subfolder is not None:
|
||||||
|
raise ValueError(
|
||||||
|
"DDUF file only allow for 1 level of directory (e.g transformer/model1/model.safetentors is not allowed). "
|
||||||
|
"Please check the DDUF structure"
|
||||||
|
)
|
||||||
|
model_file = (
|
||||||
|
weights_name
|
||||||
|
if pretrained_model_name_or_path == ""
|
||||||
|
else "/".join([pretrained_model_name_or_path, weights_name])
|
||||||
|
)
|
||||||
|
if model_file in dduf_entries:
|
||||||
|
return model_file
|
||||||
|
else:
|
||||||
|
raise EnvironmentError(f"Error no file named {weights_name} found in archive {dduf_entries.keys()}.")
|
||||||
|
elif os.path.isfile(pretrained_model_name_or_path):
|
||||||
return pretrained_model_name_or_path
|
return pretrained_model_name_or_path
|
||||||
elif os.path.isdir(pretrained_model_name_or_path):
|
elif os.path.isdir(pretrained_model_name_or_path):
|
||||||
if os.path.isfile(os.path.join(pretrained_model_name_or_path, weights_name)):
|
if os.path.isfile(os.path.join(pretrained_model_name_or_path, weights_name)):
|
||||||
@@ -419,6 +437,7 @@ def _get_checkpoint_shard_files(
|
|||||||
user_agent=None,
|
user_agent=None,
|
||||||
revision=None,
|
revision=None,
|
||||||
subfolder="",
|
subfolder="",
|
||||||
|
dduf_entries: Optional[Dict[str, DDUFEntry]] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
For a given model:
|
For a given model:
|
||||||
@@ -430,11 +449,18 @@ def _get_checkpoint_shard_files(
|
|||||||
For the description of each arg, see [`PreTrainedModel.from_pretrained`]. `index_filename` is the full path to the
|
For the description of each arg, see [`PreTrainedModel.from_pretrained`]. `index_filename` is the full path to the
|
||||||
index (downloaded and cached if `pretrained_model_name_or_path` is a model ID on the Hub).
|
index (downloaded and cached if `pretrained_model_name_or_path` is a model ID on the Hub).
|
||||||
"""
|
"""
|
||||||
if not os.path.isfile(index_filename):
|
if dduf_entries:
|
||||||
raise ValueError(f"Can't find a checkpoint index ({index_filename}) in {pretrained_model_name_or_path}.")
|
if index_filename not in dduf_entries:
|
||||||
|
raise ValueError(f"Can't find a checkpoint index ({index_filename}) in {pretrained_model_name_or_path}.")
|
||||||
|
else:
|
||||||
|
if not os.path.isfile(index_filename):
|
||||||
|
raise ValueError(f"Can't find a checkpoint index ({index_filename}) in {pretrained_model_name_or_path}.")
|
||||||
|
|
||||||
with open(index_filename, "r") as f:
|
if dduf_entries:
|
||||||
index = json.loads(f.read())
|
index = json.loads(dduf_entries[index_filename].read_text())
|
||||||
|
else:
|
||||||
|
with open(index_filename, "r") as f:
|
||||||
|
index = json.loads(f.read())
|
||||||
|
|
||||||
original_shard_filenames = sorted(set(index["weight_map"].values()))
|
original_shard_filenames = sorted(set(index["weight_map"].values()))
|
||||||
sharded_metadata = index["metadata"]
|
sharded_metadata = index["metadata"]
|
||||||
@@ -448,6 +474,8 @@ def _get_checkpoint_shard_files(
|
|||||||
pretrained_model_name_or_path, subfolder=subfolder, original_shard_filenames=original_shard_filenames
|
pretrained_model_name_or_path, subfolder=subfolder, original_shard_filenames=original_shard_filenames
|
||||||
)
|
)
|
||||||
return shards_path, sharded_metadata
|
return shards_path, sharded_metadata
|
||||||
|
elif dduf_entries:
|
||||||
|
return shards_path, sharded_metadata
|
||||||
|
|
||||||
# At this stage pretrained_model_name_or_path is a model identifier on the Hub
|
# At this stage pretrained_model_name_or_path is a model identifier on the Hub
|
||||||
allow_patterns = original_shard_filenames
|
allow_patterns = original_shard_filenames
|
||||||
|
|||||||
@@ -115,6 +115,13 @@ try:
|
|||||||
except importlib_metadata.PackageNotFoundError:
|
except importlib_metadata.PackageNotFoundError:
|
||||||
_transformers_available = False
|
_transformers_available = False
|
||||||
|
|
||||||
|
_hf_hub_available = importlib.util.find_spec("huggingface_hub") is not None
|
||||||
|
try:
|
||||||
|
_hf_hub_version = importlib_metadata.version("huggingface_hub")
|
||||||
|
logger.debug(f"Successfully imported huggingface_hub version {_hf_hub_version}")
|
||||||
|
except importlib_metadata.PackageNotFoundError:
|
||||||
|
_hf_hub_available = False
|
||||||
|
|
||||||
|
|
||||||
_inflect_available = importlib.util.find_spec("inflect") is not None
|
_inflect_available = importlib.util.find_spec("inflect") is not None
|
||||||
try:
|
try:
|
||||||
@@ -767,6 +774,21 @@ def is_transformers_version(operation: str, version: str):
|
|||||||
return compare_versions(parse(_transformers_version), operation, version)
|
return compare_versions(parse(_transformers_version), operation, version)
|
||||||
|
|
||||||
|
|
||||||
|
def is_hf_hub_version(operation: str, version: str):
|
||||||
|
"""
|
||||||
|
Compares the current Hugging Face Hub version to a given reference with an operation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
operation (`str`):
|
||||||
|
A string representation of an operator, such as `">"` or `"<="`
|
||||||
|
version (`str`):
|
||||||
|
A version string
|
||||||
|
"""
|
||||||
|
if not _hf_hub_available:
|
||||||
|
return False
|
||||||
|
return compare_versions(parse(_hf_hub_version), operation, version)
|
||||||
|
|
||||||
|
|
||||||
def is_accelerate_version(operation: str, version: str):
|
def is_accelerate_version(operation: str, version: str):
|
||||||
"""
|
"""
|
||||||
Compares the current Accelerate version to a given reference with an operation.
|
Compares the current Accelerate version to a given reference with an operation.
|
||||||
|
|||||||
@@ -478,6 +478,18 @@ def require_bitsandbytes_version_greater(bnb_version):
|
|||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def require_hf_hub_version_greater(hf_hub_version):
|
||||||
|
def decorator(test_case):
|
||||||
|
correct_hf_hub_version = version.parse(
|
||||||
|
version.parse(importlib.metadata.version("huggingface_hub")).base_version
|
||||||
|
) > version.parse(hf_hub_version)
|
||||||
|
return unittest.skipUnless(
|
||||||
|
correct_hf_hub_version, f"Test requires huggingface_hub with the version greater than {hf_hub_version}."
|
||||||
|
)(test_case)
|
||||||
|
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
def require_gguf_version_greater_or_equal(gguf_version):
|
def require_gguf_version_greater_or_equal(gguf_version):
|
||||||
def decorator(test_case):
|
def decorator(test_case):
|
||||||
correct_gguf_version = is_gguf_available() and version.parse(
|
correct_gguf_version = is_gguf_available() and version.parse(
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
import gc
|
import gc
|
||||||
import inspect
|
import inspect
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@@ -24,7 +26,9 @@ from diffusers import AllegroPipeline, AllegroTransformer3DModel, AutoencoderKLA
|
|||||||
from diffusers.utils.testing_utils import (
|
from diffusers.utils.testing_utils import (
|
||||||
enable_full_determinism,
|
enable_full_determinism,
|
||||||
numpy_cosine_similarity_distance,
|
numpy_cosine_similarity_distance,
|
||||||
|
require_hf_hub_version_greater,
|
||||||
require_torch_gpu,
|
require_torch_gpu,
|
||||||
|
require_transformers_version_greater,
|
||||||
slow,
|
slow,
|
||||||
torch_device,
|
torch_device,
|
||||||
)
|
)
|
||||||
@@ -297,6 +301,35 @@ class AllegroPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
"VAE tiling should not affect the inference results",
|
"VAE tiling should not affect the inference results",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_save_load_dduf(self):
|
||||||
|
# reimplement because it needs `enable_tiling()` on the loaded pipe.
|
||||||
|
from huggingface_hub import export_folder_as_dduf
|
||||||
|
|
||||||
|
components = self.get_dummy_components()
|
||||||
|
pipe = self.pipeline_class(**components)
|
||||||
|
pipe = pipe.to(torch_device)
|
||||||
|
pipe.set_progress_bar_config(disable=None)
|
||||||
|
|
||||||
|
inputs = self.get_dummy_inputs(device="cpu")
|
||||||
|
inputs.pop("generator")
|
||||||
|
inputs["generator"] = torch.manual_seed(0)
|
||||||
|
|
||||||
|
pipeline_out = pipe(**inputs)[0].cpu()
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
dduf_filename = os.path.join(tmpdir, f"{pipe.__class__.__name__.lower()}.dduf")
|
||||||
|
pipe.save_pretrained(tmpdir, safe_serialization=True)
|
||||||
|
export_folder_as_dduf(dduf_filename, folder_path=tmpdir)
|
||||||
|
loaded_pipe = self.pipeline_class.from_pretrained(tmpdir, dduf_file=dduf_filename).to(torch_device)
|
||||||
|
|
||||||
|
loaded_pipe.vae.enable_tiling()
|
||||||
|
inputs["generator"] = torch.manual_seed(0)
|
||||||
|
loaded_pipeline_out = loaded_pipe(**inputs)[0].cpu()
|
||||||
|
|
||||||
|
assert np.allclose(pipeline_out, loaded_pipeline_out)
|
||||||
|
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_gpu
|
@require_torch_gpu
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ class AudioLDMPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ class AudioLDM2PipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = AudioLDM2UNet2DConditionModel(
|
unet = AudioLDM2UNet2DConditionModel(
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ class BlipDiffusionPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
"prompt_reps",
|
"prompt_reps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
text_encoder_config = CLIPTextConfig(
|
text_encoder_config = CLIPTextConfig(
|
||||||
|
|||||||
@@ -291,6 +291,8 @@ class StableDiffusionMultiControlNetPipelineFastTests(
|
|||||||
batch_params = TEXT_TO_IMAGE_BATCH_PARAMS
|
batch_params = TEXT_TO_IMAGE_BATCH_PARAMS
|
||||||
image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess
|
image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
@@ -523,6 +525,8 @@ class StableDiffusionMultiControlNetOneModelPipelineFastTests(
|
|||||||
batch_params = TEXT_TO_IMAGE_BATCH_PARAMS
|
batch_params = TEXT_TO_IMAGE_BATCH_PARAMS
|
||||||
image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess
|
image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ class BlipDiffusionControlNetPipelineFastTests(PipelineTesterMixin, unittest.Tes
|
|||||||
"prompt_reps",
|
"prompt_reps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
text_encoder_config = CLIPTextConfig(
|
text_encoder_config = CLIPTextConfig(
|
||||||
|
|||||||
@@ -198,6 +198,8 @@ class StableDiffusionMultiControlNetPipelineFastTests(
|
|||||||
batch_params = TEXT_GUIDED_IMAGE_VARIATION_BATCH_PARAMS
|
batch_params = TEXT_GUIDED_IMAGE_VARIATION_BATCH_PARAMS
|
||||||
image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess
|
image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -257,6 +257,8 @@ class MultiControlNetInpaintPipelineFastTests(
|
|||||||
params = TEXT_GUIDED_IMAGE_INPAINTING_PARAMS
|
params = TEXT_GUIDED_IMAGE_INPAINTING_PARAMS
|
||||||
batch_params = TEXT_GUIDED_IMAGE_INPAINTING_BATCH_PARAMS
|
batch_params = TEXT_GUIDED_IMAGE_INPAINTING_BATCH_PARAMS
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ class ControlNetPipelineSDXLFastTests(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -487,6 +487,8 @@ class StableDiffusionXLMultiControlNetPipelineFastTests(
|
|||||||
batch_params = TEXT_TO_IMAGE_BATCH_PARAMS
|
batch_params = TEXT_TO_IMAGE_BATCH_PARAMS
|
||||||
image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess
|
image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
@@ -692,6 +694,8 @@ class StableDiffusionXLMultiControlNetOneModelPipelineFastTests(
|
|||||||
batch_params = TEXT_TO_IMAGE_BATCH_PARAMS
|
batch_params = TEXT_TO_IMAGE_BATCH_PARAMS
|
||||||
image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess
|
image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ from diffusers.utils.import_utils import is_xformers_available
|
|||||||
from diffusers.utils.testing_utils import (
|
from diffusers.utils.testing_utils import (
|
||||||
load_numpy,
|
load_numpy,
|
||||||
require_accelerator,
|
require_accelerator,
|
||||||
|
require_hf_hub_version_greater,
|
||||||
require_torch_gpu,
|
require_torch_gpu,
|
||||||
|
require_transformers_version_greater,
|
||||||
skip_mps,
|
skip_mps,
|
||||||
slow,
|
slow,
|
||||||
torch_device,
|
torch_device,
|
||||||
@@ -89,6 +91,11 @@ class IFPipelineFastTests(PipelineTesterMixin, IFPipelineTesterMixin, unittest.T
|
|||||||
def test_xformers_attention_forwardGenerator_pass(self):
|
def test_xformers_attention_forwardGenerator_pass(self):
|
||||||
self._test_xformers_attention_forwardGenerator_pass(expected_max_diff=1e-3)
|
self._test_xformers_attention_forwardGenerator_pass(expected_max_diff=1e-3)
|
||||||
|
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_save_load_dduf(self):
|
||||||
|
super().test_save_load_dduf(atol=1e-2, rtol=1e-2)
|
||||||
|
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_gpu
|
@require_torch_gpu
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ from diffusers.utils.testing_utils import (
|
|||||||
floats_tensor,
|
floats_tensor,
|
||||||
load_numpy,
|
load_numpy,
|
||||||
require_accelerator,
|
require_accelerator,
|
||||||
|
require_hf_hub_version_greater,
|
||||||
require_torch_gpu,
|
require_torch_gpu,
|
||||||
|
require_transformers_version_greater,
|
||||||
skip_mps,
|
skip_mps,
|
||||||
slow,
|
slow,
|
||||||
torch_device,
|
torch_device,
|
||||||
@@ -100,6 +102,11 @@ class IFImg2ImgPipelineFastTests(PipelineTesterMixin, IFPipelineTesterMixin, uni
|
|||||||
expected_max_diff=1e-2,
|
expected_max_diff=1e-2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_save_load_dduf(self):
|
||||||
|
super().test_save_load_dduf(atol=1e-2, rtol=1e-2)
|
||||||
|
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_gpu
|
@require_torch_gpu
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ from diffusers.utils.testing_utils import (
|
|||||||
floats_tensor,
|
floats_tensor,
|
||||||
load_numpy,
|
load_numpy,
|
||||||
require_accelerator,
|
require_accelerator,
|
||||||
|
require_hf_hub_version_greater,
|
||||||
require_torch_gpu,
|
require_torch_gpu,
|
||||||
|
require_transformers_version_greater,
|
||||||
skip_mps,
|
skip_mps,
|
||||||
slow,
|
slow,
|
||||||
torch_device,
|
torch_device,
|
||||||
@@ -97,6 +99,11 @@ class IFImg2ImgSuperResolutionPipelineFastTests(PipelineTesterMixin, IFPipelineT
|
|||||||
expected_max_diff=1e-2,
|
expected_max_diff=1e-2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_save_load_dduf(self):
|
||||||
|
super().test_save_load_dduf(atol=1e-2, rtol=1e-2)
|
||||||
|
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_gpu
|
@require_torch_gpu
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ from diffusers.utils.testing_utils import (
|
|||||||
floats_tensor,
|
floats_tensor,
|
||||||
load_numpy,
|
load_numpy,
|
||||||
require_accelerator,
|
require_accelerator,
|
||||||
|
require_hf_hub_version_greater,
|
||||||
require_torch_gpu,
|
require_torch_gpu,
|
||||||
|
require_transformers_version_greater,
|
||||||
skip_mps,
|
skip_mps,
|
||||||
slow,
|
slow,
|
||||||
torch_device,
|
torch_device,
|
||||||
@@ -97,6 +99,11 @@ class IFInpaintingPipelineFastTests(PipelineTesterMixin, IFPipelineTesterMixin,
|
|||||||
expected_max_diff=1e-2,
|
expected_max_diff=1e-2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_save_load_dduf(self):
|
||||||
|
super().test_save_load_dduf(atol=1e-2, rtol=1e-2)
|
||||||
|
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_gpu
|
@require_torch_gpu
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ from diffusers.utils.testing_utils import (
|
|||||||
floats_tensor,
|
floats_tensor,
|
||||||
load_numpy,
|
load_numpy,
|
||||||
require_accelerator,
|
require_accelerator,
|
||||||
|
require_hf_hub_version_greater,
|
||||||
require_torch_gpu,
|
require_torch_gpu,
|
||||||
|
require_transformers_version_greater,
|
||||||
skip_mps,
|
skip_mps,
|
||||||
slow,
|
slow,
|
||||||
torch_device,
|
torch_device,
|
||||||
@@ -99,6 +101,11 @@ class IFInpaintingSuperResolutionPipelineFastTests(PipelineTesterMixin, IFPipeli
|
|||||||
expected_max_diff=1e-2,
|
expected_max_diff=1e-2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_save_load_dduf(self):
|
||||||
|
super().test_save_load_dduf(atol=1e-2, rtol=1e-2)
|
||||||
|
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_gpu
|
@require_torch_gpu
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ from diffusers.utils.testing_utils import (
|
|||||||
floats_tensor,
|
floats_tensor,
|
||||||
load_numpy,
|
load_numpy,
|
||||||
require_accelerator,
|
require_accelerator,
|
||||||
|
require_hf_hub_version_greater,
|
||||||
require_torch_gpu,
|
require_torch_gpu,
|
||||||
|
require_transformers_version_greater,
|
||||||
skip_mps,
|
skip_mps,
|
||||||
slow,
|
slow,
|
||||||
torch_device,
|
torch_device,
|
||||||
@@ -92,6 +94,11 @@ class IFSuperResolutionPipelineFastTests(PipelineTesterMixin, IFPipelineTesterMi
|
|||||||
expected_max_diff=1e-2,
|
expected_max_diff=1e-2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_save_load_dduf(self):
|
||||||
|
super().test_save_load_dduf(atol=1e-2, rtol=1e-2)
|
||||||
|
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_gpu
|
@require_torch_gpu
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ class I2VGenXLPipelineFastTests(SDFunctionTesterMixin, PipelineTesterMixin, unit
|
|||||||
# No `output_type`.
|
# No `output_type`.
|
||||||
required_optional_params = frozenset(["num_inference_steps", "generator", "latents", "return_dict"])
|
required_optional_params = frozenset(["num_inference_steps", "generator", "latents", "return_dict"])
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
scheduler = DDIMScheduler(
|
scheduler = DDIMScheduler(
|
||||||
|
|||||||
@@ -204,6 +204,8 @@ class KandinskyPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
]
|
]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummy = Dummies()
|
dummy = Dummies()
|
||||||
return dummy.get_dummy_components()
|
return dummy.get_dummy_components()
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ class KandinskyPipelineCombinedFastTests(PipelineTesterMixin, unittest.TestCase)
|
|||||||
]
|
]
|
||||||
test_xformers_attention = True
|
test_xformers_attention = True
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummy = Dummies()
|
dummy = Dummies()
|
||||||
prior_dummy = PriorDummies()
|
prior_dummy = PriorDummies()
|
||||||
@@ -160,6 +162,8 @@ class KandinskyPipelineImg2ImgCombinedFastTests(PipelineTesterMixin, unittest.Te
|
|||||||
]
|
]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummy = Img2ImgDummies()
|
dummy = Img2ImgDummies()
|
||||||
prior_dummy = PriorDummies()
|
prior_dummy = PriorDummies()
|
||||||
@@ -269,6 +273,8 @@ class KandinskyPipelineInpaintCombinedFastTests(PipelineTesterMixin, unittest.Te
|
|||||||
]
|
]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummy = InpaintDummies()
|
dummy = InpaintDummies()
|
||||||
prior_dummy = PriorDummies()
|
prior_dummy = PriorDummies()
|
||||||
|
|||||||
@@ -226,6 +226,8 @@ class KandinskyImg2ImgPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
]
|
]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummies = Dummies()
|
dummies = Dummies()
|
||||||
return dummies.get_dummy_components()
|
return dummies.get_dummy_components()
|
||||||
|
|||||||
@@ -220,6 +220,8 @@ class KandinskyInpaintPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
]
|
]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummies = Dummies()
|
dummies = Dummies()
|
||||||
return dummies.get_dummy_components()
|
return dummies.get_dummy_components()
|
||||||
|
|||||||
@@ -184,6 +184,8 @@ class KandinskyPriorPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
]
|
]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummy = Dummies()
|
dummy = Dummies()
|
||||||
return dummy.get_dummy_components()
|
return dummy.get_dummy_components()
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ class KandinskyV22PipelineCombinedFastTests(PipelineTesterMixin, unittest.TestCa
|
|||||||
test_xformers_attention = True
|
test_xformers_attention = True
|
||||||
callback_cfg_params = ["image_embds"]
|
callback_cfg_params = ["image_embds"]
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummy = Dummies()
|
dummy = Dummies()
|
||||||
prior_dummy = PriorDummies()
|
prior_dummy = PriorDummies()
|
||||||
@@ -181,6 +183,8 @@ class KandinskyV22PipelineImg2ImgCombinedFastTests(PipelineTesterMixin, unittest
|
|||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
callback_cfg_params = ["image_embds"]
|
callback_cfg_params = ["image_embds"]
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummy = Img2ImgDummies()
|
dummy = Img2ImgDummies()
|
||||||
prior_dummy = PriorDummies()
|
prior_dummy = PriorDummies()
|
||||||
@@ -302,6 +306,8 @@ class KandinskyV22PipelineInpaintCombinedFastTests(PipelineTesterMixin, unittest
|
|||||||
]
|
]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummy = InpaintDummies()
|
dummy = InpaintDummies()
|
||||||
prior_dummy = PriorDummies()
|
prior_dummy = PriorDummies()
|
||||||
|
|||||||
@@ -186,6 +186,8 @@ class KandinskyV22PriorPipelineFastTests(PipelineTesterMixin, unittest.TestCase)
|
|||||||
callback_cfg_params = ["prompt_embeds", "text_encoder_hidden_states", "text_mask"]
|
callback_cfg_params = ["prompt_embeds", "text_encoder_hidden_states", "text_mask"]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
dummies = Dummies()
|
dummies = Dummies()
|
||||||
return dummies.get_dummy_components()
|
return dummies.get_dummy_components()
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ class KandinskyV22PriorEmb2EmbPipelineFastTests(PipelineTesterMixin, unittest.Te
|
|||||||
]
|
]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def text_embedder_hidden_size(self):
|
def text_embedder_hidden_size(self):
|
||||||
return 32
|
return 32
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ class KolorsPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
||||||
callback_cfg_params = TEXT_TO_IMAGE_CALLBACK_CFG_PARAMS.union({"add_text_embeds", "add_time_ids"})
|
callback_cfg_params = TEXT_TO_IMAGE_CALLBACK_CFG_PARAMS.union({"add_text_embeds", "add_time_ids"})
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self, time_cond_proj_dim=None):
|
def get_dummy_components(self, time_cond_proj_dim=None):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ class KolorsPipelineImg2ImgFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
||||||
callback_cfg_params = TEXT_TO_IMAGE_CALLBACK_CFG_PARAMS.union({"add_text_embeds", "add_time_ids"})
|
callback_cfg_params = TEXT_TO_IMAGE_CALLBACK_CFG_PARAMS.union({"add_text_embeds", "add_time_ids"})
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
# Copied from tests.pipelines.kolors.test_kolors.KolorsPipelineFastTests.get_dummy_components
|
# Copied from tests.pipelines.kolors.test_kolors.KolorsPipelineFastTests.get_dummy_components
|
||||||
def get_dummy_components(self, time_cond_proj_dim=None):
|
def get_dummy_components(self, time_cond_proj_dim=None):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ class LuminaText2ImgPipelinePipelineFastTests(unittest.TestCase, PipelineTesterM
|
|||||||
)
|
)
|
||||||
batch_params = frozenset(["prompt", "negative_prompt"])
|
batch_params = frozenset(["prompt", "negative_prompt"])
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
transformer = LuminaNextDiT2DModel(
|
transformer = LuminaNextDiT2DModel(
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ class MusicLDMPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ class KolorsPAGPipelineFastTests(
|
|||||||
image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
||||||
callback_cfg_params = TEXT_TO_IMAGE_CALLBACK_CFG_PARAMS.union({"add_text_embeds", "add_time_ids"})
|
callback_cfg_params = TEXT_TO_IMAGE_CALLBACK_CFG_PARAMS.union({"add_text_embeds", "add_time_ids"})
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
# Copied from tests.pipelines.kolors.test_kolors.KolorsPipelineFastTests.get_dummy_components
|
# Copied from tests.pipelines.kolors.test_kolors.KolorsPipelineFastTests.get_dummy_components
|
||||||
def get_dummy_components(self, time_cond_proj_dim=None):
|
def get_dummy_components(self, time_cond_proj_dim=None):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ class SanaPAGPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
)
|
)
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
transformer = SanaTransformer2DModel(
|
transformer = SanaTransformer2DModel(
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ class StableDiffusionXLPAGImg2ImgPipelineFastTests(
|
|||||||
{"add_text_embeds", "add_time_ids", "add_neg_time_ids"}
|
{"add_text_embeds", "add_time_ids", "add_neg_time_ids"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
# based on tests.pipelines.stable_diffusion_xl.test_stable_diffusion_xl_img2img_pipeline.get_dummy_components
|
# based on tests.pipelines.stable_diffusion_xl.test_stable_diffusion_xl_img2img_pipeline.get_dummy_components
|
||||||
def get_dummy_components(
|
def get_dummy_components(
|
||||||
self, skip_first_text_encoder=False, time_cond_proj_dim=None, requires_aesthetics_score=False
|
self, skip_first_text_encoder=False, time_cond_proj_dim=None, requires_aesthetics_score=False
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ class StableDiffusionXLPAGInpaintPipelineFastTests(
|
|||||||
{"add_text_embeds", "add_time_ids", "mask", "masked_image_latents"}
|
{"add_text_embeds", "add_time_ids", "mask", "masked_image_latents"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
# based on tests.pipelines.stable_diffusion_xl.test_stable_diffusion_xl_inpaint.StableDiffusionXLInpaintPipelineFastTests.get_dummy_components
|
# based on tests.pipelines.stable_diffusion_xl.test_stable_diffusion_xl_inpaint.StableDiffusionXLInpaintPipelineFastTests.get_dummy_components
|
||||||
def get_dummy_components(
|
def get_dummy_components(
|
||||||
self, skip_first_text_encoder=False, time_cond_proj_dim=None, requires_aesthetics_score=False
|
self, skip_first_text_encoder=False, time_cond_proj_dim=None, requires_aesthetics_score=False
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ class PaintByExamplePipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
batch_params = IMAGE_GUIDED_IMAGE_INPAINTING_BATCH_PARAMS
|
batch_params = IMAGE_GUIDED_IMAGE_INPAINTING_BATCH_PARAMS
|
||||||
image_params = frozenset([]) # TO_DO: update the image_prams once refactored VaeImageProcessor.preprocess
|
image_params = frozenset([]) # TO_DO: update the image_prams once refactored VaeImageProcessor.preprocess
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ class ShapEImg2ImgPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
]
|
]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def text_embedder_hidden_size(self):
|
def text_embedder_hidden_size(self):
|
||||||
return 16
|
return 16
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ class StableAudioPipelineFastTests(PipelineTesterMixin, unittest.TestCase):
|
|||||||
)
|
)
|
||||||
# There is not xformers version of the StableAudioPipeline custom attention processor
|
# There is not xformers version of the StableAudioPipeline custom attention processor
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ class StableDiffusionDepth2ImgPipelineFastTests(
|
|||||||
image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
||||||
callback_cfg_params = TEXT_TO_IMAGE_CALLBACK_CFG_PARAMS.union({"depth_mask"})
|
callback_cfg_params = TEXT_TO_IMAGE_CALLBACK_CFG_PARAMS.union({"depth_mask"})
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -389,6 +389,8 @@ class StableDiffusionLightAdapterPipelineFastTests(AdapterTests, PipelineTesterM
|
|||||||
|
|
||||||
|
|
||||||
class StableDiffusionMultiAdapterPipelineFastTests(AdapterTests, PipelineTesterMixin, unittest.TestCase):
|
class StableDiffusionMultiAdapterPipelineFastTests(AdapterTests, PipelineTesterMixin, unittest.TestCase):
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self, time_cond_proj_dim=None):
|
def get_dummy_components(self, time_cond_proj_dim=None):
|
||||||
return super().get_dummy_components("multi_adapter", time_cond_proj_dim=time_cond_proj_dim)
|
return super().get_dummy_components("multi_adapter", time_cond_proj_dim=time_cond_proj_dim)
|
||||||
|
|
||||||
|
|||||||
+2
@@ -66,6 +66,8 @@ class GligenTextImagePipelineFastTests(
|
|||||||
image_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
image_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
||||||
image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
+2
@@ -58,6 +58,8 @@ class StableDiffusionImageVariationPipelineFastTests(
|
|||||||
# TO-DO: update image_params once pipeline is refactored with VaeImageProcessor.preprocess
|
# TO-DO: update image_params once pipeline is refactored with VaeImageProcessor.preprocess
|
||||||
image_latents_params = frozenset([])
|
image_latents_params = frozenset([])
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -422,6 +422,8 @@ class StableDiffusionXLAdapterPipelineFastTests(
|
|||||||
class StableDiffusionXLMultiAdapterPipelineFastTests(
|
class StableDiffusionXLMultiAdapterPipelineFastTests(
|
||||||
StableDiffusionXLAdapterPipelineFastTests, PipelineTesterMixin, unittest.TestCase
|
StableDiffusionXLAdapterPipelineFastTests, PipelineTesterMixin, unittest.TestCase
|
||||||
):
|
):
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self, time_cond_proj_dim=None):
|
def get_dummy_components(self, time_cond_proj_dim=None):
|
||||||
return super().get_dummy_components("multi_adapter", time_cond_proj_dim=time_cond_proj_dim)
|
return super().get_dummy_components("multi_adapter", time_cond_proj_dim=time_cond_proj_dim)
|
||||||
|
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ class StableDiffusionXLImg2ImgPipelineFastTests(
|
|||||||
{"add_text_embeds", "add_time_ids", "add_neg_time_ids"}
|
{"add_text_embeds", "add_time_ids", "add_neg_time_ids"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self, skip_first_text_encoder=False, time_cond_proj_dim=None):
|
def get_dummy_components(self, skip_first_text_encoder=False, time_cond_proj_dim=None):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ class StableDiffusionXLInpaintPipelineFastTests(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self, skip_first_text_encoder=False, time_cond_proj_dim=None):
|
def get_dummy_components(self, skip_first_text_encoder=False, time_cond_proj_dim=None):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNet2DConditionModel(
|
unet = UNet2DConditionModel(
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ class StableUnCLIPImg2ImgPipelineFastTests(
|
|||||||
) # TO-DO: update image_params once pipeline is refactored with VaeImageProcessor.preprocess
|
) # TO-DO: update image_params once pipeline is refactored with VaeImageProcessor.preprocess
|
||||||
image_latents_params = frozenset([])
|
image_latents_params = frozenset([])
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
embedder_hidden_size = 32
|
embedder_hidden_size = 32
|
||||||
embedder_projection_dim = embedder_hidden_size
|
embedder_projection_dim = embedder_hidden_size
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ class StableVideoDiffusionPipelineFastTests(PipelineTesterMixin, unittest.TestCa
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
torch.manual_seed(0)
|
torch.manual_seed(0)
|
||||||
unet = UNetSpatioTemporalConditionModel(
|
unet = UNetSpatioTemporalConditionModel(
|
||||||
|
|||||||
@@ -75,9 +75,11 @@ from diffusers.utils.testing_utils import (
|
|||||||
nightly,
|
nightly,
|
||||||
require_compel,
|
require_compel,
|
||||||
require_flax,
|
require_flax,
|
||||||
|
require_hf_hub_version_greater,
|
||||||
require_onnxruntime,
|
require_onnxruntime,
|
||||||
require_torch_2,
|
require_torch_2,
|
||||||
require_torch_gpu,
|
require_torch_gpu,
|
||||||
|
require_transformers_version_greater,
|
||||||
run_test_in_subprocess,
|
run_test_in_subprocess,
|
||||||
slow,
|
slow,
|
||||||
torch_device,
|
torch_device,
|
||||||
@@ -981,6 +983,18 @@ class DownloadTests(unittest.TestCase):
|
|||||||
assert not any(f in ["vae/diffusion_pytorch_model.bin", "text_encoder/config.json"] for f in files)
|
assert not any(f in ["vae/diffusion_pytorch_model.bin", "text_encoder/config.json"] for f in files)
|
||||||
assert len(files) == 14
|
assert len(files) == 14
|
||||||
|
|
||||||
|
def test_download_dduf_with_custom_pipeline_raises_error(self):
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
_ = DiffusionPipeline.download(
|
||||||
|
"DDUF/tiny-flux-dev-pipe-dduf", dduf_file="fluxpipeline.dduf", custom_pipeline="my_pipeline"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_download_dduf_with_connected_pipeline_raises_error(self):
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
_ = DiffusionPipeline.download(
|
||||||
|
"DDUF/tiny-flux-dev-pipe-dduf", dduf_file="fluxpipeline.dduf", load_connected_pipeline=True
|
||||||
|
)
|
||||||
|
|
||||||
def test_get_pipeline_class_from_flax(self):
|
def test_get_pipeline_class_from_flax(self):
|
||||||
flax_config = {"_class_name": "FlaxStableDiffusionPipeline"}
|
flax_config = {"_class_name": "FlaxStableDiffusionPipeline"}
|
||||||
config = {"_class_name": "StableDiffusionPipeline"}
|
config = {"_class_name": "StableDiffusionPipeline"}
|
||||||
@@ -1802,6 +1816,55 @@ class PipelineFastTests(unittest.TestCase):
|
|||||||
sd.maybe_free_model_hooks()
|
sd.maybe_free_model_hooks()
|
||||||
assert sd._offload_gpu_id == 5
|
assert sd._offload_gpu_id == 5
|
||||||
|
|
||||||
|
@parameterized.expand([torch.float32, torch.float16])
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_load_dduf_from_hub(self, dtype):
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
pipe = DiffusionPipeline.from_pretrained(
|
||||||
|
"DDUF/tiny-flux-dev-pipe-dduf", dduf_file="fluxpipeline.dduf", cache_dir=tmpdir, torch_dtype=dtype
|
||||||
|
).to(torch_device)
|
||||||
|
out_1 = pipe(prompt="dog", num_inference_steps=5, generator=torch.manual_seed(0), output_type="np").images
|
||||||
|
|
||||||
|
pipe.save_pretrained(tmpdir)
|
||||||
|
loaded_pipe = DiffusionPipeline.from_pretrained(tmpdir, torch_dtype=dtype).to(torch_device)
|
||||||
|
|
||||||
|
out_2 = loaded_pipe(
|
||||||
|
prompt="dog", num_inference_steps=5, generator=torch.manual_seed(0), output_type="np"
|
||||||
|
).images
|
||||||
|
|
||||||
|
self.assertTrue(np.allclose(out_1, out_2, atol=1e-4, rtol=1e-4))
|
||||||
|
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_load_dduf_from_hub_local_files_only(self):
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
pipe = DiffusionPipeline.from_pretrained(
|
||||||
|
"DDUF/tiny-flux-dev-pipe-dduf", dduf_file="fluxpipeline.dduf", cache_dir=tmpdir
|
||||||
|
).to(torch_device)
|
||||||
|
out_1 = pipe(prompt="dog", num_inference_steps=5, generator=torch.manual_seed(0), output_type="np").images
|
||||||
|
|
||||||
|
local_files_pipe = DiffusionPipeline.from_pretrained(
|
||||||
|
"DDUF/tiny-flux-dev-pipe-dduf", dduf_file="fluxpipeline.dduf", cache_dir=tmpdir, local_files_only=True
|
||||||
|
).to(torch_device)
|
||||||
|
out_2 = local_files_pipe(
|
||||||
|
prompt="dog", num_inference_steps=5, generator=torch.manual_seed(0), output_type="np"
|
||||||
|
).images
|
||||||
|
|
||||||
|
self.assertTrue(np.allclose(out_1, out_2, atol=1e-4, rtol=1e-4))
|
||||||
|
|
||||||
|
def test_dduf_raises_error_with_custom_pipeline(self):
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
_ = DiffusionPipeline.from_pretrained(
|
||||||
|
"DDUF/tiny-flux-dev-pipe-dduf", dduf_file="fluxpipeline.dduf", custom_pipeline="my_pipeline"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_dduf_raises_error_with_connected_pipeline(self):
|
||||||
|
with self.assertRaises(NotImplementedError):
|
||||||
|
_ = DiffusionPipeline.from_pretrained(
|
||||||
|
"DDUF/tiny-flux-dev-pipe-dduf", dduf_file="fluxpipeline.dduf", load_connected_pipeline=True
|
||||||
|
)
|
||||||
|
|
||||||
def test_wrong_model(self):
|
def test_wrong_model(self):
|
||||||
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")
|
tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip")
|
||||||
with self.assertRaises(ValueError) as error_context:
|
with self.assertRaises(ValueError) as error_context:
|
||||||
@@ -1812,6 +1875,27 @@ class PipelineFastTests(unittest.TestCase):
|
|||||||
assert "is of type" in str(error_context.exception)
|
assert "is of type" in str(error_context.exception)
|
||||||
assert "but should be" in str(error_context.exception)
|
assert "but should be" in str(error_context.exception)
|
||||||
|
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_dduf_load_sharded_checkpoint_diffusion_model(self):
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
pipe = DiffusionPipeline.from_pretrained(
|
||||||
|
"hf-internal-testing/tiny-flux-dev-pipe-sharded-checkpoint-DDUF",
|
||||||
|
dduf_file="tiny-flux-dev-pipe-sharded-checkpoint.dduf",
|
||||||
|
cache_dir=tmpdir,
|
||||||
|
).to(torch_device)
|
||||||
|
|
||||||
|
out_1 = pipe(prompt="dog", num_inference_steps=5, generator=torch.manual_seed(0), output_type="np").images
|
||||||
|
|
||||||
|
pipe.save_pretrained(tmpdir)
|
||||||
|
loaded_pipe = DiffusionPipeline.from_pretrained(tmpdir).to(torch_device)
|
||||||
|
|
||||||
|
out_2 = loaded_pipe(
|
||||||
|
prompt="dog", num_inference_steps=5, generator=torch.manual_seed(0), output_type="np"
|
||||||
|
).images
|
||||||
|
|
||||||
|
self.assertTrue(np.allclose(out_1, out_2, atol=1e-4, rtol=1e-4))
|
||||||
|
|
||||||
|
|
||||||
@slow
|
@slow
|
||||||
@require_torch_gpu
|
@require_torch_gpu
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ from diffusers.utils.testing_utils import (
|
|||||||
CaptureLogger,
|
CaptureLogger,
|
||||||
require_accelerate_version_greater,
|
require_accelerate_version_greater,
|
||||||
require_accelerator,
|
require_accelerator,
|
||||||
|
require_hf_hub_version_greater,
|
||||||
require_torch,
|
require_torch,
|
||||||
|
require_transformers_version_greater,
|
||||||
skip_mps,
|
skip_mps,
|
||||||
torch_device,
|
torch_device,
|
||||||
)
|
)
|
||||||
@@ -986,6 +988,8 @@ class PipelineTesterMixin:
|
|||||||
|
|
||||||
test_xformers_attention = True
|
test_xformers_attention = True
|
||||||
|
|
||||||
|
supports_dduf = True
|
||||||
|
|
||||||
def get_generator(self, seed):
|
def get_generator(self, seed):
|
||||||
device = torch_device if torch_device != "mps" else "cpu"
|
device = torch_device if torch_device != "mps" else "cpu"
|
||||||
generator = torch.Generator(device).manual_seed(seed)
|
generator = torch.Generator(device).manual_seed(seed)
|
||||||
@@ -1990,6 +1994,39 @@ class PipelineTesterMixin:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@require_hf_hub_version_greater("0.26.5")
|
||||||
|
@require_transformers_version_greater("4.47.1")
|
||||||
|
def test_save_load_dduf(self, atol=1e-4, rtol=1e-4):
|
||||||
|
if not self.supports_dduf:
|
||||||
|
return
|
||||||
|
|
||||||
|
from huggingface_hub import export_folder_as_dduf
|
||||||
|
|
||||||
|
components = self.get_dummy_components()
|
||||||
|
pipe = self.pipeline_class(**components)
|
||||||
|
pipe = pipe.to(torch_device)
|
||||||
|
pipe.set_progress_bar_config(disable=None)
|
||||||
|
|
||||||
|
inputs = self.get_dummy_inputs(device="cpu")
|
||||||
|
inputs.pop("generator")
|
||||||
|
inputs["generator"] = torch.manual_seed(0)
|
||||||
|
|
||||||
|
pipeline_out = pipe(**inputs)[0]
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
dduf_filename = os.path.join(tmpdir, f"{pipe.__class__.__name__.lower()}.dduf")
|
||||||
|
pipe.save_pretrained(tmpdir, safe_serialization=True)
|
||||||
|
export_folder_as_dduf(dduf_filename, folder_path=tmpdir)
|
||||||
|
loaded_pipe = self.pipeline_class.from_pretrained(tmpdir, dduf_file=dduf_filename).to(torch_device)
|
||||||
|
|
||||||
|
inputs["generator"] = torch.manual_seed(0)
|
||||||
|
loaded_pipeline_out = loaded_pipe(**inputs)[0]
|
||||||
|
|
||||||
|
if isinstance(pipeline_out, np.ndarray) and isinstance(loaded_pipeline_out, np.ndarray):
|
||||||
|
assert np.allclose(pipeline_out, loaded_pipeline_out, atol=atol, rtol=rtol)
|
||||||
|
elif isinstance(pipeline_out, torch.Tensor) and isinstance(loaded_pipeline_out, torch.Tensor):
|
||||||
|
assert torch.allclose(pipeline_out, loaded_pipeline_out, atol=atol, rtol=rtol)
|
||||||
|
|
||||||
|
|
||||||
@is_staging_test
|
@is_staging_test
|
||||||
class PipelinePushToHubTester(unittest.TestCase):
|
class PipelinePushToHubTester(unittest.TestCase):
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class UnCLIPImageVariationPipelineFastTests(PipelineTesterMixin, unittest.TestCa
|
|||||||
"super_res_num_inference_steps",
|
"super_res_num_inference_steps",
|
||||||
]
|
]
|
||||||
test_xformers_attention = False
|
test_xformers_attention = False
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def text_embedder_hidden_size(self):
|
def text_embedder_hidden_size(self):
|
||||||
|
|||||||
@@ -86,6 +86,8 @@ class UniDiffuserPipelineFastTests(
|
|||||||
# vae_latents, not latents, is the argument that corresponds to VAE latent inputs
|
# vae_latents, not latents, is the argument that corresponds to VAE latent inputs
|
||||||
image_latents_params = frozenset(["vae_latents"])
|
image_latents_params = frozenset(["vae_latents"])
|
||||||
|
|
||||||
|
supports_dduf = False
|
||||||
|
|
||||||
def get_dummy_components(self):
|
def get_dummy_components(self):
|
||||||
unet = UniDiffuserModel.from_pretrained(
|
unet = UniDiffuserModel.from_pretrained(
|
||||||
"hf-internal-testing/unidiffuser-diffusers-test",
|
"hf-internal-testing/unidiffuser-diffusers-test",
|
||||||
|
|||||||
@@ -476,6 +476,18 @@ class TorchAoTest(unittest.TestCase):
|
|||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
self.get_dummy_components(TorchAoConfig("int42"))
|
self.get_dummy_components(TorchAoConfig("int42"))
|
||||||
|
|
||||||
|
def test_sequential_cpu_offload(self):
|
||||||
|
r"""
|
||||||
|
A test that checks if inference runs as expected when sequential cpu offloading is enabled.
|
||||||
|
"""
|
||||||
|
quantization_config = TorchAoConfig("int8wo")
|
||||||
|
components = self.get_dummy_components(quantization_config)
|
||||||
|
pipe = FluxPipeline(**components)
|
||||||
|
pipe.enable_sequential_cpu_offload()
|
||||||
|
|
||||||
|
inputs = self.get_dummy_inputs(torch_device)
|
||||||
|
_ = pipe(**inputs)
|
||||||
|
|
||||||
|
|
||||||
# Slices for these tests have been obtained on our aws-g6e-xlarge-plus runners
|
# Slices for these tests have been obtained on our aws-g6e-xlarge-plus runners
|
||||||
@require_torch
|
@require_torch
|
||||||
|
|||||||
Reference in New Issue
Block a user