From 1fb86e34c006583e9e1f43a84f127fed3b8996f3 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Wed, 27 Nov 2024 18:01:36 +0100 Subject: [PATCH 01/65] load and save dduf archive --- src/diffusers/pipelines/pipeline_utils.py | 62 +++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index 2e1858b16148..c7b56ac53b22 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -193,6 +193,8 @@ def save_pretrained( variant: Optional[str] = None, max_shard_size: Optional[Union[int, str]] = None, push_to_hub: bool = False, + dduf_format: bool = False, + dduf_filename: Optional[Union[str, os.PathLike]] = None, **kwargs, ): """ @@ -227,6 +229,9 @@ class implements both a save and loading method. The pipeline is easily reloaded model_index_dict.pop("_module", None) model_index_dict.pop("_name_or_path", None) + if dduf_format and dduf_filename is None: + raise RuntimeError("You need set dduf_filename if you want to save your model in DDUF format.") + if push_to_hub: commit_message = kwargs.pop("commit_message", None) private = kwargs.pop("private", False) @@ -301,6 +306,31 @@ def is_saveable_module(name, value): save_method(os.path.join(save_directory, pipeline_component_name), **save_kwargs) + if dduf_format: + import shutil + import tarfile + dduf_file_path = os.path.join(save_directory, dduf_filename) + + if os.path.isdir(dduf_file_path): + logger.warning(f"Removing the existing folder {dduf_file_path} so that we can save the DDUF archive.") + shutil.rmtree(dduf_file_path) + if ( + os.path.exists(dduf_file_path) + and os.path.isfile(dduf_file_path) + and tarfile.is_tarfile(dduf_file_path) + ): + # Open in append mode if the file exists + mode = "a" + else: + # Open in write mode to create it if it doesn't exist + mode = "w:" + with tarfile.open(dduf_file_path, mode) as tar: + dir_to_archive = os.path.join(save_directory, pipeline_component_name) + if os.path.isdir(dir_to_archive): + tar.add(dir_to_archive, arcname=os.path.basename(dir_to_archive)) + # remove from save_directory after we added it to the archive + shutil.rmtree(dir_to_archive) + # finally save the config self.save_config(save_directory) @@ -523,6 +553,8 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P - A path to a *directory* (for example `./my_pipeline_directory/`) containing pipeline weights saved using [`~DiffusionPipeline.save_pretrained`]. + - A path to a *directory* (for example `./my_pipeline_directory/`) containing a dduf archive or + folder torch_dtype (`str` or `torch.dtype`, *optional*): 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. @@ -617,6 +649,8 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P variant (`str`, *optional*): Load weights from a specified variant filename such as `"fp16"` or `"ema"`. This is ignored when loading `from_flax`. + dduf(`str`, *optional*): + Load weights from the specified dduf archive or folder. @@ -666,6 +700,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P offload_state_dict = kwargs.pop("offload_state_dict", False) low_cpu_mem_usage = kwargs.pop("low_cpu_mem_usage", _LOW_CPU_MEM_USAGE_DEFAULT) variant = kwargs.pop("variant", None) + dduf = kwargs.pop("dduf", None) use_safetensors = kwargs.pop("use_safetensors", None) use_onnx = kwargs.pop("use_onnx", None) load_connected_pipeline = kwargs.pop("load_connected_pipeline", False) @@ -736,6 +771,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P custom_pipeline=custom_pipeline, custom_revision=custom_revision, variant=variant, + dduf=dduf, load_connected_pipeline=load_connected_pipeline, **kwargs, ) @@ -762,6 +798,25 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P # pop out "_ignore_files" as it is only needed for download config_dict.pop("_ignore_files", None) + if dduf: + import tarfile + + tar_file_path = os.path.join(cached_folder, dduf) + extract_to = os.path.join(cached_folder, f"{dduf}_extracted") + # if tar file, we need to extract the tarfile and remove it + if os.path.isfile(tar_file_path): + if tarfile.is_tarfile(tar_file_path): + with tarfile.open(tar_file_path, "r") as tar: + tar.extractall(extract_to) + # remove tar archive to free memory + os.remove(tar_file_path) + # rename folder to match the name of the dduf archive + os.rename(extract_to, tar_file_path) + else: + raise RuntimeError("The dduf path passed is not a tar archive") + # udapte cached folder location as the dduf content is in a seperate folder + cached_folder = tar_file_path + # 2. Define which model components should load variants # We retrieve the information by matching whether variant model checkpoints exist in the subfolders. # Example: `diffusion_pytorch_model.safetensors` -> `diffusion_pytorch_model.fp16.safetensors` @@ -1227,6 +1282,8 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: variant (`str`, *optional*): Load weights from a specified variant filename such as `"fp16"` or `"ema"`. This is ignored when loading `from_flax`. + dduf(`str`, *optional*): + Load weights from the specified DDUF archive or folder. use_safetensors (`bool`, *optional*, defaults to `None`): 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 @@ -1267,6 +1324,7 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: use_onnx = kwargs.pop("use_onnx", None) load_connected_pipeline = kwargs.pop("load_connected_pipeline", False) trust_remote_code = kwargs.pop("trust_remote_code", False) + dduf = kwargs.pop("dduf", False) allow_pickle = False if use_safetensors is None: @@ -1346,6 +1404,10 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: allow_patterns += [f"{custom_pipeline}.py"] if f"{custom_pipeline}.py" in filenames else [] # also allow downloading config.json files with the model allow_patterns += [os.path.join(k, "config.json") for k in model_folder_names] + # also allow downloading the dduf + # TODO: check that the file actually exist + if dduf is not None: + allow_patterns += [dduf] allow_patterns += [ SCHEDULER_CONFIG_NAME, From 0389333113681786ded963d91974acca2a2da7a6 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Wed, 27 Nov 2024 18:01:43 +0100 Subject: [PATCH 02/65] style --- src/diffusers/pipelines/pipeline_utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index c7b56ac53b22..a59c15c5ba96 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -309,10 +309,13 @@ def is_saveable_module(name, value): if dduf_format: import shutil import tarfile + dduf_file_path = os.path.join(save_directory, dduf_filename) if os.path.isdir(dduf_file_path): - logger.warning(f"Removing the existing folder {dduf_file_path} so that we can save the DDUF archive.") + logger.warning( + f"Removing the existing folder {dduf_file_path} so that we can save the DDUF archive." + ) shutil.rmtree(dduf_file_path) if ( os.path.exists(dduf_file_path) From 2eeda2532192ebcd1c589caa83ab679c955ba4a4 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 28 Nov 2024 16:06:04 +0100 Subject: [PATCH 03/65] switch to zip uncompressed --- src/diffusers/pipelines/pipeline_utils.py | 71 ++++++++++++++--------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index a59c15c5ba96..d71edb055004 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -193,7 +193,6 @@ def save_pretrained( variant: Optional[str] = None, max_shard_size: Optional[Union[int, str]] = None, push_to_hub: bool = False, - dduf_format: bool = False, dduf_filename: Optional[Union[str, os.PathLike]] = None, **kwargs, ): @@ -229,9 +228,6 @@ class implements both a save and loading method. The pipeline is easily reloaded model_index_dict.pop("_module", None) model_index_dict.pop("_name_or_path", None) - if dduf_format and dduf_filename is None: - raise RuntimeError("You need set dduf_filename if you want to save your model in DDUF format.") - if push_to_hub: commit_message = kwargs.pop("commit_message", None) private = kwargs.pop("private", False) @@ -306,9 +302,19 @@ def is_saveable_module(name, value): save_method(os.path.join(save_directory, pipeline_component_name), **save_kwargs) - if dduf_format: + if dduf_filename: import shutil - import tarfile + import zipfile + + def zipdir(dir_to_archive, zipf): + "zip a directory" + for root, dirs, files in os.walk(dir_to_archive): + for file in files: + file_path = os.path.join(root, file) + arcname = os.path.join( + os.path.basename(dir_to_archive), os.path.relpath(file_path, start=dir_to_archive) + ) + zipf.write(file_path, arcname=arcname) dduf_file_path = os.path.join(save_directory, dduf_filename) @@ -320,23 +326,30 @@ def is_saveable_module(name, value): if ( os.path.exists(dduf_file_path) and os.path.isfile(dduf_file_path) - and tarfile.is_tarfile(dduf_file_path) + and zipfile.is_zipfile(dduf_file_path) ): # Open in append mode if the file exists mode = "a" else: # Open in write mode to create it if it doesn't exist - mode = "w:" - with tarfile.open(dduf_file_path, mode) as tar: + mode = "w" + with zipfile.ZipFile(dduf_file_path, mode=mode, compression=zipfile.ZIP_STORED) as zipf: dir_to_archive = os.path.join(save_directory, pipeline_component_name) if os.path.isdir(dir_to_archive): - tar.add(dir_to_archive, arcname=os.path.basename(dir_to_archive)) - # remove from save_directory after we added it to the archive + zipdir(dir_to_archive, zipf) shutil.rmtree(dir_to_archive) # finally save the config self.save_config(save_directory) + if dduf_filename: + import zipfile + + with zipfile.ZipFile(dduf_file_path, mode="a", compression=zipfile.ZIP_STORED) as zipf: + config_path = os.path.join(save_directory, self.config_name) + zipf.write(config_path, arcname=os.path.basename(config_path)) + os.remove(config_path) + if push_to_hub: # Create a new empty model card and eventually tag it model_card = load_or_create_model_card(repo_id, token=token, is_pipeline=True) @@ -652,7 +665,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P variant (`str`, *optional*): Load weights from a specified variant filename such as `"fp16"` or `"ema"`. This is ignored when loading `from_flax`. - dduf(`str`, *optional*): + dduf (`str`, *optional*): Load weights from the specified dduf archive or folder. @@ -796,29 +809,29 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P ) logger.warning(warn_msg) - config_dict = cls.load_config(cached_folder) - - # pop out "_ignore_files" as it is only needed for download - config_dict.pop("_ignore_files", None) - if dduf: - import tarfile + import zipfile - tar_file_path = os.path.join(cached_folder, dduf) + zip_file_path = os.path.join(cached_folder, dduf) extract_to = os.path.join(cached_folder, f"{dduf}_extracted") - # if tar file, we need to extract the tarfile and remove it - if os.path.isfile(tar_file_path): - if tarfile.is_tarfile(tar_file_path): - with tarfile.open(tar_file_path, "r") as tar: - tar.extractall(extract_to) - # remove tar archive to free memory - os.remove(tar_file_path) + # if zip file, we need to extract the zipfile and remove it + if os.path.isfile(zip_file_path): + if zipfile.is_zipfile(zip_file_path): + with zipfile.ZipFile(zip_file_path, "r") as zipf: + zipf.extractall(extract_to) + # remove zip archive to free memory + os.remove(zip_file_path) # rename folder to match the name of the dduf archive - os.rename(extract_to, tar_file_path) + os.rename(extract_to, zip_file_path) else: - raise RuntimeError("The dduf path passed is not a tar archive") + raise RuntimeError("The dduf path passed is not a zip archive") # udapte cached folder location as the dduf content is in a seperate folder - cached_folder = tar_file_path + cached_folder = zip_file_path + + config_dict = cls.load_config(cached_folder) + + # pop out "_ignore_files" as it is only needed for download + config_dict.pop("_ignore_files", None) # 2. Define which model components should load variants # We retrieve the information by matching whether variant model checkpoints exist in the subfolders. From d8408677c545c07ea916d391f9287b0c9b142334 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Fri, 29 Nov 2024 09:18:23 +0530 Subject: [PATCH 04/65] updates --- src/diffusers/pipelines/pipeline_utils.py | 71 +++++++++++++---------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index d71edb055004..33af56be61e5 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -817,8 +817,12 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P # if zip file, we need to extract the zipfile and remove it if os.path.isfile(zip_file_path): if zipfile.is_zipfile(zip_file_path): - with zipfile.ZipFile(zip_file_path, "r") as zipf: - zipf.extractall(extract_to) + # with zipfile.ZipFile(zip_file_path, "r") as zipf: + # zipf.extractall(extract_to) + with zipfile.ZipFile(zip_file_path, "r") as zip_ref: + file_list = zip_ref.infolist() + for file_info in tqdm(file_list, desc="Extracting files"): + zip_ref.extract(file_info, extract_to) # remove zip archive to free memory os.remove(zip_file_path) # rename folder to match the name of the dduf archive @@ -1340,7 +1344,7 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: use_onnx = kwargs.pop("use_onnx", None) load_connected_pipeline = kwargs.pop("load_connected_pipeline", False) trust_remote_code = kwargs.pop("trust_remote_code", False) - dduf = kwargs.pop("dduf", False) + dduf = kwargs.pop("dduf", None) allow_pickle = False if use_safetensors is None: @@ -1359,7 +1363,14 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: 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: + if dduf is not None and not local_files_only: + dduf_available = False + for sibling in info.siblings: + dduf_available = dduf in sibling.rfilename + if not dduf_available: + raise ValueError(f"Requested {dduf} file is not available in {pretrained_model_name}.") + + if not local_files_only and not dduf: filenames = {sibling.rfilename for sibling in info.siblings} if variant is not None and _check_legacy_sharding_variant_format(filenames=filenames, variant=variant): warn_msg = ( @@ -1420,11 +1431,6 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: allow_patterns += [f"{custom_pipeline}.py"] if f"{custom_pipeline}.py" in filenames else [] # also allow downloading config.json files with the model allow_patterns += [os.path.join(k, "config.json") for k in model_folder_names] - # also allow downloading the dduf - # TODO: check that the file actually exist - if dduf is not None: - allow_patterns += [dduf] - allow_patterns += [ SCHEDULER_CONFIG_NAME, CONFIG_NAME, @@ -1503,10 +1509,14 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: return snapshot_folder user_agent = {"pipeline_class": cls.__name__} - if custom_pipeline is not None and not custom_pipeline.endswith(".py"): + if not dduf and custom_pipeline is not None and not custom_pipeline.endswith(".py"): user_agent["custom_pipeline"] = custom_pipeline # download all allow_patterns - ignore_patterns + # also allow downloading the dduf + if dduf is not None: + allow_patterns = [dduf] + ignore_patterns = [] try: cached_folder = snapshot_download( pretrained_model_name, @@ -1521,26 +1531,27 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: ) # 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_name[4:] if isinstance(cls_name, str) and cls_name.startswith("Flax") else cls_name - - diffusers_module = importlib.import_module(__name__.split(".")[0]) - pipeline_class = getattr(diffusers_module, cls_name, None) if isinstance(cls_name, str) else None - - if pipeline_class is not None and pipeline_class._load_connected_pipes: - modelcard = ModelCard.load(os.path.join(cached_folder, "README.md")) - connected_pipes = sum([getattr(modelcard.data, k, []) for k in CONNECTED_PIPES_KEYS], []) - for connected_pipe_repo_id in connected_pipes: - download_kwargs = { - "cache_dir": cache_dir, - "force_download": force_download, - "proxies": proxies, - "local_files_only": local_files_only, - "token": token, - "variant": variant, - "use_safetensors": use_safetensors, - } - DiffusionPipeline.download(connected_pipe_repo_id, **download_kwargs) + if not dduf: + 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 + + diffusers_module = importlib.import_module(__name__.split(".")[0]) + pipeline_class = getattr(diffusers_module, cls_name, None) if isinstance(cls_name, str) else None + + if pipeline_class is not None and pipeline_class._load_connected_pipes: + modelcard = ModelCard.load(os.path.join(cached_folder, "README.md")) + connected_pipes = sum([getattr(modelcard.data, k, []) for k in CONNECTED_PIPES_KEYS], []) + for connected_pipe_repo_id in connected_pipes: + download_kwargs = { + "cache_dir": cache_dir, + "force_download": force_download, + "proxies": proxies, + "local_files_only": local_files_only, + "token": token, + "variant": variant, + "use_safetensors": use_safetensors, + } + DiffusionPipeline.download(connected_pipe_repo_id, **download_kwargs) return cached_folder From 7d2c7d5553eea668a60ba6eaf320179cebf3f22f Mon Sep 17 00:00:00 2001 From: Marc Sun <57196510+SunMarc@users.noreply.github.com> Date: Wed, 4 Dec 2024 13:56:21 +0100 Subject: [PATCH 05/65] Update src/diffusers/pipelines/pipeline_utils.py Co-authored-by: Sayak Paul --- src/diffusers/pipelines/pipeline_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index b6d63b5fec4f..00741137cd22 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -307,7 +307,7 @@ def is_saveable_module(name, value): import zipfile def zipdir(dir_to_archive, zipf): - "zip a directory" + """Archive a directory""" for root, dirs, files in os.walk(dir_to_archive): for file in files: file_path = os.path.join(root, file) From e66c4d0dab8fa84b6ff91716e9c7ca84f95ff119 Mon Sep 17 00:00:00 2001 From: Marc Sun <57196510+SunMarc@users.noreply.github.com> Date: Wed, 4 Dec 2024 13:57:21 +0100 Subject: [PATCH 06/65] Update src/diffusers/pipelines/pipeline_utils.py Co-authored-by: Sayak Paul --- src/diffusers/pipelines/pipeline_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index 00741137cd22..8079b79cd61a 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -342,6 +342,8 @@ def zipdir(dir_to_archive, zipf): # finally save the config self.save_config(save_directory) + # Takes care of including the "model_index.json" inside the ZIP. + # TODO: Include a DDUF a metadata file. if dduf_filename: import zipfile From b14bffeffe2b57b076ce635b2dfc5b47fa6ae6f7 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Wed, 4 Dec 2024 13:03:35 +0000 Subject: [PATCH 07/65] first draft --- src/diffusers/configuration_utils.py | 35 ++++++++++++---- src/diffusers/models/model_loading_utils.py | 13 +++++- src/diffusers/models/modeling_utils.py | 12 ++++-- .../pipelines/pipeline_loading_utils.py | 6 ++- src/diffusers/pipelines/pipeline_utils.py | 30 ++++---------- .../stable_audio/pipeline_stable_audio.py | 3 +- src/diffusers/utils/__init__.py | 1 + src/diffusers/utils/dduf.py | 41 +++++++++++++++++++ src/diffusers/utils/hub_utils.py | 13 +++++- 9 files changed, 116 insertions(+), 38 deletions(-) create mode 100644 src/diffusers/utils/dduf.py diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index d21ada6fbe60..85461834b0e0 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -347,6 +347,7 @@ def load_config( _ = kwargs.pop("mirror", None) subfolder = kwargs.pop("subfolder", None) user_agent = kwargs.pop("user_agent", {}) + dduf_reader = kwargs.pop("dduf_reader", None) user_agent = {**user_agent, "file_type": "config"} user_agent = http_user_agent(user_agent) @@ -358,8 +359,25 @@ def load_config( "`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`" ) - - if os.path.isfile(pretrained_model_name_or_path): + # Custom path for now + if dduf_reader: + if subfolder is not None: + if dduf_reader.has_file(os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name)): + config_file = os.path.join(subfolder, cls.config_name) + else: + raise ValueError( + f"We did not manage to find the file {os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name)} in the archive. We only have the following files {dduf_reader.files}" + ) + elif dduf_reader.has_file(os.path.join(pretrained_model_name_or_path, cls.config_name)): + config_file = os.path.join(pretrained_model_name_or_path, cls.config_name) + else: + raise ValueError( + f"We did not manage to find the file {os.path.join(pretrained_model_name_or_path, cls.config_name)} in the archive. We only have the following files {dduf_reader.files}" + ) + print(f"File found: {config_file}") + elif not dduf_reader: + print("not dduf") + elif os.path.isfile(pretrained_model_name_or_path): config_file = pretrained_model_name_or_path elif os.path.isdir(pretrained_model_name_or_path): if subfolder is not None and os.path.isfile( @@ -426,10 +444,8 @@ def load_config( f"Otherwise, make sure '{pretrained_model_name_or_path}' is the correct path to a directory " f"containing a {cls.config_name} file" ) - try: - # Load config dict - config_dict = cls._dict_from_json_file(config_file) + config_dict = cls._dict_from_json_file(config_file, dduf_reader=dduf_reader) commit_hash = extract_commit_hash(config_file) except (json.JSONDecodeError, UnicodeDecodeError): @@ -552,9 +568,12 @@ def extract_init_dict(cls, config_dict, **kwargs): return init_dict, unused_kwargs, hidden_config_dict @classmethod - def _dict_from_json_file(cls, json_file: Union[str, os.PathLike]): - with open(json_file, "r", encoding="utf-8") as reader: - text = reader.read() + def _dict_from_json_file(cls, json_file: Union[str, os.PathLike], dduf_reader=None): + if dduf_reader: + text = dduf_reader.read_file(json_file, encoding="utf-8") + else: + with open(json_file, "r", encoding="utf-8") as reader: + text = reader.read() return json.loads(text) def __repr__(self): diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index 932a94571107..0f32d7eeb494 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -128,7 +128,7 @@ def _fetch_remapped_cls_from_config(config, old_class): return old_class -def load_state_dict(checkpoint_file: Union[str, os.PathLike], variant: Optional[str] = None): +def load_state_dict(checkpoint_file: Union[str, os.PathLike], variant: Optional[str] = None, dduf_reader=None): """ Reads a checkpoint file, returning properly formatted errors if they arise. """ @@ -138,8 +138,15 @@ def load_state_dict(checkpoint_file: Union[str, os.PathLike], variant: Optional[ return checkpoint_file try: file_extension = os.path.basename(checkpoint_file).split(".")[-1] + if dduf_reader: + checkpoint_file = dduf_reader.read_file(checkpoint_file) if file_extension == SAFETENSORS_FILE_EXTENSION: - return safetensors.torch.load_file(checkpoint_file, device="cpu") + if dduf_reader: + # tensors are loaded on cpu + return safetensors.torch.load(checkpoint_file) + else: + return safetensors.torch.load_file(checkpoint_file, device="cpu") + else: weights_only_kwarg = {"weights_only": True} if is_torch_version(">=", "1.13") else {} return torch.load( @@ -272,6 +279,7 @@ def _fetch_index_file( revision, user_agent, commit_hash, + dduf_reader=None, ): if is_local: index_file = Path( @@ -297,6 +305,7 @@ def _fetch_index_file( subfolder=None, user_agent=user_agent, commit_hash=commit_hash, + dduf_reader=dduf_reader, ) index_file = Path(index_file) except (EntryNotFoundError, EnvironmentError): diff --git a/src/diffusers/models/modeling_utils.py b/src/diffusers/models/modeling_utils.py index 76f6c5f6309d..c7e1b31cd71f 100644 --- a/src/diffusers/models/modeling_utils.py +++ b/src/diffusers/models/modeling_utils.py @@ -557,6 +557,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P variant = kwargs.pop("variant", None) use_safetensors = kwargs.pop("use_safetensors", None) quantization_config = kwargs.pop("quantization_config", None) + dduf_reader = kwargs.pop("dduf_reader", None) allow_pickle = False if use_safetensors is None: @@ -649,6 +650,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P revision=revision, subfolder=subfolder, user_agent=user_agent, + dduf_reader=dduf_reader, **kwargs, ) # no in-place modification of the original config. @@ -724,6 +726,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P "revision": revision, "user_agent": user_agent, "commit_hash": commit_hash, + "dduf_reader": dduf_reader, } index_file = _fetch_index_file(**index_file_kwargs) # In case the index file was not found we still have to consider the legacy format. @@ -759,7 +762,8 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P model = load_flax_checkpoint_in_pytorch_model(model, model_file) else: - if is_sharded: + # in the case it is sharded, we have already the index + if is_sharded and not dduf_reader: sharded_ckpt_cached_folder, sharded_metadata = _get_checkpoint_shard_files( pretrained_model_name_or_path, index_file, @@ -790,6 +794,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P subfolder=subfolder, user_agent=user_agent, commit_hash=commit_hash, + dduf_reader=dduf_reader, ) except IOError as e: @@ -813,6 +818,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P subfolder=subfolder, user_agent=user_agent, commit_hash=commit_hash, + dduf_reader=dduf_reader, ) if low_cpu_mem_usage: @@ -837,7 +843,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P # TODO (sayakpaul, SunMarc): remove this after model loading refactor elif is_quant_method_bnb: param_device = torch.cuda.current_device() - state_dict = load_state_dict(model_file, variant=variant) + state_dict = load_state_dict(model_file, variant=variant, dduf_reader=dduf_reader) model._convert_deprecated_attention_blocks(state_dict) # move the params from meta device to cpu @@ -937,7 +943,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P else: model = cls.from_config(config, **unused_kwargs) - state_dict = load_state_dict(model_file, variant=variant) + state_dict = load_state_dict(model_file, variant=variant, dduf_reader=dduf_reader) model._convert_deprecated_attention_blocks(state_dict) model, missing_keys, unexpected_keys, mismatched_keys, error_msgs = cls._load_pretrained_model( diff --git a/src/diffusers/pipelines/pipeline_loading_utils.py b/src/diffusers/pipelines/pipeline_loading_utils.py index 0a7a222ec007..b555dac6f793 100644 --- a/src/diffusers/pipelines/pipeline_loading_utils.py +++ b/src/diffusers/pipelines/pipeline_loading_utils.py @@ -627,6 +627,7 @@ def load_sub_model( low_cpu_mem_usage: bool, cached_folder: Union[str, os.PathLike], use_safetensors: bool, + dduf_reader, ): """Helper method to load the module `name` from `library_name` and `class_name`""" @@ -721,7 +722,10 @@ def load_sub_model( loading_kwargs["low_cpu_mem_usage"] = False # check if the module is in a subdirectory - if os.path.isdir(os.path.join(cached_folder, name)): + if dduf_reader: + loading_kwargs["dduf_reader"] = dduf_reader + 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) else: # else load from the root directory diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index 8079b79cd61a..d0f94db7ab7d 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -50,6 +50,7 @@ CONFIG_NAME, DEPRECATED_REVISION_ARGS, BaseOutput, + DDUFReader, PushToHubMixin, is_accelerate_available, is_accelerate_version, @@ -343,7 +344,7 @@ def zipdir(dir_to_archive, zipf): self.save_config(save_directory) # Takes care of including the "model_index.json" inside the ZIP. - # TODO: Include a DDUF a metadata file. + # TODO: Include a DDUF a metadata file. if dduf_filename: import zipfile @@ -811,30 +812,14 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P ) logger.warning(warn_msg) + dduf_reader = None if dduf: - import zipfile - zip_file_path = os.path.join(cached_folder, dduf) - extract_to = os.path.join(cached_folder, f"{dduf}_extracted") - # if zip file, we need to extract the zipfile and remove it - if os.path.isfile(zip_file_path): - if zipfile.is_zipfile(zip_file_path): - # with zipfile.ZipFile(zip_file_path, "r") as zipf: - # zipf.extractall(extract_to) - with zipfile.ZipFile(zip_file_path, "r") as zip_ref: - file_list = zip_ref.infolist() - for file_info in tqdm(file_list, desc="Extracting files"): - zip_ref.extract(file_info, extract_to) - # remove zip archive to free memory - os.remove(zip_file_path) - # rename folder to match the name of the dduf archive - os.rename(extract_to, zip_file_path) - else: - raise RuntimeError("The dduf path passed is not a zip archive") - # udapte cached folder location as the dduf content is in a seperate folder - cached_folder = zip_file_path + dduf_reader = DDUFReader(zip_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) + config_dict = cls.load_config(cached_folder, dduf_reader=dduf_reader) # pop out "_ignore_files" as it is only needed for download config_dict.pop("_ignore_files", None) @@ -991,6 +976,7 @@ def load_module(name, value): low_cpu_mem_usage=low_cpu_mem_usage, cached_folder=cached_folder, use_safetensors=use_safetensors, + dduf_reader=dduf_reader, ) logger.info( f"Loaded {name} as {class_name} from `{name}` subfolder of {pretrained_model_name_or_path}." diff --git a/src/diffusers/pipelines/stable_audio/pipeline_stable_audio.py b/src/diffusers/pipelines/stable_audio/pipeline_stable_audio.py index a30af53f77a7..cef63cf7e63d 100644 --- a/src/diffusers/pipelines/stable_audio/pipeline_stable_audio.py +++ b/src/diffusers/pipelines/stable_audio/pipeline_stable_audio.py @@ -34,6 +34,7 @@ from ..pipeline_utils import AudioPipelineOutput, DiffusionPipeline from .modeling_stable_audio import StableAudioProjectionModel + if is_torch_xla_available(): import torch_xla.core.xla_model as xm @@ -732,7 +733,7 @@ def __call__( if callback is not None and i % callback_steps == 0: step_idx = i // getattr(self.scheduler, "order", 1) callback(step_idx, t, latents) - + if XLA_AVAILABLE: xm.mark_step() diff --git a/src/diffusers/utils/__init__.py b/src/diffusers/utils/__init__.py index c8f64adf3e8a..6493b1b09287 100644 --- a/src/diffusers/utils/__init__.py +++ b/src/diffusers/utils/__init__.py @@ -35,6 +35,7 @@ WEIGHTS_INDEX_NAME, WEIGHTS_NAME, ) +from .dduf import DDUFReader from .deprecation_utils import deprecate from .doc_utils import replace_example_docstring from .dynamic_modules_utils import get_class_from_dynamic_module diff --git a/src/diffusers/utils/dduf.py b/src/diffusers/utils/dduf.py new file mode 100644 index 000000000000..ae6c5e91a1a2 --- /dev/null +++ b/src/diffusers/utils/dduf.py @@ -0,0 +1,41 @@ +import zipfile + + +class DDUFReader: + def __init__(self, dduf_file): + self.dduf_file = dduf_file + self.files = [] + self.post_init() + + def post_init(self): + """ + Check that the DDUF file is valid + """ + if not zipfile.is_zipfile(self.dduf_file): + raise ValueError(f"The file '{self.dduf_file}' is not a valid ZIP archive.") + + try: + with zipfile.ZipFile(self.dduf_file, "r") as zf: + # Check integrity and store file list + zf.testzip() # Returns None if no corrupt files are found + self.files = zf.namelist() + except zipfile.BadZipFile: + raise ValueError(f"The file '{self.dduf_file}' is not a valid ZIP archive.") + except Exception as e: + raise RuntimeError(f"An error occurred while validating the ZIP file: {e}") + + def has_file(self, file): + return file in self.files + + def read_file(self, file_name, encoding=None): + """ + Reads the content of a specific file in the ZIP archive without extracting. + """ + if file_name not in self.files: + raise ValueError(f"{file_name} is not in the list of files {self.files}") + with zipfile.ZipFile(self.dduf_file, "r") as zf: + with zf.open(file_name) as file: + file = file.read() + if encoding is not None: + file = file.decode(encoding) + return file diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index ef4715ee0e1e..99447808483c 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -291,9 +291,20 @@ def _get_model_file( user_agent: Optional[Union[Dict, str]] = None, revision: Optional[str] = None, commit_hash: Optional[str] = None, + dduf_reader=None, ): pretrained_model_name_or_path = str(pretrained_model_name_or_path) - if os.path.isfile(pretrained_model_name_or_path): + + if dduf_reader: + if dduf_reader.has_file(os.path.join(pretrained_model_name_or_path, weights_name)): + return os.path.join(pretrained_model_name_or_path, weights_name) + elif subfolder is not None and os.path.isfile( + os.path.join(pretrained_model_name_or_path, subfolder, weights_name) + ): + return os.path.join(pretrained_model_name_or_path, weights_name) + else: + raise EnvironmentError(f"Error no file named {weights_name} found in archive {dduf_reader.files}.") + elif os.path.isfile(pretrained_model_name_or_path): return 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)): From 1cd5155bb8e4aec8bcd7f5fff2b95b14007bd601 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Wed, 4 Dec 2024 13:04:48 +0000 Subject: [PATCH 08/65] remove print --- src/diffusers/configuration_utils.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 85461834b0e0..7152b03aa937 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -374,9 +374,6 @@ def load_config( raise ValueError( f"We did not manage to find the file {os.path.join(pretrained_model_name_or_path, cls.config_name)} in the archive. We only have the following files {dduf_reader.files}" ) - print(f"File found: {config_file}") - elif not dduf_reader: - print("not dduf") elif os.path.isfile(pretrained_model_name_or_path): config_file = pretrained_model_name_or_path elif os.path.isdir(pretrained_model_name_or_path): From b8a43e7f9c65aae50881aac080aa9e8cd3bcfa04 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 5 Dec 2024 16:22:13 +0000 Subject: [PATCH 09/65] switch to dduf_file for consistency --- src/diffusers/pipelines/pipeline_utils.py | 50 ++++++++++++----------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index d0f94db7ab7d..be9a7b1715fa 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -194,7 +194,7 @@ def save_pretrained( variant: Optional[str] = None, max_shard_size: Optional[Union[int, str]] = None, push_to_hub: bool = False, - dduf_filename: Optional[Union[str, os.PathLike]] = None, + dduf_file: Optional[Union[str, os.PathLike]] = None, **kwargs, ): """ @@ -220,6 +220,9 @@ class implements both a save and loading method. The pipeline is easily reloaded 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 namespace). + dduf_file (`str` or `os.PathLike`, *optional*, defaults to `None`): + If specified, the weights will be saved in dduf format with the specified name. + kwargs (`Dict[str, Any]`, *optional*): Additional keyword arguments passed along to the [`~utils.PushToHubMixin.push_to_hub`] method. """ @@ -303,7 +306,7 @@ def is_saveable_module(name, value): save_method(os.path.join(save_directory, pipeline_component_name), **save_kwargs) - if dduf_filename: + if dduf_file: import shutil import zipfile @@ -317,7 +320,7 @@ def zipdir(dir_to_archive, zipf): ) zipf.write(file_path, arcname=arcname) - dduf_file_path = os.path.join(save_directory, dduf_filename) + dduf_file_path = os.path.join(save_directory, dduf_file) if os.path.isdir(dduf_file_path): logger.warning( @@ -345,7 +348,7 @@ def zipdir(dir_to_archive, zipf): # Takes care of including the "model_index.json" inside the ZIP. # TODO: Include a DDUF a metadata file. - if dduf_filename: + if dduf_file: import zipfile with zipfile.ZipFile(dduf_file_path, mode="a", compression=zipfile.ZIP_STORED) as zipf: @@ -572,8 +575,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P - A path to a *directory* (for example `./my_pipeline_directory/`) containing pipeline weights saved using [`~DiffusionPipeline.save_pretrained`]. - - A path to a *directory* (for example `./my_pipeline_directory/`) containing a dduf archive or - folder + - A path to a *directory* (for example `./my_pipeline_directory/`) containing a dduf file torch_dtype (`str` or `torch.dtype`, *optional*): 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. @@ -668,8 +670,8 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P variant (`str`, *optional*): Load weights from a specified variant filename such as `"fp16"` or `"ema"`. This is ignored when loading `from_flax`. - dduf (`str`, *optional*): - Load weights from the specified dduf archive or folder. + dduf_file(`str`, *optional*): + Load weights from the specified dduf file @@ -719,7 +721,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P offload_state_dict = kwargs.pop("offload_state_dict", False) low_cpu_mem_usage = kwargs.pop("low_cpu_mem_usage", _LOW_CPU_MEM_USAGE_DEFAULT) variant = kwargs.pop("variant", None) - dduf = kwargs.pop("dduf", None) + dduf_file = kwargs.pop("dduf_file", None) use_safetensors = kwargs.pop("use_safetensors", None) use_onnx = kwargs.pop("use_onnx", None) load_connected_pipeline = kwargs.pop("load_connected_pipeline", False) @@ -790,7 +792,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P custom_pipeline=custom_pipeline, custom_revision=custom_revision, variant=variant, - dduf=dduf, + dduf_file=dduf_file, load_connected_pipeline=load_connected_pipeline, **kwargs, ) @@ -813,8 +815,8 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P logger.warning(warn_msg) dduf_reader = None - if dduf: - zip_file_path = os.path.join(cached_folder, dduf) + if dduf_file: + zip_file_path = os.path.join(cached_folder, dduf_file) dduf_reader = DDUFReader(zip_file_path) # The reader contains already all the files needed, no need to check it again cached_folder = "" @@ -1290,8 +1292,8 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: variant (`str`, *optional*): Load weights from a specified variant filename such as `"fp16"` or `"ema"`. This is ignored when loading `from_flax`. - dduf(`str`, *optional*): - Load weights from the specified DDUF archive or folder. + dduf_file(`str`, *optional*): + Load weights from the specified DDUF file. use_safetensors (`bool`, *optional*, defaults to `None`): 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 @@ -1332,7 +1334,7 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: use_onnx = kwargs.pop("use_onnx", None) load_connected_pipeline = kwargs.pop("load_connected_pipeline", False) trust_remote_code = kwargs.pop("trust_remote_code", False) - dduf = kwargs.pop("dduf", None) + dduf_file = kwargs.pop("dduf_file", None) allow_pickle = False if use_safetensors is None: @@ -1351,14 +1353,14 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: local_files_only = True model_info_call_error = e # save error to reraise it if model is not cached locally - if dduf is not None and not local_files_only: + if dduf_file is not None and not local_files_only: dduf_available = False for sibling in info.siblings: - dduf_available = dduf in sibling.rfilename + dduf_available = dduf_file in sibling.rfilename if not dduf_available: - raise ValueError(f"Requested {dduf} file is not available in {pretrained_model_name}.") + raise ValueError(f"Requested {dduf_file} file is not available in {pretrained_model_name}.") - if not local_files_only and not dduf: + if not local_files_only and not dduf_file: filenames = {sibling.rfilename for sibling in info.siblings} if variant is not None and _check_legacy_sharding_variant_format(filenames=filenames, variant=variant): warn_msg = ( @@ -1497,13 +1499,13 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: return snapshot_folder user_agent = {"pipeline_class": cls.__name__} - if not dduf and custom_pipeline is not None and not custom_pipeline.endswith(".py"): + if not dduf_file and custom_pipeline is not None and not custom_pipeline.endswith(".py"): user_agent["custom_pipeline"] = custom_pipeline # download all allow_patterns - ignore_patterns - # also allow downloading the dduf - if dduf is not None: - allow_patterns = [dduf] + # also allow downloading the dduf_file + if dduf_file is not None: + allow_patterns = [dduf_file] ignore_patterns = [] try: cached_folder = snapshot_download( @@ -1519,7 +1521,7 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: ) # retrieve pipeline class from local file - if not dduf: + if not dduf_file: 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 From 977baa3a25ee866039086e778d0b46ae390a3046 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 5 Dec 2024 17:52:29 +0000 Subject: [PATCH 10/65] switch to huggingface hub api --- src/diffusers/configuration_utils.py | 20 ++++++++-------- src/diffusers/models/model_loading_utils.py | 13 +++++----- src/diffusers/models/modeling_utils.py | 16 ++++++------- .../pipelines/pipeline_loading_utils.py | 6 ++--- src/diffusers/pipelines/pipeline_utils.py | 21 +++++++++++----- src/diffusers/utils/__init__.py | 1 + src/diffusers/utils/hub_utils.py | 13 +++++----- src/diffusers/utils/import_utils.py | 24 +++++++++++++++++++ 8 files changed, 74 insertions(+), 40 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 7152b03aa937..0d1e5e62e7ca 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -347,7 +347,7 @@ def load_config( _ = kwargs.pop("mirror", None) subfolder = kwargs.pop("subfolder", None) user_agent = kwargs.pop("user_agent", {}) - dduf_reader = kwargs.pop("dduf_reader", None) + dduf_entries = kwargs.pop("dduf_entries", None) user_agent = {**user_agent, "file_type": "config"} user_agent = http_user_agent(user_agent) @@ -360,19 +360,19 @@ def load_config( "`ConfigMixin`. Please make sure to define `config_name` in a class inheriting from `ConfigMixin`" ) # Custom path for now - if dduf_reader: + if dduf_entries: if subfolder is not None: - if dduf_reader.has_file(os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name)): + if os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name) in dduf_entries: config_file = os.path.join(subfolder, cls.config_name) else: raise ValueError( - f"We did not manage to find the file {os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name)} in the archive. We only have the following files {dduf_reader.files}" + f"We did not manage to find the file {os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name)} in the dduf file. We only have the following files {dduf_entries.keys()}" ) - elif dduf_reader.has_file(os.path.join(pretrained_model_name_or_path, cls.config_name)): + elif os.path.join(pretrained_model_name_or_path, cls.config_name) in dduf_entries: config_file = os.path.join(pretrained_model_name_or_path, cls.config_name) else: raise ValueError( - f"We did not manage to find the file {os.path.join(pretrained_model_name_or_path, cls.config_name)} in the archive. We only have the following files {dduf_reader.files}" + f"We did not manage to find the file {os.path.join(pretrained_model_name_or_path, cls.config_name)} in the dduf file. We only have the following files {dduf_entries.keys()}" ) elif os.path.isfile(pretrained_model_name_or_path): config_file = pretrained_model_name_or_path @@ -442,7 +442,7 @@ def load_config( f"containing a {cls.config_name} file" ) try: - config_dict = cls._dict_from_json_file(config_file, dduf_reader=dduf_reader) + config_dict = cls._dict_from_json_file(config_file, dduf_entries=dduf_entries) commit_hash = extract_commit_hash(config_file) except (json.JSONDecodeError, UnicodeDecodeError): @@ -565,9 +565,9 @@ def extract_init_dict(cls, config_dict, **kwargs): return init_dict, unused_kwargs, hidden_config_dict @classmethod - def _dict_from_json_file(cls, json_file: Union[str, os.PathLike], dduf_reader=None): - if dduf_reader: - text = dduf_reader.read_file(json_file, encoding="utf-8") + def _dict_from_json_file(cls, json_file: Union[str, os.PathLike], dduf_entries=None): + if dduf_entries: + text = dduf_entries[json_file].read_text() else: with open(json_file, "r", encoding="utf-8") as reader: text = reader.read() diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index 518eb104834b..852ad85f9b92 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -128,7 +128,7 @@ def _fetch_remapped_cls_from_config(config, old_class): return old_class -def load_state_dict(checkpoint_file: Union[str, os.PathLike], variant: Optional[str] = None, dduf_reader=None): +def load_state_dict(checkpoint_file: Union[str, os.PathLike], variant: Optional[str] = None, dduf_entries=None): """ Reads a checkpoint file, returning properly formatted errors if they arise. """ @@ -138,12 +138,11 @@ def load_state_dict(checkpoint_file: Union[str, os.PathLike], variant: Optional[ return checkpoint_file try: file_extension = os.path.basename(checkpoint_file).split(".")[-1] - if dduf_reader: - checkpoint_file = dduf_reader.read_file(checkpoint_file) if file_extension == SAFETENSORS_FILE_EXTENSION: - if dduf_reader: + if dduf_entries: # tensors are loaded on cpu - return safetensors.torch.load(checkpoint_file) + with dduf_entries[checkpoint_file].as_mmap() as mm: + return safetensors.torch.load(mm) else: return safetensors.torch.load_file(checkpoint_file, device="cpu") @@ -281,7 +280,7 @@ def _fetch_index_file( revision, user_agent, commit_hash, - dduf_reader=None, + dduf_entries=None, ): if is_local: index_file = Path( @@ -307,7 +306,7 @@ def _fetch_index_file( subfolder=None, user_agent=user_agent, commit_hash=commit_hash, - dduf_reader=dduf_reader, + dduf_entries=dduf_entries, ) index_file = Path(index_file) except (EntryNotFoundError, EnvironmentError): diff --git a/src/diffusers/models/modeling_utils.py b/src/diffusers/models/modeling_utils.py index a4968940c759..357e1ef65851 100644 --- a/src/diffusers/models/modeling_utils.py +++ b/src/diffusers/models/modeling_utils.py @@ -557,7 +557,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P variant = kwargs.pop("variant", None) use_safetensors = kwargs.pop("use_safetensors", None) quantization_config = kwargs.pop("quantization_config", None) - dduf_reader = kwargs.pop("dduf_reader", None) + dduf_entries = kwargs.pop("dduf_entries", None) allow_pickle = False if use_safetensors is None: @@ -650,7 +650,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P revision=revision, subfolder=subfolder, user_agent=user_agent, - dduf_reader=dduf_reader, + dduf_entries=dduf_entries, **kwargs, ) # no in-place modification of the original config. @@ -726,7 +726,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P "revision": revision, "user_agent": user_agent, "commit_hash": commit_hash, - "dduf_reader": dduf_reader, + "dduf_entries": dduf_entries, } index_file = _fetch_index_file(**index_file_kwargs) # In case the index file was not found we still have to consider the legacy format. @@ -763,7 +763,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P model = load_flax_checkpoint_in_pytorch_model(model, model_file) else: # in the case it is sharded, we have already the index - if is_sharded and not dduf_reader: + if is_sharded and not dduf_entries: sharded_ckpt_cached_folder, sharded_metadata = _get_checkpoint_shard_files( pretrained_model_name_or_path, index_file, @@ -794,7 +794,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P subfolder=subfolder, user_agent=user_agent, commit_hash=commit_hash, - dduf_reader=dduf_reader, + dduf_entries=dduf_entries, ) except IOError as e: @@ -818,7 +818,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P subfolder=subfolder, user_agent=user_agent, commit_hash=commit_hash, - dduf_reader=dduf_reader, + dduf_entries=dduf_entries, ) if low_cpu_mem_usage: @@ -843,7 +843,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P # TODO (sayakpaul, SunMarc): remove this after model loading refactor elif is_quant_method_bnb: param_device = torch.device(torch.cuda.current_device()) - state_dict = load_state_dict(model_file, variant=variant, dduf_reader=dduf_reader) + state_dict = load_state_dict(model_file, variant=variant, dduf_entries=dduf_entries) model._convert_deprecated_attention_blocks(state_dict) # move the params from meta device to cpu @@ -943,7 +943,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P else: model = cls.from_config(config, **unused_kwargs) - state_dict = load_state_dict(model_file, variant=variant, dduf_reader=dduf_reader) + state_dict = load_state_dict(model_file, variant=variant, dduf_entries=dduf_entries) model._convert_deprecated_attention_blocks(state_dict) model, missing_keys, unexpected_keys, mismatched_keys, error_msgs = cls._load_pretrained_model( diff --git a/src/diffusers/pipelines/pipeline_loading_utils.py b/src/diffusers/pipelines/pipeline_loading_utils.py index b555dac6f793..934edef5b86e 100644 --- a/src/diffusers/pipelines/pipeline_loading_utils.py +++ b/src/diffusers/pipelines/pipeline_loading_utils.py @@ -627,7 +627,7 @@ def load_sub_model( low_cpu_mem_usage: bool, cached_folder: Union[str, os.PathLike], use_safetensors: bool, - dduf_reader, + dduf_entries, ): """Helper method to load the module `name` from `library_name` and `class_name`""" @@ -722,8 +722,8 @@ def load_sub_model( loading_kwargs["low_cpu_mem_usage"] = False # check if the module is in a subdirectory - if dduf_reader: - loading_kwargs["dduf_reader"] = dduf_reader + 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) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index f9ea990fa502..41d72fa46806 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -50,10 +50,10 @@ CONFIG_NAME, DEPRECATED_REVISION_ARGS, BaseOutput, - DDUFReader, PushToHubMixin, is_accelerate_available, is_accelerate_version, + is_huggingface_hub_version, is_torch_npu_available, is_torch_version, is_transformers_version, @@ -820,14 +820,23 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P ) logger.warning(warn_msg) - dduf_reader = None + dduf_entries = None if dduf_file: - zip_file_path = os.path.join(cached_folder, dduf_file) - dduf_reader = DDUFReader(zip_file_path) + if not is_huggingface_hub_version(">", "0.26.3"): + (">=", "0.17.0.dev0") + raise RuntimeError( + "In order to load a dduf file, you need to install huggingface_hub>0.26.3" + "You can install it with the following: `pip install --upgrade huggingface_hub" + ) + + from huggingface_hub import read_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_reader=dduf_reader) + config_dict = cls.load_config(cached_folder, dduf_entries=dduf_entries) # pop out "_ignore_files" as it is only needed for download config_dict.pop("_ignore_files", None) @@ -984,7 +993,7 @@ def load_module(name, value): low_cpu_mem_usage=low_cpu_mem_usage, cached_folder=cached_folder, use_safetensors=use_safetensors, - dduf_reader=dduf_reader, + dduf_entries=dduf_entries, ) logger.info( f"Loaded {name} as {class_name} from `{name}` subfolder of {pretrained_model_name_or_path}." diff --git a/src/diffusers/utils/__init__.py b/src/diffusers/utils/__init__.py index 6493b1b09287..076f90185cf3 100644 --- a/src/diffusers/utils/__init__.py +++ b/src/diffusers/utils/__init__.py @@ -68,6 +68,7 @@ is_flax_available, is_ftfy_available, is_google_colab, + is_huggingface_hub_version, is_inflect_available, is_invisible_watermark_available, is_k_diffusion_available, diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index 99447808483c..492622aa60b4 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -291,19 +291,20 @@ def _get_model_file( user_agent: Optional[Union[Dict, str]] = None, revision: Optional[str] = None, commit_hash: Optional[str] = None, - dduf_reader=None, + dduf_entries=None, ): pretrained_model_name_or_path = str(pretrained_model_name_or_path) - if dduf_reader: - if dduf_reader.has_file(os.path.join(pretrained_model_name_or_path, weights_name)): + if dduf_entries: + if os.path.join(pretrained_model_name_or_path, weights_name) in dduf_entries: return os.path.join(pretrained_model_name_or_path, weights_name) - elif subfolder is not None and os.path.isfile( - os.path.join(pretrained_model_name_or_path, subfolder, weights_name) + elif ( + subfolder is not None + and os.path.join(pretrained_model_name_or_path, subfolder, weights_name) in dduf_entries ): return os.path.join(pretrained_model_name_or_path, weights_name) else: - raise EnvironmentError(f"Error no file named {weights_name} found in archive {dduf_reader.files}.") + 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 elif os.path.isdir(pretrained_model_name_or_path): diff --git a/src/diffusers/utils/import_utils.py b/src/diffusers/utils/import_utils.py index f1323bf00ea4..d97d58037750 100644 --- a/src/diffusers/utils/import_utils.py +++ b/src/diffusers/utils/import_utils.py @@ -317,6 +317,15 @@ _timm_available = False +_huggingface_hub_available = importlib.util.find_spec("huggingface_hub") is not None +if _huggingface_hub_available: + try: + _huggingface_hub_version = importlib_metadata.version("huggingface_hub") + logger.info(f"huggingface_hub version {_huggingface_hub_version} available.") + except importlib_metadata.PackageNotFoundError: + _huggingface_hub_available = False + + def is_timm_available(): return _timm_available @@ -774,6 +783,21 @@ def is_k_diffusion_version(operation: str, version: str): return compare_versions(parse(_k_diffusion_version), operation, version) +def is_huggingface_hub_version(operation: str, version: str): + """ + Compares the current huggingface_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 _huggingface_hub_available: + return False + return compare_versions(parse(_huggingface_hub_version), operation, version) + + def get_objects_from_module(module): """ Returns a dict of object names and values in a module, while skipping private/internal objects From 81bd0974e378b0d94c506b07d0406c553d832ebb Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Fri, 6 Dec 2024 12:50:24 +0000 Subject: [PATCH 11/65] fix log --- src/diffusers/pipelines/pipeline_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index 41d72fa46806..a14ab6e31320 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -825,7 +825,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P if not is_huggingface_hub_version(">", "0.26.3"): (">=", "0.17.0.dev0") raise RuntimeError( - "In order to load a dduf file, you need to install huggingface_hub>0.26.3" + "In order to load a dduf file, you need to install huggingface_hub>0.26.3. " "You can install it with the following: `pip install --upgrade huggingface_hub" ) From d0a861ccacb337ffb199d4b458c464e10bb8a5f1 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Sun, 8 Dec 2024 18:11:01 +0530 Subject: [PATCH 12/65] add a basic test --- tests/pipelines/test_pipelines_common.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/pipelines/test_pipelines_common.py b/tests/pipelines/test_pipelines_common.py index 4d2b534c9a28..c218c2ab7e12 100644 --- a/tests/pipelines/test_pipelines_common.py +++ b/tests/pipelines/test_pipelines_common.py @@ -1902,6 +1902,30 @@ def test_StableDiffusionMixin_component(self): ) ) + # @pytest.mark.xfail(condition=not os.getenv("RUN_DDUF_TEST", False), strict=True) + # Should consider guarding the test with proper transformers and huggingface_hub versions. + def test_save_load_dduf(self): + 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).images + + with tempfile.TemporaryDirectory() as tmpdir: + dduf_filename = f"{pipe.__class__.__name__.lower()}.dduf" + pipe.save_pretrained(tmpdir, dduf_file=dduf_filename) + 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).images + + assert np.allclose(pipeline_out, loaded_pipeline_out) + @is_staging_test class PipelinePushToHubTester(unittest.TestCase): From 1ec988f3a4e29bdd90aec7301e86746a079eabb9 Mon Sep 17 00:00:00 2001 From: Marc Sun <57196510+SunMarc@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:09:57 +0100 Subject: [PATCH 13/65] Update src/diffusers/configuration_utils.py Co-authored-by: Sayak Paul --- src/diffusers/configuration_utils.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 0d1e5e62e7ca..d7a385ba3123 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -360,19 +360,13 @@ def load_config( "`ConfigMixin`. Please make sure to define `config_name` in a class inheriting from `ConfigMixin`" ) # Custom path for now - if dduf_entries: if subfolder is not None: - if os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name) in dduf_entries: - config_file = os.path.join(subfolder, cls.config_name) - else: - raise ValueError( - f"We did not manage to find the file {os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name)} in the dduf file. We only have the following files {dduf_entries.keys()}" - ) - elif os.path.join(pretrained_model_name_or_path, cls.config_name) in dduf_entries: - config_file = os.path.join(pretrained_model_name_or_path, cls.config_name) + config_file = if os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name) in dduf_entries else: + config_file = if os.path.join(pretrained_model_name_or_path, cls.config_name) + if config_filepath not in dduf_entries: raise ValueError( - f"We did not manage to find the file {os.path.join(pretrained_model_name_or_path, cls.config_name)} in the dduf file. We only have the following files {dduf_entries.keys()}" + f"We did not manage to find the file {os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name)} in the dduf file. We only have the following files {dduf_entries.keys()}" ) elif os.path.isfile(pretrained_model_name_or_path): config_file = pretrained_model_name_or_path From 52177120933860f0dd8e8363a1691d7498615b33 Mon Sep 17 00:00:00 2001 From: Marc Sun <57196510+SunMarc@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:10:12 +0100 Subject: [PATCH 14/65] Update src/diffusers/pipelines/pipeline_utils.py Co-authored-by: Sayak Paul --- src/diffusers/pipelines/pipeline_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index a14ab6e31320..f0770778f38a 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -825,8 +825,8 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P if not is_huggingface_hub_version(">", "0.26.3"): (">=", "0.17.0.dev0") raise RuntimeError( - "In order to load a dduf file, you need to install huggingface_hub>0.26.3. " - "You can install it with the following: `pip install --upgrade huggingface_hub" + "To load a dduf file, you need to install huggingface_hub>0.26.3. " + "You can install it with the following: `pip install --upgrade huggingface_hub`." ) from huggingface_hub import read_dduf_file From 6922226a257df4ce417d2acba831bf71bc03f3c3 Mon Sep 17 00:00:00 2001 From: Marc Sun <57196510+SunMarc@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:44:33 +0100 Subject: [PATCH 15/65] Update src/diffusers/pipelines/pipeline_utils.py Co-authored-by: Sayak Paul From 3b0d84d10338e69396586622b3b2f300ad2dfcb6 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Mon, 9 Dec 2024 15:47:44 +0000 Subject: [PATCH 16/65] fix --- src/diffusers/configuration_utils.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index d7a385ba3123..5a454f8216ba 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -360,13 +360,14 @@ def load_config( "`ConfigMixin`. Please make sure to define `config_name` in a class inheriting from `ConfigMixin`" ) # Custom path for now + if dduf_entries: if subfolder is not None: - config_file = if os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name) in dduf_entries + config_file = os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name) else: - config_file = if os.path.join(pretrained_model_name_or_path, cls.config_name) - if config_filepath not in dduf_entries: + config_file = os.path.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 {os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name)} in the dduf file. We only have the following files {dduf_entries.keys()}" + f"We did not manage to find the file {config_file} in the dduf file. We only have the following files {dduf_entries.keys()}" ) elif os.path.isfile(pretrained_model_name_or_path): config_file = pretrained_model_name_or_path From 04ecf0e544227b05db7fca30eeb1be5b51ceeafc Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Mon, 9 Dec 2024 18:15:08 +0000 Subject: [PATCH 17/65] fix variant --- src/diffusers/models/model_loading_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index 852ad85f9b92..c5867d855019 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -358,6 +358,7 @@ def _fetch_index_file_legacy( revision, user_agent, commit_hash, + dduf_entries=None, ): if is_local: index_file = Path( @@ -398,6 +399,7 @@ def _fetch_index_file_legacy( subfolder=None, user_agent=user_agent, commit_hash=commit_hash, + dduf_entries=dduf_entries, ) 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()`." From 9fff68ab4962a47cc6b60688f75ff558d7eda707 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Tue, 10 Dec 2024 10:48:27 +0000 Subject: [PATCH 18/65] change saving logic --- src/diffusers/pipelines/pipeline_utils.py | 56 ++++++++--------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index f0770778f38a..637920880ea2 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -239,6 +239,13 @@ class implements both a save and loading method. The pipeline is easily reloaded repo_id = kwargs.pop("repo_id", save_directory.split(os.path.sep)[-1]) repo_id = create_repo(repo_id, exist_ok=True, private=private, token=token).repo_id + if dduf_file: + if not is_huggingface_hub_version(">", "0.26.3"): + raise RuntimeError( + "In order to load a dduf file, you need to install huggingface_hub>0.26.3. " + "You can install it with the following: `pip install --upgrade huggingface_hub" + ) + expected_modules, optional_kwargs = self._get_signature_keys(self) def is_saveable_module(name, value): @@ -307,53 +314,26 @@ def is_saveable_module(name, value): if dduf_file: import shutil - import zipfile - - def zipdir(dir_to_archive, zipf): - """Archive a directory""" - for root, dirs, files in os.walk(dir_to_archive): - for file in files: - file_path = os.path.join(root, file) - arcname = os.path.join( - os.path.basename(dir_to_archive), os.path.relpath(file_path, start=dir_to_archive) - ) - zipf.write(file_path, arcname=arcname) - dduf_file_path = os.path.join(save_directory, dduf_file) + from huggingface_hub import export_folder_as_dduf - if os.path.isdir(dduf_file_path): - logger.warning( - f"Removing the existing folder {dduf_file_path} so that we can save the DDUF archive." - ) - shutil.rmtree(dduf_file_path) - if ( - os.path.exists(dduf_file_path) - and os.path.isfile(dduf_file_path) - and zipfile.is_zipfile(dduf_file_path) - ): - # Open in append mode if the file exists - mode = "a" - else: - # Open in write mode to create it if it doesn't exist - mode = "w" - with zipfile.ZipFile(dduf_file_path, mode=mode, compression=zipfile.ZIP_STORED) as zipf: - dir_to_archive = os.path.join(save_directory, pipeline_component_name) - if os.path.isdir(dir_to_archive): - zipdir(dir_to_archive, zipf) - shutil.rmtree(dir_to_archive) + dduf_file_path = os.path.join(save_directory, dduf_file) + dir_to_archive = os.path.join(save_directory, pipeline_component_name) + if os.path.isdir(dir_to_archive): + export_folder_as_dduf(dduf_file_path, dir_to_archive, append=True, retain_base_folder=True) + shutil.rmtree(dir_to_archive) # finally save the config self.save_config(save_directory) # Takes care of including the "model_index.json" inside the ZIP. - # TODO: Include a DDUF a metadata file. if dduf_file: - import zipfile + from huggingface_hub import add_entry_to_dduf - with zipfile.ZipFile(dduf_file_path, mode="a", compression=zipfile.ZIP_STORED) as zipf: - config_path = os.path.join(save_directory, self.config_name) - zipf.write(config_path, arcname=os.path.basename(config_path)) - os.remove(config_path) + config_path = os.path.join(save_directory, self.config_name) + # add config.json to the root of the dduf_file_path + add_entry_to_dduf(dduf_file_path, self.config_name, content=config_path) + os.remove(config_path) if push_to_hub: # Create a new empty model card and eventually tag it From ed6c727dab66a46736724e45f55a83497b1e9eb0 Mon Sep 17 00:00:00 2001 From: Lucain Date: Wed, 11 Dec 2024 11:50:47 +0100 Subject: [PATCH 19/65] DDUF - Load transformers components manually (#10171) * update hfh version * Load transformers components manually * load encoder from_pretrained with state_dict --- setup.py | 2 +- src/diffusers/dependency_versions_table.py | 2 +- .../pipelines/pipeline_loading_utils.py | 25 ++++- src/diffusers/pipelines/pipeline_utils.py | 14 +-- .../pipelines/transformers_loading_utils.py | 97 +++++++++++++++++++ 5 files changed, 122 insertions(+), 18 deletions(-) create mode 100644 src/diffusers/pipelines/transformers_loading_utils.py diff --git a/setup.py b/setup.py index 90ffd3495391..dd3decd8624b 100644 --- a/setup.py +++ b/setup.py @@ -101,7 +101,7 @@ "filelock", "flax>=0.4.1", "hf-doc-builder>=0.3.0", - "huggingface-hub>=0.23.2", + "huggingface-hub>=0.27.0", "requests-mock==1.10.0", "importlib_metadata", "invisible-watermark>=0.2.0", diff --git a/src/diffusers/dependency_versions_table.py b/src/diffusers/dependency_versions_table.py index 9e7bf242eca7..7e2ec1c51459 100644 --- a/src/diffusers/dependency_versions_table.py +++ b/src/diffusers/dependency_versions_table.py @@ -9,7 +9,7 @@ "filelock": "filelock", "flax": "flax>=0.4.1", "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", "importlib_metadata": "importlib_metadata", "invisible-watermark": "invisible-watermark>=0.2.0", diff --git a/src/diffusers/pipelines/pipeline_loading_utils.py b/src/diffusers/pipelines/pipeline_loading_utils.py index 934edef5b86e..ee7a78eb0471 100644 --- a/src/diffusers/pipelines/pipeline_loading_utils.py +++ b/src/diffusers/pipelines/pipeline_loading_utils.py @@ -12,14 +12,12 @@ # 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 importlib import os import re import warnings from pathlib import Path -from typing import Any, Dict, List, Optional, Union +from typing import Any, Callable, Dict, List, Optional, Union import torch from huggingface_hub import ModelCard, model_info @@ -41,11 +39,12 @@ logging, ) 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(): 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 SAFE_WEIGHTS_NAME as TRANSFORMERS_SAFE_WEIGHTS_NAME from transformers.utils import WEIGHTS_NAME as TRANSFORMERS_WEIGHTS_NAME @@ -664,7 +663,7 @@ def load_sub_model( 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 diffusers_module = importlib.import_module(__name__.split(".")[0]) @@ -750,6 +749,22 @@ def load_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 (won't use `from_pretrained`). + """ + 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): # import it here to avoid circular import diffusers_module = importlib.import_module(__name__.split(".")[0]) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index 637920880ea2..e47e983e6664 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -32,6 +32,7 @@ create_repo, hf_hub_download, model_info, + read_dduf_file, snapshot_download, ) from huggingface_hub.utils import OfflineModeIsEnabled, validate_hf_hub_args @@ -53,7 +54,6 @@ PushToHubMixin, is_accelerate_available, is_accelerate_version, - is_huggingface_hub_version, is_torch_npu_available, is_torch_version, is_transformers_version, @@ -657,7 +657,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P Load weights from a specified variant filename such as `"fp16"` or `"ema"`. This is ignored when loading `from_flax`. dduf_file(`str`, *optional*): - Load weights from the specified dduf file + Load weights from the specified dduf file. @@ -802,15 +802,6 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P dduf_entries = None if dduf_file: - if not is_huggingface_hub_version(">", "0.26.3"): - (">=", "0.17.0.dev0") - raise RuntimeError( - "To load a dduf file, you need to install huggingface_hub>0.26.3. " - "You can install it with the following: `pip install --upgrade huggingface_hub`." - ) - - from huggingface_hub import read_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 @@ -825,6 +816,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P # We retrieve the information by matching whether variant model checkpoints exist in the subfolders. # Example: `diffusion_pytorch_model.safetensors` -> `diffusion_pytorch_model.fp16.safetensors` # with variant being `"fp16"`. + # TODO: adapt logic for DDUF files (at the moment, scans the local directory which doesn't make sense in DDUF context) model_variants = _identify_model_variants(folder=cached_folder, variant=variant, config=config_dict) if len(model_variants) == 0 and variant is not None: error_message = f"You are trying to load the model files of the `variant={variant}`, but no such modeling files are available." diff --git a/src/diffusers/pipelines/transformers_loading_utils.py b/src/diffusers/pipelines/transformers_loading_utils.py new file mode 100644 index 000000000000..e4aa331eeeeb --- /dev/null +++ b/src/diffusers/pipelines/transformers_loading_utils.py @@ -0,0 +1,97 @@ +# 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 os +import contextlib +import tempfile +from typing import TYPE_CHECKING, Dict + +from huggingface_hub import DDUFEntry + +from ..utils import is_safetensors_available, is_transformers_available + + +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] +) -> "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("/")) + with open(tmp_entry_path, "wb") as f: + with entry.as_mmap() as mm: + f.write(mm) + return cls.from_pretrained(tmp_dir, **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()})." + ) + + 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`." + ) + + with tempfile.TemporaryDirectory() as tmp_dir: + tmp_config_file = os.path.join(tmp_dir, "config.json") + with open(tmp_config_file, "w") as f: + f.write(config_file.read_text()) + + with contextlib.ExitStack() as stack: + state_dict = { + key: tensor + for entry in weight_files # loop over safetensors files + for key, tensor in safetensors.torch.load( # load tensors from mmap-ed bytes + stack.enter_context(entry.as_mmap()) # use enter_context to close the mmap when done + ).items() + } + return cls.from_pretrained(tmp_dir, state_dict=state_dict, **kwargs) From 17d50d1b9d42d5331a52052c2acc21e913a3ebb4 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Wed, 11 Dec 2024 18:27:14 +0000 Subject: [PATCH 20/65] working version with transformers and tokenizer ! --- src/diffusers/pipelines/pipeline_utils.py | 7 ---- .../pipelines/transformers_loading_utils.py | 40 ++++++++++++------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index e47e983e6664..35e04ae126ba 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -239,13 +239,6 @@ class implements both a save and loading method. The pipeline is easily reloaded repo_id = kwargs.pop("repo_id", save_directory.split(os.path.sep)[-1]) repo_id = create_repo(repo_id, exist_ok=True, private=private, token=token).repo_id - if dduf_file: - if not is_huggingface_hub_version(">", "0.26.3"): - raise RuntimeError( - "In order to load a dduf file, you need to install huggingface_hub>0.26.3. " - "You can install it with the following: `pip install --upgrade huggingface_hub" - ) - expected_modules, optional_kwargs = self._get_signature_keys(self) def is_saveable_module(name, value): diff --git a/src/diffusers/pipelines/transformers_loading_utils.py b/src/diffusers/pipelines/transformers_loading_utils.py index e4aa331eeeeb..5b810b271477 100644 --- a/src/diffusers/pipelines/transformers_loading_utils.py +++ b/src/diffusers/pipelines/transformers_loading_utils.py @@ -12,12 +12,13 @@ # 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 os 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 @@ -33,23 +34,26 @@ def load_tokenizer_from_dduf( - cls: "PreTrainedTokenizer", name: str, dduf_entries: Dict[str, DDUFEntry] + 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. + 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(tmp_dir, **kwargs) + return cls.from_pretrained(os.path.dirname(tmp_entry_path), **kwargs) def load_transformers_model_from_dduf( @@ -85,13 +89,19 @@ def load_transformers_model_from_dduf( tmp_config_file = os.path.join(tmp_dir, "config.json") with open(tmp_config_file, "w") as f: f.write(config_file.read_text()) - + # TODO: I feel like it is easier if we pass the config file directly. Otherwise, if we pass + # pretrained_model_name_or_path, we will need to do more checks in transformers. + from transformers import AutoConfig + config = AutoConfig.from_pretrained(tmp_config_file) + state_dict = {} with contextlib.ExitStack() as stack: - state_dict = { - key: tensor - for entry in weight_files # loop over safetensors files - for key, tensor in safetensors.torch.load( # load tensors from mmap-ed bytes - stack.enter_context(entry.as_mmap()) # use enter_context to close the mmap when done - ).items() - } - return cls.from_pretrained(tmp_dir, state_dict=state_dict, **kwargs) + 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, state_dict=state_dict, **kwargs + ) From 59929a5f6dc4c540d5edb7f9b7b045e46b7b2d9f Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 11:19:44 +0000 Subject: [PATCH 21/65] add generation_config case --- .../pipelines/transformers_loading_utils.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/diffusers/pipelines/transformers_loading_utils.py b/src/diffusers/pipelines/transformers_loading_utils.py index 5b810b271477..df70fcf73d88 100644 --- a/src/diffusers/pipelines/transformers_loading_utils.py +++ b/src/diffusers/pipelines/transformers_loading_utils.py @@ -70,6 +70,7 @@ def load_transformers_model_from_dduf( 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 @@ -86,13 +87,16 @@ def load_transformers_model_from_dduf( ) 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()) - # TODO: I feel like it is easier if we pass the config file directly. Otherwise, if we pass - # pretrained_model_name_or_path, we will need to do more checks in transformers. - from transformers import AutoConfig config = AutoConfig.from_pretrained(tmp_config_file) + if generation_config is not None: + tmp_generation_config_file = os.path.join(tmp_generation_config_file, "generation_config.json") + with open(tmp_generation_config_file, "w") as f: + f.write(generation_config.read_text()) + generation_config = GenerationConfig.from_pretrained(tmp_config_file) state_dict = {} with contextlib.ExitStack() as stack: for entry in tqdm(weight_files, desc="Loading state_dict"): # Loop over safetensors files @@ -103,5 +107,5 @@ def load_transformers_model_from_dduf( # Update the state dictionary with tensors state_dict.update(tensors) return cls.from_pretrained( - pretrained_model_name_or_path=None, config=config, state_dict=state_dict, **kwargs - ) + pretrained_model_name_or_path=None, config=config, generation_config=generation_config, state_dict=state_dict, **kwargs + ) From aa0d497ca30efa57507fd91cbbbd07ac9fde7270 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Thu, 12 Dec 2024 18:00:37 +0530 Subject: [PATCH 22/65] fix tests --- src/diffusers/pipelines/pipeline_utils.py | 2 +- tests/pipelines/test_pipelines_common.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index 35e04ae126ba..e5cde46928eb 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -313,7 +313,7 @@ def is_saveable_module(name, value): dduf_file_path = os.path.join(save_directory, dduf_file) dir_to_archive = os.path.join(save_directory, pipeline_component_name) if os.path.isdir(dir_to_archive): - export_folder_as_dduf(dduf_file_path, dir_to_archive, append=True, retain_base_folder=True) + export_folder_as_dduf(dduf_file_path, dir_to_archive) shutil.rmtree(dir_to_archive) # finally save the config diff --git a/tests/pipelines/test_pipelines_common.py b/tests/pipelines/test_pipelines_common.py index c218c2ab7e12..137c4ae45ae8 100644 --- a/tests/pipelines/test_pipelines_common.py +++ b/tests/pipelines/test_pipelines_common.py @@ -1905,6 +1905,8 @@ def test_StableDiffusionMixin_component(self): # @pytest.mark.xfail(condition=not os.getenv("RUN_DDUF_TEST", False), strict=True) # Should consider guarding the test with proper transformers and huggingface_hub versions. def test_save_load_dduf(self): + from huggingface_hub import export_folder_as_dduf + components = self.get_dummy_components() pipe = self.pipeline_class(**components) pipe = pipe.to(torch_device) @@ -1917,8 +1919,10 @@ def test_save_load_dduf(self): pipeline_out = pipe(**inputs).images with tempfile.TemporaryDirectory() as tmpdir: - dduf_filename = f"{pipe.__class__.__name__.lower()}.dduf" - pipe.save_pretrained(tmpdir, dduf_file=dduf_filename) + 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) + print(f"{os.listdir(tmpdir)=}") loaded_pipe = self.pipeline_class.from_pretrained(tmpdir, dduf_file=dduf_filename).to(torch_device) inputs["generator"] = torch.manual_seed(0) From 760295251f6f0c3794b3c962afd7ba1c9e62809b Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 15:43:37 +0000 Subject: [PATCH 23/65] remove saving for now --- src/diffusers/pipelines/pipeline_utils.py | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index e5cde46928eb..6136fed78394 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -193,7 +193,6 @@ def save_pretrained( variant: Optional[str] = None, max_shard_size: Optional[Union[int, str]] = None, push_to_hub: bool = False, - dduf_file: Optional[Union[str, os.PathLike]] = None, **kwargs, ): """ @@ -219,8 +218,6 @@ class implements both a save and loading method. The pipeline is easily reloaded 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 namespace). - dduf_file (`str` or `os.PathLike`, *optional*, defaults to `None`): - If specified, the weights will be saved in dduf format with the specified name. kwargs (`Dict[str, Any]`, *optional*): Additional keyword arguments passed along to the [`~utils.PushToHubMixin.push_to_hub`] method. @@ -305,29 +302,9 @@ def is_saveable_module(name, value): save_method(os.path.join(save_directory, pipeline_component_name), **save_kwargs) - if dduf_file: - import shutil - - from huggingface_hub import export_folder_as_dduf - - dduf_file_path = os.path.join(save_directory, dduf_file) - dir_to_archive = os.path.join(save_directory, pipeline_component_name) - if os.path.isdir(dir_to_archive): - export_folder_as_dduf(dduf_file_path, dir_to_archive) - shutil.rmtree(dir_to_archive) - # finally save the config self.save_config(save_directory) - # Takes care of including the "model_index.json" inside the ZIP. - if dduf_file: - from huggingface_hub import add_entry_to_dduf - - config_path = os.path.join(save_directory, self.config_name) - # add config.json to the root of the dduf_file_path - add_entry_to_dduf(dduf_file_path, self.config_name, content=config_path) - os.remove(config_path) - if push_to_hub: # Create a new empty model card and eventually tag it model_card = load_or_create_model_card(repo_id, token=token, is_pipeline=True) From 660d7c821c154c1266ce8632dbf6aee5b2264c9e Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 15:56:20 +0000 Subject: [PATCH 24/65] typing --- src/diffusers/models/model_loading_utils.py | 5 +++-- src/diffusers/pipelines/pipeline_loading_utils.py | 4 ++-- src/diffusers/utils/hub_utils.py | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index c5867d855019..6ce558a53caf 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -19,10 +19,11 @@ import os from collections import OrderedDict from pathlib import Path -from typing import List, Optional, Union +from typing import Dict, List, Optional, Union import safetensors import torch +from huggingface_hub import DDUFEntry from huggingface_hub.utils import EntryNotFoundError from ..quantizers.quantization_config import QuantizationMethod @@ -128,7 +129,7 @@ def _fetch_remapped_cls_from_config(config, old_class): return old_class -def load_state_dict(checkpoint_file: Union[str, os.PathLike], variant: Optional[str] = None, dduf_entries=None): +def load_state_dict(checkpoint_file: Union[str, os.PathLike], variant: Optional[str] = None, dduf_entries: Optional[Dict[str, DDUFEntry]]=None): """ Reads a checkpoint file, returning properly formatted errors if they arise. """ diff --git a/src/diffusers/pipelines/pipeline_loading_utils.py b/src/diffusers/pipelines/pipeline_loading_utils.py index ee7a78eb0471..42b577dc963a 100644 --- a/src/diffusers/pipelines/pipeline_loading_utils.py +++ b/src/diffusers/pipelines/pipeline_loading_utils.py @@ -20,7 +20,7 @@ from typing import Any, Callable, Dict, List, Optional, Union import torch -from huggingface_hub import ModelCard, model_info +from huggingface_hub import DDUFEntry, ModelCard, model_info from huggingface_hub.utils import validate_hf_hub_args from packaging import version @@ -626,7 +626,7 @@ def load_sub_model( low_cpu_mem_usage: bool, cached_folder: Union[str, os.PathLike], use_safetensors: bool, - dduf_entries, + dduf_entries: Optional[Dict[str, DDUFEntry]], ): """Helper method to load the module `name` from `library_name` and `class_name`""" diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index 492622aa60b4..c6efea503452 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -26,6 +26,7 @@ from uuid import uuid4 from huggingface_hub import ( + DDUFEntry, ModelCard, ModelCardData, create_repo, @@ -291,7 +292,7 @@ def _get_model_file( user_agent: Optional[Union[Dict, str]] = None, revision: Optional[str] = None, commit_hash: Optional[str] = None, - dduf_entries=None, + dduf_entries: Optional[Dict[str, DDUFEntry]]=None, ): pretrained_model_name_or_path = str(pretrained_model_name_or_path) From 8358ef6e7c775df58b2c8f57486dd56c5a11e639 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 16:04:03 +0000 Subject: [PATCH 25/65] need next version from transformers --- src/diffusers/pipelines/pipeline_loading_utils.py | 2 +- src/diffusers/pipelines/transformers_loading_utils.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_loading_utils.py b/src/diffusers/pipelines/pipeline_loading_utils.py index 42b577dc963a..9bdb76b4e964 100644 --- a/src/diffusers/pipelines/pipeline_loading_utils.py +++ b/src/diffusers/pipelines/pipeline_loading_utils.py @@ -755,7 +755,7 @@ def _get_load_method(class_obj: object, load_method_name: str, is_dduf: bool) -> 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 (won't use `from_pretrained`). + method that we need to use. """ if is_dduf: if issubclass(class_obj, PreTrainedTokenizerBase): diff --git a/src/diffusers/pipelines/transformers_loading_utils.py b/src/diffusers/pipelines/transformers_loading_utils.py index df70fcf73d88..099b1b7640df 100644 --- a/src/diffusers/pipelines/transformers_loading_utils.py +++ b/src/diffusers/pipelines/transformers_loading_utils.py @@ -20,7 +20,7 @@ from huggingface_hub import DDUFEntry from tqdm import tqdm -from ..utils import is_safetensors_available, is_transformers_available +from ..utils import is_safetensors_available, is_transformers_version if TYPE_CHECKING: @@ -85,6 +85,11 @@ def load_transformers_model_from_dduf( 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 From 4e7d15a1e162b8ceeff6fec92669bb597eecb16c Mon Sep 17 00:00:00 2001 From: Marc Sun <57196510+SunMarc@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:14:25 +0100 Subject: [PATCH 26/65] Update src/diffusers/configuration_utils.py Co-authored-by: Lucain --- src/diffusers/configuration_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 5a454f8216ba..ebcca03c308d 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -560,7 +560,7 @@ def extract_init_dict(cls, config_dict, **kwargs): return init_dict, unused_kwargs, hidden_config_dict @classmethod - def _dict_from_json_file(cls, json_file: Union[str, os.PathLike], dduf_entries=None): + def _dict_from_json_file(cls, json_file: Union[str, os.PathLike], dduf_entries: Optional[Dict[str, DDUFEntry]] = None): if dduf_entries: text = dduf_entries[json_file].read_text() else: From cc75db3bf428168830aced62e4051e2a0f02cd40 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 16:15:08 +0000 Subject: [PATCH 27/65] check path corectly --- src/diffusers/configuration_utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 5a454f8216ba..eb0711d76702 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -361,10 +361,11 @@ def load_config( ) # Custom path for now if dduf_entries: + # paths inside a DDUF file must always be "/" if subfolder is not None: - config_file = os.path.join(pretrained_model_name_or_path, subfolder, cls.config_name) + config_file = "/".join([pretrained_model_name_or_path, subfolder, cls.config_name]) else: - config_file = os.path.join(pretrained_model_name_or_path, cls.config_name) + config_file = "/".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()}" From 1e5ebf54c47b34a661d89ca1c55f676a99970b08 Mon Sep 17 00:00:00 2001 From: Marc Sun <57196510+SunMarc@users.noreply.github.com> Date: Thu, 12 Dec 2024 17:25:30 +0100 Subject: [PATCH 28/65] Apply suggestions from code review Co-authored-by: Lucain --- src/diffusers/models/model_loading_utils.py | 4 +- src/diffusers/models/modeling_utils.py | 2 +- src/diffusers/pipelines/pipeline_utils.py | 56 +++++++++++---------- src/diffusers/utils/__init__.py | 2 - src/diffusers/utils/import_utils.py | 24 --------- 5 files changed, 32 insertions(+), 56 deletions(-) diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index 6ce558a53caf..e2959dc64f8e 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -281,7 +281,7 @@ def _fetch_index_file( revision, user_agent, commit_hash, - dduf_entries=None, + dduf_entries: Optional[Dict[str, DDUFEntry]] = None, ): if is_local: index_file = Path( @@ -359,7 +359,7 @@ def _fetch_index_file_legacy( revision, user_agent, commit_hash, - dduf_entries=None, + dduf_entries: Optional[Dict[str, DDUFEntry]] = None, ): if is_local: index_file = Path( diff --git a/src/diffusers/models/modeling_utils.py b/src/diffusers/models/modeling_utils.py index 52172a16cdd1..3c6d39ed0dcc 100644 --- a/src/diffusers/models/modeling_utils.py +++ b/src/diffusers/models/modeling_utils.py @@ -586,7 +586,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P variant = kwargs.pop("variant", None) use_safetensors = kwargs.pop("use_safetensors", None) quantization_config = kwargs.pop("quantization_config", None) - dduf_entries = kwargs.pop("dduf_entries", None) + dduf_entries: Optional[Dict[str, DDUFEntry]] = kwargs.pop("dduf_entries", None) allow_pickle = False if use_safetensors is None: diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index 6136fed78394..f0bfa38e3ae4 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -1291,7 +1291,7 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: use_onnx = kwargs.pop("use_onnx", None) load_connected_pipeline = kwargs.pop("load_connected_pipeline", False) trust_remote_code = kwargs.pop("trust_remote_code", False) - dduf_file = kwargs.pop("dduf_file", None) + dduf_file: Optional[Dict[str, DDUFEntry]] = kwargs.pop("dduf_file", None) allow_pickle = False if use_safetensors is None: @@ -1310,11 +1310,11 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: local_files_only = True model_info_call_error = e # save error to reraise it if model is not cached locally - if dduf_file is not None and not local_files_only: - dduf_available = False - for sibling in info.siblings: - dduf_available = dduf_file in sibling.rfilename - if not dduf_available: + 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}.") if not local_files_only and not dduf_file: @@ -1478,27 +1478,29 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: ) # retrieve pipeline class from local file - if not dduf_file: - 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 - - diffusers_module = importlib.import_module(__name__.split(".")[0]) - pipeline_class = getattr(diffusers_module, cls_name, None) if isinstance(cls_name, str) else None - - if pipeline_class is not None and pipeline_class._load_connected_pipes: - modelcard = ModelCard.load(os.path.join(cached_folder, "README.md")) - connected_pipes = sum([getattr(modelcard.data, k, []) for k in CONNECTED_PIPES_KEYS], []) - for connected_pipe_repo_id in connected_pipes: - download_kwargs = { - "cache_dir": cache_dir, - "force_download": force_download, - "proxies": proxies, - "local_files_only": local_files_only, - "token": token, - "variant": variant, - "use_safetensors": use_safetensors, - } - DiffusionPipeline.download(connected_pipe_repo_id, **download_kwargs) + if dduf_file: + return cached_folder + + 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 + + diffusers_module = importlib.import_module(__name__.split(".")[0]) + pipeline_class = getattr(diffusers_module, cls_name, None) if isinstance(cls_name, str) else None + + if pipeline_class is not None and pipeline_class._load_connected_pipes: + modelcard = ModelCard.load(os.path.join(cached_folder, "README.md")) + connected_pipes = sum([getattr(modelcard.data, k, []) for k in CONNECTED_PIPES_KEYS], []) + for connected_pipe_repo_id in connected_pipes: + download_kwargs = { + "cache_dir": cache_dir, + "force_download": force_download, + "proxies": proxies, + "local_files_only": local_files_only, + "token": token, + "variant": variant, + "use_safetensors": use_safetensors, + } + DiffusionPipeline.download(connected_pipe_repo_id, **download_kwargs) return cached_folder diff --git a/src/diffusers/utils/__init__.py b/src/diffusers/utils/__init__.py index df4fbe27063e..f91cee8113f2 100644 --- a/src/diffusers/utils/__init__.py +++ b/src/diffusers/utils/__init__.py @@ -35,7 +35,6 @@ WEIGHTS_INDEX_NAME, WEIGHTS_NAME, ) -from .dduf import DDUFReader from .deprecation_utils import deprecate from .doc_utils import replace_example_docstring from .dynamic_modules_utils import get_class_from_dynamic_module @@ -68,7 +67,6 @@ is_flax_available, is_ftfy_available, is_google_colab, - is_huggingface_hub_version, is_inflect_available, is_invisible_watermark_available, is_k_diffusion_available, diff --git a/src/diffusers/utils/import_utils.py b/src/diffusers/utils/import_utils.py index 3ea89050061a..e3b7655737a8 100644 --- a/src/diffusers/utils/import_utils.py +++ b/src/diffusers/utils/import_utils.py @@ -317,15 +317,6 @@ _timm_available = False -_huggingface_hub_available = importlib.util.find_spec("huggingface_hub") is not None -if _huggingface_hub_available: - try: - _huggingface_hub_version = importlib_metadata.version("huggingface_hub") - logger.info(f"huggingface_hub version {_huggingface_hub_version} available.") - except importlib_metadata.PackageNotFoundError: - _huggingface_hub_available = False - - def is_timm_available(): return _timm_available @@ -798,21 +789,6 @@ def is_k_diffusion_version(operation: str, version: str): return compare_versions(parse(_k_diffusion_version), operation, version) -def is_huggingface_hub_version(operation: str, version: str): - """ - Compares the current huggingface_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 _huggingface_hub_available: - return False - return compare_versions(parse(_huggingface_hub_version), operation, version) - - def get_objects_from_module(module): """ Returns a dict of object names and values in a module, while skipping private/internal objects From 53e100b56e7de62554af56980ca5406b7164c787 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 16:26:54 +0000 Subject: [PATCH 29/65] udapte --- src/diffusers/pipelines/pipeline_utils.py | 1 - src/diffusers/utils/dduf.py | 41 ----------------------- src/diffusers/utils/hub_utils.py | 8 ++--- 3 files changed, 4 insertions(+), 46 deletions(-) delete mode 100644 src/diffusers/utils/dduf.py diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index 6136fed78394..28ac07ec22a8 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -786,7 +786,6 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P # We retrieve the information by matching whether variant model checkpoints exist in the subfolders. # Example: `diffusion_pytorch_model.safetensors` -> `diffusion_pytorch_model.fp16.safetensors` # with variant being `"fp16"`. - # TODO: adapt logic for DDUF files (at the moment, scans the local directory which doesn't make sense in DDUF context) model_variants = _identify_model_variants(folder=cached_folder, variant=variant, config=config_dict) if len(model_variants) == 0 and variant is not None: error_message = f"You are trying to load the model files of the `variant={variant}`, but no such modeling files are available." diff --git a/src/diffusers/utils/dduf.py b/src/diffusers/utils/dduf.py deleted file mode 100644 index ae6c5e91a1a2..000000000000 --- a/src/diffusers/utils/dduf.py +++ /dev/null @@ -1,41 +0,0 @@ -import zipfile - - -class DDUFReader: - def __init__(self, dduf_file): - self.dduf_file = dduf_file - self.files = [] - self.post_init() - - def post_init(self): - """ - Check that the DDUF file is valid - """ - if not zipfile.is_zipfile(self.dduf_file): - raise ValueError(f"The file '{self.dduf_file}' is not a valid ZIP archive.") - - try: - with zipfile.ZipFile(self.dduf_file, "r") as zf: - # Check integrity and store file list - zf.testzip() # Returns None if no corrupt files are found - self.files = zf.namelist() - except zipfile.BadZipFile: - raise ValueError(f"The file '{self.dduf_file}' is not a valid ZIP archive.") - except Exception as e: - raise RuntimeError(f"An error occurred while validating the ZIP file: {e}") - - def has_file(self, file): - return file in self.files - - def read_file(self, file_name, encoding=None): - """ - Reads the content of a specific file in the ZIP archive without extracting. - """ - if file_name not in self.files: - raise ValueError(f"{file_name} is not in the list of files {self.files}") - with zipfile.ZipFile(self.dduf_file, "r") as zf: - with zf.open(file_name) as file: - file = file.read() - if encoding is not None: - file = file.decode(encoding) - return file diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index c6efea503452..5814dae6a2ab 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -297,13 +297,13 @@ def _get_model_file( pretrained_model_name_or_path = str(pretrained_model_name_or_path) if dduf_entries: - if os.path.join(pretrained_model_name_or_path, weights_name) in dduf_entries: - return os.path.join(pretrained_model_name_or_path, weights_name) + if "/".join([pretrained_model_name_or_path, weights_name]) in dduf_entries: + return "/".join([pretrained_model_name_or_path, weights_name]) elif ( subfolder is not None - and os.path.join(pretrained_model_name_or_path, subfolder, weights_name) in dduf_entries + and "/".join([pretrained_model_name_or_path, subfolder, weights_name]) in dduf_entries ): - return os.path.join(pretrained_model_name_or_path, weights_name) + return "/".join([pretrained_model_name_or_path, subfolder, weights_name]) 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): From 1eb25dcd28e2ccb46d087f85430c4b187260d972 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 16:34:36 +0000 Subject: [PATCH 30/65] typing --- src/diffusers/configuration_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 2479a6787cde..605b059b6870 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -24,10 +24,10 @@ import re from collections import OrderedDict from pathlib import Path -from typing import Any, Dict, Tuple, Union +from typing import Any, Dict, Tuple, Union, Optional, Dict import numpy as np -from huggingface_hub import create_repo, hf_hub_download +from huggingface_hub import create_repo, hf_hub_download, DDUFEntry from huggingface_hub.utils import ( EntryNotFoundError, RepositoryNotFoundError, @@ -347,7 +347,7 @@ def load_config( _ = kwargs.pop("mirror", None) subfolder = kwargs.pop("subfolder", None) user_agent = kwargs.pop("user_agent", {}) - dduf_entries = kwargs.pop("dduf_entries", None) + dduf_entries: Optional[Dict[str, DDUFEntry]] = kwargs.pop("dduf_entries", None) user_agent = {**user_agent, "file_type": "config"} user_agent = http_user_agent(user_agent) From 0cb1b9819961afc5a90344f36513de994ba0a096 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 16:41:04 +0000 Subject: [PATCH 31/65] remove check for subfolder --- src/diffusers/configuration_utils.py | 7 +++---- src/diffusers/utils/hub_utils.py | 7 ++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 605b059b6870..c37680777c21 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -361,11 +361,10 @@ def load_config( ) # Custom path for now if dduf_entries: - # paths inside a DDUF file must always be "/" if subfolder is not None: - config_file = "/".join([pretrained_model_name_or_path, subfolder, cls.config_name]) - else: - config_file = "/".join([pretrained_model_name_or_path, cls.config_name]) + raise ValueError("DDUF file only allow for 1 level of directory. Please check the DDUF structure") + # paths inside a DDUF file must always be "/" + config_file = "/".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()}" diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index 5814dae6a2ab..447f6b24add3 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -297,13 +297,10 @@ def _get_model_file( pretrained_model_name_or_path = str(pretrained_model_name_or_path) if dduf_entries: + if subfolder is not None: + raise ValueError("DDUF file only allow for 1 level of directory. Please check the DDUF structure") if "/".join([pretrained_model_name_or_path, weights_name]) in dduf_entries: return "/".join([pretrained_model_name_or_path, weights_name]) - elif ( - subfolder is not None - and "/".join([pretrained_model_name_or_path, subfolder, weights_name]) in dduf_entries - ): - return "/".join([pretrained_model_name_or_path, subfolder, weights_name]) 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): From 5ec3951fbbee647b081cfbcfaab08f3dc4c0213f Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 16:48:04 +0000 Subject: [PATCH 32/65] quality --- setup.py | 2 +- src/diffusers/configuration_utils.py | 8 +++++--- src/diffusers/dependency_versions_table.py | 2 +- src/diffusers/models/model_loading_utils.py | 6 +++++- src/diffusers/models/modeling_utils.py | 2 +- src/diffusers/pipelines/pipeline_utils.py | 5 +++-- .../pipelines/transformers_loading_utils.py | 15 ++++++++++----- src/diffusers/utils/hub_utils.py | 2 +- 8 files changed, 27 insertions(+), 15 deletions(-) diff --git a/setup.py b/setup.py index dd3decd8624b..9a417c2f756b 100644 --- a/setup.py +++ b/setup.py @@ -101,7 +101,7 @@ "filelock", "flax>=0.4.1", "hf-doc-builder>=0.3.0", - "huggingface-hub>=0.27.0", + "huggingface-hub>=0.26.0", "requests-mock==1.10.0", "importlib_metadata", "invisible-watermark>=0.2.0", diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index c37680777c21..ae12c0420656 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -24,10 +24,10 @@ import re from collections import OrderedDict from pathlib import Path -from typing import Any, Dict, Tuple, Union, Optional, Dict +from typing import Any, Dict, Optional, Tuple, Union import numpy as np -from huggingface_hub import create_repo, hf_hub_download, DDUFEntry +from huggingface_hub import DDUFEntry, create_repo, hf_hub_download from huggingface_hub.utils import ( EntryNotFoundError, RepositoryNotFoundError, @@ -560,7 +560,9 @@ def extract_init_dict(cls, config_dict, **kwargs): return init_dict, unused_kwargs, hidden_config_dict @classmethod - def _dict_from_json_file(cls, json_file: Union[str, os.PathLike], dduf_entries: Optional[Dict[str, DDUFEntry]] = None): + def _dict_from_json_file( + cls, json_file: Union[str, os.PathLike], dduf_entries: Optional[Dict[str, DDUFEntry]] = None + ): if dduf_entries: text = dduf_entries[json_file].read_text() else: diff --git a/src/diffusers/dependency_versions_table.py b/src/diffusers/dependency_versions_table.py index 7e2ec1c51459..72ef0ef156bb 100644 --- a/src/diffusers/dependency_versions_table.py +++ b/src/diffusers/dependency_versions_table.py @@ -9,7 +9,7 @@ "filelock": "filelock", "flax": "flax>=0.4.1", "hf-doc-builder": "hf-doc-builder>=0.3.0", - "huggingface-hub": "huggingface-hub>=0.27.0", + "huggingface-hub": "huggingface-hub>=0.26.0", "requests-mock": "requests-mock==1.10.0", "importlib_metadata": "importlib_metadata", "invisible-watermark": "invisible-watermark>=0.2.0", diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index e2959dc64f8e..c155496632d3 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -129,7 +129,11 @@ def _fetch_remapped_cls_from_config(config, old_class): return old_class -def load_state_dict(checkpoint_file: Union[str, os.PathLike], variant: Optional[str] = None, dduf_entries: Optional[Dict[str, DDUFEntry]]=None): +def load_state_dict( + checkpoint_file: Union[str, os.PathLike], + variant: Optional[str] = None, + dduf_entries: Optional[Dict[str, DDUFEntry]] = None, +): """ Reads a checkpoint file, returning properly formatted errors if they arise. """ diff --git a/src/diffusers/models/modeling_utils.py b/src/diffusers/models/modeling_utils.py index 3c6d39ed0dcc..42c70338bd75 100644 --- a/src/diffusers/models/modeling_utils.py +++ b/src/diffusers/models/modeling_utils.py @@ -27,7 +27,7 @@ import safetensors import torch -from huggingface_hub import create_repo, split_torch_state_dict_into_shards +from huggingface_hub import DDUFEntry, Dict, create_repo, split_torch_state_dict_into_shards from huggingface_hub.utils import validate_hf_hub_args from torch import Tensor, nn diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index be97970f197c..4c2561cd5359 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -28,6 +28,7 @@ import requests import torch from huggingface_hub import ( + DDUFEntry, ModelCard, create_repo, hf_hub_download, @@ -1313,8 +1314,8 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: 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}.") + ): + raise ValueError(f"Requested {dduf_file} file is not available in {pretrained_model_name}.") if not local_files_only and not dduf_file: filenames = {sibling.rfilename for sibling in info.siblings} diff --git a/src/diffusers/pipelines/transformers_loading_utils.py b/src/diffusers/pipelines/transformers_loading_utils.py index 099b1b7640df..50fdddae1d40 100644 --- a/src/diffusers/pipelines/transformers_loading_utils.py +++ b/src/diffusers/pipelines/transformers_loading_utils.py @@ -20,7 +20,7 @@ from huggingface_hub import DDUFEntry from tqdm import tqdm -from ..utils import is_safetensors_available, is_transformers_version +from ..utils import is_safetensors_available, is_transformers_available, is_transformers_version if TYPE_CHECKING: @@ -93,15 +93,16 @@ def load_transformers_model_from_dduf( 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_generation_config_file, "generation_config.json") + 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_config_file) + 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 @@ -112,5 +113,9 @@ def load_transformers_model_from_dduf( # 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 - ) + pretrained_model_name_or_path=None, + config=config, + generation_config=generation_config, + state_dict=state_dict, + **kwargs, + ) diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index 447f6b24add3..f750f688ad7c 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -292,7 +292,7 @@ def _get_model_file( user_agent: Optional[Union[Dict, str]] = None, revision: Optional[str] = None, commit_hash: Optional[str] = None, - dduf_entries: Optional[Dict[str, DDUFEntry]]=None, + dduf_entries: Optional[Dict[str, DDUFEntry]] = None, ): pretrained_model_name_or_path = str(pretrained_model_name_or_path) From 1785eaa84c4e862a8cf39766829f3253e3aac5f7 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 16:49:22 +0000 Subject: [PATCH 33/65] revert setup changes --- setup.py | 2 +- src/diffusers/dependency_versions_table.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 9a417c2f756b..dd3decd8624b 100644 --- a/setup.py +++ b/setup.py @@ -101,7 +101,7 @@ "filelock", "flax>=0.4.1", "hf-doc-builder>=0.3.0", - "huggingface-hub>=0.26.0", + "huggingface-hub>=0.27.0", "requests-mock==1.10.0", "importlib_metadata", "invisible-watermark>=0.2.0", diff --git a/src/diffusers/dependency_versions_table.py b/src/diffusers/dependency_versions_table.py index 72ef0ef156bb..7e2ec1c51459 100644 --- a/src/diffusers/dependency_versions_table.py +++ b/src/diffusers/dependency_versions_table.py @@ -9,7 +9,7 @@ "filelock": "filelock", "flax": "flax>=0.4.1", "hf-doc-builder": "hf-doc-builder>=0.3.0", - "huggingface-hub": "huggingface-hub>=0.26.0", + "huggingface-hub": "huggingface-hub>=0.27.0", "requests-mock": "requests-mock==1.10.0", "importlib_metadata": "importlib_metadata", "invisible-watermark": "invisible-watermark>=0.2.0", From 7486016d0b08200ad95d5bbb871cb859ad8a702f Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 16:58:58 +0000 Subject: [PATCH 34/65] oups --- src/diffusers/models/modeling_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diffusers/models/modeling_utils.py b/src/diffusers/models/modeling_utils.py index 42c70338bd75..858f97c492eb 100644 --- a/src/diffusers/models/modeling_utils.py +++ b/src/diffusers/models/modeling_utils.py @@ -23,11 +23,11 @@ from collections import OrderedDict from functools import partial, wraps 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 torch -from huggingface_hub import DDUFEntry, Dict, 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 torch import Tensor, nn From 73e81a55c367aad903a3c95c0b0f08977c15c1ed Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Thu, 12 Dec 2024 17:08:05 +0000 Subject: [PATCH 35/65] more readable condition --- src/diffusers/configuration_utils.py | 2 +- src/diffusers/utils/hub_utils.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index ae12c0420656..4661c9315451 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -364,7 +364,7 @@ def load_config( if subfolder is not None: raise ValueError("DDUF file only allow for 1 level of directory. Please check the DDUF structure") # paths inside a DDUF file must always be "/" - config_file = "/".join([pretrained_model_name_or_path, cls.config_name]) + 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()}" diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index f750f688ad7c..1dc153f0860f 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -299,8 +299,9 @@ def _get_model_file( if dduf_entries: if subfolder is not None: raise ValueError("DDUF file only allow for 1 level of directory. Please check the DDUF structure") - if "/".join([pretrained_model_name_or_path, weights_name]) in dduf_entries: - return "/".join([pretrained_model_name_or_path, weights_name]) + 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): From ea0126d7914a2247a7536795d25cfa49a2b42e42 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Fri, 13 Dec 2024 10:50:48 +0530 Subject: [PATCH 36/65] add loading from the hub test --- src/diffusers/configuration_utils.py | 6 +++++- src/diffusers/utils/hub_utils.py | 6 +++++- src/diffusers/utils/testing_utils.py | 12 ++++++++++++ tests/pipelines/test_pipelines.py | 21 +++++++++++++++++++++ tests/pipelines/test_pipelines_common.py | 7 ++++--- 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 4661c9315451..32477a9b8a77 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -364,7 +364,11 @@ def load_config( if subfolder is not None: raise ValueError("DDUF file only allow for 1 level of directory. Please check the DDUF structure") # 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]) + 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()}" diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index 1dc153f0860f..4afc43dc7373 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -299,7 +299,11 @@ def _get_model_file( if dduf_entries: if subfolder is not None: raise ValueError("DDUF file only allow for 1 level of directory. Please check the DDUF structure") - model_file = weights_name if pretrained_model_name_or_path == "" else "/".join([pretrained_model_name_or_path, weights_name]) + 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: diff --git a/src/diffusers/utils/testing_utils.py b/src/diffusers/utils/testing_utils.py index b3e381f7d3fb..62c799026836 100644 --- a/src/diffusers/utils/testing_utils.py +++ b/src/diffusers/utils/testing_utils.py @@ -476,6 +476,18 @@ def decorator(test_case): 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 deprecate_after_peft_backend(test_case): """ Decorator marking a test that will be skipped after PEFT backend diff --git a/tests/pipelines/test_pipelines.py b/tests/pipelines/test_pipelines.py index 43b01c40f5bb..c039b325e6df 100644 --- a/tests/pipelines/test_pipelines.py +++ b/tests/pipelines/test_pipelines.py @@ -75,9 +75,11 @@ nightly, require_compel, require_flax, + require_hf_hub_version_greater, require_onnxruntime, require_torch_2, require_torch_gpu, + require_transformers_version_greater, run_test_in_subprocess, slow, torch_device, @@ -1802,6 +1804,25 @@ def test_pipe_same_device_id_offload(self): sd.maybe_free_model_hooks() assert sd._offload_gpu_id == 5 + @require_hf_hub_version_greater("0.26.5") + @require_transformers_version_greater("4.47.0") + @parameterized.expand([torch.float32, torch.float16]) + 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)) + @slow @require_torch_gpu diff --git a/tests/pipelines/test_pipelines_common.py b/tests/pipelines/test_pipelines_common.py index 137c4ae45ae8..08f64cb561db 100644 --- a/tests/pipelines/test_pipelines_common.py +++ b/tests/pipelines/test_pipelines_common.py @@ -43,7 +43,9 @@ CaptureLogger, require_accelerate_version_greater, require_accelerator, + require_hf_hub_version_greater, require_torch, + require_transformers_version_greater, skip_mps, torch_device, ) @@ -1902,8 +1904,8 @@ def test_StableDiffusionMixin_component(self): ) ) - # @pytest.mark.xfail(condition=not os.getenv("RUN_DDUF_TEST", False), strict=True) - # Should consider guarding the test with proper transformers and huggingface_hub versions. + @require_hf_hub_version_greater("0.26.5") + @require_transformers_version_greater("4.47.0") def test_save_load_dduf(self): from huggingface_hub import export_folder_as_dduf @@ -1922,7 +1924,6 @@ def test_save_load_dduf(self): 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) - print(f"{os.listdir(tmpdir)=}") loaded_pipe = self.pipeline_class.from_pretrained(tmpdir, dduf_file=dduf_filename).to(torch_device) inputs["generator"] = torch.manual_seed(0) From 3ebdcff04aceccc9a7d63bf2db923e0cbb6f6c9d Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Fri, 13 Dec 2024 11:18:16 +0530 Subject: [PATCH 37/65] add basic docs. --- .../en/using-diffusers/other-formats.md | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/docs/source/en/using-diffusers/other-formats.md b/docs/source/en/using-diffusers/other-formats.md index 24ac9ced84ce..c8de95f5ac7e 100644 --- a/docs/source/en/using-diffusers/other-formats.md +++ b/docs/source/en/using-diffusers/other-formats.md @@ -240,6 +240,50 @@ 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. 2. Easier to manage (download and share) a single file. +### DDUF + + + +DDUF is an experimental file format and APIs related to it can change in the future. + + + +DDUF, aka (**D**DUF’s **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 tries to provide a sweet spot between our multi-folder format and widely popular single-file format. To learn more about it, please check out the documentation [here](https://huggingface.co/docs/hub/dduf). + +Below we show, how to load a DDUF checkpoint in a [`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 obtain `.dduf` checkpoint, we rely on `huggingface_hub`'s `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) + + + +We support packaging and loading quantized checkpoints in the DDUF format as long as they respect the multi-folder structure. + + + ## 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. From 021abf0332e01b24f79693f85cab81fcc29da0b0 Mon Sep 17 00:00:00 2001 From: Marc Sun <57196510+SunMarc@users.noreply.github.com> Date: Fri, 13 Dec 2024 14:26:46 +0100 Subject: [PATCH 38/65] Apply suggestions from code review Co-authored-by: Lucain --- docs/source/en/using-diffusers/other-formats.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/en/using-diffusers/other-formats.md b/docs/source/en/using-diffusers/other-formats.md index c8de95f5ac7e..08e749805c44 100644 --- a/docs/source/en/using-diffusers/other-formats.md +++ b/docs/source/en/using-diffusers/other-formats.md @@ -265,7 +265,7 @@ image = pipe( image.save("cat.png") ``` -To obtain `.dduf` checkpoint, we rely on `huggingface_hub`'s `export_folder_as_dduf()` utility, which takes care of all the necessary file-level validations: +To save a pipeline as a `.dduf` checkpoint, we rely on `huggingface_hub`'s `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 af2ca07b1d22425892454a87d1e553b7a6439a64 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Fri, 13 Dec 2024 14:20:21 +0000 Subject: [PATCH 39/65] add example --- src/diffusers/configuration_utils.py | 11 +++++++++-- src/diffusers/utils/hub_utils.py | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 4661c9315451..55cd47537cea 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -362,9 +362,16 @@ def load_config( # Custom path for now if dduf_entries: if subfolder is not None: - raise ValueError("DDUF file only allow for 1 level of directory. Please check the DDUF structure") + 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" + ) # 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]) + 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()}" diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index 1dc153f0860f..30f075933d15 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -298,8 +298,15 @@ def _get_model_file( if dduf_entries: if subfolder is not None: - raise ValueError("DDUF file only allow for 1 level of directory. Please check the DDUF structure") - model_file = weights_name if pretrained_model_name_or_path == "" else "/".join([pretrained_model_name_or_path, weights_name]) + 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: From c9734ab140b9f0cb45471f21eac94be6a3824c9c Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Fri, 13 Dec 2024 14:21:26 +0000 Subject: [PATCH 40/65] add --- src/diffusers/utils/hub_utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index 4afc43dc7373..30f075933d15 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -298,7 +298,10 @@ def _get_model_file( if dduf_entries: if subfolder is not None: - raise ValueError("DDUF file only allow for 1 level of directory. Please check the DDUF structure") + 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 == "" From 27ebf9e037e328203af5ec922370aa02c44346e5 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Fri, 13 Dec 2024 14:25:45 +0000 Subject: [PATCH 41/65] make functions private --- src/diffusers/pipelines/pipeline_loading_utils.py | 6 +++--- src/diffusers/pipelines/transformers_loading_utils.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_loading_utils.py b/src/diffusers/pipelines/pipeline_loading_utils.py index 9bdb76b4e964..0c4a4bd8945a 100644 --- a/src/diffusers/pipelines/pipeline_loading_utils.py +++ b/src/diffusers/pipelines/pipeline_loading_utils.py @@ -39,7 +39,7 @@ logging, ) from ..utils.torch_utils import is_compiled_module -from .transformers_loading_utils import load_tokenizer_from_dduf, load_transformers_model_from_dduf +from .transformers_loading_utils import _load_tokenizer_from_dduf, _load_transformers_model_from_dduf if is_transformers_available(): @@ -759,9 +759,9 @@ def _get_load_method(class_obj: object, load_method_name: str, is_dduf: bool) -> """ if is_dduf: if issubclass(class_obj, PreTrainedTokenizerBase): - return lambda *args, **kwargs: load_tokenizer_from_dduf(class_obj, *args, **kwargs) + 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 lambda *args, **kwargs: _load_transformers_model_from_dduf(class_obj, *args, **kwargs) return getattr(class_obj, load_method_name) diff --git a/src/diffusers/pipelines/transformers_loading_utils.py b/src/diffusers/pipelines/transformers_loading_utils.py index 50fdddae1d40..f080adb23deb 100644 --- a/src/diffusers/pipelines/transformers_loading_utils.py +++ b/src/diffusers/pipelines/transformers_loading_utils.py @@ -33,7 +33,7 @@ import safetensors.torch -def load_tokenizer_from_dduf( +def _load_tokenizer_from_dduf( cls: "PreTrainedTokenizer", name: str, dduf_entries: Dict[str, DDUFEntry], **kwargs ) -> "PreTrainedTokenizer": """ @@ -56,7 +56,7 @@ def load_tokenizer_from_dduf( return cls.from_pretrained(os.path.dirname(tmp_entry_path), **kwargs) -def load_transformers_model_from_dduf( +def _load_transformers_model_from_dduf( cls: "PreTrainedModel", name: str, dduf_entries: Dict[str, DDUFEntry], **kwargs ) -> "PreTrainedModel": """ From d5dbb5c01f33efcc7fa8b3350fe3d1778218ef10 Mon Sep 17 00:00:00 2001 From: Marc Sun <57196510+SunMarc@users.noreply.github.com> Date: Fri, 13 Dec 2024 17:40:29 +0100 Subject: [PATCH 42/65] Apply suggestions from code review Co-authored-by: Steven Liu <59462357+stevhliu@users.noreply.github.com> --- .../en/using-diffusers/other-formats.md | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/docs/source/en/using-diffusers/other-formats.md b/docs/source/en/using-diffusers/other-formats.md index 08e749805c44..eed4ebdeaac7 100644 --- a/docs/source/en/using-diffusers/other-formats.md +++ b/docs/source/en/using-diffusers/other-formats.md @@ -242,15 +242,14 @@ Benefits of using a single-file layout include: ### DDUF - - -DDUF is an experimental file format and APIs related to it can change in the future. +> [!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. -DDUF, aka (**D**DUF’s **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 tries to provide a sweet spot between our multi-folder format and widely popular single-file format. To learn more about it, please check out the documentation [here](https://huggingface.co/docs/hub/dduf). +Learn more details about DDUF on the Hugging Face Hub [documentation](https://huggingface.co/docs/hub/dduf). -Below we show, how to load a DDUF checkpoint in a [`DiffusionPipeline`]: +Pass a checkpoint to the `dduf_file` parameter to load it in [`DiffusionPipeline`]. ```py from diffusers import DiffusionPipeline @@ -265,7 +264,7 @@ image = pipe( image.save("cat.png") ``` -To save a pipeline as a `.dduf` checkpoint, we rely on `huggingface_hub`'s `export_folder_as_dduf()` utility, which takes care of all the necessary file-level validations: +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 @@ -278,11 +277,8 @@ save_folder = "flux-dev" pipe.save_pretrained("flux-dev") export_folder_as_dduf("flux-dev.dduf", folder_path=save_folder) - - -We support packaging and loading quantized checkpoints in the DDUF format as long as they respect the multi-folder structure. - - +> [!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 From e9b74293cb60c9a590396f0449fccc6cbf586f2f Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Wed, 18 Dec 2024 14:38:27 +0530 Subject: [PATCH 43/65] minor. --- docs/source/en/using-diffusers/other-formats.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/en/using-diffusers/other-formats.md b/docs/source/en/using-diffusers/other-formats.md index eed4ebdeaac7..e662e3940a38 100644 --- a/docs/source/en/using-diffusers/other-formats.md +++ b/docs/source/en/using-diffusers/other-formats.md @@ -243,7 +243,7 @@ Benefits of using a single-file layout include: ### DDUF > [!WARNING] ->DDUF is an experimental file format and APIs related to it can change in the future. +> 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. From b8b699a654e90e9f6957953e9ab47bb08e1c63af Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Wed, 18 Dec 2024 15:41:56 +0530 Subject: [PATCH 44/65] fixes --- src/diffusers/pipelines/pipeline_utils.py | 10 +++++++ src/diffusers/utils/testing_utils.py | 2 ++ tests/pipelines/allegro/test_allegro.py | 33 +++++++++++++++++++++++ tests/pipelines/test_pipelines.py | 2 +- tests/pipelines/test_pipelines_common.py | 6 ++--- 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index 4c2561cd5359..785d551b6c6d 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -780,6 +780,16 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P config_dict = cls.load_config(cached_folder, dduf_entries=dduf_entries) + if dduf_file: + 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.2"): + raise ValueError("Please upgrade your `transformers` installation to use DDUF.") + # pop out "_ignore_files" as it is only needed for download config_dict.pop("_ignore_files", None) diff --git a/src/diffusers/utils/testing_utils.py b/src/diffusers/utils/testing_utils.py index 0cc0973fb9f7..16aa265f588d 100644 --- a/src/diffusers/utils/testing_utils.py +++ b/src/diffusers/utils/testing_utils.py @@ -487,6 +487,8 @@ def decorator(test_case): 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 decorator(test_case): diff --git a/tests/pipelines/allegro/test_allegro.py b/tests/pipelines/allegro/test_allegro.py index d09fc0488378..6ca96b19b8ab 100644 --- a/tests/pipelines/allegro/test_allegro.py +++ b/tests/pipelines/allegro/test_allegro.py @@ -14,6 +14,8 @@ import gc import inspect +import os +import tempfile import unittest import numpy as np @@ -24,7 +26,9 @@ from diffusers.utils.testing_utils import ( enable_full_determinism, numpy_cosine_similarity_distance, + require_hf_hub_version_greater, require_torch_gpu, + require_transformers_version_greater, slow, torch_device, ) @@ -297,6 +301,35 @@ def test_vae_tiling(self, expected_diff_max: float = 0.2): "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 @require_torch_gpu diff --git a/tests/pipelines/test_pipelines.py b/tests/pipelines/test_pipelines.py index c039b325e6df..3533ab97cb71 100644 --- a/tests/pipelines/test_pipelines.py +++ b/tests/pipelines/test_pipelines.py @@ -1805,7 +1805,7 @@ def test_pipe_same_device_id_offload(self): assert sd._offload_gpu_id == 5 @require_hf_hub_version_greater("0.26.5") - @require_transformers_version_greater("4.47.0") + @require_transformers_version_greater("4.47.1") @parameterized.expand([torch.float32, torch.float16]) def test_load_dduf_from_hub(self, dtype): with tempfile.TemporaryDirectory() as tmpdir: diff --git a/tests/pipelines/test_pipelines_common.py b/tests/pipelines/test_pipelines_common.py index 08f64cb561db..5758fdc156f0 100644 --- a/tests/pipelines/test_pipelines_common.py +++ b/tests/pipelines/test_pipelines_common.py @@ -1905,7 +1905,7 @@ def test_StableDiffusionMixin_component(self): ) @require_hf_hub_version_greater("0.26.5") - @require_transformers_version_greater("4.47.0") + @require_transformers_version_greater("4.47.1") def test_save_load_dduf(self): from huggingface_hub import export_folder_as_dduf @@ -1918,7 +1918,7 @@ def test_save_load_dduf(self): inputs.pop("generator") inputs["generator"] = torch.manual_seed(0) - pipeline_out = pipe(**inputs).images + pipeline_out = pipe(**inputs)[0].cpu() with tempfile.TemporaryDirectory() as tmpdir: dduf_filename = os.path.join(tmpdir, f"{pipe.__class__.__name__.lower()}.dduf") @@ -1927,7 +1927,7 @@ def test_save_load_dduf(self): 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).images + loaded_pipeline_out = loaded_pipe(**inputs)[0].cpu() assert np.allclose(pipeline_out, loaded_pipeline_out) From 0e54b068381159a5b520ea254a98a7af305ec519 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Wed, 18 Dec 2024 16:38:45 +0530 Subject: [PATCH 45/65] fix --- src/diffusers/pipelines/pipeline_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index 785d551b6c6d..e26c2b6ddc48 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -787,8 +787,8 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P has_transformers_component = config_dict[k][0] == "transformers" if has_transformers_component: break - if has_transformers_component and not is_transformers_version(">", "4.47.2"): - raise ValueError("Please upgrade your `transformers` installation to use DDUF.") + 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.") # pop out "_ignore_files" as it is only needed for download config_dict.pop("_ignore_files", None) From a026055dcf1c13327ebd852fd94915252cef284d Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Wed, 18 Dec 2024 17:06:06 +0530 Subject: [PATCH 46/65] change the precdence of parameterized. --- tests/pipelines/test_pipelines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pipelines/test_pipelines.py b/tests/pipelines/test_pipelines.py index 3533ab97cb71..2de6f9ed7aee 100644 --- a/tests/pipelines/test_pipelines.py +++ b/tests/pipelines/test_pipelines.py @@ -1804,9 +1804,9 @@ def test_pipe_same_device_id_offload(self): sd.maybe_free_model_hooks() 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") - @parameterized.expand([torch.float32, torch.float16]) def test_load_dduf_from_hub(self, dtype): with tempfile.TemporaryDirectory() as tmpdir: pipe = DiffusionPipeline.from_pretrained( From 6a163c7d3e5d095ed7d2fedd137184e23b8e3da0 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Mon, 30 Dec 2024 19:48:19 +0530 Subject: [PATCH 47/65] error out when custom pipeline is passed with dduf_file. --- src/diffusers/pipelines/pipeline_utils.py | 8 +++++++- tests/pipelines/test_pipelines.py | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index ecec93c0b73f..c38722684102 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -728,6 +728,9 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P " dispatching. Please make sure to set `low_cpu_mem_usage=True`." ) + if dduf_file and custom_pipeline: + raise NotImplementedError("Custom pipelines are not supported with DDUF at the moment.") + # 1. Download the checkpoints and configs # use snapshot download here to get it working from from_pretrained if not os.path.isdir(pretrained_model_name_or_path): @@ -1325,6 +1328,9 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: trust_remote_code = kwargs.pop("trust_remote_code", False) dduf_file: Optional[Dict[str, DDUFEntry]] = kwargs.pop("dduf_file", None) + if dduf_file and custom_pipeline: + raise NotImplementedError("Custom pipelines are not supported with DDUF at the moment.") + allow_pickle = False if use_safetensors is None: use_safetensors = True @@ -1488,7 +1494,7 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: return snapshot_folder user_agent = {"pipeline_class": cls.__name__} - if not dduf_file and custom_pipeline is not None and not custom_pipeline.endswith(".py"): + if custom_pipeline is not None and not custom_pipeline.endswith(".py"): user_agent["custom_pipeline"] = custom_pipeline # download all allow_patterns - ignore_patterns diff --git a/tests/pipelines/test_pipelines.py b/tests/pipelines/test_pipelines.py index 8e4171be16d3..1b4d0c3741b5 100644 --- a/tests/pipelines/test_pipelines.py +++ b/tests/pipelines/test_pipelines.py @@ -983,6 +983,12 @@ def test_download_ignore_files(self): assert not any(f in ["vae/diffusion_pytorch_model.bin", "text_encoder/config.json"] for f in files) 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_get_pipeline_class_from_flax(self): flax_config = {"_class_name": "FlaxStableDiffusionPipeline"} config = {"_class_name": "StableDiffusionPipeline"} @@ -1823,6 +1829,14 @@ def test_load_dduf_from_hub(self, dtype): 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_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_wrong_model(self): tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip") with self.assertRaises(ValueError) as error_context: From 67b617e4f0e47c7eac5ad484433ddb2cadcb3f3f Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Tue, 31 Dec 2024 10:14:23 +0530 Subject: [PATCH 48/65] updates --- src/diffusers/configuration_utils.py | 37 ++++++---- .../pipelines/pipeline_loading_utils.py | 74 ++++++++++++++++++- src/diffusers/pipelines/pipeline_utils.py | 52 ++++++------- src/diffusers/utils/__init__.py | 1 + src/diffusers/utils/import_utils.py | 22 ++++++ .../kandinsky/test_kandinsky_combined.py | 12 +++ .../kandinsky2_2/test_kandinsky_combined.py | 12 +++ .../test_stable_diffusion_adapter.py | 4 + .../test_stable_diffusion_xl_adapter.py | 4 + tests/pipelines/test_pipelines.py | 47 ++++++++++-- tests/pipelines/test_pipelines_common.py | 21 ++++-- 11 files changed, 227 insertions(+), 59 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 55cd47537cea..4629e5efc765 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -361,21 +361,7 @@ def load_config( ) # Custom path for now 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" - ) - # 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()}" - ) + config_file = cls._get_config_file_from_dduf(pretrained_model_name_or_path, subfolder, dduf_entries) elif os.path.isfile(pretrained_model_name_or_path): config_file = pretrained_model_name_or_path elif os.path.isdir(pretrained_model_name_or_path): @@ -636,6 +622,27 @@ def to_json_file(self, json_file_path: Union[str, os.PathLike]): with open(json_file_path, "w", encoding="utf-8") as writer: writer.write(self.to_json_string()) + @classmethod + def _get_config_file_from_dduf( + cls, pretrained_model_name_or_path: str, subfolder: str, dduf_entries: Dict[str, DDUFEntry] + ): + 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" + ) + # 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): r""" diff --git a/src/diffusers/pipelines/pipeline_loading_utils.py b/src/diffusers/pipelines/pipeline_loading_utils.py index 0c4a4bd8945a..12cdc2a10248 100644 --- a/src/diffusers/pipelines/pipeline_loading_utils.py +++ b/src/diffusers/pipelines/pipeline_loading_utils.py @@ -19,10 +19,12 @@ from pathlib import Path from typing import Any, Callable, Dict, List, Optional, Union +import requests import torch -from huggingface_hub import DDUFEntry, ModelCard, model_info -from huggingface_hub.utils import validate_hf_hub_args +from huggingface_hub import DDUFEntry, ModelCard, model_info, snapshot_download +from huggingface_hub.utils import OfflineModeIsEnabled, validate_hf_hub_args from packaging import version +from requests.exceptions import HTTPError from .. import __version__ from ..utils import ( @@ -36,6 +38,7 @@ is_accelerate_available, is_peft_available, is_transformers_available, + is_transformers_version, logging, ) from ..utils.torch_utils import is_compiled_module @@ -987,3 +990,70 @@ def _get_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.") diff --git a/src/diffusers/pipelines/pipeline_utils.py b/src/diffusers/pipelines/pipeline_utils.py index c38722684102..bb1f06203e8c 100644 --- a/src/diffusers/pipelines/pipeline_utils.py +++ b/src/diffusers/pipelines/pipeline_utils.py @@ -74,6 +74,7 @@ CONNECTED_PIPES_KEYS, CUSTOM_PIPELINE_FILE_NAME, LOADABLE_CLASSES, + _download_dduf_file, _fetch_class_library_tuple, _get_custom_components_and_folders, _get_custom_pipeline_class, @@ -81,6 +82,7 @@ _get_ignore_patterns, _get_pipeline_class, _identify_model_variants, + _maybe_raise_error_for_incorrect_transformers, _maybe_raise_warning_for_inpainting, _resolve_custom_pipeline_and_cls, _unwrap_model, @@ -728,8 +730,11 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P " dispatching. Please make sure to set `low_cpu_mem_usage=True`." ) - if dduf_file and custom_pipeline: - raise NotImplementedError("Custom pipelines are not supported with DDUF at the moment.") + 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 # use snapshot download here to get it working from from_pretrained @@ -785,14 +790,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P config_dict = cls.load_config(cached_folder, dduf_entries=dduf_entries) if dduf_file: - 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.") + _maybe_raise_error_for_incorrect_transformers(config_dict) # pop out "_ignore_files" as it is only needed for download config_dict.pop("_ignore_files", None) @@ -1328,8 +1326,21 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: trust_remote_code = kwargs.pop("trust_remote_code", False) dduf_file: Optional[Dict[str, DDUFEntry]] = kwargs.pop("dduf_file", None) - if dduf_file and custom_pipeline: - raise NotImplementedError("Custom pipelines are not supported with DDUF at the moment.") + 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 if use_safetensors is None: @@ -1348,14 +1359,7 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: 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}.") - - if not local_files_only and not dduf_file: + if not local_files_only: filenames = {sibling.rfilename for sibling in info.siblings} if variant is not None and _check_legacy_sharding_variant_format(filenames=filenames, variant=variant): warn_msg = ( @@ -1498,10 +1502,6 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: user_agent["custom_pipeline"] = custom_pipeline # download all allow_patterns - ignore_patterns - # also allow downloading the dduf_file - if dduf_file is not None: - allow_patterns = [dduf_file] - ignore_patterns = [] try: cached_folder = snapshot_download( pretrained_model_name, @@ -1515,10 +1515,6 @@ def download(cls, pretrained_model_name, **kwargs) -> Union[str, os.PathLike]: user_agent=user_agent, ) - # retrieve pipeline class from local file - if dduf_file: - return cached_folder - 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 diff --git a/src/diffusers/utils/__init__.py b/src/diffusers/utils/__init__.py index f8de48ecfc78..5a171d078ce3 100644 --- a/src/diffusers/utils/__init__.py +++ b/src/diffusers/utils/__init__.py @@ -70,6 +70,7 @@ is_gguf_available, is_gguf_version, is_google_colab, + is_hf_hub_version, is_inflect_available, is_invisible_watermark_available, is_k_diffusion_available, diff --git a/src/diffusers/utils/import_utils.py b/src/diffusers/utils/import_utils.py index 3014efebc82e..2c684adb8e56 100644 --- a/src/diffusers/utils/import_utils.py +++ b/src/diffusers/utils/import_utils.py @@ -115,6 +115,13 @@ except importlib_metadata.PackageNotFoundError: _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 {_transformers_version}") +except importlib_metadata.PackageNotFoundError: + _hf_hub_available = False + _inflect_available = importlib.util.find_spec("inflect") is not None try: @@ -767,6 +774,21 @@ def is_transformers_version(operation: str, version: str): 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): """ Compares the current Accelerate version to a given reference with an operation. diff --git a/tests/pipelines/kandinsky/test_kandinsky_combined.py b/tests/pipelines/kandinsky/test_kandinsky_combined.py index 607a47e08e58..22716be2b9da 100644 --- a/tests/pipelines/kandinsky/test_kandinsky_combined.py +++ b/tests/pipelines/kandinsky/test_kandinsky_combined.py @@ -139,6 +139,10 @@ def test_float16_inference(self): def test_dict_tuple_outputs_equivalent(self): super().test_dict_tuple_outputs_equivalent(expected_max_difference=5e-4) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class KandinskyPipelineImg2ImgCombinedFastTests(PipelineTesterMixin, unittest.TestCase): pipeline_class = KandinskyImg2ImgCombinedPipeline @@ -248,6 +252,10 @@ def test_dict_tuple_outputs_equivalent(self): def test_save_load_optional_components(self): super().test_save_load_optional_components(expected_max_difference=5e-4) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class KandinskyPipelineInpaintCombinedFastTests(PipelineTesterMixin, unittest.TestCase): pipeline_class = KandinskyInpaintCombinedPipeline @@ -363,3 +371,7 @@ def test_save_load_optional_components(self): def test_save_load_local(self): super().test_save_load_local(expected_max_difference=5e-3) + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/kandinsky2_2/test_kandinsky_combined.py b/tests/pipelines/kandinsky2_2/test_kandinsky_combined.py index dbba0831397b..4fda67f95e7d 100644 --- a/tests/pipelines/kandinsky2_2/test_kandinsky_combined.py +++ b/tests/pipelines/kandinsky2_2/test_kandinsky_combined.py @@ -159,6 +159,10 @@ def test_callback_inputs(self): def test_callback_cfg(self): pass + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class KandinskyV22PipelineImg2ImgCombinedFastTests(PipelineTesterMixin, unittest.TestCase): pipeline_class = KandinskyV22Img2ImgCombinedPipeline @@ -281,6 +285,10 @@ def test_callback_inputs(self): def test_callback_cfg(self): pass + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class KandinskyV22PipelineInpaintCombinedFastTests(PipelineTesterMixin, unittest.TestCase): pipeline_class = KandinskyV22InpaintCombinedPipeline @@ -404,3 +412,7 @@ def test_callback_inputs(self): def test_callback_cfg(self): pass + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/stable_diffusion_adapter/test_stable_diffusion_adapter.py b/tests/pipelines/stable_diffusion_adapter/test_stable_diffusion_adapter.py index 2a1e691e9e8f..3833a76c63f0 100644 --- a/tests/pipelines/stable_diffusion_adapter/test_stable_diffusion_adapter.py +++ b/tests/pipelines/stable_diffusion_adapter/test_stable_diffusion_adapter.py @@ -336,6 +336,10 @@ def test_adapter_lcm_custom_timesteps(self): assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class StableDiffusionFullAdapterPipelineFastTests( AdapterTests, PipelineTesterMixin, PipelineFromPipeTesterMixin, unittest.TestCase diff --git a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_adapter.py b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_adapter.py index 2091af9c0383..06b6fcc4c699 100644 --- a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_adapter.py +++ b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_adapter.py @@ -671,3 +671,7 @@ def test_adapter_sdxl_lcm_custom_timesteps(self): print(",".join(debug)) assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/test_pipelines.py b/tests/pipelines/test_pipelines.py index 1b4d0c3741b5..1d2d4e4e80f7 100644 --- a/tests/pipelines/test_pipelines.py +++ b/tests/pipelines/test_pipelines.py @@ -26,6 +26,7 @@ import numpy as np import PIL.Image +import pytest import requests_mock import safetensors.torch import torch @@ -63,6 +64,8 @@ from diffusers.utils import ( CONFIG_NAME, WEIGHTS_NAME, + is_hf_hub_version, + is_transformers_version, ) from diffusers.utils.testing_utils import ( CaptureLogger, @@ -75,11 +78,9 @@ nightly, require_compel, require_flax, - require_hf_hub_version_greater, require_onnxruntime, require_torch_2, require_torch_gpu, - require_transformers_version_greater, run_test_in_subprocess, slow, torch_device, @@ -989,6 +990,12 @@ def test_download_dduf_with_custom_pipeline_raises_error(self): "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): flax_config = {"_class_name": "FlaxStableDiffusionPipeline"} config = {"_class_name": "StableDiffusionPipeline"} @@ -1811,8 +1818,11 @@ def test_pipe_same_device_id_offload(self): 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") + @pytest.mark.xfail( + condition=is_hf_hub_version("<", "0.26.5") and is_transformers_version("<", "4.47.1"), + reason="Test requires hf hub and transformers latests", + strict=True, + ) def test_load_dduf_from_hub(self, dtype): with tempfile.TemporaryDirectory() as tmpdir: pipe = DiffusionPipeline.from_pretrained( @@ -1829,14 +1839,39 @@ def test_load_dduf_from_hub(self, dtype): 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") + @pytest.mark.xfail( + condition=is_hf_hub_version("<", "0.26.5") and is_transformers_version("<", "4.47.1"), + reason="Test requires hf hub and transformers latests", + strict=True, + ) + 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): tokenizer = CLIPTokenizer.from_pretrained("hf-internal-testing/tiny-random-clip") with self.assertRaises(ValueError) as error_context: diff --git a/tests/pipelines/test_pipelines_common.py b/tests/pipelines/test_pipelines_common.py index ed821bc0016b..a57268cac7ed 100644 --- a/tests/pipelines/test_pipelines_common.py +++ b/tests/pipelines/test_pipelines_common.py @@ -9,6 +9,7 @@ import numpy as np import PIL.Image +import pytest import torch import torch.nn as nn from huggingface_hub import ModelCard, delete_repo @@ -37,15 +38,13 @@ from diffusers.models.unets.unet_motion_model import UNetMotionModel from diffusers.pipelines.pipeline_utils import StableDiffusionMixin from diffusers.schedulers import KarrasDiffusionSchedulers -from diffusers.utils import logging +from diffusers.utils import is_hf_hub_version, is_transformers_version, logging from diffusers.utils.import_utils import is_xformers_available from diffusers.utils.testing_utils import ( CaptureLogger, require_accelerate_version_greater, require_accelerator, - require_hf_hub_version_greater, require_torch, - require_transformers_version_greater, skip_mps, torch_device, ) @@ -1993,8 +1992,11 @@ def test_StableDiffusionMixin_component(self): ) ) - @require_hf_hub_version_greater("0.26.5") - @require_transformers_version_greater("4.47.1") + @pytest.mark.xfail( + condition=is_hf_hub_version("<", "0.26.5") and is_transformers_version("<", "4.47.1"), + reason="Test requires hf hub and transformers latests", + strict=True, + ) def test_save_load_dduf(self): from huggingface_hub import export_folder_as_dduf @@ -2007,7 +2009,7 @@ def test_save_load_dduf(self): inputs.pop("generator") inputs["generator"] = torch.manual_seed(0) - pipeline_out = pipe(**inputs)[0].cpu() + pipeline_out = pipe(**inputs)[0] with tempfile.TemporaryDirectory() as tmpdir: dduf_filename = os.path.join(tmpdir, f"{pipe.__class__.__name__.lower()}.dduf") @@ -2016,9 +2018,12 @@ def test_save_load_dduf(self): 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].cpu() + loaded_pipeline_out = loaded_pipe(**inputs)[0] - assert np.allclose(pipeline_out, loaded_pipeline_out) + if isinstance(pipeline_out, np.ndarray) and isinstance(loaded_pipeline_out, np.ndarray): + assert np.allclose(pipeline_out, loaded_pipeline_out) + elif isinstance(pipeline_out, torch.Tensor) and isinstance(loaded_pipeline_out, torch.Tensor): + assert torch.allclose(pipeline_out, loaded_pipeline_out) @is_staging_test From b40272ef9c39c79b990849ddd29f6405203556f5 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Tue, 31 Dec 2024 10:16:45 +0530 Subject: [PATCH 49/65] fix --- src/diffusers/utils/import_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffusers/utils/import_utils.py b/src/diffusers/utils/import_utils.py index 2c684adb8e56..c7d002651f3a 100644 --- a/src/diffusers/utils/import_utils.py +++ b/src/diffusers/utils/import_utils.py @@ -118,7 +118,7 @@ _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 {_transformers_version}") + logger.debug(f"Successfully imported huggingface_hub version {_hf_hub_version}") except importlib_metadata.PackageNotFoundError: _hf_hub_available = False From ce237f385f7c1c10ec780bfe4176b941fa0637e4 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Tue, 31 Dec 2024 10:28:09 +0530 Subject: [PATCH 50/65] updates --- tests/pipelines/controlnet/test_controlnet.py | 12 ++++++++++++ .../controlnet/test_controlnet_blip_diffusion.py | 4 ++++ .../pipelines/controlnet/test_controlnet_img2img.py | 8 ++++++++ .../pipelines/controlnet/test_controlnet_inpaint.py | 4 ++++ .../controlnet/test_controlnet_inpaint_sdxl.py | 4 ++++ tests/pipelines/controlnet/test_controlnet_sdxl.py | 12 ++++++++++++ .../controlnet/test_controlnet_sdxl_img2img.py | 4 ++++ 7 files changed, 48 insertions(+) diff --git a/tests/pipelines/controlnet/test_controlnet.py b/tests/pipelines/controlnet/test_controlnet.py index b12655d989d4..11fec9800312 100644 --- a/tests/pipelines/controlnet/test_controlnet.py +++ b/tests/pipelines/controlnet/test_controlnet.py @@ -282,6 +282,10 @@ def test_controlnet_lcm_custom_timesteps(self): assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class StableDiffusionMultiControlNetPipelineFastTests( IPAdapterTesterMixin, PipelineTesterMixin, PipelineKarrasSchedulerTesterMixin, unittest.TestCase @@ -514,6 +518,10 @@ def test_inference_multiple_prompt_input(self): assert image.shape == (4, 64, 64, 3) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class StableDiffusionMultiControlNetOneModelPipelineFastTests( IPAdapterTesterMixin, PipelineTesterMixin, PipelineKarrasSchedulerTesterMixin, unittest.TestCase @@ -697,6 +705,10 @@ def test_save_pretrained_raise_not_implemented_exception(self): except NotImplementedError: pass + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/controlnet/test_controlnet_blip_diffusion.py b/tests/pipelines/controlnet/test_controlnet_blip_diffusion.py index 99a238caf53a..d3992569fed2 100644 --- a/tests/pipelines/controlnet/test_controlnet_blip_diffusion.py +++ b/tests/pipelines/controlnet/test_controlnet_blip_diffusion.py @@ -220,3 +220,7 @@ def test_blipdiffusion_controlnet(self): assert ( np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 ), f" expected_slice {expected_slice}, but got {image_slice.flatten()}" + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/controlnet/test_controlnet_img2img.py b/tests/pipelines/controlnet/test_controlnet_img2img.py index 7c4ae716b37d..83d979d76f1b 100644 --- a/tests/pipelines/controlnet/test_controlnet_img2img.py +++ b/tests/pipelines/controlnet/test_controlnet_img2img.py @@ -189,6 +189,10 @@ def test_xformers_attention_forwardGenerator_pass(self): def test_inference_batch_single_identical(self): self._test_inference_batch_single_identical(expected_max_diff=2e-3) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class StableDiffusionMultiControlNetPipelineFastTests( IPAdapterTesterMixin, PipelineTesterMixin, PipelineKarrasSchedulerTesterMixin, unittest.TestCase @@ -389,6 +393,10 @@ def test_save_pretrained_raise_not_implemented_exception(self): except NotImplementedError: pass + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/controlnet/test_controlnet_inpaint.py b/tests/pipelines/controlnet/test_controlnet_inpaint.py index e49106334c2e..fff973cefb96 100644 --- a/tests/pipelines/controlnet/test_controlnet_inpaint.py +++ b/tests/pipelines/controlnet/test_controlnet_inpaint.py @@ -441,6 +441,10 @@ def test_save_pretrained_raise_not_implemented_exception(self): except NotImplementedError: pass + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/controlnet/test_controlnet_inpaint_sdxl.py b/tests/pipelines/controlnet/test_controlnet_inpaint_sdxl.py index d2c63137c99e..628fc2823c53 100644 --- a/tests/pipelines/controlnet/test_controlnet_inpaint_sdxl.py +++ b/tests/pipelines/controlnet/test_controlnet_inpaint_sdxl.py @@ -352,3 +352,7 @@ def test_save_load_optional_components(self): def test_float16_inference(self): super().test_float16_inference(expected_max_diff=5e-1) + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/controlnet/test_controlnet_sdxl.py b/tests/pipelines/controlnet/test_controlnet_sdxl.py index ea7fff5537a5..0d079a08fa97 100644 --- a/tests/pipelines/controlnet/test_controlnet_sdxl.py +++ b/tests/pipelines/controlnet/test_controlnet_sdxl.py @@ -478,6 +478,10 @@ def new_step(self, *args, **kwargs): ]: assert_run_mixture(steps, split, scheduler_cls_timesteps[0], scheduler_cls_timesteps[1]) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class StableDiffusionXLMultiControlNetPipelineFastTests( PipelineTesterMixin, PipelineKarrasSchedulerTesterMixin, SDXLOptionalComponentsTesterMixin, unittest.TestCase @@ -683,6 +687,10 @@ def test_inference_batch_single_identical(self): def test_save_load_optional_components(self): return self._test_save_load_optional_components() + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class StableDiffusionXLMultiControlNetOneModelPipelineFastTests( PipelineKarrasSchedulerTesterMixin, PipelineTesterMixin, SDXLOptionalComponentsTesterMixin, unittest.TestCase @@ -887,6 +895,10 @@ def test_negative_conditions(self): self.assertTrue(np.abs(image_slice_without_neg_cond - image_slice_with_neg_cond).max() > 1e-2) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/controlnet/test_controlnet_sdxl_img2img.py b/tests/pipelines/controlnet/test_controlnet_sdxl_img2img.py index 6a5976bd0dda..9e9beae4b191 100644 --- a/tests/pipelines/controlnet/test_controlnet_sdxl_img2img.py +++ b/tests/pipelines/controlnet/test_controlnet_sdxl_img2img.py @@ -361,3 +361,7 @@ def test_stable_diffusion_xl_prompt_embeds(self): # make sure that it's equal assert np.abs(image_slice_1.flatten() - image_slice_2.flatten()).max() < 1e-4 + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass From 454b9b92815c1618a4355464e6b3f77e9f2d1eec Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Tue, 31 Dec 2024 10:46:40 +0530 Subject: [PATCH 51/65] fixes --- tests/pipelines/audioldm/test_audioldm.py | 4 ++++ tests/pipelines/deepfloyd_if/test_if.py | 3 +++ tests/pipelines/deepfloyd_if/test_if_img2img.py | 3 +++ .../deepfloyd_if/test_if_img2img_superresolution.py | 3 +++ tests/pipelines/deepfloyd_if/test_if_inpainting.py | 3 +++ .../deepfloyd_if/test_if_inpainting_superresolution.py | 3 +++ tests/pipelines/deepfloyd_if/test_if_superresolution.py | 3 +++ tests/pipelines/kolors/test_kolors.py | 4 ++++ tests/pipelines/kolors/test_kolors_img2img.py | 4 ++++ tests/pipelines/pag/test_pag_kolors.py | 4 ++++ tests/pipelines/pag/test_pag_sana.py | 4 ++++ tests/pipelines/pag/test_pag_sdxl_img2img.py | 4 ++++ tests/pipelines/pag/test_pag_sdxl_inpaint.py | 4 ++++ tests/pipelines/test_pipelines_common.py | 8 ++++---- 14 files changed, 50 insertions(+), 4 deletions(-) diff --git a/tests/pipelines/audioldm/test_audioldm.py b/tests/pipelines/audioldm/test_audioldm.py index eddab54a3c03..29668bb75c1e 100644 --- a/tests/pipelines/audioldm/test_audioldm.py +++ b/tests/pipelines/audioldm/test_audioldm.py @@ -370,6 +370,10 @@ def test_inference_batch_single_identical(self): def test_xformers_attention_forwardGenerator_pass(self): self._test_xformers_attention_forwardGenerator_pass(test_mean_pixel_difference=False) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @nightly class AudioLDMPipelineSlowTests(unittest.TestCase): diff --git a/tests/pipelines/deepfloyd_if/test_if.py b/tests/pipelines/deepfloyd_if/test_if.py index 13a05855f145..0e840e6ddc4c 100644 --- a/tests/pipelines/deepfloyd_if/test_if.py +++ b/tests/pipelines/deepfloyd_if/test_if.py @@ -89,6 +89,9 @@ def test_inference_batch_single_identical(self): def test_xformers_attention_forwardGenerator_pass(self): self._test_xformers_attention_forwardGenerator_pass(expected_max_diff=1e-3) + def test_save_load_dduf(self): + super().test_save_load_dduf(atol=1e-2, rtol=1e-2) + @slow @require_torch_gpu diff --git a/tests/pipelines/deepfloyd_if/test_if_img2img.py b/tests/pipelines/deepfloyd_if/test_if_img2img.py index 26ac42831b8b..d6063e378659 100644 --- a/tests/pipelines/deepfloyd_if/test_if_img2img.py +++ b/tests/pipelines/deepfloyd_if/test_if_img2img.py @@ -100,6 +100,9 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) + def test_save_load_dduf(self): + super().test_save_load_dduf(atol=1e-2, rtol=1e-2) + @slow @require_torch_gpu diff --git a/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py b/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py index 1d1244c96c33..401bff64d940 100644 --- a/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py +++ b/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py @@ -97,6 +97,9 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) + def test_save_load_dduf(self): + super().test_save_load_dduf(atol=1e-2, rtol=1e-2) + @slow @require_torch_gpu diff --git a/tests/pipelines/deepfloyd_if/test_if_inpainting.py b/tests/pipelines/deepfloyd_if/test_if_inpainting.py index 1c4f27403332..e99dff0c4041 100644 --- a/tests/pipelines/deepfloyd_if/test_if_inpainting.py +++ b/tests/pipelines/deepfloyd_if/test_if_inpainting.py @@ -97,6 +97,9 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) + def test_save_load_dduf(self): + super().test_save_load_dduf(atol=1e-2, rtol=1e-2) + @slow @require_torch_gpu diff --git a/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py b/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py index fc1b04aacb9b..bc7e26e4cfcd 100644 --- a/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py +++ b/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py @@ -99,6 +99,9 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) + def test_save_load_dduf(self): + super().test_save_load_dduf(atol=1e-2, rtol=1e-2) + @slow @require_torch_gpu diff --git a/tests/pipelines/deepfloyd_if/test_if_superresolution.py b/tests/pipelines/deepfloyd_if/test_if_superresolution.py index bdb9f8a76d8a..36e2c2bb6904 100644 --- a/tests/pipelines/deepfloyd_if/test_if_superresolution.py +++ b/tests/pipelines/deepfloyd_if/test_if_superresolution.py @@ -92,6 +92,9 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) + def test_save_load_dduf(self): + super().test_save_load_dduf(atol=1e-2, rtol=1e-2) + @slow @require_torch_gpu diff --git a/tests/pipelines/kolors/test_kolors.py b/tests/pipelines/kolors/test_kolors.py index de44af6d5908..52904d7b35f8 100644 --- a/tests/pipelines/kolors/test_kolors.py +++ b/tests/pipelines/kolors/test_kolors.py @@ -141,3 +141,7 @@ def test_save_load_float16(self): def test_inference_batch_single_identical(self): self._test_inference_batch_single_identical(expected_max_diff=5e-4) + + @unittest.skip("Test unsupported because of custom code.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/kolors/test_kolors_img2img.py b/tests/pipelines/kolors/test_kolors_img2img.py index 2010dbd7055a..c2a8a4bca758 100644 --- a/tests/pipelines/kolors/test_kolors_img2img.py +++ b/tests/pipelines/kolors/test_kolors_img2img.py @@ -150,3 +150,7 @@ def test_inference_batch_single_identical(self): def test_float16_inference(self): super().test_float16_inference(expected_max_diff=7e-2) + + @unittest.skip("Test unsupported because of custom code.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/pag/test_pag_kolors.py b/tests/pipelines/pag/test_pag_kolors.py index 8cfb2c3fd16a..8ee4c433e3f1 100644 --- a/tests/pipelines/pag/test_pag_kolors.py +++ b/tests/pipelines/pag/test_pag_kolors.py @@ -250,3 +250,7 @@ def test_pag_inference(self): def test_inference_batch_single_identical(self): self._test_inference_batch_single_identical(expected_max_diff=3e-3) + + @unittest.skip("Test is not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/pag/test_pag_sana.py b/tests/pipelines/pag/test_pag_sana.py index 12addabeb0a8..cfbab250081d 100644 --- a/tests/pipelines/pag/test_pag_sana.py +++ b/tests/pipelines/pag/test_pag_sana.py @@ -337,3 +337,7 @@ def test_inference_batch_single_identical(self): def test_float16_inference(self): # Requires higher tolerance as model seems very sensitive to dtype super().test_float16_inference(expected_max_diff=0.08) + + @unittest.skip("Test is not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/pag/test_pag_sdxl_img2img.py b/tests/pipelines/pag/test_pag_sdxl_img2img.py index 7e5fc5fa28b9..1a8657c793b0 100644 --- a/tests/pipelines/pag/test_pag_sdxl_img2img.py +++ b/tests/pipelines/pag/test_pag_sdxl_img2img.py @@ -265,6 +265,10 @@ def test_pag_inference(self): max_diff = np.abs(image_slice.flatten() - expected_slice).max() assert max_diff < 1e-3, f"output is different from expected, {image_slice.flatten()}" + @unittest.skip("Test is not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/pag/test_pag_sdxl_inpaint.py b/tests/pipelines/pag/test_pag_sdxl_inpaint.py index efc37abd0682..e69cb248766a 100644 --- a/tests/pipelines/pag/test_pag_sdxl_inpaint.py +++ b/tests/pipelines/pag/test_pag_sdxl_inpaint.py @@ -270,6 +270,10 @@ def test_pag_inference(self): max_diff = np.abs(image_slice.flatten() - expected_slice).max() assert max_diff < 1e-3, f"output is different from expected, {image_slice.flatten()}" + @unittest.skip("Test is not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/test_pipelines_common.py b/tests/pipelines/test_pipelines_common.py index a57268cac7ed..6ab9b118222c 100644 --- a/tests/pipelines/test_pipelines_common.py +++ b/tests/pipelines/test_pipelines_common.py @@ -1993,11 +1993,11 @@ def test_StableDiffusionMixin_component(self): ) @pytest.mark.xfail( - condition=is_hf_hub_version("<", "0.26.5") and is_transformers_version("<", "4.47.1"), + condition=is_hf_hub_version("<=", "0.26.5") and is_transformers_version("<=", "4.47.1"), reason="Test requires hf hub and transformers latests", strict=True, ) - def test_save_load_dduf(self): + def test_save_load_dduf(self, atol=1e-4, rtol=1e-4): from huggingface_hub import export_folder_as_dduf components = self.get_dummy_components() @@ -2021,9 +2021,9 @@ def test_save_load_dduf(self): 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) + 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) + assert torch.allclose(pipeline_out, loaded_pipeline_out, atol=atol, rtol=rtol) @is_staging_test From 366aa2fd060ab1fdd4584fa2106b078ed40b2ed4 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Tue, 31 Dec 2024 11:32:30 +0530 Subject: [PATCH 52/65] updates --- tests/pipelines/audioldm2/test_audioldm2.py | 4 ++++ tests/pipelines/blipdiffusion/test_blipdiffusion.py | 4 ++++ tests/pipelines/i2vgen_xl/test_i2vgenxl.py | 4 ++++ tests/pipelines/kandinsky/test_kandinsky.py | 4 ++++ tests/pipelines/kandinsky/test_kandinsky_img2img.py | 4 ++++ tests/pipelines/kandinsky/test_kandinsky_inpaint.py | 4 ++++ tests/pipelines/kandinsky/test_kandinsky_prior.py | 4 ++++ tests/pipelines/kandinsky2_2/test_kandinsky_prior.py | 4 ++++ tests/pipelines/kandinsky2_2/test_kandinsky_prior_emb2emb.py | 4 ++++ tests/pipelines/lumina/test_lumina_nextdit.py | 4 ++++ tests/pipelines/musicldm/test_musicldm.py | 4 ++++ tests/pipelines/paint_by_example/test_paint_by_example.py | 4 ++++ tests/pipelines/shap_e/test_shap_e_img2img.py | 4 ++++ .../stable_diffusion_2/test_stable_diffusion_depth.py | 4 ++++ .../test_stable_diffusion_gligen_text_image.py | 4 ++++ .../test_stable_diffusion_image_variation.py | 4 ++++ .../stable_diffusion_xl/test_stable_diffusion_xl_img2img.py | 4 ++++ .../stable_diffusion_xl/test_stable_diffusion_xl_inpaint.py | 4 ++++ tests/pipelines/stable_unclip/test_stable_unclip_img2img.py | 4 ++++ .../stable_video_diffusion/test_stable_video_diffusion.py | 4 ++++ tests/pipelines/test_pipelines_common.py | 2 +- tests/pipelines/unclip/test_unclip_image_variation.py | 4 ++++ tests/pipelines/unidiffuser/test_unidiffuser.py | 4 ++++ 23 files changed, 89 insertions(+), 1 deletion(-) diff --git a/tests/pipelines/audioldm2/test_audioldm2.py b/tests/pipelines/audioldm2/test_audioldm2.py index fb550dd3219d..6bb9310a8d04 100644 --- a/tests/pipelines/audioldm2/test_audioldm2.py +++ b/tests/pipelines/audioldm2/test_audioldm2.py @@ -509,6 +509,10 @@ def test_to_dtype(self): def test_sequential_cpu_offload_forward_pass(self): pass + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @nightly class AudioLDM2PipelineSlowTests(unittest.TestCase): diff --git a/tests/pipelines/blipdiffusion/test_blipdiffusion.py b/tests/pipelines/blipdiffusion/test_blipdiffusion.py index 7e85cef65129..11bdd43367d4 100644 --- a/tests/pipelines/blipdiffusion/test_blipdiffusion.py +++ b/tests/pipelines/blipdiffusion/test_blipdiffusion.py @@ -196,3 +196,7 @@ def test_blipdiffusion(self): assert ( np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 ), f" expected_slice {image_slice.flatten()}, but got {image_slice.flatten()}" + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/i2vgen_xl/test_i2vgenxl.py b/tests/pipelines/i2vgen_xl/test_i2vgenxl.py index 592ebd35f4a9..7ef971427434 100644 --- a/tests/pipelines/i2vgen_xl/test_i2vgenxl.py +++ b/tests/pipelines/i2vgen_xl/test_i2vgenxl.py @@ -224,6 +224,10 @@ def test_num_videos_per_prompt(self): assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/kandinsky/test_kandinsky.py b/tests/pipelines/kandinsky/test_kandinsky.py index 8553ed96e9e1..2d67f45636cf 100644 --- a/tests/pipelines/kandinsky/test_kandinsky.py +++ b/tests/pipelines/kandinsky/test_kandinsky.py @@ -271,6 +271,10 @@ def test_offloads(self): assert np.abs(image_slices[0] - image_slices[1]).max() < 1e-3 assert np.abs(image_slices[0] - image_slices[2]).max() < 1e-3 + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/kandinsky/test_kandinsky_img2img.py b/tests/pipelines/kandinsky/test_kandinsky_img2img.py index ea289c5ccd71..916f8b669750 100644 --- a/tests/pipelines/kandinsky/test_kandinsky_img2img.py +++ b/tests/pipelines/kandinsky/test_kandinsky_img2img.py @@ -295,6 +295,10 @@ def test_offloads(self): def test_dict_tuple_outputs_equivalent(self): super().test_dict_tuple_outputs_equivalent(expected_max_difference=5e-4) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/kandinsky/test_kandinsky_inpaint.py b/tests/pipelines/kandinsky/test_kandinsky_inpaint.py index 740046678744..162de6356efa 100644 --- a/tests/pipelines/kandinsky/test_kandinsky_inpaint.py +++ b/tests/pipelines/kandinsky/test_kandinsky_inpaint.py @@ -293,6 +293,10 @@ def test_offloads(self): def test_float16_inference(self): super().test_float16_inference(expected_max_diff=5e-1) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @nightly @require_torch_gpu diff --git a/tests/pipelines/kandinsky/test_kandinsky_prior.py b/tests/pipelines/kandinsky/test_kandinsky_prior.py index 5f42447bd9d5..e57e83cd9551 100644 --- a/tests/pipelines/kandinsky/test_kandinsky_prior.py +++ b/tests/pipelines/kandinsky/test_kandinsky_prior.py @@ -236,3 +236,7 @@ def test_attention_slicing_forward_pass(self): test_max_difference=test_max_difference, test_mean_pixel_difference=test_mean_pixel_difference, ) + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/kandinsky2_2/test_kandinsky_prior.py b/tests/pipelines/kandinsky2_2/test_kandinsky_prior.py index be0bc238d4da..451aeee92320 100644 --- a/tests/pipelines/kandinsky2_2/test_kandinsky_prior.py +++ b/tests/pipelines/kandinsky2_2/test_kandinsky_prior.py @@ -277,3 +277,7 @@ def callback_inputs_test(pipe, i, t, callback_kwargs): output = pipe(**inputs)[0] assert output.abs().sum() == 0 + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/kandinsky2_2/test_kandinsky_prior_emb2emb.py b/tests/pipelines/kandinsky2_2/test_kandinsky_prior_emb2emb.py index e898824e2d17..cb2c4eed7501 100644 --- a/tests/pipelines/kandinsky2_2/test_kandinsky_prior_emb2emb.py +++ b/tests/pipelines/kandinsky2_2/test_kandinsky_prior_emb2emb.py @@ -240,3 +240,7 @@ def test_attention_slicing_forward_pass(self): test_max_difference=test_max_difference, test_mean_pixel_difference=test_mean_pixel_difference, ) + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/lumina/test_lumina_nextdit.py b/tests/pipelines/lumina/test_lumina_nextdit.py index 5fd0dbf06050..4c677cfa2acf 100644 --- a/tests/pipelines/lumina/test_lumina_nextdit.py +++ b/tests/pipelines/lumina/test_lumina_nextdit.py @@ -123,6 +123,10 @@ def test_lumina_prompt_embeds(self): def test_xformers_attention_forwardGenerator_pass(self): pass + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/musicldm/test_musicldm.py b/tests/pipelines/musicldm/test_musicldm.py index e51f5103933a..7a7905ee76c6 100644 --- a/tests/pipelines/musicldm/test_musicldm.py +++ b/tests/pipelines/musicldm/test_musicldm.py @@ -404,6 +404,10 @@ def test_to_dtype(self): model_dtypes = {key: component.dtype for key, component in components.items() if hasattr(component, "dtype")} self.assertTrue(all(dtype == torch.float16 for dtype in model_dtypes.values())) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @nightly @require_torch_gpu diff --git a/tests/pipelines/paint_by_example/test_paint_by_example.py b/tests/pipelines/paint_by_example/test_paint_by_example.py index c71e2d4761c2..a3d3d244175d 100644 --- a/tests/pipelines/paint_by_example/test_paint_by_example.py +++ b/tests/pipelines/paint_by_example/test_paint_by_example.py @@ -170,6 +170,10 @@ def test_paint_by_example_image_tensor(self): def test_inference_batch_single_identical(self): super().test_inference_batch_single_identical(expected_max_diff=3e-3) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @nightly @require_torch_gpu diff --git a/tests/pipelines/shap_e/test_shap_e_img2img.py b/tests/pipelines/shap_e/test_shap_e_img2img.py index f3661355e9dd..f5d41f61cfa0 100644 --- a/tests/pipelines/shap_e/test_shap_e_img2img.py +++ b/tests/pipelines/shap_e/test_shap_e_img2img.py @@ -246,6 +246,10 @@ def test_save_load_local(self): def test_sequential_cpu_offload_forward_pass(self): pass + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @nightly @require_torch_gpu diff --git a/tests/pipelines/stable_diffusion_2/test_stable_diffusion_depth.py b/tests/pipelines/stable_diffusion_2/test_stable_diffusion_depth.py index 01a0a3abe4ee..ace1de5f67e2 100644 --- a/tests/pipelines/stable_diffusion_2/test_stable_diffusion_depth.py +++ b/tests/pipelines/stable_diffusion_2/test_stable_diffusion_depth.py @@ -367,6 +367,10 @@ def test_attention_slicing_forward_pass(self): def test_inference_batch_single_identical(self): super().test_inference_batch_single_identical(expected_max_diff=7e-3) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/stable_diffusion_gligen_text_image/test_stable_diffusion_gligen_text_image.py b/tests/pipelines/stable_diffusion_gligen_text_image/test_stable_diffusion_gligen_text_image.py index 748702541b1e..3488f1e6f499 100644 --- a/tests/pipelines/stable_diffusion_gligen_text_image/test_stable_diffusion_gligen_text_image.py +++ b/tests/pipelines/stable_diffusion_gligen_text_image/test_stable_diffusion_gligen_text_image.py @@ -205,3 +205,7 @@ def test_attention_slicing_forward_pass(self): def test_inference_batch_single_identical(self): super().test_inference_batch_single_identical(batch_size=3, expected_max_diff=3e-3) + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/stable_diffusion_image_variation/test_stable_diffusion_image_variation.py b/tests/pipelines/stable_diffusion_image_variation/test_stable_diffusion_image_variation.py index 7a3b0f70ccb1..7ba2be0ed3ab 100644 --- a/tests/pipelines/stable_diffusion_image_variation/test_stable_diffusion_image_variation.py +++ b/tests/pipelines/stable_diffusion_image_variation/test_stable_diffusion_image_variation.py @@ -160,6 +160,10 @@ def test_stable_diffusion_img_variation_multiple_images(self): def test_inference_batch_single_identical(self): super().test_inference_batch_single_identical(expected_max_diff=3e-3) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_img2img.py b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_img2img.py index db0905a48310..4cb0b056eb4b 100644 --- a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_img2img.py +++ b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_img2img.py @@ -515,6 +515,10 @@ def callback_on_step_end(pipe, i, t, callback_kwargs): # they should be the same assert torch.allclose(intermediate_latent, output_interrupted, atol=1e-4) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + class StableDiffusionXLImg2ImgRefinerOnlyPipelineFastTests( PipelineLatentTesterMixin, PipelineTesterMixin, SDXLOptionalComponentsTesterMixin, unittest.TestCase diff --git a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_inpaint.py b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_inpaint.py index 964c7123dd32..39395d5ffc06 100644 --- a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_inpaint.py +++ b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_inpaint.py @@ -815,3 +815,7 @@ def callback_on_step_end(pipe, i, t, callback_kwargs): # compare the intermediate latent to the output of the interrupted process # they should be the same assert torch.allclose(intermediate_latent, output_interrupted, atol=1e-4) + + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass diff --git a/tests/pipelines/stable_unclip/test_stable_unclip_img2img.py b/tests/pipelines/stable_unclip/test_stable_unclip_img2img.py index a5cbf7761501..d5893c04627c 100644 --- a/tests/pipelines/stable_unclip/test_stable_unclip_img2img.py +++ b/tests/pipelines/stable_unclip/test_stable_unclip_img2img.py @@ -205,6 +205,10 @@ def test_inference_batch_single_identical(self): def test_xformers_attention_forwardGenerator_pass(self): self._test_xformers_attention_forwardGenerator_pass(test_max_difference=False) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @nightly @require_torch_gpu diff --git a/tests/pipelines/stable_video_diffusion/test_stable_video_diffusion.py b/tests/pipelines/stable_video_diffusion/test_stable_video_diffusion.py index ac9acb26afd3..5624d3a39b98 100644 --- a/tests/pipelines/stable_video_diffusion/test_stable_video_diffusion.py +++ b/tests/pipelines/stable_video_diffusion/test_stable_video_diffusion.py @@ -511,6 +511,10 @@ def test_disable_cfg(self): output = pipe(**inputs).frames self.assertEqual(len(output.shape), 5) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @slow @require_torch_gpu diff --git a/tests/pipelines/test_pipelines_common.py b/tests/pipelines/test_pipelines_common.py index 6ab9b118222c..fcf216db9b40 100644 --- a/tests/pipelines/test_pipelines_common.py +++ b/tests/pipelines/test_pipelines_common.py @@ -1993,7 +1993,7 @@ def test_StableDiffusionMixin_component(self): ) @pytest.mark.xfail( - condition=is_hf_hub_version("<=", "0.26.5") and is_transformers_version("<=", "4.47.1"), + condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), reason="Test requires hf hub and transformers latests", strict=True, ) diff --git a/tests/pipelines/unclip/test_unclip_image_variation.py b/tests/pipelines/unclip/test_unclip_image_variation.py index dfc3acc0c0f2..dcd3f5bb9835 100644 --- a/tests/pipelines/unclip/test_unclip_image_variation.py +++ b/tests/pipelines/unclip/test_unclip_image_variation.py @@ -492,6 +492,10 @@ def test_save_load_optional_components(self): def test_float16_inference(self): super().test_float16_inference(expected_max_diff=1.0) + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @nightly @require_torch_gpu diff --git a/tests/pipelines/unidiffuser/test_unidiffuser.py b/tests/pipelines/unidiffuser/test_unidiffuser.py index 2e0ba1cfb8eb..6bb3d7b7e7d0 100644 --- a/tests/pipelines/unidiffuser/test_unidiffuser.py +++ b/tests/pipelines/unidiffuser/test_unidiffuser.py @@ -576,6 +576,10 @@ def test_unidiffuser_default_img2text_v1_cuda_fp16(self): expected_text_prefix = '" This This' assert text[0][: len(expected_text_prefix)] == expected_text_prefix + @unittest.skip("Test not supported.") + def test_save_load_dduf(self): + pass + @nightly @require_torch_gpu From 6648995133e9958d85e6ea4cf7c30b5a0b2ec0fc Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Tue, 31 Dec 2024 11:49:37 +0530 Subject: [PATCH 53/65] fix xfail condition. --- tests/pipelines/test_pipelines.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/pipelines/test_pipelines.py b/tests/pipelines/test_pipelines.py index 1d2d4e4e80f7..be12af9ef729 100644 --- a/tests/pipelines/test_pipelines.py +++ b/tests/pipelines/test_pipelines.py @@ -1819,7 +1819,7 @@ def test_pipe_same_device_id_offload(self): @parameterized.expand([torch.float32, torch.float16]) @pytest.mark.xfail( - condition=is_hf_hub_version("<", "0.26.5") and is_transformers_version("<", "4.47.1"), + condition=is_hf_hub_version("<", "0.26.5") or is_transformers_version("<", "4.47.1"), reason="Test requires hf hub and transformers latests", strict=True, ) @@ -1840,7 +1840,7 @@ def test_load_dduf_from_hub(self, dtype): self.assertTrue(np.allclose(out_1, out_2, atol=1e-4, rtol=1e-4)) @pytest.mark.xfail( - condition=is_hf_hub_version("<", "0.26.5") and is_transformers_version("<", "4.47.1"), + condition=is_hf_hub_version("<", "0.26.5") or is_transformers_version("<", "4.47.1"), reason="Test requires hf hub and transformers latests", strict=True, ) From 21ae7ee5f6f55cb3e3ecfebb7e1b672b50017af7 Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Tue, 31 Dec 2024 11:52:37 +0530 Subject: [PATCH 54/65] fix xfail --- tests/pipelines/deepfloyd_if/test_if.py | 8 +++++++- tests/pipelines/deepfloyd_if/test_if_img2img.py | 8 +++++++- .../deepfloyd_if/test_if_img2img_superresolution.py | 8 +++++++- tests/pipelines/deepfloyd_if/test_if_inpainting.py | 8 +++++++- .../deepfloyd_if/test_if_inpainting_superresolution.py | 8 +++++++- tests/pipelines/deepfloyd_if/test_if_superresolution.py | 8 +++++++- 6 files changed, 42 insertions(+), 6 deletions(-) diff --git a/tests/pipelines/deepfloyd_if/test_if.py b/tests/pipelines/deepfloyd_if/test_if.py index 0e840e6ddc4c..fd8fde9959ea 100644 --- a/tests/pipelines/deepfloyd_if/test_if.py +++ b/tests/pipelines/deepfloyd_if/test_if.py @@ -16,13 +16,14 @@ import gc import unittest +import pytest import torch from diffusers import ( IFPipeline, ) from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_xformers_available +from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available from diffusers.utils.testing_utils import ( load_numpy, require_accelerator, @@ -89,6 +90,11 @@ def test_inference_batch_single_identical(self): def test_xformers_attention_forwardGenerator_pass(self): self._test_xformers_attention_forwardGenerator_pass(expected_max_diff=1e-3) + @pytest.mark.xfail( + condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), + reason="Test requires hf hub and transformers latests", + strict=True, + ) def test_save_load_dduf(self): super().test_save_load_dduf(atol=1e-2, rtol=1e-2) diff --git a/tests/pipelines/deepfloyd_if/test_if_img2img.py b/tests/pipelines/deepfloyd_if/test_if_img2img.py index d6063e378659..68c630460745 100644 --- a/tests/pipelines/deepfloyd_if/test_if_img2img.py +++ b/tests/pipelines/deepfloyd_if/test_if_img2img.py @@ -17,11 +17,12 @@ import random import unittest +import pytest import torch from diffusers import IFImg2ImgPipeline from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_xformers_available +from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available from diffusers.utils.testing_utils import ( floats_tensor, load_numpy, @@ -100,6 +101,11 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) + @pytest.mark.xfail( + condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), + reason="Test requires hf hub and transformers latests", + strict=True, + ) def test_save_load_dduf(self): super().test_save_load_dduf(atol=1e-2, rtol=1e-2) diff --git a/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py b/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py index 401bff64d940..dc9c1c42fe78 100644 --- a/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py +++ b/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py @@ -17,11 +17,12 @@ import random import unittest +import pytest import torch from diffusers import IFImg2ImgSuperResolutionPipeline from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_xformers_available +from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available from diffusers.utils.testing_utils import ( floats_tensor, load_numpy, @@ -97,6 +98,11 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) + @pytest.mark.xfail( + condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), + reason="Test requires hf hub and transformers latests", + strict=True, + ) def test_save_load_dduf(self): super().test_save_load_dduf(atol=1e-2, rtol=1e-2) diff --git a/tests/pipelines/deepfloyd_if/test_if_inpainting.py b/tests/pipelines/deepfloyd_if/test_if_inpainting.py index e99dff0c4041..e10aa92323a7 100644 --- a/tests/pipelines/deepfloyd_if/test_if_inpainting.py +++ b/tests/pipelines/deepfloyd_if/test_if_inpainting.py @@ -17,11 +17,12 @@ import random import unittest +import pytest import torch from diffusers import IFInpaintingPipeline from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_xformers_available +from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available from diffusers.utils.testing_utils import ( floats_tensor, load_numpy, @@ -97,6 +98,11 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) + @pytest.mark.xfail( + condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), + reason="Test requires hf hub and transformers latests", + strict=True, + ) def test_save_load_dduf(self): super().test_save_load_dduf(atol=1e-2, rtol=1e-2) diff --git a/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py b/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py index bc7e26e4cfcd..731a62172b65 100644 --- a/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py +++ b/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py @@ -17,11 +17,12 @@ import random import unittest +import pytest import torch from diffusers import IFInpaintingSuperResolutionPipeline from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_xformers_available +from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available from diffusers.utils.testing_utils import ( floats_tensor, load_numpy, @@ -99,6 +100,11 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) + @pytest.mark.xfail( + condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), + reason="Test requires hf hub and transformers latests", + strict=True, + ) def test_save_load_dduf(self): super().test_save_load_dduf(atol=1e-2, rtol=1e-2) diff --git a/tests/pipelines/deepfloyd_if/test_if_superresolution.py b/tests/pipelines/deepfloyd_if/test_if_superresolution.py index 36e2c2bb6904..f0982551f8d3 100644 --- a/tests/pipelines/deepfloyd_if/test_if_superresolution.py +++ b/tests/pipelines/deepfloyd_if/test_if_superresolution.py @@ -17,11 +17,12 @@ import random import unittest +import pytest import torch from diffusers import IFSuperResolutionPipeline from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_xformers_available +from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available from diffusers.utils.testing_utils import ( floats_tensor, load_numpy, @@ -92,6 +93,11 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) + @pytest.mark.xfail( + condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), + reason="Test requires hf hub and transformers latests", + strict=True, + ) def test_save_load_dduf(self): super().test_save_load_dduf(atol=1e-2, rtol=1e-2) From 15d4569ec3fdd154508aef78c178d024dff7605f Mon Sep 17 00:00:00 2001 From: sayakpaul Date: Tue, 31 Dec 2024 12:20:18 +0530 Subject: [PATCH 55/65] fixes --- tests/pipelines/deepfloyd_if/test_if.py | 12 +++++------- .../pipelines/deepfloyd_if/test_if_img2img.py | 12 +++++------- .../test_if_img2img_superresolution.py | 12 +++++------- .../deepfloyd_if/test_if_inpainting.py | 12 +++++------- .../test_if_inpainting_superresolution.py | 12 +++++------- .../deepfloyd_if/test_if_superresolution.py | 12 +++++------- tests/pipelines/test_pipelines.py | 19 ++++++------------- tests/pipelines/test_pipelines_common.py | 12 +++++------- 8 files changed, 41 insertions(+), 62 deletions(-) diff --git a/tests/pipelines/deepfloyd_if/test_if.py b/tests/pipelines/deepfloyd_if/test_if.py index fd8fde9959ea..2231821fbc4a 100644 --- a/tests/pipelines/deepfloyd_if/test_if.py +++ b/tests/pipelines/deepfloyd_if/test_if.py @@ -16,18 +16,19 @@ import gc import unittest -import pytest import torch from diffusers import ( IFPipeline, ) from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available +from diffusers.utils.import_utils import is_xformers_available from diffusers.utils.testing_utils import ( load_numpy, require_accelerator, + require_hf_hub_version_greater, require_torch_gpu, + require_transformers_version_greater, skip_mps, slow, torch_device, @@ -90,11 +91,8 @@ def test_inference_batch_single_identical(self): def test_xformers_attention_forwardGenerator_pass(self): self._test_xformers_attention_forwardGenerator_pass(expected_max_diff=1e-3) - @pytest.mark.xfail( - condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), - reason="Test requires hf hub and transformers latests", - strict=True, - ) + @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) diff --git a/tests/pipelines/deepfloyd_if/test_if_img2img.py b/tests/pipelines/deepfloyd_if/test_if_img2img.py index 68c630460745..c6d5384e2467 100644 --- a/tests/pipelines/deepfloyd_if/test_if_img2img.py +++ b/tests/pipelines/deepfloyd_if/test_if_img2img.py @@ -17,17 +17,18 @@ import random import unittest -import pytest import torch from diffusers import IFImg2ImgPipeline from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available +from diffusers.utils.import_utils import is_xformers_available from diffusers.utils.testing_utils import ( floats_tensor, load_numpy, require_accelerator, + require_hf_hub_version_greater, require_torch_gpu, + require_transformers_version_greater, skip_mps, slow, torch_device, @@ -101,11 +102,8 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) - @pytest.mark.xfail( - condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), - reason="Test requires hf hub and transformers latests", - strict=True, - ) + @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) diff --git a/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py b/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py index dc9c1c42fe78..7cdd8cd147f8 100644 --- a/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py +++ b/tests/pipelines/deepfloyd_if/test_if_img2img_superresolution.py @@ -17,17 +17,18 @@ import random import unittest -import pytest import torch from diffusers import IFImg2ImgSuperResolutionPipeline from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available +from diffusers.utils.import_utils import is_xformers_available from diffusers.utils.testing_utils import ( floats_tensor, load_numpy, require_accelerator, + require_hf_hub_version_greater, require_torch_gpu, + require_transformers_version_greater, skip_mps, slow, torch_device, @@ -98,11 +99,8 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) - @pytest.mark.xfail( - condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), - reason="Test requires hf hub and transformers latests", - strict=True, - ) + @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) diff --git a/tests/pipelines/deepfloyd_if/test_if_inpainting.py b/tests/pipelines/deepfloyd_if/test_if_inpainting.py index e10aa92323a7..9f151190251f 100644 --- a/tests/pipelines/deepfloyd_if/test_if_inpainting.py +++ b/tests/pipelines/deepfloyd_if/test_if_inpainting.py @@ -17,17 +17,18 @@ import random import unittest -import pytest import torch from diffusers import IFInpaintingPipeline from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available +from diffusers.utils.import_utils import is_xformers_available from diffusers.utils.testing_utils import ( floats_tensor, load_numpy, require_accelerator, + require_hf_hub_version_greater, require_torch_gpu, + require_transformers_version_greater, skip_mps, slow, torch_device, @@ -98,11 +99,8 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) - @pytest.mark.xfail( - condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), - reason="Test requires hf hub and transformers latests", - strict=True, - ) + @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) diff --git a/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py b/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py index 731a62172b65..c2b48bfd6d77 100644 --- a/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py +++ b/tests/pipelines/deepfloyd_if/test_if_inpainting_superresolution.py @@ -17,17 +17,18 @@ import random import unittest -import pytest import torch from diffusers import IFInpaintingSuperResolutionPipeline from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available +from diffusers.utils.import_utils import is_xformers_available from diffusers.utils.testing_utils import ( floats_tensor, load_numpy, require_accelerator, + require_hf_hub_version_greater, require_torch_gpu, + require_transformers_version_greater, skip_mps, slow, torch_device, @@ -100,11 +101,8 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) - @pytest.mark.xfail( - condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), - reason="Test requires hf hub and transformers latests", - strict=True, - ) + @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) diff --git a/tests/pipelines/deepfloyd_if/test_if_superresolution.py b/tests/pipelines/deepfloyd_if/test_if_superresolution.py index f0982551f8d3..57e12899e4fd 100644 --- a/tests/pipelines/deepfloyd_if/test_if_superresolution.py +++ b/tests/pipelines/deepfloyd_if/test_if_superresolution.py @@ -17,17 +17,18 @@ import random import unittest -import pytest import torch from diffusers import IFSuperResolutionPipeline from diffusers.models.attention_processor import AttnAddedKVProcessor -from diffusers.utils.import_utils import is_hf_hub_version, is_transformers_version, is_xformers_available +from diffusers.utils.import_utils import is_xformers_available from diffusers.utils.testing_utils import ( floats_tensor, load_numpy, require_accelerator, + require_hf_hub_version_greater, require_torch_gpu, + require_transformers_version_greater, skip_mps, slow, torch_device, @@ -93,11 +94,8 @@ def test_inference_batch_single_identical(self): expected_max_diff=1e-2, ) - @pytest.mark.xfail( - condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), - reason="Test requires hf hub and transformers latests", - strict=True, - ) + @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) diff --git a/tests/pipelines/test_pipelines.py b/tests/pipelines/test_pipelines.py index be12af9ef729..6d6403095df1 100644 --- a/tests/pipelines/test_pipelines.py +++ b/tests/pipelines/test_pipelines.py @@ -26,7 +26,6 @@ import numpy as np import PIL.Image -import pytest import requests_mock import safetensors.torch import torch @@ -64,8 +63,6 @@ from diffusers.utils import ( CONFIG_NAME, WEIGHTS_NAME, - is_hf_hub_version, - is_transformers_version, ) from diffusers.utils.testing_utils import ( CaptureLogger, @@ -78,9 +75,11 @@ nightly, require_compel, require_flax, + require_hf_hub_version_greater, require_onnxruntime, require_torch_2, require_torch_gpu, + require_transformers_version_greater, run_test_in_subprocess, slow, torch_device, @@ -1818,11 +1817,8 @@ def test_pipe_same_device_id_offload(self): assert sd._offload_gpu_id == 5 @parameterized.expand([torch.float32, torch.float16]) - @pytest.mark.xfail( - condition=is_hf_hub_version("<", "0.26.5") or is_transformers_version("<", "4.47.1"), - reason="Test requires hf hub and transformers latests", - strict=True, - ) + @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( @@ -1839,11 +1835,8 @@ def test_load_dduf_from_hub(self, dtype): self.assertTrue(np.allclose(out_1, out_2, atol=1e-4, rtol=1e-4)) - @pytest.mark.xfail( - condition=is_hf_hub_version("<", "0.26.5") or is_transformers_version("<", "4.47.1"), - reason="Test requires hf hub and transformers latests", - strict=True, - ) + @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( diff --git a/tests/pipelines/test_pipelines_common.py b/tests/pipelines/test_pipelines_common.py index fcf216db9b40..0a2a884badb6 100644 --- a/tests/pipelines/test_pipelines_common.py +++ b/tests/pipelines/test_pipelines_common.py @@ -9,7 +9,6 @@ import numpy as np import PIL.Image -import pytest import torch import torch.nn as nn from huggingface_hub import ModelCard, delete_repo @@ -38,13 +37,15 @@ from diffusers.models.unets.unet_motion_model import UNetMotionModel from diffusers.pipelines.pipeline_utils import StableDiffusionMixin from diffusers.schedulers import KarrasDiffusionSchedulers -from diffusers.utils import is_hf_hub_version, is_transformers_version, logging +from diffusers.utils import logging from diffusers.utils.import_utils import is_xformers_available from diffusers.utils.testing_utils import ( CaptureLogger, require_accelerate_version_greater, require_accelerator, + require_hf_hub_version_greater, require_torch, + require_transformers_version_greater, skip_mps, torch_device, ) @@ -1992,11 +1993,8 @@ def test_StableDiffusionMixin_component(self): ) ) - @pytest.mark.xfail( - condition=is_hf_hub_version("<=", "0.26.5") or is_transformers_version("<=", "4.47.1"), - reason="Test requires hf hub and transformers latests", - strict=True, - ) + @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): from huggingface_hub import export_folder_as_dduf From f3a4ddc27156e07a8b99368c984512bc2c847533 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Fri, 3 Jan 2025 12:24:34 +0100 Subject: [PATCH 56/65] sharded checkpoint compat --- src/diffusers/models/model_loading_utils.py | 22 ++++++++++++++------- src/diffusers/models/modeling_utils.py | 11 +++++++---- src/diffusers/utils/hub_utils.py | 12 ++++++++--- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index 04fc1894ea8c..76070b16df24 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -315,7 +315,8 @@ def _fetch_index_file( 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): index_file = None @@ -324,7 +325,9 @@ def _fetch_index_file( # Adapted from # 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) if weight_map is None: raise KeyError("'weight_map' key not found in the shard index file.") @@ -337,14 +340,19 @@ def _merge_sharded_checkpoints(sharded_ckpt_cached_folder, sharded_metadata): # Load tensors from each unique file for file_name in files_to_load: part_file_path = os.path.join(sharded_ckpt_cached_folder, file_name) - if not os.path.exists(part_file_path): + if not os.path.exists(part_file_path) and (dduf_entries and part_file_path not in dduf_entries): raise FileNotFoundError(f"Part file {file_name} not found.") if is_safetensors: - 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) + if dduf_entries: + with dduf_entries[part_file_path].as_mmap() as mm: + tensors = safetensors.torch.load(mm) + 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: merged_state_dict.update(torch.load(part_file_path, weights_only=True, map_location="cpu")) diff --git a/src/diffusers/models/modeling_utils.py b/src/diffusers/models/modeling_utils.py index e886f7275704..04644f81c0f7 100644 --- a/src/diffusers/models/modeling_utils.py +++ b/src/diffusers/models/modeling_utils.py @@ -782,7 +782,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P # 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)): 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 if is_sharded and from_flax: @@ -812,7 +812,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P model = load_flax_checkpoint_in_pytorch_model(model, model_file) else: # in the case it is sharded, we have already the index - if is_sharded and not dduf_entries: + if is_sharded: sharded_ckpt_cached_folder, sharded_metadata = _get_checkpoint_shard_files( pretrained_model_name_or_path, index_file, @@ -823,9 +823,12 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P user_agent=user_agent, revision=revision, subfolder=subfolder or "", + dduf_entries=dduf_entries, ) - if hf_quantizer is not None and is_bnb_quantization_method: - model_file = _merge_sharded_checkpoints(sharded_ckpt_cached_folder, sharded_metadata) + if (hf_quantizer is not None and is_bnb_quantization_method) or dduf_entries: + 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.") is_sharded = False diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index 13092ad641a5..db5d9c5afa1a 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -437,6 +437,7 @@ def _get_checkpoint_shard_files( user_agent=None, revision=None, subfolder="", + dduf_entries: Optional[Dict[str, DDUFEntry]] = None, ): """ For a given model: @@ -448,11 +449,14 @@ def _get_checkpoint_shard_files( 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). """ - if not os.path.isfile(index_filename): + if not os.path.isfile(index_filename) and (dduf_entries and index_filename not in dduf_entries): raise ValueError(f"Can't find a checkpoint index ({index_filename}) in {pretrained_model_name_or_path}.") - with open(index_filename, "r") as f: - index = json.loads(f.read()) + if dduf_entries: + 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())) sharded_metadata = index["metadata"] @@ -466,6 +470,8 @@ def _get_checkpoint_shard_files( pretrained_model_name_or_path, subfolder=subfolder, original_shard_filenames=original_shard_filenames ) 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 allow_patterns = original_shard_filenames From 0205cc86494113799eb9f74619138ceff4e924f4 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Fri, 3 Jan 2025 14:52:39 +0100 Subject: [PATCH 57/65] add test for sharded checkpoint --- src/diffusers/models/modeling_utils.py | 2 +- tests/pipelines/test_pipelines.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/diffusers/models/modeling_utils.py b/src/diffusers/models/modeling_utils.py index 53bcdfcdb5ec..705ce221599e 100644 --- a/src/diffusers/models/modeling_utils.py +++ b/src/diffusers/models/modeling_utils.py @@ -825,7 +825,7 @@ def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.P dduf_entries=dduf_entries, ) # 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, dduf_entries=dduf_entries ) diff --git a/tests/pipelines/test_pipelines.py b/tests/pipelines/test_pipelines.py index 6d6403095df1..48ee784f24ff 100644 --- a/tests/pipelines/test_pipelines.py +++ b/tests/pipelines/test_pipelines.py @@ -1875,6 +1875,18 @@ def test_wrong_model(self): assert "is of type" 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) + + pipe(prompt="dog", num_inference_steps=5, generator=torch.manual_seed(0), output_type="np").images + @slow @require_torch_gpu From 5037d3952e8c200a415109b40dbc62e15aad2f71 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Mon, 6 Jan 2025 14:55:48 +0100 Subject: [PATCH 58/65] add suggestions --- tests/pipelines/test_pipelines.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/pipelines/test_pipelines.py b/tests/pipelines/test_pipelines.py index 48ee784f24ff..6665a005ba96 100644 --- a/tests/pipelines/test_pipelines.py +++ b/tests/pipelines/test_pipelines.py @@ -1885,7 +1885,16 @@ def test_dduf_load_sharded_checkpoint_diffusion_model(self): cache_dir=tmpdir, ).to(torch_device) - pipe(prompt="dog", num_inference_steps=5, generator=torch.manual_seed(0), output_type="np").images + 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 From 02a368b567d66a933db6e057b8c94097e987329a Mon Sep 17 00:00:00 2001 From: Marc Sun <57196510+SunMarc@users.noreply.github.com> Date: Tue, 7 Jan 2025 16:19:20 +0100 Subject: [PATCH 59/65] Update src/diffusers/models/model_loading_utils.py Co-authored-by: YiYi Xu --- src/diffusers/models/model_loading_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index 76070b16df24..2c02cd69ba0f 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -340,7 +340,7 @@ def _merge_sharded_checkpoints( # Load tensors from each unique file for file_name in files_to_load: part_file_path = os.path.join(sharded_ckpt_cached_folder, file_name) - if not os.path.exists(part_file_path) and (dduf_entries and part_file_path not in dduf_entries): + if not os.path.exists(part_file_path) or (dduf_entries and part_file_path not in dduf_entries): raise FileNotFoundError(f"Part file {file_name} not found.") if is_safetensors: From 7bc93475a00f73ab1e4458dd80b93ca80d3989fa Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Tue, 7 Jan 2025 16:28:18 +0100 Subject: [PATCH 60/65] from suggestions --- src/diffusers/configuration_utils.py | 16 +++++++--------- src/diffusers/models/model_loading_utils.py | 4 +++- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/diffusers/configuration_utils.py b/src/diffusers/configuration_utils.py index 4629e5efc765..9dd4f0121a44 100644 --- a/src/diffusers/configuration_utils.py +++ b/src/diffusers/configuration_utils.py @@ -361,7 +361,12 @@ def load_config( ) # Custom path for now if dduf_entries: - config_file = cls._get_config_file_from_dduf(pretrained_model_name_or_path, subfolder, 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 elif os.path.isdir(pretrained_model_name_or_path): @@ -623,14 +628,7 @@ def to_json_file(self, json_file_path: Union[str, os.PathLike]): writer.write(self.to_json_string()) @classmethod - def _get_config_file_from_dduf( - cls, pretrained_model_name_or_path: str, subfolder: str, dduf_entries: Dict[str, DDUFEntry] - ): - 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" - ) + 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 diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index 2c02cd69ba0f..e86bb2932ef1 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -28,6 +28,7 @@ from huggingface_hub.utils import EntryNotFoundError from ..utils import ( + GGUF_FILE_EXTENSION, SAFE_WEIGHTS_INDEX_NAME, SAFETENSORS_FILE_EXTENSION, WEIGHTS_INDEX_NAME, @@ -152,7 +153,8 @@ def load_state_dict( return safetensors.torch.load(mm) else: return safetensors.torch.load_file(checkpoint_file, device="cpu") - + elif file_extension == GGUF_FILE_EXTENSION: + return load_gguf_checkpoint(checkpoint_file) else: weights_only_kwarg = {"weights_only": True} if is_torch_version(">=", "1.13") else {} return torch.load( From fff5954a8b9f723c43d3d2d18839a3bbdfa026d0 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Tue, 7 Jan 2025 17:58:05 +0100 Subject: [PATCH 61/65] add class attributes to flag dduf tests --- tests/pipelines/audioldm/test_audioldm.py | 6 ++---- tests/pipelines/audioldm2/test_audioldm2.py | 6 ++---- .../blipdiffusion/test_blipdiffusion.py | 6 ++---- tests/pipelines/controlnet/test_controlnet.py | 16 ++++------------ .../test_controlnet_blip_diffusion.py | 6 ++---- .../controlnet/test_controlnet_img2img.py | 8 -------- .../controlnet/test_controlnet_inpaint.py | 6 ++---- .../controlnet/test_controlnet_inpaint_sdxl.py | 6 ++---- .../controlnet/test_controlnet_sdxl.py | 16 ++++------------ .../controlnet/test_controlnet_sdxl_img2img.py | 4 ---- tests/pipelines/i2vgen_xl/test_i2vgenxl.py | 6 ++---- tests/pipelines/kandinsky/test_kandinsky.py | 6 ++---- .../kandinsky/test_kandinsky_combined.py | 18 ++++++------------ .../kandinsky/test_kandinsky_img2img.py | 6 ++---- .../kandinsky/test_kandinsky_inpaint.py | 6 ++---- .../kandinsky/test_kandinsky_prior.py | 6 ++---- .../kandinsky2_2/test_kandinsky_combined.py | 18 ++++++------------ .../kandinsky2_2/test_kandinsky_prior.py | 6 ++---- .../test_kandinsky_prior_emb2emb.py | 6 ++---- tests/pipelines/kolors/test_kolors.py | 6 ++---- tests/pipelines/kolors/test_kolors_img2img.py | 6 ++---- tests/pipelines/lumina/test_lumina_nextdit.py | 6 ++---- tests/pipelines/musicldm/test_musicldm.py | 6 ++---- tests/pipelines/pag/test_pag_kolors.py | 6 ++---- tests/pipelines/pag/test_pag_sana.py | 6 ++---- tests/pipelines/pag/test_pag_sdxl_img2img.py | 6 ++---- tests/pipelines/pag/test_pag_sdxl_inpaint.py | 6 ++---- .../paint_by_example/test_paint_by_example.py | 6 ++---- tests/pipelines/shap_e/test_shap_e_img2img.py | 6 ++---- .../stable_audio/test_stable_audio.py | 1 + .../test_stable_diffusion_depth.py | 6 ++---- .../test_stable_diffusion_adapter.py | 6 ++---- .../test_stable_diffusion_gligen_text_image.py | 6 ++---- .../test_stable_diffusion_image_variation.py | 6 ++---- .../test_stable_diffusion_xl_adapter.py | 6 ++---- .../test_stable_diffusion_xl_img2img.py | 6 ++---- .../test_stable_diffusion_xl_inpaint.py | 6 ++---- .../test_stable_unclip_img2img.py | 6 ++---- .../test_stable_video_diffusion.py | 6 ++---- tests/pipelines/test_pipelines_common.py | 5 +++++ .../unclip/test_unclip_image_variation.py | 5 +---- .../pipelines/unidiffuser/test_unidiffuser.py | 6 ++---- 42 files changed, 93 insertions(+), 196 deletions(-) diff --git a/tests/pipelines/audioldm/test_audioldm.py b/tests/pipelines/audioldm/test_audioldm.py index 29668bb75c1e..aaf44985aafd 100644 --- a/tests/pipelines/audioldm/test_audioldm.py +++ b/tests/pipelines/audioldm/test_audioldm.py @@ -63,6 +63,8 @@ class AudioLDMPipelineFastTests(PipelineTesterMixin, unittest.TestCase): ] ) + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -370,10 +372,6 @@ def test_inference_batch_single_identical(self): def test_xformers_attention_forwardGenerator_pass(self): self._test_xformers_attention_forwardGenerator_pass(test_mean_pixel_difference=False) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @nightly class AudioLDMPipelineSlowTests(unittest.TestCase): diff --git a/tests/pipelines/audioldm2/test_audioldm2.py b/tests/pipelines/audioldm2/test_audioldm2.py index 6bb9310a8d04..166344fa891c 100644 --- a/tests/pipelines/audioldm2/test_audioldm2.py +++ b/tests/pipelines/audioldm2/test_audioldm2.py @@ -70,6 +70,8 @@ class AudioLDM2PipelineFastTests(PipelineTesterMixin, unittest.TestCase): ] ) + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = AudioLDM2UNet2DConditionModel( @@ -509,10 +511,6 @@ def test_to_dtype(self): def test_sequential_cpu_offload_forward_pass(self): pass - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @nightly class AudioLDM2PipelineSlowTests(unittest.TestCase): diff --git a/tests/pipelines/blipdiffusion/test_blipdiffusion.py b/tests/pipelines/blipdiffusion/test_blipdiffusion.py index 11bdd43367d4..6d422745ce5a 100644 --- a/tests/pipelines/blipdiffusion/test_blipdiffusion.py +++ b/tests/pipelines/blipdiffusion/test_blipdiffusion.py @@ -60,6 +60,8 @@ class BlipDiffusionPipelineFastTests(PipelineTesterMixin, unittest.TestCase): "prompt_reps", ] + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) text_encoder_config = CLIPTextConfig( @@ -196,7 +198,3 @@ def test_blipdiffusion(self): assert ( np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 ), f" expected_slice {image_slice.flatten()}, but got {image_slice.flatten()}" - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/controlnet/test_controlnet.py b/tests/pipelines/controlnet/test_controlnet.py index 11fec9800312..fc8ea5284ccc 100644 --- a/tests/pipelines/controlnet/test_controlnet.py +++ b/tests/pipelines/controlnet/test_controlnet.py @@ -282,10 +282,6 @@ def test_controlnet_lcm_custom_timesteps(self): assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class StableDiffusionMultiControlNetPipelineFastTests( IPAdapterTesterMixin, PipelineTesterMixin, PipelineKarrasSchedulerTesterMixin, unittest.TestCase @@ -295,6 +291,8 @@ class StableDiffusionMultiControlNetPipelineFastTests( batch_params = TEXT_TO_IMAGE_BATCH_PARAMS image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -518,10 +516,6 @@ def test_inference_multiple_prompt_input(self): assert image.shape == (4, 64, 64, 3) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class StableDiffusionMultiControlNetOneModelPipelineFastTests( IPAdapterTesterMixin, PipelineTesterMixin, PipelineKarrasSchedulerTesterMixin, unittest.TestCase @@ -531,6 +525,8 @@ class StableDiffusionMultiControlNetOneModelPipelineFastTests( batch_params = TEXT_TO_IMAGE_BATCH_PARAMS image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -705,10 +701,6 @@ def test_save_pretrained_raise_not_implemented_exception(self): except NotImplementedError: pass - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/controlnet/test_controlnet_blip_diffusion.py b/tests/pipelines/controlnet/test_controlnet_blip_diffusion.py index d3992569fed2..b4d3e3aaa8ed 100644 --- a/tests/pipelines/controlnet/test_controlnet_blip_diffusion.py +++ b/tests/pipelines/controlnet/test_controlnet_blip_diffusion.py @@ -68,6 +68,8 @@ class BlipDiffusionControlNetPipelineFastTests(PipelineTesterMixin, unittest.Tes "prompt_reps", ] + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) text_encoder_config = CLIPTextConfig( @@ -220,7 +222,3 @@ def test_blipdiffusion_controlnet(self): assert ( np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 ), f" expected_slice {expected_slice}, but got {image_slice.flatten()}" - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/controlnet/test_controlnet_img2img.py b/tests/pipelines/controlnet/test_controlnet_img2img.py index 83d979d76f1b..7c4ae716b37d 100644 --- a/tests/pipelines/controlnet/test_controlnet_img2img.py +++ b/tests/pipelines/controlnet/test_controlnet_img2img.py @@ -189,10 +189,6 @@ def test_xformers_attention_forwardGenerator_pass(self): def test_inference_batch_single_identical(self): self._test_inference_batch_single_identical(expected_max_diff=2e-3) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class StableDiffusionMultiControlNetPipelineFastTests( IPAdapterTesterMixin, PipelineTesterMixin, PipelineKarrasSchedulerTesterMixin, unittest.TestCase @@ -393,10 +389,6 @@ def test_save_pretrained_raise_not_implemented_exception(self): except NotImplementedError: pass - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/controlnet/test_controlnet_inpaint.py b/tests/pipelines/controlnet/test_controlnet_inpaint.py index fff973cefb96..0e4dba4265e2 100644 --- a/tests/pipelines/controlnet/test_controlnet_inpaint.py +++ b/tests/pipelines/controlnet/test_controlnet_inpaint.py @@ -257,6 +257,8 @@ class MultiControlNetInpaintPipelineFastTests( params = TEXT_GUIDED_IMAGE_INPAINTING_PARAMS batch_params = TEXT_GUIDED_IMAGE_INPAINTING_BATCH_PARAMS + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -441,10 +443,6 @@ def test_save_pretrained_raise_not_implemented_exception(self): except NotImplementedError: pass - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/controlnet/test_controlnet_inpaint_sdxl.py b/tests/pipelines/controlnet/test_controlnet_inpaint_sdxl.py index 628fc2823c53..6e752804e2e0 100644 --- a/tests/pipelines/controlnet/test_controlnet_inpaint_sdxl.py +++ b/tests/pipelines/controlnet/test_controlnet_inpaint_sdxl.py @@ -78,6 +78,8 @@ class ControlNetPipelineSDXLFastTests( } ) + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -352,7 +354,3 @@ def test_save_load_optional_components(self): def test_float16_inference(self): super().test_float16_inference(expected_max_diff=5e-1) - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/controlnet/test_controlnet_sdxl.py b/tests/pipelines/controlnet/test_controlnet_sdxl.py index 0d079a08fa97..fc15973faeaf 100644 --- a/tests/pipelines/controlnet/test_controlnet_sdxl.py +++ b/tests/pipelines/controlnet/test_controlnet_sdxl.py @@ -478,10 +478,6 @@ def new_step(self, *args, **kwargs): ]: assert_run_mixture(steps, split, scheduler_cls_timesteps[0], scheduler_cls_timesteps[1]) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class StableDiffusionXLMultiControlNetPipelineFastTests( PipelineTesterMixin, PipelineKarrasSchedulerTesterMixin, SDXLOptionalComponentsTesterMixin, unittest.TestCase @@ -491,6 +487,8 @@ class StableDiffusionXLMultiControlNetPipelineFastTests( batch_params = TEXT_TO_IMAGE_BATCH_PARAMS image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -687,10 +685,6 @@ def test_inference_batch_single_identical(self): def test_save_load_optional_components(self): return self._test_save_load_optional_components() - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class StableDiffusionXLMultiControlNetOneModelPipelineFastTests( PipelineKarrasSchedulerTesterMixin, PipelineTesterMixin, SDXLOptionalComponentsTesterMixin, unittest.TestCase @@ -700,6 +694,8 @@ class StableDiffusionXLMultiControlNetOneModelPipelineFastTests( batch_params = TEXT_TO_IMAGE_BATCH_PARAMS image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -895,10 +891,6 @@ def test_negative_conditions(self): self.assertTrue(np.abs(image_slice_without_neg_cond - image_slice_with_neg_cond).max() > 1e-2) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/controlnet/test_controlnet_sdxl_img2img.py b/tests/pipelines/controlnet/test_controlnet_sdxl_img2img.py index 9e9beae4b191..6a5976bd0dda 100644 --- a/tests/pipelines/controlnet/test_controlnet_sdxl_img2img.py +++ b/tests/pipelines/controlnet/test_controlnet_sdxl_img2img.py @@ -361,7 +361,3 @@ def test_stable_diffusion_xl_prompt_embeds(self): # make sure that it's equal assert np.abs(image_slice_1.flatten() - image_slice_2.flatten()).max() < 1e-4 - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/i2vgen_xl/test_i2vgenxl.py b/tests/pipelines/i2vgen_xl/test_i2vgenxl.py index 7ef971427434..f4d6165f9010 100644 --- a/tests/pipelines/i2vgen_xl/test_i2vgenxl.py +++ b/tests/pipelines/i2vgen_xl/test_i2vgenxl.py @@ -59,6 +59,8 @@ class I2VGenXLPipelineFastTests(SDFunctionTesterMixin, PipelineTesterMixin, unit # No `output_type`. required_optional_params = frozenset(["num_inference_steps", "generator", "latents", "return_dict"]) + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) scheduler = DDIMScheduler( @@ -224,10 +226,6 @@ def test_num_videos_per_prompt(self): assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/kandinsky/test_kandinsky.py b/tests/pipelines/kandinsky/test_kandinsky.py index 2d67f45636cf..1a13ec75d082 100644 --- a/tests/pipelines/kandinsky/test_kandinsky.py +++ b/tests/pipelines/kandinsky/test_kandinsky.py @@ -204,6 +204,8 @@ class KandinskyPipelineFastTests(PipelineTesterMixin, unittest.TestCase): ] test_xformers_attention = False + supports_dduf = False + def get_dummy_components(self): dummy = Dummies() return dummy.get_dummy_components() @@ -271,10 +273,6 @@ def test_offloads(self): assert np.abs(image_slices[0] - image_slices[1]).max() < 1e-3 assert np.abs(image_slices[0] - image_slices[2]).max() < 1e-3 - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/kandinsky/test_kandinsky_combined.py b/tests/pipelines/kandinsky/test_kandinsky_combined.py index 22716be2b9da..1b2c48524a2a 100644 --- a/tests/pipelines/kandinsky/test_kandinsky_combined.py +++ b/tests/pipelines/kandinsky/test_kandinsky_combined.py @@ -52,6 +52,8 @@ class KandinskyPipelineCombinedFastTests(PipelineTesterMixin, unittest.TestCase) ] test_xformers_attention = True + supports_dduf = False + def get_dummy_components(self): dummy = Dummies() prior_dummy = PriorDummies() @@ -139,10 +141,6 @@ def test_float16_inference(self): def test_dict_tuple_outputs_equivalent(self): super().test_dict_tuple_outputs_equivalent(expected_max_difference=5e-4) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class KandinskyPipelineImg2ImgCombinedFastTests(PipelineTesterMixin, unittest.TestCase): pipeline_class = KandinskyImg2ImgCombinedPipeline @@ -164,6 +162,8 @@ class KandinskyPipelineImg2ImgCombinedFastTests(PipelineTesterMixin, unittest.Te ] test_xformers_attention = False + supports_dduf = False + def get_dummy_components(self): dummy = Img2ImgDummies() prior_dummy = PriorDummies() @@ -252,10 +252,6 @@ def test_dict_tuple_outputs_equivalent(self): def test_save_load_optional_components(self): super().test_save_load_optional_components(expected_max_difference=5e-4) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class KandinskyPipelineInpaintCombinedFastTests(PipelineTesterMixin, unittest.TestCase): pipeline_class = KandinskyInpaintCombinedPipeline @@ -277,6 +273,8 @@ class KandinskyPipelineInpaintCombinedFastTests(PipelineTesterMixin, unittest.Te ] test_xformers_attention = False + supports_dduf = False + def get_dummy_components(self): dummy = InpaintDummies() prior_dummy = PriorDummies() @@ -371,7 +369,3 @@ def test_save_load_optional_components(self): def test_save_load_local(self): super().test_save_load_local(expected_max_difference=5e-3) - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/kandinsky/test_kandinsky_img2img.py b/tests/pipelines/kandinsky/test_kandinsky_img2img.py index 916f8b669750..23f13ffee223 100644 --- a/tests/pipelines/kandinsky/test_kandinsky_img2img.py +++ b/tests/pipelines/kandinsky/test_kandinsky_img2img.py @@ -226,6 +226,8 @@ class KandinskyImg2ImgPipelineFastTests(PipelineTesterMixin, unittest.TestCase): ] test_xformers_attention = False + supports_dduf = False + def get_dummy_components(self): dummies = Dummies() return dummies.get_dummy_components() @@ -295,10 +297,6 @@ def test_offloads(self): def test_dict_tuple_outputs_equivalent(self): super().test_dict_tuple_outputs_equivalent(expected_max_difference=5e-4) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/kandinsky/test_kandinsky_inpaint.py b/tests/pipelines/kandinsky/test_kandinsky_inpaint.py index 162de6356efa..ebb1a4d88739 100644 --- a/tests/pipelines/kandinsky/test_kandinsky_inpaint.py +++ b/tests/pipelines/kandinsky/test_kandinsky_inpaint.py @@ -220,6 +220,8 @@ class KandinskyInpaintPipelineFastTests(PipelineTesterMixin, unittest.TestCase): ] test_xformers_attention = False + supports_dduf = False + def get_dummy_components(self): dummies = Dummies() return dummies.get_dummy_components() @@ -293,10 +295,6 @@ def test_offloads(self): def test_float16_inference(self): super().test_float16_inference(expected_max_diff=5e-1) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @nightly @require_torch_gpu diff --git a/tests/pipelines/kandinsky/test_kandinsky_prior.py b/tests/pipelines/kandinsky/test_kandinsky_prior.py index e57e83cd9551..abb53bfb792f 100644 --- a/tests/pipelines/kandinsky/test_kandinsky_prior.py +++ b/tests/pipelines/kandinsky/test_kandinsky_prior.py @@ -184,6 +184,8 @@ class KandinskyPriorPipelineFastTests(PipelineTesterMixin, unittest.TestCase): ] test_xformers_attention = False + supports_dduf = False + def get_dummy_components(self): dummy = Dummies() return dummy.get_dummy_components() @@ -236,7 +238,3 @@ def test_attention_slicing_forward_pass(self): test_max_difference=test_max_difference, test_mean_pixel_difference=test_mean_pixel_difference, ) - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/kandinsky2_2/test_kandinsky_combined.py b/tests/pipelines/kandinsky2_2/test_kandinsky_combined.py index 4fda67f95e7d..bbf2f08a7b08 100644 --- a/tests/pipelines/kandinsky2_2/test_kandinsky_combined.py +++ b/tests/pipelines/kandinsky2_2/test_kandinsky_combined.py @@ -57,6 +57,8 @@ class KandinskyV22PipelineCombinedFastTests(PipelineTesterMixin, unittest.TestCa test_xformers_attention = True callback_cfg_params = ["image_embds"] + supports_dduf = False + def get_dummy_components(self): dummy = Dummies() prior_dummy = PriorDummies() @@ -159,10 +161,6 @@ def test_callback_inputs(self): def test_callback_cfg(self): pass - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class KandinskyV22PipelineImg2ImgCombinedFastTests(PipelineTesterMixin, unittest.TestCase): pipeline_class = KandinskyV22Img2ImgCombinedPipeline @@ -185,6 +183,8 @@ class KandinskyV22PipelineImg2ImgCombinedFastTests(PipelineTesterMixin, unittest test_xformers_attention = False callback_cfg_params = ["image_embds"] + supports_dduf = False + def get_dummy_components(self): dummy = Img2ImgDummies() prior_dummy = PriorDummies() @@ -285,10 +285,6 @@ def test_callback_inputs(self): def test_callback_cfg(self): pass - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class KandinskyV22PipelineInpaintCombinedFastTests(PipelineTesterMixin, unittest.TestCase): pipeline_class = KandinskyV22InpaintCombinedPipeline @@ -310,6 +306,8 @@ class KandinskyV22PipelineInpaintCombinedFastTests(PipelineTesterMixin, unittest ] test_xformers_attention = False + supports_dduf = False + def get_dummy_components(self): dummy = InpaintDummies() prior_dummy = PriorDummies() @@ -412,7 +410,3 @@ def test_callback_inputs(self): def test_callback_cfg(self): pass - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/kandinsky2_2/test_kandinsky_prior.py b/tests/pipelines/kandinsky2_2/test_kandinsky_prior.py index 451aeee92320..bdec6c132f80 100644 --- a/tests/pipelines/kandinsky2_2/test_kandinsky_prior.py +++ b/tests/pipelines/kandinsky2_2/test_kandinsky_prior.py @@ -186,6 +186,8 @@ class KandinskyV22PriorPipelineFastTests(PipelineTesterMixin, unittest.TestCase) callback_cfg_params = ["prompt_embeds", "text_encoder_hidden_states", "text_mask"] test_xformers_attention = False + supports_dduf = False + def get_dummy_components(self): dummies = Dummies() return dummies.get_dummy_components() @@ -277,7 +279,3 @@ def callback_inputs_test(pipe, i, t, callback_kwargs): output = pipe(**inputs)[0] assert output.abs().sum() == 0 - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/kandinsky2_2/test_kandinsky_prior_emb2emb.py b/tests/pipelines/kandinsky2_2/test_kandinsky_prior_emb2emb.py index cb2c4eed7501..0ea32981d518 100644 --- a/tests/pipelines/kandinsky2_2/test_kandinsky_prior_emb2emb.py +++ b/tests/pipelines/kandinsky2_2/test_kandinsky_prior_emb2emb.py @@ -59,6 +59,8 @@ class KandinskyV22PriorEmb2EmbPipelineFastTests(PipelineTesterMixin, unittest.Te ] test_xformers_attention = False + supports_dduf = False + @property def text_embedder_hidden_size(self): return 32 @@ -240,7 +242,3 @@ def test_attention_slicing_forward_pass(self): test_max_difference=test_max_difference, test_mean_pixel_difference=test_mean_pixel_difference, ) - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/kolors/test_kolors.py b/tests/pipelines/kolors/test_kolors.py index 52904d7b35f8..e88ba0282096 100644 --- a/tests/pipelines/kolors/test_kolors.py +++ b/tests/pipelines/kolors/test_kolors.py @@ -47,6 +47,8 @@ class KolorsPipelineFastTests(PipelineTesterMixin, unittest.TestCase): image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS 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): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -141,7 +143,3 @@ def test_save_load_float16(self): def test_inference_batch_single_identical(self): self._test_inference_batch_single_identical(expected_max_diff=5e-4) - - @unittest.skip("Test unsupported because of custom code.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/kolors/test_kolors_img2img.py b/tests/pipelines/kolors/test_kolors_img2img.py index c2a8a4bca758..9f1ca43a081f 100644 --- a/tests/pipelines/kolors/test_kolors_img2img.py +++ b/tests/pipelines/kolors/test_kolors_img2img.py @@ -51,6 +51,8 @@ class KolorsPipelineImg2ImgFastTests(PipelineTesterMixin, unittest.TestCase): image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS 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 def get_dummy_components(self, time_cond_proj_dim=None): torch.manual_seed(0) @@ -150,7 +152,3 @@ def test_inference_batch_single_identical(self): def test_float16_inference(self): super().test_float16_inference(expected_max_diff=7e-2) - - @unittest.skip("Test unsupported because of custom code.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/lumina/test_lumina_nextdit.py b/tests/pipelines/lumina/test_lumina_nextdit.py index 4c677cfa2acf..e0fd06847b77 100644 --- a/tests/pipelines/lumina/test_lumina_nextdit.py +++ b/tests/pipelines/lumina/test_lumina_nextdit.py @@ -31,6 +31,8 @@ class LuminaText2ImgPipelinePipelineFastTests(unittest.TestCase, PipelineTesterM ) batch_params = frozenset(["prompt", "negative_prompt"]) + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) transformer = LuminaNextDiT2DModel( @@ -123,10 +125,6 @@ def test_lumina_prompt_embeds(self): def test_xformers_attention_forwardGenerator_pass(self): pass - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/musicldm/test_musicldm.py b/tests/pipelines/musicldm/test_musicldm.py index 7a7905ee76c6..bdd536b6ff86 100644 --- a/tests/pipelines/musicldm/test_musicldm.py +++ b/tests/pipelines/musicldm/test_musicldm.py @@ -65,6 +65,8 @@ class MusicLDMPipelineFastTests(PipelineTesterMixin, unittest.TestCase): ] ) + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -404,10 +406,6 @@ def test_to_dtype(self): model_dtypes = {key: component.dtype for key, component in components.items() if hasattr(component, "dtype")} self.assertTrue(all(dtype == torch.float16 for dtype in model_dtypes.values())) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @nightly @require_torch_gpu diff --git a/tests/pipelines/pag/test_pag_kolors.py b/tests/pipelines/pag/test_pag_kolors.py index 8ee4c433e3f1..cf9466988d85 100644 --- a/tests/pipelines/pag/test_pag_kolors.py +++ b/tests/pipelines/pag/test_pag_kolors.py @@ -56,6 +56,8 @@ class KolorsPAGPipelineFastTests( image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS 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 def get_dummy_components(self, time_cond_proj_dim=None): torch.manual_seed(0) @@ -250,7 +252,3 @@ def test_pag_inference(self): def test_inference_batch_single_identical(self): self._test_inference_batch_single_identical(expected_max_diff=3e-3) - - @unittest.skip("Test is not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/pag/test_pag_sana.py b/tests/pipelines/pag/test_pag_sana.py index cfbab250081d..a2c657297860 100644 --- a/tests/pipelines/pag/test_pag_sana.py +++ b/tests/pipelines/pag/test_pag_sana.py @@ -53,6 +53,8 @@ class SanaPAGPipelineFastTests(PipelineTesterMixin, unittest.TestCase): ) test_xformers_attention = False + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) transformer = SanaTransformer2DModel( @@ -337,7 +339,3 @@ def test_inference_batch_single_identical(self): def test_float16_inference(self): # Requires higher tolerance as model seems very sensitive to dtype super().test_float16_inference(expected_max_diff=0.08) - - @unittest.skip("Test is not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/pag/test_pag_sdxl_img2img.py b/tests/pipelines/pag/test_pag_sdxl_img2img.py index 1a8657c793b0..33bd47bfee10 100644 --- a/tests/pipelines/pag/test_pag_sdxl_img2img.py +++ b/tests/pipelines/pag/test_pag_sdxl_img2img.py @@ -82,6 +82,8 @@ class StableDiffusionXLPAGImg2ImgPipelineFastTests( {"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 def get_dummy_components( self, skip_first_text_encoder=False, time_cond_proj_dim=None, requires_aesthetics_score=False @@ -265,10 +267,6 @@ def test_pag_inference(self): max_diff = np.abs(image_slice.flatten() - expected_slice).max() assert max_diff < 1e-3, f"output is different from expected, {image_slice.flatten()}" - @unittest.skip("Test is not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/pag/test_pag_sdxl_inpaint.py b/tests/pipelines/pag/test_pag_sdxl_inpaint.py index e69cb248766a..8378b07e9f74 100644 --- a/tests/pipelines/pag/test_pag_sdxl_inpaint.py +++ b/tests/pipelines/pag/test_pag_sdxl_inpaint.py @@ -82,6 +82,8 @@ class StableDiffusionXLPAGInpaintPipelineFastTests( {"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 def get_dummy_components( self, skip_first_text_encoder=False, time_cond_proj_dim=None, requires_aesthetics_score=False @@ -270,10 +272,6 @@ def test_pag_inference(self): max_diff = np.abs(image_slice.flatten() - expected_slice).max() assert max_diff < 1e-3, f"output is different from expected, {image_slice.flatten()}" - @unittest.skip("Test is not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/paint_by_example/test_paint_by_example.py b/tests/pipelines/paint_by_example/test_paint_by_example.py index a3d3d244175d..6b668de2762a 100644 --- a/tests/pipelines/paint_by_example/test_paint_by_example.py +++ b/tests/pipelines/paint_by_example/test_paint_by_example.py @@ -46,6 +46,8 @@ class PaintByExamplePipelineFastTests(PipelineTesterMixin, unittest.TestCase): batch_params = IMAGE_GUIDED_IMAGE_INPAINTING_BATCH_PARAMS image_params = frozenset([]) # TO_DO: update the image_prams once refactored VaeImageProcessor.preprocess + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -170,10 +172,6 @@ def test_paint_by_example_image_tensor(self): def test_inference_batch_single_identical(self): super().test_inference_batch_single_identical(expected_max_diff=3e-3) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @nightly @require_torch_gpu diff --git a/tests/pipelines/shap_e/test_shap_e_img2img.py b/tests/pipelines/shap_e/test_shap_e_img2img.py index f5d41f61cfa0..ac7096874b31 100644 --- a/tests/pipelines/shap_e/test_shap_e_img2img.py +++ b/tests/pipelines/shap_e/test_shap_e_img2img.py @@ -50,6 +50,8 @@ class ShapEImg2ImgPipelineFastTests(PipelineTesterMixin, unittest.TestCase): ] test_xformers_attention = False + supports_dduf = False + @property def text_embedder_hidden_size(self): return 16 @@ -246,10 +248,6 @@ def test_save_load_local(self): def test_sequential_cpu_offload_forward_pass(self): pass - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @nightly @require_torch_gpu diff --git a/tests/pipelines/stable_audio/test_stable_audio.py b/tests/pipelines/stable_audio/test_stable_audio.py index 41ac94891c6f..b2ca3ddd0e84 100644 --- a/tests/pipelines/stable_audio/test_stable_audio.py +++ b/tests/pipelines/stable_audio/test_stable_audio.py @@ -70,6 +70,7 @@ class StableAudioPipelineFastTests(PipelineTesterMixin, unittest.TestCase): ) # There is not xformers version of the StableAudioPipeline custom attention processor test_xformers_attention = False + supports_dduf = False def get_dummy_components(self): torch.manual_seed(0) diff --git a/tests/pipelines/stable_diffusion_2/test_stable_diffusion_depth.py b/tests/pipelines/stable_diffusion_2/test_stable_diffusion_depth.py index ace1de5f67e2..430d99781a25 100644 --- a/tests/pipelines/stable_diffusion_2/test_stable_diffusion_depth.py +++ b/tests/pipelines/stable_diffusion_2/test_stable_diffusion_depth.py @@ -76,6 +76,8 @@ class StableDiffusionDepth2ImgPipelineFastTests( image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS callback_cfg_params = TEXT_TO_IMAGE_CALLBACK_CFG_PARAMS.union({"depth_mask"}) + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -367,10 +369,6 @@ def test_attention_slicing_forward_pass(self): def test_inference_batch_single_identical(self): super().test_inference_batch_single_identical(expected_max_diff=7e-3) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/stable_diffusion_adapter/test_stable_diffusion_adapter.py b/tests/pipelines/stable_diffusion_adapter/test_stable_diffusion_adapter.py index 3833a76c63f0..15f298c67e11 100644 --- a/tests/pipelines/stable_diffusion_adapter/test_stable_diffusion_adapter.py +++ b/tests/pipelines/stable_diffusion_adapter/test_stable_diffusion_adapter.py @@ -336,10 +336,6 @@ def test_adapter_lcm_custom_timesteps(self): assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class StableDiffusionFullAdapterPipelineFastTests( AdapterTests, PipelineTesterMixin, PipelineFromPipeTesterMixin, unittest.TestCase @@ -393,6 +389,8 @@ def test_stable_diffusion_adapter_default_case(self): class StableDiffusionMultiAdapterPipelineFastTests(AdapterTests, PipelineTesterMixin, unittest.TestCase): + supports_dduf = False + 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) diff --git a/tests/pipelines/stable_diffusion_gligen_text_image/test_stable_diffusion_gligen_text_image.py b/tests/pipelines/stable_diffusion_gligen_text_image/test_stable_diffusion_gligen_text_image.py index 3488f1e6f499..15e4c60db82d 100644 --- a/tests/pipelines/stable_diffusion_gligen_text_image/test_stable_diffusion_gligen_text_image.py +++ b/tests/pipelines/stable_diffusion_gligen_text_image/test_stable_diffusion_gligen_text_image.py @@ -66,6 +66,8 @@ class GligenTextImagePipelineFastTests( image_params = TEXT_TO_IMAGE_IMAGE_PARAMS image_latents_params = TEXT_TO_IMAGE_IMAGE_PARAMS + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -205,7 +207,3 @@ def test_attention_slicing_forward_pass(self): def test_inference_batch_single_identical(self): super().test_inference_batch_single_identical(batch_size=3, expected_max_diff=3e-3) - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/stable_diffusion_image_variation/test_stable_diffusion_image_variation.py b/tests/pipelines/stable_diffusion_image_variation/test_stable_diffusion_image_variation.py index 7ba2be0ed3ab..d7567afdee1f 100644 --- a/tests/pipelines/stable_diffusion_image_variation/test_stable_diffusion_image_variation.py +++ b/tests/pipelines/stable_diffusion_image_variation/test_stable_diffusion_image_variation.py @@ -58,6 +58,8 @@ class StableDiffusionImageVariationPipelineFastTests( # TO-DO: update image_params once pipeline is refactored with VaeImageProcessor.preprocess image_latents_params = frozenset([]) + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -160,10 +162,6 @@ def test_stable_diffusion_img_variation_multiple_images(self): def test_inference_batch_single_identical(self): super().test_inference_batch_single_identical(expected_max_diff=3e-3) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_adapter.py b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_adapter.py index 06b6fcc4c699..b590b0a9a24d 100644 --- a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_adapter.py +++ b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_adapter.py @@ -422,6 +422,8 @@ def test_adapter_sdxl_lcm_custom_timesteps(self): class StableDiffusionXLMultiAdapterPipelineFastTests( StableDiffusionXLAdapterPipelineFastTests, PipelineTesterMixin, unittest.TestCase ): + supports_dduf = False + 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) @@ -671,7 +673,3 @@ def test_adapter_sdxl_lcm_custom_timesteps(self): print(",".join(debug)) assert np.abs(image_slice.flatten() - expected_slice).max() < 1e-2 - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_img2img.py b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_img2img.py index 4cb0b056eb4b..ceec86a811c0 100644 --- a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_img2img.py +++ b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_img2img.py @@ -77,6 +77,8 @@ class StableDiffusionXLImg2ImgPipelineFastTests( {"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): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -515,10 +517,6 @@ def callback_on_step_end(pipe, i, t, callback_kwargs): # they should be the same assert torch.allclose(intermediate_latent, output_interrupted, atol=1e-4) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - class StableDiffusionXLImg2ImgRefinerOnlyPipelineFastTests( PipelineLatentTesterMixin, PipelineTesterMixin, SDXLOptionalComponentsTesterMixin, unittest.TestCase diff --git a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_inpaint.py b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_inpaint.py index 39395d5ffc06..c759f4c112d9 100644 --- a/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_inpaint.py +++ b/tests/pipelines/stable_diffusion_xl/test_stable_diffusion_xl_inpaint.py @@ -72,6 +72,8 @@ class StableDiffusionXLInpaintPipelineFastTests( } ) + supports_dduf = False + def get_dummy_components(self, skip_first_text_encoder=False, time_cond_proj_dim=None): torch.manual_seed(0) unet = UNet2DConditionModel( @@ -815,7 +817,3 @@ def callback_on_step_end(pipe, i, t, callback_kwargs): # compare the intermediate latent to the output of the interrupted process # they should be the same assert torch.allclose(intermediate_latent, output_interrupted, atol=1e-4) - - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass diff --git a/tests/pipelines/stable_unclip/test_stable_unclip_img2img.py b/tests/pipelines/stable_unclip/test_stable_unclip_img2img.py index d5893c04627c..34f2553a9184 100644 --- a/tests/pipelines/stable_unclip/test_stable_unclip_img2img.py +++ b/tests/pipelines/stable_unclip/test_stable_unclip_img2img.py @@ -51,6 +51,8 @@ class StableUnCLIPImg2ImgPipelineFastTests( ) # TO-DO: update image_params once pipeline is refactored with VaeImageProcessor.preprocess image_latents_params = frozenset([]) + supports_dduf = False + def get_dummy_components(self): embedder_hidden_size = 32 embedder_projection_dim = embedder_hidden_size @@ -205,10 +207,6 @@ def test_inference_batch_single_identical(self): def test_xformers_attention_forwardGenerator_pass(self): self._test_xformers_attention_forwardGenerator_pass(test_max_difference=False) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @nightly @require_torch_gpu diff --git a/tests/pipelines/stable_video_diffusion/test_stable_video_diffusion.py b/tests/pipelines/stable_video_diffusion/test_stable_video_diffusion.py index 5624d3a39b98..352477ecec56 100644 --- a/tests/pipelines/stable_video_diffusion/test_stable_video_diffusion.py +++ b/tests/pipelines/stable_video_diffusion/test_stable_video_diffusion.py @@ -58,6 +58,8 @@ class StableVideoDiffusionPipelineFastTests(PipelineTesterMixin, unittest.TestCa ] ) + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNetSpatioTemporalConditionModel( @@ -511,10 +513,6 @@ def test_disable_cfg(self): output = pipe(**inputs).frames self.assertEqual(len(output.shape), 5) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @slow @require_torch_gpu diff --git a/tests/pipelines/test_pipelines_common.py b/tests/pipelines/test_pipelines_common.py index 0a2a884badb6..d639dc4d763e 100644 --- a/tests/pipelines/test_pipelines_common.py +++ b/tests/pipelines/test_pipelines_common.py @@ -988,6 +988,8 @@ class PipelineTesterMixin: test_xformers_attention = True + supports_dduf = True + def get_generator(self, seed): device = torch_device if torch_device != "mps" else "cpu" generator = torch.Generator(device).manual_seed(seed) @@ -1996,6 +1998,9 @@ def test_StableDiffusionMixin_component(self): @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() diff --git a/tests/pipelines/unclip/test_unclip_image_variation.py b/tests/pipelines/unclip/test_unclip_image_variation.py index dcd3f5bb9835..23a6cd6663b7 100644 --- a/tests/pipelines/unclip/test_unclip_image_variation.py +++ b/tests/pipelines/unclip/test_unclip_image_variation.py @@ -66,6 +66,7 @@ class UnCLIPImageVariationPipelineFastTests(PipelineTesterMixin, unittest.TestCa "super_res_num_inference_steps", ] test_xformers_attention = False + supports_dduf = False @property def text_embedder_hidden_size(self): @@ -492,10 +493,6 @@ def test_save_load_optional_components(self): def test_float16_inference(self): super().test_float16_inference(expected_max_diff=1.0) - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @nightly @require_torch_gpu diff --git a/tests/pipelines/unidiffuser/test_unidiffuser.py b/tests/pipelines/unidiffuser/test_unidiffuser.py index 6bb3d7b7e7d0..310e46a2e8c6 100644 --- a/tests/pipelines/unidiffuser/test_unidiffuser.py +++ b/tests/pipelines/unidiffuser/test_unidiffuser.py @@ -86,6 +86,8 @@ class UniDiffuserPipelineFastTests( # vae_latents, not latents, is the argument that corresponds to VAE latent inputs image_latents_params = frozenset(["vae_latents"]) + supports_dduf = False + def get_dummy_components(self): unet = UniDiffuserModel.from_pretrained( "hf-internal-testing/unidiffuser-diffusers-test", @@ -576,10 +578,6 @@ def test_unidiffuser_default_img2text_v1_cuda_fp16(self): expected_text_prefix = '" This This' assert text[0][: len(expected_text_prefix)] == expected_text_prefix - @unittest.skip("Test not supported.") - def test_save_load_dduf(self): - pass - @nightly @require_torch_gpu From da402da44f7e57deea7a4e12c692ba455c043077 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Tue, 7 Jan 2025 17:58:13 +0100 Subject: [PATCH 62/65] last one --- tests/pipelines/controlnet/test_controlnet_img2img.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/pipelines/controlnet/test_controlnet_img2img.py b/tests/pipelines/controlnet/test_controlnet_img2img.py index 7c4ae716b37d..516fcc513b99 100644 --- a/tests/pipelines/controlnet/test_controlnet_img2img.py +++ b/tests/pipelines/controlnet/test_controlnet_img2img.py @@ -198,6 +198,8 @@ class StableDiffusionMultiControlNetPipelineFastTests( batch_params = TEXT_GUIDED_IMAGE_VARIATION_BATCH_PARAMS image_params = frozenset([]) # TO_DO: add image_params once refactored VaeImageProcessor.preprocess + supports_dduf = False + def get_dummy_components(self): torch.manual_seed(0) unet = UNet2DConditionModel( From ac420af2c35a7aa93c899b17af8dd97cae951dd7 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Mon, 13 Jan 2025 17:26:16 +0100 Subject: [PATCH 63/65] fix logic --- src/diffusers/models/model_loading_utils.py | 13 ++++++++----- src/diffusers/utils/hub_utils.py | 10 ++++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index 7b570604b6fd..f2a4884ce4ac 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -136,7 +136,6 @@ def load_state_dict( 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. @@ -152,8 +151,6 @@ def load_state_dict( # tensors are loaded on cpu with dduf_entries[checkpoint_file].as_mmap() as mm: return safetensors.torch.load(mm) - if disable_mmap: - return safetensors.torch.load(open(checkpoint_file, "rb").read()) else: return safetensors.torch.load_file(checkpoint_file, device="cpu") elif file_extension == GGUF_FILE_EXTENSION: @@ -345,8 +342,14 @@ def _merge_sharded_checkpoints( # Load tensors from each unique file for file_name in files_to_load: part_file_path = os.path.join(sharded_ckpt_cached_folder, file_name) - if not os.path.exists(part_file_path) or (dduf_entries and part_file_path not in dduf_entries): - raise FileNotFoundError(f"Part file {file_name} not found.") + if dduf_entries: + # If dduf_entries is provided, check if part_file_path is in it + if part_file_path not in dduf_entries: + raise FileNotFoundError(f"Part file {file_name} not found.") + else: + # If dduf_entries is not provided, check if the file exists on disk + if not os.path.exists(part_file_path): + raise FileNotFoundError(f"Part file {file_name} not found.") if is_safetensors: if dduf_entries: diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index db5d9c5afa1a..ddcfbaa23233 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -449,8 +449,14 @@ def _get_checkpoint_shard_files( 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). """ - if not os.path.isfile(index_filename) and (dduf_entries and index_filename not in dduf_entries): - raise ValueError(f"Can't find a checkpoint index ({index_filename}) in {pretrained_model_name_or_path}.") + if dduf_entries: + # If dduf_entries is provided, check if part_file_path is in it + 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 dduf_entries is not provided, check if the file exists on disk + if not os.path.isfile(index_filename): + raise ValueError(f"Can't find a checkpoint index ({index_filename}) in {pretrained_model_name_or_path}.") if dduf_entries: index = json.loads(dduf_entries[index_filename].read_text()) From f62527fd78523a0079d8348a6da89372dbb148ab Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Mon, 13 Jan 2025 17:27:25 +0100 Subject: [PATCH 64/65] remove comment --- src/diffusers/models/model_loading_utils.py | 2 -- src/diffusers/utils/hub_utils.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index f2a4884ce4ac..66968b91caba 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -343,11 +343,9 @@ def _merge_sharded_checkpoints( for file_name in files_to_load: part_file_path = os.path.join(sharded_ckpt_cached_folder, file_name) if dduf_entries: - # If dduf_entries is provided, check if part_file_path is in it if part_file_path not in dduf_entries: raise FileNotFoundError(f"Part file {file_name} not found.") else: - # If dduf_entries is not provided, check if the file exists on disk if not os.path.exists(part_file_path): raise FileNotFoundError(f"Part file {file_name} not found.") diff --git a/src/diffusers/utils/hub_utils.py b/src/diffusers/utils/hub_utils.py index ddcfbaa23233..839e696c0ce9 100644 --- a/src/diffusers/utils/hub_utils.py +++ b/src/diffusers/utils/hub_utils.py @@ -450,11 +450,9 @@ def _get_checkpoint_shard_files( index (downloaded and cached if `pretrained_model_name_or_path` is a model ID on the Hub). """ if dduf_entries: - # If dduf_entries is provided, check if part_file_path is in it 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 dduf_entries is not provided, check if the file exists on disk if not os.path.isfile(index_filename): raise ValueError(f"Can't find a checkpoint index ({index_filename}) in {pretrained_model_name_or_path}.") From c899fd02c85e15cbf45753d4d08ac7ffc85a6b00 Mon Sep 17 00:00:00 2001 From: Marc Sun Date: Mon, 13 Jan 2025 17:57:55 +0100 Subject: [PATCH 65/65] revert changes --- src/diffusers/models/model_loading_utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/diffusers/models/model_loading_utils.py b/src/diffusers/models/model_loading_utils.py index 66968b91caba..386c07e8747c 100644 --- a/src/diffusers/models/model_loading_utils.py +++ b/src/diffusers/models/model_loading_utils.py @@ -136,6 +136,7 @@ def load_state_dict( 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. @@ -151,6 +152,8 @@ def load_state_dict( # tensors are loaded on cpu with dduf_entries[checkpoint_file].as_mmap() as mm: return safetensors.torch.load(mm) + if disable_mmap: + return safetensors.torch.load(open(checkpoint_file, "rb").read()) else: return safetensors.torch.load_file(checkpoint_file, device="cpu") elif file_extension == GGUF_FILE_EXTENSION: