diffusers/community-pipelines-mirror
Community Pipeline Examples For more information about community pipelines, please have a look at this issue. Community pipeline examples consist pipelines that have been added by the community. Please have a look at the following tables to get an overview of all community examples. Click on the Code Example to get a copy-and-paste ready code example that you can try out. If a community pipeline doesn't work as expected, please open an issue and ping the author on it. Please… See the full description on the dataset page: https://huggingface.co/datasets/diffusers/community-pipelines-mirror.
922k
1import glob2import os3from typing import Dict, List, Union4 5import safetensors.torch6import torch7from huggingface_hub import snapshot_download8from huggingface_hub.utils import validate_hf_hub_args9 10from diffusers import DiffusionPipeline, __version__11from diffusers.schedulers.scheduling_utils import SCHEDULER_CONFIG_NAME12from diffusers.utils import CONFIG_NAME, ONNX_WEIGHTS_NAME, WEIGHTS_NAME13 14 15class CheckpointMergerPipeline(DiffusionPipeline):16 """17 A class that supports merging diffusion models based on the discussion here:18 https://github.com/huggingface/diffusers/issues/87719 20 Example usage:-21 22 pipe = DiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4", custom_pipeline="checkpoint_merger.py")23 24 merged_pipe = pipe.merge(["CompVis/stable-diffusion-v1-4","prompthero/openjourney"], interp = 'inv_sigmoid', alpha = 0.8, force = True)25 26 merged_pipe.to('cuda')27 28 prompt = "An astronaut riding a unicycle on Mars"29 30 results = merged_pipe(prompt)31 32 ## For more details, see the docstring for the merge method.33 34 """35 36 def __init__(self):37 self.register_to_config()38 super().__init__()39 40 def _compare_model_configs(self, dict0, dict1):41 if dict0 == dict1:42 return True43 else:44 config0, meta_keys0 = self._remove_meta_keys(dict0)45 config1, meta_keys1 = self._remove_meta_keys(dict1)46 if config0 == config1:47 print(f"Warning !: Mismatch in keys {meta_keys0} and {meta_keys1}.")48 return True49 return False50 51 def _remove_meta_keys(self, config_dict: Dict):52 meta_keys = []53 temp_dict = config_dict.copy()54 for key in config_dict.keys():55 if key.startswith("_"):56 temp_dict.pop(key)57 meta_keys.append(key)58 return (temp_dict, meta_keys)59 60 @torch.no_grad()61 @validate_hf_hub_args62 def merge(self, pretrained_model_name_or_path_list: List[Union[str, os.PathLike]], **kwargs):63 """64 Returns a new pipeline object of the class 'DiffusionPipeline' with the merged checkpoints(weights) of the models passed65 in the argument 'pretrained_model_name_or_path_list' as a list.66 67 Parameters:68 -----------69 pretrained_model_name_or_path_list : A list of valid pretrained model names in the HuggingFace hub or paths to locally stored models in the HuggingFace format.70 71 **kwargs:72 Supports all the default DiffusionPipeline.get_config_dict kwargs viz..73 74 cache_dir, resume_download, force_download, proxies, local_files_only, token, revision, torch_dtype, device_map.75 76 alpha - The interpolation parameter. Ranges from 0 to 1. It affects the ratio in which the checkpoints are merged. A 0.8 alpha77 would mean that the first model checkpoints would affect the final result far less than an alpha of 0.278 79 interp - The interpolation method to use for the merging. Supports "sigmoid", "inv_sigmoid", "add_diff" and None.80 Passing None uses the default interpolation which is weighted sum interpolation. For merging three checkpoints, only "add_diff" is supported.81 82 force - Whether to ignore mismatch in model_config.json for the current models. Defaults to False.83 84 variant - which variant of a pretrained model to load, e.g. "fp16" (None)85 86 """87 # Default kwargs from DiffusionPipeline88 cache_dir = kwargs.pop("cache_dir", None)89 resume_download = kwargs.pop("resume_download", False)90 force_download = kwargs.pop("force_download", False)91 proxies = kwargs.pop("proxies", None)92 local_files_only = kwargs.pop("local_files_only", False)93 token = kwargs.pop("token", None)94 variant = kwargs.pop("variant", None)95 revision = kwargs.pop("revision", None)96 torch_dtype = kwargs.pop("torch_dtype", None)97 device_map = kwargs.pop("device_map", None)98 99 alpha = kwargs.pop("alpha", 0.5)100 interp = kwargs.pop("interp", None)101 102 print("Received list", pretrained_model_name_or_path_list)103 print(f"Combining with alpha={alpha}, interpolation mode={interp}")104 105 checkpoint_count = len(pretrained_model_name_or_path_list)106 # Ignore result from model_index_json comparison of the two checkpoints107 force = kwargs.pop("force", False)108 109 # If less than 2 checkpoints, nothing to merge. If more than 3, not supported for now.110 if checkpoint_count > 3 or checkpoint_count < 2:111 raise ValueError(112 "Received incorrect number of checkpoints to merge. Ensure that either 2 or 3 checkpoints are being"113 " passed."114 )115 116 print("Received the right number of checkpoints")117 # chkpt0, chkpt1 = pretrained_model_name_or_path_list[0:2]118 # chkpt2 = pretrained_model_name_or_path_list[2] if checkpoint_count == 3 else None119 120 # Validate that the checkpoints can be merged121 # Step 1: Load the model config and compare the checkpoints. We'll compare the model_index.json first while ignoring the keys starting with '_'122 config_dicts = []123 for pretrained_model_name_or_path in pretrained_model_name_or_path_list:124 config_dict = DiffusionPipeline.load_config(125 pretrained_model_name_or_path,126 cache_dir=cache_dir,127 resume_download=resume_download,128 force_download=force_download,129 proxies=proxies,130 local_files_only=local_files_only,131 token=token,132 revision=revision,133 )134 config_dicts.append(config_dict)135 136 comparison_result = True137 for idx in range(1, len(config_dicts)):138 comparison_result &= self._compare_model_configs(config_dicts[idx - 1], config_dicts[idx])139 if not force and comparison_result is False:140 raise ValueError("Incompatible checkpoints. Please check model_index.json for the models.")141 print("Compatible model_index.json files found")142 # Step 2: Basic Validation has succeeded. Let's download the models and save them into our local files.143 cached_folders = []144 for pretrained_model_name_or_path, config_dict in zip(pretrained_model_name_or_path_list, config_dicts):145 folder_names = [k for k in config_dict.keys() if not k.startswith("_")]146 allow_patterns = [os.path.join(k, "*") for k in folder_names]147 allow_patterns += [148 WEIGHTS_NAME,149 SCHEDULER_CONFIG_NAME,150 CONFIG_NAME,151 ONNX_WEIGHTS_NAME,152 DiffusionPipeline.config_name,153 ]154 requested_pipeline_class = config_dict.get("_class_name")155 user_agent = {"diffusers": __version__, "pipeline_class": requested_pipeline_class}156 157 cached_folder = (158 pretrained_model_name_or_path159 if os.path.isdir(pretrained_model_name_or_path)160 else snapshot_download(161 pretrained_model_name_or_path,162 cache_dir=cache_dir,163 resume_download=resume_download,164 proxies=proxies,165 local_files_only=local_files_only,166 token=token,167 revision=revision,168 allow_patterns=allow_patterns,169 user_agent=user_agent,170 )171 )172 print("Cached Folder", cached_folder)173 cached_folders.append(cached_folder)174 175 # Step 3:-176 # Load the first checkpoint as a diffusion pipeline and modify its module state_dict in place177 final_pipe = DiffusionPipeline.from_pretrained(178 cached_folders[0],179 torch_dtype=torch_dtype,180 device_map=device_map,181 variant=variant,182 )183 final_pipe.to(self.device)184 185 checkpoint_path_2 = None186 if len(cached_folders) > 2:187 checkpoint_path_2 = os.path.join(cached_folders[2])188 189 if interp == "sigmoid":190 theta_func = CheckpointMergerPipeline.sigmoid191 elif interp == "inv_sigmoid":192 theta_func = CheckpointMergerPipeline.inv_sigmoid193 elif interp == "add_diff":194 theta_func = CheckpointMergerPipeline.add_difference195 else:196 theta_func = CheckpointMergerPipeline.weighted_sum197 198 # Find each module's state dict.199 for attr in final_pipe.config.keys():200 if not attr.startswith("_"):201 checkpoint_path_1 = os.path.join(cached_folders[1], attr)202 if os.path.exists(checkpoint_path_1):203 files = [204 *glob.glob(os.path.join(checkpoint_path_1, "*.safetensors")),205 *glob.glob(os.path.join(checkpoint_path_1, "*.bin")),206 ]207 checkpoint_path_1 = files[0] if len(files) > 0 else None208 if len(cached_folders) < 3:209 checkpoint_path_2 = None210 else:211 checkpoint_path_2 = os.path.join(cached_folders[2], attr)212 if os.path.exists(checkpoint_path_2):213 files = [214 *glob.glob(os.path.join(checkpoint_path_2, "*.safetensors")),215 *glob.glob(os.path.join(checkpoint_path_2, "*.bin")),216 ]217 checkpoint_path_2 = files[0] if len(files) > 0 else None218 # For an attr if both checkpoint_path_1 and 2 are None, ignore.219 # If at least one is present, deal with it according to interp method, of course only if the state_dict keys match.220 if checkpoint_path_1 is None and checkpoint_path_2 is None:221 print(f"Skipping {attr}: not present in 2nd or 3d model")222 continue223 try:224 module = getattr(final_pipe, attr)225 if isinstance(module, bool): # ignore requires_safety_checker boolean226 continue227 theta_0 = getattr(module, "state_dict")228 theta_0 = theta_0()229 230 update_theta_0 = getattr(module, "load_state_dict")231 theta_1 = (232 safetensors.torch.load_file(checkpoint_path_1)233 if (checkpoint_path_1.endswith(".safetensors"))234 else torch.load(checkpoint_path_1, map_location="cpu")235 )236 theta_2 = None237 if checkpoint_path_2:238 theta_2 = (239 safetensors.torch.load_file(checkpoint_path_2)240 if (checkpoint_path_2.endswith(".safetensors"))241 else torch.load(checkpoint_path_2, map_location="cpu")242 )243 244 if not theta_0.keys() == theta_1.keys():245 print(f"Skipping {attr}: key mismatch")246 continue247 if theta_2 and not theta_1.keys() == theta_2.keys():248 print(f"Skipping {attr}:y mismatch")249 except Exception as e:250 print(f"Skipping {attr} do to an unexpected error: {str(e)}")251 continue252 print(f"MERGING {attr}")253 254 for key in theta_0.keys():255 if theta_2:256 theta_0[key] = theta_func(theta_0[key], theta_1[key], theta_2[key], alpha)257 else:258 theta_0[key] = theta_func(theta_0[key], theta_1[key], None, alpha)259 260 del theta_1261 del theta_2262 update_theta_0(theta_0)263 264 del theta_0265 return final_pipe266 267 @staticmethod268 def weighted_sum(theta0, theta1, theta2, alpha):269 return ((1 - alpha) * theta0) + (alpha * theta1)270 271 # Smoothstep (https://en.wikipedia.org/wiki/Smoothstep)272 @staticmethod273 def sigmoid(theta0, theta1, theta2, alpha):274 alpha = alpha * alpha * (3 - (2 * alpha))275 return theta0 + ((theta1 - theta0) * alpha)276 277 # Inverse Smoothstep (https://en.wikipedia.org/wiki/Smoothstep)278 @staticmethod279 def inv_sigmoid(theta0, theta1, theta2, alpha):280 import math281 282 alpha = 0.5 - math.sin(math.asin(1.0 - 2.0 * alpha) / 3.0)283 return theta0 + ((theta1 - theta0) * alpha)284 285 @staticmethod286 def add_difference(theta0, theta1, theta2, alpha):287 return theta0 + (theta1 - theta2) * (1.0 - alpha)288 