Spaces:
Runtime error
Runtime error
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved. | |
# Copyright 2022 The HuggingFace Team. All rights reserved. | |
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
import importlib | |
import inspect | |
import os | |
import tempfile | |
from dataclasses import dataclass | |
from typing import Any, Dict, List, Optional, Union | |
import numpy as np | |
import paddle | |
import paddle.nn as nn | |
import PIL | |
from huggingface_hub import ( | |
create_repo, | |
get_hf_file_metadata, | |
hf_hub_url, | |
repo_type_and_id_from_hf_id, | |
upload_folder, | |
) | |
from huggingface_hub.utils import EntryNotFoundError | |
from packaging import version | |
from PIL import Image | |
from tqdm.auto import tqdm | |
from . import FastDeployRuntimeModel | |
from .configuration_utils import ConfigMixin | |
from .utils import PPDIFFUSERS_CACHE, BaseOutput, deprecate, logging | |
INDEX_FILE = "model_state.pdparams" | |
CUSTOM_PIPELINE_FILE_NAME = "pipeline.py" | |
DUMMY_MODULES_FOLDER = "ppdiffusers.utils" | |
PADDLENLP_DUMMY_MODULES_FOLDER = "paddlenlp.transformers.utils" | |
logger = logging.get_logger(__name__) | |
LOADABLE_CLASSES = { | |
"ppdiffusers": { | |
"ModelMixin": ["save_pretrained", "from_pretrained"], | |
"SchedulerMixin": ["save_pretrained", "from_pretrained"], | |
"DiffusionPipeline": ["save_pretrained", "from_pretrained"], | |
"FastDeployRuntimeModel": ["save_pretrained", "from_pretrained"], | |
}, | |
"paddlenlp.transformers": { | |
"PretrainedTokenizer": ["save_pretrained", "from_pretrained"], | |
"PretrainedModel": ["save_pretrained", "from_pretrained"], | |
"FeatureExtractionMixin": ["save_pretrained", "from_pretrained"], | |
"ProcessorMixin": ["save_pretrained", "from_pretrained"], | |
"ImageProcessingMixin": ["save_pretrained", "from_pretrained"], | |
}, | |
} | |
ALL_IMPORTABLE_CLASSES = {} | |
for library in LOADABLE_CLASSES: | |
ALL_IMPORTABLE_CLASSES.update(LOADABLE_CLASSES[library]) | |
class ImagePipelineOutput(BaseOutput): | |
""" | |
Output class for image pipelines. | |
Args: | |
images (`List[PIL.Image.Image]` or `np.ndarray`) | |
List of denoised PIL images of length `batch_size` or numpy array of shape `(batch_size, height, width, | |
num_channels)`. PIL images or numpy array present the denoised images of the diffusion pipeline. | |
""" | |
images: Union[List[PIL.Image.Image], np.ndarray] | |
class AudioPipelineOutput(BaseOutput): | |
""" | |
Output class for audio pipelines. | |
Args: | |
audios (`np.ndarray`) | |
List of denoised samples of shape `(batch_size, num_channels, sample_rate)`. Numpy array present the | |
denoised audio samples of the diffusion pipeline. | |
""" | |
audios: np.ndarray | |
class DiffusionPipeline(ConfigMixin): | |
r""" | |
Base class for all models. | |
[`DiffusionPipeline`] takes care of storing all components (models, schedulers, processors) for diffusion pipelines | |
and handles methods for loading, downloading and saving models as well as a few methods common to all pipelines to: | |
- move all Paddle modules to the device of your choice | |
- enabling/disabling the progress bar for the denoising iteration | |
Class attributes: | |
- **config_name** (`str`) -- name of the config file that will store the class and module names of all | |
- **_optional_components** (List[`str`]) -- list of all components that are optional so they don't have to be | |
passed for the pipeline to function (should be overridden by subclasses). | |
""" | |
config_name = "model_index.json" | |
_optional_components = [] | |
def register_modules(self, **kwargs): | |
# import it here to avoid circular import | |
from . import pipelines | |
for name, module in kwargs.items(): | |
# retrieve library | |
if module is None: | |
register_dict = {name: (None, None)} | |
else: | |
# TODO (junnyu) support paddlenlp.transformers | |
if "paddlenlp" in module.__module__.split(".") or "ppnlp_patch_utils" in module.__module__.split("."): | |
library = "paddlenlp.transformers" | |
else: | |
library = module.__module__.split(".")[0] | |
# check if the module is a pipeline module | |
pipeline_dir = module.__module__.split(".")[-2] if len(module.__module__.split(".")) > 2 else None | |
path = module.__module__.split(".") | |
is_pipeline_module = pipeline_dir in path and hasattr(pipelines, pipeline_dir) | |
# if library is not in LOADABLE_CLASSES, then it is a custom module. | |
# Or if it's a pipeline module, then the module is inside the pipeline | |
# folder so we set the library to module name. | |
if library not in LOADABLE_CLASSES or is_pipeline_module: | |
library = pipeline_dir | |
# retrieve class_name | |
class_name = module.__class__.__name__ | |
register_dict = {name: (library, class_name)} | |
# save model index config | |
self.register_to_config(**register_dict) | |
# set models | |
setattr(self, name, module) | |
def save_pretrained(self, save_directory: Union[str, os.PathLike]): | |
""" | |
Save all variables of the pipeline that can be saved and loaded as well as the pipelines configuration file to | |
a directory. A pipeline variable can be saved and loaded if its class implements both a save and loading | |
method. The pipeline can easily be re-loaded using the `[`~DiffusionPipeline.from_pretrained`]` class method. | |
Arguments: | |
save_directory (`str` or `os.PathLike`): | |
Directory to which to save. Will be created if it doesn't exist. | |
""" | |
self.save_config(save_directory) | |
model_index_dict = dict(self.config) | |
model_index_dict.pop("_class_name") | |
# TODO (junnyu) support old version | |
model_index_dict.pop("_diffusers_paddle_version", None) | |
model_index_dict.pop("_diffusers_version", None) | |
model_index_dict.pop("_ppdiffusers_version", None) | |
model_index_dict.pop("_module", None) | |
expected_modules, optional_kwargs = self._get_signature_keys(self) | |
def is_saveable_module(name, value): | |
if name not in expected_modules: | |
return False | |
if name in self._optional_components and value[0] is None: | |
return False | |
return True | |
model_index_dict = {k: v for k, v in model_index_dict.items() if is_saveable_module(k, v)} | |
for pipeline_component_name in model_index_dict.keys(): | |
sub_model = getattr(self, pipeline_component_name) | |
model_cls = sub_model.__class__ | |
save_method_name = None | |
# search for the model's base class in LOADABLE_CLASSES | |
for library_name, library_classes in LOADABLE_CLASSES.items(): | |
library = importlib.import_module(library_name) | |
for base_class, save_load_methods in library_classes.items(): | |
class_candidate = getattr(library, base_class, None) | |
if class_candidate is not None and issubclass(model_cls, class_candidate): | |
# if we found a suitable base class in LOADABLE_CLASSES then grab its save method | |
save_method_name = save_load_methods[0] | |
break | |
if save_method_name is not None: | |
break | |
save_method = getattr(sub_model, save_method_name) | |
save_method(os.path.join(save_directory, pipeline_component_name)) | |
def save_to_hf_hub( | |
self, | |
repo_id: str, | |
private: Optional[bool] = None, | |
commit_message: Optional[str] = None, | |
revision: Optional[str] = None, | |
create_pr: bool = False, | |
): | |
""" | |
Uploads all elements of this pipeline to a new HuggingFace Hub repository. | |
Args: | |
repo_id (str): Repository name for your model/tokenizer in the Hub. | |
private (bool, optional): Whether the model/tokenizer is set to private | |
commit_message (str, optional) — The summary / title / first line of the generated commit. Defaults to: f"Upload {path_in_repo} with huggingface_hub" | |
revision (str, optional) — The git revision to commit from. Defaults to the head of the "main" branch. | |
create_pr (boolean, optional) — Whether or not to create a Pull Request with that commit. Defaults to False. | |
If revision is not set, PR is opened against the "main" branch. If revision is set and is a branch, PR is opened against this branch. | |
If revision is set and is not a branch name (example: a commit oid), an RevisionNotFoundError is returned by the server. | |
Returns: The url of the commit of your model in the given repository. | |
""" | |
repo_url = create_repo(repo_id, private=private, exist_ok=True) | |
# Infer complete repo_id from repo_url | |
# Can be different from the input `repo_id` if repo_owner was implicit | |
_, repo_owner, repo_name = repo_type_and_id_from_hf_id(repo_url) | |
repo_id = f"{repo_owner}/{repo_name}" | |
# Check if README file already exist in repo | |
try: | |
get_hf_file_metadata(hf_hub_url(repo_id=repo_id, filename="README.md", revision=revision)) | |
has_readme = True | |
except EntryNotFoundError: | |
has_readme = False | |
with tempfile.TemporaryDirectory() as tmp_dir: | |
# save model | |
self.save_pretrained(tmp_dir) | |
# Add readme if does not exist | |
logger.info("README.md not found, adding the default README.md") | |
if not has_readme: | |
with open(os.path.join(tmp_dir, "README.md"), "w") as f: | |
f.write(f"---\nlibrary_name: ppdiffusers\n---\n# {repo_id}") | |
# Upload model and return | |
logger.info(f"Pushing to the {repo_id}. This might take a while") | |
return upload_folder( | |
repo_id=repo_id, | |
repo_type="model", | |
folder_path=tmp_dir, | |
commit_message=commit_message, | |
revision=revision, | |
create_pr=create_pr, | |
) | |
def to(self, paddle_device: Optional[str] = None): | |
if paddle_device is None: | |
return self | |
module_names, _, _ = self.extract_init_dict(dict(self.config)) | |
for name in module_names.keys(): | |
module = getattr(self, name) | |
if isinstance(module, nn.Layer): | |
if module.dtype == paddle.float16 and str(paddle_device) in ["cpu"]: | |
logger.warning( | |
"Pipelines loaded with `paddle_dtype=paddle.float16` cannot run with `cpu` device. It" | |
" is not recommended to move them to `cpu` as running them will fail. Please make" | |
" sure to use an accelerator to run the pipeline in inference, due to the lack of" | |
" support for`float16` operations on this device in Paddle. Please, remove the" | |
" `paddle_dtype=paddle.float16` argument, or use another device for inference." | |
) | |
module.to(paddle_device) | |
return self | |
def device(self): | |
r""" | |
Returns: | |
`paddle.device`: The paddle device on which the pipeline is located. | |
""" | |
module_names, _, _ = self.extract_init_dict(dict(self.config)) | |
for name in module_names.keys(): | |
module = getattr(self, name) | |
if isinstance(module, nn.Layer): | |
return module.place | |
return "cpu" | |
def from_pretrained(cls, pretrained_model_name_or_path: Optional[Union[str, os.PathLike]], **kwargs): | |
r""" | |
Instantiate a Paddle diffusion pipeline from pre-trained pipeline weights. | |
The pipeline is set in evaluation mode by default using `model.eval()` (Dropout modules are deactivated). | |
The warning *Weights from XXX not initialized from pretrained model* means that the weights of XXX do not come | |
pretrained with the rest of the model. It is up to you to train those weights with a downstream fine-tuning | |
task. | |
The warning *Weights from XXX not used in YYY* means that the layer XXX is not used by YYY, therefore those | |
weights are discarded. | |
Parameters: | |
pretrained_model_name_or_path (`str` or `os.PathLike`, *optional*): | |
Can be either: | |
- A string, the *model id* of a pretrained pipeline hosted inside in `https://bj.bcebos.com/paddlenlp/models/community`. | |
like `CompVis/stable-diffusion-v1-4`, `CompVis/ldm-text2im-large-256`. | |
- A path to a *directory* containing pipeline weights saved using | |
[`~DiffusionPipeline.save_pretrained`], e.g., `./my_pipeline_directory/`. | |
paddle_dtype (`str` or `paddle.dtype`, *optional*): | |
Override the default `paddle.dtype` and load the model under this dtype. If `"auto"` is passed the dtype | |
will be automatically derived from the model's weights. | |
output_loading_info(`bool`, *optional*, defaults to `False`): | |
Whether or not to also return a dictionary containing missing keys, unexpected keys and error messages. | |
from_hf_hub (bool, *optional*): | |
Whether to load from Hugging Face Hub. Defaults to False | |
kwargs (remaining dictionary of keyword arguments, *optional*): | |
Can be used to overwrite load - and saveable variables - *i.e.* the pipeline components - of the | |
specific pipeline class. The overwritten components are then directly passed to the pipelines | |
`__init__` method. See example below for more information. | |
Examples: | |
```py | |
>>> from ppdiffusers import DiffusionPipeline | |
>>> # Download pipeline from bos and cache. | |
>>> pipeline = DiffusionPipeline.from_pretrained("CompVis/ldm-text2im-large-256") | |
>>> # Download pipeline that requires an authorization token | |
>>> # For more information on access tokens, please refer to this section | |
>>> # of the documentation](https://huggingface.co/docs/hub/security-tokens) | |
>>> pipeline = DiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5") | |
>>> # Use a different scheduler | |
>>> from ppdiffusers import LMSDiscreteScheduler | |
>>> scheduler = LMSDiscreteScheduler.from_config(pipeline.scheduler.config) | |
>>> pipeline.scheduler = scheduler | |
``` | |
""" | |
cache_dir = kwargs.pop("cache_dir", PPDIFFUSERS_CACHE) | |
paddle_dtype = kwargs.pop("paddle_dtype", None) | |
# (TODO junnyu, we donot suuport this.) | |
# custom_pipeline = kwargs.pop("custom_pipeline", None) | |
# for fastdeploy model | |
runtime_options = kwargs.pop("runtime_options", None) | |
from_hf_hub = kwargs.pop("from_hf_hub", False) | |
# 1. Download the checkpoints and configs | |
if not os.path.isdir(pretrained_model_name_or_path): | |
config_dict = cls.load_config( | |
pretrained_model_name_or_path, | |
cache_dir=cache_dir, | |
from_hf_hub=from_hf_hub, | |
) | |
else: | |
config_dict = cls.load_config(pretrained_model_name_or_path) | |
# 2. Load the pipeline class | |
if cls != DiffusionPipeline: | |
pipeline_class = cls | |
else: | |
diffusers_module = importlib.import_module(cls.__module__.split(".")[0]) | |
pipeline_class = getattr(diffusers_module, config_dict["_class_name"]) | |
# To be removed in 1.0.0 | |
# TODO (junnyu) support old version | |
_ppdiffusers_version = ( | |
config_dict["_diffusers_paddle_version"] | |
if "_diffusers_paddle_version" in config_dict | |
else config_dict["_ppdiffusers_version"] | |
) | |
if pipeline_class.__name__ == "StableDiffusionInpaintPipeline" and version.parse( | |
version.parse(_ppdiffusers_version).base_version | |
) <= version.parse("0.5.1"): | |
from . import ( | |
StableDiffusionInpaintPipeline, | |
StableDiffusionInpaintPipelineLegacy, | |
) | |
pipeline_class = StableDiffusionInpaintPipelineLegacy | |
deprecation_message = ( | |
"You are using a legacy checkpoint for inpainting with Stable Diffusion, therefore we are loading the" | |
f" {StableDiffusionInpaintPipelineLegacy} class instead of {StableDiffusionInpaintPipeline}. For" | |
" better inpainting results, we strongly suggest using Stable Diffusion's official inpainting" | |
" checkpoint: https://huggingface.co/runwayml/stable-diffusion-inpainting instead or adapting your" | |
f" checkpoint {pretrained_model_name_or_path} to the format of" | |
" https://huggingface.co/runwayml/stable-diffusion-inpainting. Note that we do not actively maintain" | |
" the {StableDiffusionInpaintPipelineLegacy} class and will likely remove it in version 1.0.0." | |
) | |
deprecate("StableDiffusionInpaintPipelineLegacy", "1.0.0", deprecation_message, standard_warn=False) | |
# some modules can be passed directly to the init | |
# in this case they are already instantiated in `kwargs` | |
# extract them here | |
expected_modules, optional_kwargs = cls._get_signature_keys(pipeline_class) | |
passed_class_obj = {k: kwargs.pop(k) for k in expected_modules if k in kwargs} | |
passed_pipe_kwargs = {k: kwargs.pop(k) for k in optional_kwargs if k in kwargs} | |
init_dict, unused_kwargs, _ = pipeline_class.extract_init_dict(config_dict, **kwargs) | |
# define init kwargs | |
init_kwargs = {k: init_dict.pop(k) for k in optional_kwargs if k in init_dict} | |
init_kwargs = {**init_kwargs, **passed_pipe_kwargs} | |
# remove `null` components | |
def load_module(name, value): | |
if value[0] is None: | |
return False | |
if name in passed_class_obj and passed_class_obj[name] is None: | |
return False | |
return True | |
init_dict = {k: v for k, v in init_dict.items() if load_module(k, v)} | |
if len(unused_kwargs) > 0: | |
logger.warning( | |
f"Keyword arguments {unused_kwargs} are not expected by {pipeline_class.__name__} and will be ignored." | |
) | |
# import it here to avoid circular import | |
from . import pipelines | |
# 3. Load each module in the pipeline | |
for name, (library_name, class_name) in init_dict.items(): | |
# TODO (junnyu) support old model_index.json | |
if library_name == "diffusers_paddle": | |
library_name = "ppdiffusers" | |
is_pipeline_module = hasattr(pipelines, library_name) | |
loaded_sub_model = None | |
# if the model is in a pipeline module, then we load it from the pipeline | |
if name in passed_class_obj: | |
# 1. check that passed_class_obj has correct parent class | |
if not is_pipeline_module: | |
library = importlib.import_module(library_name) | |
class_obj = getattr(library, class_name) | |
importable_classes = LOADABLE_CLASSES[library_name] | |
class_candidates = {c: getattr(library, c, None) for c in importable_classes.keys()} | |
expected_class_obj = None | |
for class_name, class_candidate in class_candidates.items(): | |
if class_candidate is not None and issubclass(class_obj, class_candidate): | |
expected_class_obj = class_candidate | |
if not issubclass(passed_class_obj[name].__class__, expected_class_obj): | |
raise ValueError( | |
f"{passed_class_obj[name]} is of type: {type(passed_class_obj[name])}, but should be" | |
f" {expected_class_obj}" | |
) | |
else: | |
logger.warning( | |
f"You have passed a non-standard module {passed_class_obj[name]}. We cannot verify whether it" | |
" has the correct type" | |
) | |
# set passed class object | |
loaded_sub_model = passed_class_obj[name] | |
elif is_pipeline_module: | |
pipeline_module = getattr(pipelines, library_name) | |
class_obj = getattr(pipeline_module, class_name) | |
importable_classes = ALL_IMPORTABLE_CLASSES | |
class_candidates = {c: class_obj for c in importable_classes.keys()} | |
else: | |
# else we just import it from the library. | |
library = importlib.import_module(library_name) | |
class_obj = getattr(library, class_name) | |
importable_classes = LOADABLE_CLASSES[library_name] | |
class_candidates = {c: getattr(library, c, None) for c in importable_classes.keys()} | |
if loaded_sub_model is None: | |
load_method_name = None | |
for class_name, class_candidate in class_candidates.items(): | |
if class_candidate is not None and issubclass(class_obj, class_candidate): | |
load_method_name = importable_classes[class_name][1] | |
if load_method_name is None: | |
none_module = class_obj.__module__ | |
is_dummy_path = none_module.startswith(DUMMY_MODULES_FOLDER) or none_module.startswith( | |
PADDLENLP_DUMMY_MODULES_FOLDER | |
) | |
if is_dummy_path and "dummy" in none_module: | |
# call class_obj for nice error message of missing requirements | |
class_obj() | |
raise ValueError( | |
f"The component {class_obj} of {pipeline_class} cannot be loaded as it does not seem to have" | |
f" any of the loading methods defined in {ALL_IMPORTABLE_CLASSES}." | |
) | |
load_method = getattr(class_obj, load_method_name) | |
loading_kwargs = { | |
"from_hf_hub": from_hf_hub, | |
"cache_dir": cache_dir, | |
} | |
if issubclass(class_obj, FastDeployRuntimeModel): | |
if isinstance(runtime_options, dict): | |
options = runtime_options.get(name, None) | |
else: | |
options = runtime_options | |
loading_kwargs["runtime_options"] = options | |
if os.path.isdir(pretrained_model_name_or_path): | |
model_path_dir = os.path.join(pretrained_model_name_or_path, name) | |
elif from_hf_hub: | |
model_path_dir = pretrained_model_name_or_path | |
loading_kwargs["subfolder"] = name | |
else: | |
# BOS does not require 'subfolder'. We simpy concat the model name with the subfolder | |
model_path_dir = pretrained_model_name_or_path + "/" + name | |
loaded_sub_model = load_method(model_path_dir, **loading_kwargs) | |
# TODO junnyu find a better way to covert to float16 | |
if isinstance(loaded_sub_model, nn.Layer): | |
if paddle_dtype is not None and next(loaded_sub_model.named_parameters())[1].dtype != paddle_dtype: | |
loaded_sub_model = loaded_sub_model.to(dtype=paddle_dtype) | |
# paddlenlp model is training mode not eval mode | |
loaded_sub_model.eval() | |
init_kwargs[name] = loaded_sub_model # UNet(...), # DiffusionScheduler(...) | |
# 4. Potentially add passed objects if expected | |
missing_modules = set(expected_modules) - set(init_kwargs.keys()) | |
passed_modules = list(passed_class_obj.keys()) | |
optional_modules = pipeline_class._optional_components | |
if len(missing_modules) > 0 and missing_modules <= set(passed_modules + optional_modules): | |
for module in missing_modules: | |
init_kwargs[module] = passed_class_obj.get(module, None) | |
elif len(missing_modules) > 0: | |
passed_modules = set(list(init_kwargs.keys()) + list(passed_class_obj.keys())) - optional_kwargs | |
raise ValueError( | |
f"Pipeline {pipeline_class} expected {expected_modules}, but only {passed_modules} were passed." | |
) | |
# 5. Instantiate the pipeline | |
model = pipeline_class(**init_kwargs) | |
return model | |
def enable_attention_slicing(self, slice_size: Optional[Union[str, int]] = "auto"): | |
r""" | |
Enable sliced attention computation. | |
When this option is enabled, the attention module will split the input tensor in slices, to compute attention | |
in several steps. This is useful to save some memory in exchange for a small speed decrease. | |
Args: | |
slice_size (`str` or `int`, *optional*, defaults to `"auto"`): | |
When `"auto"`, halves the input to the attention heads, so attention will be computed in two steps. If | |
`"max"`, maxium amount of memory will be saved by running only one slice at a time. If a number is | |
provided, uses as many slices as `attention_head_dim // slice_size`. In this case, `attention_head_dim` | |
must be a multiple of `slice_size`. | |
""" | |
self.set_attention_slice(slice_size) | |
def disable_attention_slicing(self): | |
r""" | |
Disable sliced attention computation. If `enable_attention_slicing` was previously invoked, this method will go | |
back to computing attention in one step. | |
""" | |
# set slice_size = `None` to disable `attention slicing` | |
self.enable_attention_slicing(None) | |
def set_attention_slice(self, slice_size: Optional[int]): | |
module_names, _, _ = self.extract_init_dict(dict(self.config)) | |
for module_name in module_names: | |
module = getattr(self, module_name) | |
if isinstance(module, nn.Layer) and hasattr(module, "set_attention_slice"): | |
module.set_attention_slice(slice_size) | |
def _get_signature_keys(obj): | |
parameters = inspect.signature(obj.__init__).parameters | |
required_parameters = {k: v for k, v in parameters.items() if v.default == inspect._empty} | |
optional_parameters = set({k for k, v in parameters.items() if v.default != inspect._empty}) | |
expected_modules = set(required_parameters.keys()) - set(["self"]) | |
return expected_modules, optional_parameters | |
def components(self) -> Dict[str, Any]: | |
r""" | |
The `self.components` property can be useful to run different pipelines with the same weights and | |
configurations to not have to re-allocate memory. | |
Examples: | |
```py | |
>>> from ppdiffusers import ( | |
... StableDiffusionPipeline, | |
... StableDiffusionImg2ImgPipeline, | |
... StableDiffusionInpaintPipeline, | |
... ) | |
>>> text2img = StableDiffusionPipeline.from_pretrained("runwayml/stable-diffusion-v1-5") | |
>>> img2img = StableDiffusionImg2ImgPipeline(**text2img.components) | |
>>> inpaint = StableDiffusionInpaintPipeline(**text2img.components) | |
``` | |
Returns: | |
A dictionaly containing all the modules needed to initialize the pipeline. | |
""" | |
expected_modules, optional_parameters = self._get_signature_keys(self) | |
components = { | |
k: getattr(self, k) for k in self.config.keys() if not k.startswith("_") and k not in optional_parameters | |
} | |
if set(components.keys()) != expected_modules: | |
raise ValueError( | |
f"{self} has been incorrectly initialized or {self.__class__} is incorrectly implemented. Expected" | |
f" {expected_modules} to be defined, but {components} are defined." | |
) | |
return components | |
def numpy_to_pil(images): | |
""" | |
Convert a numpy image or a batch of images to a PIL image. | |
""" | |
if images.ndim == 3: | |
images = images[None, ...] | |
images = (images * 255).round().astype("uint8") | |
if images.shape[-1] == 1: | |
# special case for grayscale (single channel) images | |
pil_images = [Image.fromarray(image.squeeze(), mode="L") for image in images] | |
else: | |
pil_images = [Image.fromarray(image) for image in images] | |
return pil_images | |
def progress_bar(self, iterable=None, total=None): | |
if not hasattr(self, "_progress_bar_config"): | |
self._progress_bar_config = {} | |
elif not isinstance(self._progress_bar_config, dict): | |
raise ValueError( | |
f"`self._progress_bar_config` should be of type `dict`, but is {type(self._progress_bar_config)}." | |
) | |
if iterable is not None: | |
return tqdm(iterable, **self._progress_bar_config) | |
elif total is not None: | |
return tqdm(total=total, **self._progress_bar_config) | |
else: | |
raise ValueError("Either `total` or `iterable` has to be defined.") | |
def set_progress_bar_config(self, **kwargs): | |
self._progress_bar_config = kwargs | |