CoolFace
Modelpublic

getsep/instantid-dependencies

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
model_util.py473 linesDownload Raw Back to root
1from typing import Literal, Union, Optional, Tuple, List2 3import torch4from transformers import CLIPTextModel, CLIPTokenizer, CLIPTextModelWithProjection5from diffusers import (6    UNet2DConditionModel,7    SchedulerMixin,8    StableDiffusionPipeline,9    StableDiffusionXLPipeline,10    AutoencoderKL,11)12from diffusers.pipelines.stable_diffusion.convert_from_ckpt import (13    convert_ldm_unet_checkpoint,14)15from safetensors.torch import load_file16from diffusers.schedulers import (17    DDIMScheduler,18    DDPMScheduler,19    LMSDiscreteScheduler,20    EulerDiscreteScheduler,21    EulerAncestralDiscreteScheduler,22    UniPCMultistepScheduler,23)24 25from omegaconf import OmegaConf26 27# DiffUsers版StableDiffusionのモデルパラメータ28NUM_TRAIN_TIMESTEPS = 100029BETA_START = 0.0008530BETA_END = 0.012031 32UNET_PARAMS_MODEL_CHANNELS = 32033UNET_PARAMS_CHANNEL_MULT = [1, 2, 4, 4]34UNET_PARAMS_ATTENTION_RESOLUTIONS = [4, 2, 1]35UNET_PARAMS_IMAGE_SIZE = 64  # fixed from old invalid value `32`36UNET_PARAMS_IN_CHANNELS = 437UNET_PARAMS_OUT_CHANNELS = 438UNET_PARAMS_NUM_RES_BLOCKS = 239UNET_PARAMS_CONTEXT_DIM = 76840UNET_PARAMS_NUM_HEADS = 841# UNET_PARAMS_USE_LINEAR_PROJECTION = False42 43VAE_PARAMS_Z_CHANNELS = 444VAE_PARAMS_RESOLUTION = 25645VAE_PARAMS_IN_CHANNELS = 346VAE_PARAMS_OUT_CH = 347VAE_PARAMS_CH = 12848VAE_PARAMS_CH_MULT = [1, 2, 4, 4]49VAE_PARAMS_NUM_RES_BLOCKS = 250 51# V252V2_UNET_PARAMS_ATTENTION_HEAD_DIM = [5, 10, 20, 20]53V2_UNET_PARAMS_CONTEXT_DIM = 102454# V2_UNET_PARAMS_USE_LINEAR_PROJECTION = True55 56TOKENIZER_V1_MODEL_NAME = "CompVis/stable-diffusion-v1-4"57TOKENIZER_V2_MODEL_NAME = "stabilityai/stable-diffusion-2-1"58 59AVAILABLE_SCHEDULERS = Literal["ddim", "ddpm", "lms", "euler_a", "euler", "uniPC"]60 61SDXL_TEXT_ENCODER_TYPE = Union[CLIPTextModel, CLIPTextModelWithProjection]62 63DIFFUSERS_CACHE_DIR = None  # if you want to change the cache dir, change this64 65 66def load_checkpoint_with_text_encoder_conversion(ckpt_path: str, device="cpu"):67    # text encoderの格納形式が違うモデルに対応する ('text_model'がない)68    TEXT_ENCODER_KEY_REPLACEMENTS = [69        (70            "cond_stage_model.transformer.embeddings.",71            "cond_stage_model.transformer.text_model.embeddings.",72        ),73        (74            "cond_stage_model.transformer.encoder.",75            "cond_stage_model.transformer.text_model.encoder.",76        ),77        (78            "cond_stage_model.transformer.final_layer_norm.",79            "cond_stage_model.transformer.text_model.final_layer_norm.",80        ),81    ]82 83    if ckpt_path.endswith(".safetensors"):84        checkpoint = None85        state_dict = load_file(ckpt_path)  # , device) # may causes error86    else:87        checkpoint = torch.load(ckpt_path, map_location=device)88        if "state_dict" in checkpoint:89            state_dict = checkpoint["state_dict"]90        else:91            state_dict = checkpoint92            checkpoint = None93 94    key_reps = []95    for rep_from, rep_to in TEXT_ENCODER_KEY_REPLACEMENTS:96        for key in state_dict.keys():97            if key.startswith(rep_from):98                new_key = rep_to + key[len(rep_from) :]99                key_reps.append((key, new_key))100 101    for key, new_key in key_reps:102        state_dict[new_key] = state_dict[key]103        del state_dict[key]104 105    return checkpoint, state_dict106 107 108def create_unet_diffusers_config(v2, use_linear_projection_in_v2=False):109    """110    Creates a config for the diffusers based on the config of the LDM model.111    """112    # unet_params = original_config.model.params.unet_config.params113 114    block_out_channels = [115        UNET_PARAMS_MODEL_CHANNELS * mult for mult in UNET_PARAMS_CHANNEL_MULT116    ]117 118    down_block_types = []119    resolution = 1120    for i in range(len(block_out_channels)):121        block_type = (122            "CrossAttnDownBlock2D"123            if resolution in UNET_PARAMS_ATTENTION_RESOLUTIONS124            else "DownBlock2D"125        )126        down_block_types.append(block_type)127        if i != len(block_out_channels) - 1:128            resolution *= 2129 130    up_block_types = []131    for i in range(len(block_out_channels)):132        block_type = (133            "CrossAttnUpBlock2D"134            if resolution in UNET_PARAMS_ATTENTION_RESOLUTIONS135            else "UpBlock2D"136        )137        up_block_types.append(block_type)138        resolution //= 2139 140    config = dict(141        sample_size=UNET_PARAMS_IMAGE_SIZE,142        in_channels=UNET_PARAMS_IN_CHANNELS,143        out_channels=UNET_PARAMS_OUT_CHANNELS,144        down_block_types=tuple(down_block_types),145        up_block_types=tuple(up_block_types),146        block_out_channels=tuple(block_out_channels),147        layers_per_block=UNET_PARAMS_NUM_RES_BLOCKS,148        cross_attention_dim=UNET_PARAMS_CONTEXT_DIM149        if not v2150        else V2_UNET_PARAMS_CONTEXT_DIM,151        attention_head_dim=UNET_PARAMS_NUM_HEADS152        if not v2153        else V2_UNET_PARAMS_ATTENTION_HEAD_DIM,154        # use_linear_projection=UNET_PARAMS_USE_LINEAR_PROJECTION if not v2 else V2_UNET_PARAMS_USE_LINEAR_PROJECTION,155    )156    if v2 and use_linear_projection_in_v2:157        config["use_linear_projection"] = True158 159    return config160 161 162def load_diffusers_model(163    pretrained_model_name_or_path: str,164    v2: bool = False,165    clip_skip: Optional[int] = None,166    weight_dtype: torch.dtype = torch.float32,167) -> Tuple[CLIPTokenizer, CLIPTextModel, UNet2DConditionModel,]:168    if v2:169        tokenizer = CLIPTokenizer.from_pretrained(170            TOKENIZER_V2_MODEL_NAME,171            subfolder="tokenizer",172            torch_dtype=weight_dtype,173            cache_dir=DIFFUSERS_CACHE_DIR,174        )175        text_encoder = CLIPTextModel.from_pretrained(176            pretrained_model_name_or_path,177            subfolder="text_encoder",178            # default is clip skip 2179            num_hidden_layers=24 - (clip_skip - 1) if clip_skip is not None else 23,180            torch_dtype=weight_dtype,181            cache_dir=DIFFUSERS_CACHE_DIR,182        )183    else:184        tokenizer = CLIPTokenizer.from_pretrained(185            TOKENIZER_V1_MODEL_NAME,186            subfolder="tokenizer",187            torch_dtype=weight_dtype,188            cache_dir=DIFFUSERS_CACHE_DIR,189        )190        text_encoder = CLIPTextModel.from_pretrained(191            pretrained_model_name_or_path,192            subfolder="text_encoder",193            num_hidden_layers=12 - (clip_skip - 1) if clip_skip is not None else 12,194            torch_dtype=weight_dtype,195            cache_dir=DIFFUSERS_CACHE_DIR,196        )197 198    unet = UNet2DConditionModel.from_pretrained(199        pretrained_model_name_or_path,200        subfolder="unet",201        torch_dtype=weight_dtype,202        cache_dir=DIFFUSERS_CACHE_DIR,203    )204 205    vae = AutoencoderKL.from_pretrained(pretrained_model_name_or_path, subfolder="vae")206 207    return tokenizer, text_encoder, unet, vae208 209 210def load_checkpoint_model(211    checkpoint_path: str,212    v2: bool = False,213    clip_skip: Optional[int] = None,214    weight_dtype: torch.dtype = torch.float32,215) -> Tuple[CLIPTokenizer, CLIPTextModel, UNet2DConditionModel,]:216    pipe = StableDiffusionPipeline.from_single_file(217        checkpoint_path,218        upcast_attention=True if v2 else False,219        torch_dtype=weight_dtype,220        cache_dir=DIFFUSERS_CACHE_DIR,221    )222 223    _, state_dict = load_checkpoint_with_text_encoder_conversion(checkpoint_path)224    unet_config = create_unet_diffusers_config(v2, use_linear_projection_in_v2=v2)225    unet_config["class_embed_type"] = None226    unet_config["addition_embed_type"] = None227    converted_unet_checkpoint = convert_ldm_unet_checkpoint(state_dict, unet_config)228    unet = UNet2DConditionModel(**unet_config)229    unet.load_state_dict(converted_unet_checkpoint)230 231    tokenizer = pipe.tokenizer232    text_encoder = pipe.text_encoder233    vae = pipe.vae234    if clip_skip is not None:235        if v2:236            text_encoder.config.num_hidden_layers = 24 - (clip_skip - 1)237        else:238            text_encoder.config.num_hidden_layers = 12 - (clip_skip - 1)239 240    del pipe241 242    return tokenizer, text_encoder, unet, vae243 244 245def load_models(246    pretrained_model_name_or_path: str,247    scheduler_name: str,248    v2: bool = False,249    v_pred: bool = False,250    weight_dtype: torch.dtype = torch.float32,251) -> Tuple[CLIPTokenizer, CLIPTextModel, UNet2DConditionModel, SchedulerMixin,]:252    if pretrained_model_name_or_path.endswith(253        ".ckpt"254    ) or pretrained_model_name_or_path.endswith(".safetensors"):255        tokenizer, text_encoder, unet, vae = load_checkpoint_model(256            pretrained_model_name_or_path, v2=v2, weight_dtype=weight_dtype257        )258    else:  # diffusers259        tokenizer, text_encoder, unet, vae = load_diffusers_model(260            pretrained_model_name_or_path, v2=v2, weight_dtype=weight_dtype261        )262 263    if scheduler_name:264        scheduler = create_noise_scheduler(265            scheduler_name,266            prediction_type="v_prediction" if v_pred else "epsilon",267        )268    else:269        scheduler = None270 271    return tokenizer, text_encoder, unet, scheduler, vae272 273 274def load_diffusers_model_xl(275    pretrained_model_name_or_path: str,276    weight_dtype: torch.dtype = torch.float32,277) -> Tuple[List[CLIPTokenizer], List[SDXL_TEXT_ENCODER_TYPE], UNet2DConditionModel,]:278    # returns tokenizer, tokenizer_2, text_encoder, text_encoder_2, unet279 280    tokenizers = [281        CLIPTokenizer.from_pretrained(282            pretrained_model_name_or_path,283            subfolder="tokenizer",284            torch_dtype=weight_dtype,285            cache_dir=DIFFUSERS_CACHE_DIR,286        ),287        CLIPTokenizer.from_pretrained(288            pretrained_model_name_or_path,289            subfolder="tokenizer_2",290            torch_dtype=weight_dtype,291            cache_dir=DIFFUSERS_CACHE_DIR,292            pad_token_id=0,  # same as open clip293        ),294    ]295 296    text_encoders = [297        CLIPTextModel.from_pretrained(298            pretrained_model_name_or_path,299            subfolder="text_encoder",300            torch_dtype=weight_dtype,301            cache_dir=DIFFUSERS_CACHE_DIR,302        ),303        CLIPTextModelWithProjection.from_pretrained(304            pretrained_model_name_or_path,305            subfolder="text_encoder_2",306            torch_dtype=weight_dtype,307            cache_dir=DIFFUSERS_CACHE_DIR,308        ),309    ]310 311    unet = UNet2DConditionModel.from_pretrained(312        pretrained_model_name_or_path,313        subfolder="unet",314        torch_dtype=weight_dtype,315        cache_dir=DIFFUSERS_CACHE_DIR,316    )317    vae = AutoencoderKL.from_pretrained(pretrained_model_name_or_path, subfolder="vae")318    return tokenizers, text_encoders, unet, vae319 320 321def load_checkpoint_model_xl(322    checkpoint_path: str,323    weight_dtype: torch.dtype = torch.float32,324) -> Tuple[List[CLIPTokenizer], List[SDXL_TEXT_ENCODER_TYPE], UNet2DConditionModel,]:325    pipe = StableDiffusionXLPipeline.from_single_file(326        checkpoint_path,327        torch_dtype=weight_dtype,328        cache_dir=DIFFUSERS_CACHE_DIR,329    )330 331    unet = pipe.unet332    vae = pipe.vae333    tokenizers = [pipe.tokenizer, pipe.tokenizer_2]334    text_encoders = [pipe.text_encoder, pipe.text_encoder_2]335    if len(text_encoders) == 2:336        text_encoders[1].pad_token_id = 0337 338    del pipe339 340    return tokenizers, text_encoders, unet, vae341 342 343def load_models_xl(344    pretrained_model_name_or_path: str,345    scheduler_name: str,346    weight_dtype: torch.dtype = torch.float32,347    noise_scheduler_kwargs=None,348) -> Tuple[349    List[CLIPTokenizer],350    List[SDXL_TEXT_ENCODER_TYPE],351    UNet2DConditionModel,352    SchedulerMixin,353]:354    if pretrained_model_name_or_path.endswith(355        ".ckpt"356    ) or pretrained_model_name_or_path.endswith(".safetensors"):357        (tokenizers, text_encoders, unet, vae) = load_checkpoint_model_xl(358            pretrained_model_name_or_path, weight_dtype359        )360    else:  # diffusers361        (tokenizers, text_encoders, unet, vae) = load_diffusers_model_xl(362            pretrained_model_name_or_path, weight_dtype363        )364    if scheduler_name:365        scheduler = create_noise_scheduler(scheduler_name, noise_scheduler_kwargs)366    else:367        scheduler = None368 369    return tokenizers, text_encoders, unet, scheduler, vae370 371def create_noise_scheduler(372    scheduler_name: AVAILABLE_SCHEDULERS = "ddpm",373    noise_scheduler_kwargs=None,374    prediction_type: Literal["epsilon", "v_prediction"] = "epsilon",375) -> SchedulerMixin:376    name = scheduler_name.lower().replace(" ", "_")377    if name.lower() == "ddim":378        # https://huggingface.co/docs/diffusers/v0.17.1/en/api/schedulers/ddim379        scheduler = DDIMScheduler(**OmegaConf.to_container(noise_scheduler_kwargs))380    elif name.lower() == "ddpm":381        # https://huggingface.co/docs/diffusers/v0.17.1/en/api/schedulers/ddpm382        scheduler = DDPMScheduler(**OmegaConf.to_container(noise_scheduler_kwargs))383    elif name.lower() == "lms":384        # https://huggingface.co/docs/diffusers/v0.17.1/en/api/schedulers/lms_discrete385        scheduler = LMSDiscreteScheduler(386            **OmegaConf.to_container(noise_scheduler_kwargs)387        )388    elif name.lower() == "euler_a":389        # https://huggingface.co/docs/diffusers/v0.17.1/en/api/schedulers/euler_ancestral390        scheduler = EulerAncestralDiscreteScheduler(391            **OmegaConf.to_container(noise_scheduler_kwargs)392        )393    elif name.lower() == "euler":394        # https://huggingface.co/docs/diffusers/v0.17.1/en/api/schedulers/euler_ancestral395        scheduler = EulerDiscreteScheduler(396            **OmegaConf.to_container(noise_scheduler_kwargs)397        )398    elif name.lower() == "unipc":399        # https://huggingface.co/docs/diffusers/v0.17.1/en/api/schedulers/unipc400        scheduler = UniPCMultistepScheduler(401            **OmegaConf.to_container(noise_scheduler_kwargs)402        )403    else:404        raise ValueError(f"Unknown scheduler name: {name}")405 406    return scheduler407 408 409def torch_gc():410    import gc411 412    gc.collect()413    if torch.cuda.is_available():414        with torch.cuda.device("cuda"):415            torch.cuda.empty_cache()416            torch.cuda.ipc_collect()417 418 419from enum import Enum420 421 422class CPUState(Enum):423    GPU = 0424    CPU = 1425    MPS = 2426 427 428cpu_state = CPUState.GPU429xpu_available = False430directml_enabled = False431 432 433def is_intel_xpu():434    global cpu_state435    global xpu_available436    if cpu_state == CPUState.GPU:437        if xpu_available:438            return True439    return False440 441 442try:443    import intel_extension_for_pytorch as ipex444 445    if torch.xpu.is_available():446        xpu_available = True447except:448    pass449 450try:451    if torch.backends.mps.is_available():452        cpu_state = CPUState.MPS453        import torch.mps454except:455    pass456 457 458def get_torch_device():459    global directml_enabled460    global cpu_state461    if directml_enabled:462        global directml_device463        return directml_device464    if cpu_state == CPUState.MPS:465        return torch.device("mps")466    if cpu_state == CPUState.CPU:467        return torch.device("cpu")468    else:469        if is_intel_xpu():470            return torch.device("xpu")471        else:472            return torch.device(torch.cuda.current_device())473