CoolFace
Apppublic

tsi-org/tango

sourceHugging Faceupdated 3y agoView on Hugging Face
0likes
convert_versatile_diffusion_to_diffusers.py792 linesDownload Raw Back to scripts
1# coding=utf-82# Copyright 2023 The HuggingFace Inc. team.3#4# Licensed under the Apache License, Version 2.0 (the "License");5# you may not use this file except in compliance with the License.6# You may obtain a copy of the License at7#8#     http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing, software11# distributed under the License is distributed on an "AS IS" BASIS,12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13# See the License for the specific language governing permissions and14# limitations under the License.15""" Conversion script for the Versatile Stable Diffusion checkpoints. """16 17import argparse18from argparse import Namespace19 20import torch21from transformers import (22    CLIPImageProcessor,23    CLIPTextModelWithProjection,24    CLIPTokenizer,25    CLIPVisionModelWithProjection,26)27 28from diffusers import (29    AutoencoderKL,30    DDIMScheduler,31    DPMSolverMultistepScheduler,32    EulerAncestralDiscreteScheduler,33    EulerDiscreteScheduler,34    LMSDiscreteScheduler,35    PNDMScheduler,36    UNet2DConditionModel,37    VersatileDiffusionPipeline,38)39from diffusers.pipelines.versatile_diffusion.modeling_text_unet import UNetFlatConditionModel40 41 42SCHEDULER_CONFIG = Namespace(43    **{44        "beta_linear_start": 0.00085,45        "beta_linear_end": 0.012,46        "timesteps": 1000,47        "scale_factor": 0.18215,48    }49)50 51IMAGE_UNET_CONFIG = Namespace(52    **{53        "input_channels": 4,54        "model_channels": 320,55        "output_channels": 4,56        "num_noattn_blocks": [2, 2, 2, 2],57        "channel_mult": [1, 2, 4, 4],58        "with_attn": [True, True, True, False],59        "num_heads": 8,60        "context_dim": 768,61        "use_checkpoint": True,62    }63)64 65TEXT_UNET_CONFIG = Namespace(66    **{67        "input_channels": 768,68        "model_channels": 320,69        "output_channels": 768,70        "num_noattn_blocks": [2, 2, 2, 2],71        "channel_mult": [1, 2, 4, 4],72        "second_dim": [4, 4, 4, 4],73        "with_attn": [True, True, True, False],74        "num_heads": 8,75        "context_dim": 768,76        "use_checkpoint": True,77    }78)79 80AUTOENCODER_CONFIG = Namespace(81    **{82        "double_z": True,83        "z_channels": 4,84        "resolution": 256,85        "in_channels": 3,86        "out_ch": 3,87        "ch": 128,88        "ch_mult": [1, 2, 4, 4],89        "num_res_blocks": 2,90        "attn_resolutions": [],91        "dropout": 0.0,92    }93)94 95 96def shave_segments(path, n_shave_prefix_segments=1):97    """98    Removes segments. Positive values shave the first segments, negative shave the last segments.99    """100    if n_shave_prefix_segments >= 0:101        return ".".join(path.split(".")[n_shave_prefix_segments:])102    else:103        return ".".join(path.split(".")[:n_shave_prefix_segments])104 105 106def renew_resnet_paths(old_list, n_shave_prefix_segments=0):107    """108    Updates paths inside resnets to the new naming scheme (local renaming)109    """110    mapping = []111    for old_item in old_list:112        new_item = old_item.replace("in_layers.0", "norm1")113        new_item = new_item.replace("in_layers.2", "conv1")114 115        new_item = new_item.replace("out_layers.0", "norm2")116        new_item = new_item.replace("out_layers.3", "conv2")117 118        new_item = new_item.replace("emb_layers.1", "time_emb_proj")119        new_item = new_item.replace("skip_connection", "conv_shortcut")120 121        new_item = shave_segments(new_item, n_shave_prefix_segments=n_shave_prefix_segments)122 123        mapping.append({"old": old_item, "new": new_item})124 125    return mapping126 127 128def renew_vae_resnet_paths(old_list, n_shave_prefix_segments=0):129    """130    Updates paths inside resnets to the new naming scheme (local renaming)131    """132    mapping = []133    for old_item in old_list:134        new_item = old_item135 136        new_item = new_item.replace("nin_shortcut", "conv_shortcut")137        new_item = shave_segments(new_item, n_shave_prefix_segments=n_shave_prefix_segments)138 139        mapping.append({"old": old_item, "new": new_item})140 141    return mapping142 143 144def renew_attention_paths(old_list, n_shave_prefix_segments=0):145    """146    Updates paths inside attentions to the new naming scheme (local renaming)147    """148    mapping = []149    for old_item in old_list:150        new_item = old_item151 152        #         new_item = new_item.replace('norm.weight', 'group_norm.weight')153        #         new_item = new_item.replace('norm.bias', 'group_norm.bias')154 155        #         new_item = new_item.replace('proj_out.weight', 'proj_attn.weight')156        #         new_item = new_item.replace('proj_out.bias', 'proj_attn.bias')157 158        #         new_item = shave_segments(new_item, n_shave_prefix_segments=n_shave_prefix_segments)159 160        mapping.append({"old": old_item, "new": new_item})161 162    return mapping163 164 165def renew_vae_attention_paths(old_list, n_shave_prefix_segments=0):166    """167    Updates paths inside attentions to the new naming scheme (local renaming)168    """169    mapping = []170    for old_item in old_list:171        new_item = old_item172 173        new_item = new_item.replace("norm.weight", "group_norm.weight")174        new_item = new_item.replace("norm.bias", "group_norm.bias")175 176        new_item = new_item.replace("q.weight", "query.weight")177        new_item = new_item.replace("q.bias", "query.bias")178 179        new_item = new_item.replace("k.weight", "key.weight")180        new_item = new_item.replace("k.bias", "key.bias")181 182        new_item = new_item.replace("v.weight", "value.weight")183        new_item = new_item.replace("v.bias", "value.bias")184 185        new_item = new_item.replace("proj_out.weight", "proj_attn.weight")186        new_item = new_item.replace("proj_out.bias", "proj_attn.bias")187 188        new_item = shave_segments(new_item, n_shave_prefix_segments=n_shave_prefix_segments)189 190        mapping.append({"old": old_item, "new": new_item})191 192    return mapping193 194 195def assign_to_checkpoint(196    paths, checkpoint, old_checkpoint, attention_paths_to_split=None, additional_replacements=None, config=None197):198    """199    This does the final conversion step: take locally converted weights and apply a global renaming200    to them. It splits attention layers, and takes into account additional replacements201    that may arise.202 203    Assigns the weights to the new checkpoint.204    """205    assert isinstance(paths, list), "Paths should be a list of dicts containing 'old' and 'new' keys."206 207    # Splits the attention layers into three variables.208    if attention_paths_to_split is not None:209        for path, path_map in attention_paths_to_split.items():210            old_tensor = old_checkpoint[path]211            channels = old_tensor.shape[0] // 3212 213            target_shape = (-1, channels) if len(old_tensor.shape) == 3 else (-1)214 215            num_heads = old_tensor.shape[0] // config["num_head_channels"] // 3216 217            old_tensor = old_tensor.reshape((num_heads, 3 * channels // num_heads) + old_tensor.shape[1:])218            query, key, value = old_tensor.split(channels // num_heads, dim=1)219 220            checkpoint[path_map["query"]] = query.reshape(target_shape)221            checkpoint[path_map["key"]] = key.reshape(target_shape)222            checkpoint[path_map["value"]] = value.reshape(target_shape)223 224    for path in paths:225        new_path = path["new"]226 227        # These have already been assigned228        if attention_paths_to_split is not None and new_path in attention_paths_to_split:229            continue230 231        # Global renaming happens here232        new_path = new_path.replace("middle_block.0", "mid_block.resnets.0")233        new_path = new_path.replace("middle_block.1", "mid_block.attentions.0")234        new_path = new_path.replace("middle_block.2", "mid_block.resnets.1")235 236        if additional_replacements is not None:237            for replacement in additional_replacements:238                new_path = new_path.replace(replacement["old"], replacement["new"])239 240        # proj_attn.weight has to be converted from conv 1D to linear241        if "proj_attn.weight" in new_path:242            checkpoint[new_path] = old_checkpoint[path["old"]][:, :, 0]243        elif path["old"] in old_checkpoint:244            checkpoint[new_path] = old_checkpoint[path["old"]]245 246 247def conv_attn_to_linear(checkpoint):248    keys = list(checkpoint.keys())249    attn_keys = ["query.weight", "key.weight", "value.weight"]250    for key in keys:251        if ".".join(key.split(".")[-2:]) in attn_keys:252            if checkpoint[key].ndim > 2:253                checkpoint[key] = checkpoint[key][:, :, 0, 0]254        elif "proj_attn.weight" in key:255            if checkpoint[key].ndim > 2:256                checkpoint[key] = checkpoint[key][:, :, 0]257 258 259def create_image_unet_diffusers_config(unet_params):260    """261    Creates a config for the diffusers based on the config of the VD model.262    """263 264    block_out_channels = [unet_params.model_channels * mult for mult in unet_params.channel_mult]265 266    down_block_types = []267    resolution = 1268    for i in range(len(block_out_channels)):269        block_type = "CrossAttnDownBlock2D" if unet_params.with_attn[i] else "DownBlock2D"270        down_block_types.append(block_type)271        if i != len(block_out_channels) - 1:272            resolution *= 2273 274    up_block_types = []275    for i in range(len(block_out_channels)):276        block_type = "CrossAttnUpBlock2D" if unet_params.with_attn[-i - 1] else "UpBlock2D"277        up_block_types.append(block_type)278        resolution //= 2279 280    if not all(n == unet_params.num_noattn_blocks[0] for n in unet_params.num_noattn_blocks):281        raise ValueError("Not all num_res_blocks are equal, which is not supported in this script.")282 283    config = {284        "sample_size": None,285        "in_channels": unet_params.input_channels,286        "out_channels": unet_params.output_channels,287        "down_block_types": tuple(down_block_types),288        "up_block_types": tuple(up_block_types),289        "block_out_channels": tuple(block_out_channels),290        "layers_per_block": unet_params.num_noattn_blocks[0],291        "cross_attention_dim": unet_params.context_dim,292        "attention_head_dim": unet_params.num_heads,293    }294 295    return config296 297 298def create_text_unet_diffusers_config(unet_params):299    """300    Creates a config for the diffusers based on the config of the VD model.301    """302 303    block_out_channels = [unet_params.model_channels * mult for mult in unet_params.channel_mult]304 305    down_block_types = []306    resolution = 1307    for i in range(len(block_out_channels)):308        block_type = "CrossAttnDownBlockFlat" if unet_params.with_attn[i] else "DownBlockFlat"309        down_block_types.append(block_type)310        if i != len(block_out_channels) - 1:311            resolution *= 2312 313    up_block_types = []314    for i in range(len(block_out_channels)):315        block_type = "CrossAttnUpBlockFlat" if unet_params.with_attn[-i - 1] else "UpBlockFlat"316        up_block_types.append(block_type)317        resolution //= 2318 319    if not all(n == unet_params.num_noattn_blocks[0] for n in unet_params.num_noattn_blocks):320        raise ValueError("Not all num_res_blocks are equal, which is not supported in this script.")321 322    config = {323        "sample_size": None,324        "in_channels": (unet_params.input_channels, 1, 1),325        "out_channels": (unet_params.output_channels, 1, 1),326        "down_block_types": tuple(down_block_types),327        "up_block_types": tuple(up_block_types),328        "block_out_channels": tuple(block_out_channels),329        "layers_per_block": unet_params.num_noattn_blocks[0],330        "cross_attention_dim": unet_params.context_dim,331        "attention_head_dim": unet_params.num_heads,332    }333 334    return config335 336 337def create_vae_diffusers_config(vae_params):338    """339    Creates a config for the diffusers based on the config of the VD model.340    """341 342    block_out_channels = [vae_params.ch * mult for mult in vae_params.ch_mult]343    down_block_types = ["DownEncoderBlock2D"] * len(block_out_channels)344    up_block_types = ["UpDecoderBlock2D"] * len(block_out_channels)345 346    config = {347        "sample_size": vae_params.resolution,348        "in_channels": vae_params.in_channels,349        "out_channels": vae_params.out_ch,350        "down_block_types": tuple(down_block_types),351        "up_block_types": tuple(up_block_types),352        "block_out_channels": tuple(block_out_channels),353        "latent_channels": vae_params.z_channels,354        "layers_per_block": vae_params.num_res_blocks,355    }356    return config357 358 359def create_diffusers_scheduler(original_config):360    schedular = DDIMScheduler(361        num_train_timesteps=original_config.model.params.timesteps,362        beta_start=original_config.model.params.linear_start,363        beta_end=original_config.model.params.linear_end,364        beta_schedule="scaled_linear",365    )366    return schedular367 368 369def convert_vd_unet_checkpoint(checkpoint, config, unet_key, extract_ema=False):370    """371    Takes a state dict and a config, and returns a converted checkpoint.372    """373 374    # extract state_dict for UNet375    unet_state_dict = {}376    keys = list(checkpoint.keys())377 378    # at least a 100 parameters have to start with `model_ema` in order for the checkpoint to be EMA379    if sum(k.startswith("model_ema") for k in keys) > 100:380        print("Checkpoint has both EMA and non-EMA weights.")381        if extract_ema:382            print(383                "In this conversion only the EMA weights are extracted. If you want to instead extract the non-EMA"384                " weights (useful to continue fine-tuning), please make sure to remove the `--extract_ema` flag."385            )386            for key in keys:387                if key.startswith("model.diffusion_model"):388                    flat_ema_key = "model_ema." + "".join(key.split(".")[1:])389                    unet_state_dict[key.replace(unet_key, "")] = checkpoint.pop(flat_ema_key)390        else:391            print(392                "In this conversion only the non-EMA weights are extracted. If you want to instead extract the EMA"393                " weights (usually better for inference), please make sure to add the `--extract_ema` flag."394            )395 396    for key in keys:397        if key.startswith(unet_key):398            unet_state_dict[key.replace(unet_key, "")] = checkpoint.pop(key)399 400    new_checkpoint = {}401 402    new_checkpoint["time_embedding.linear_1.weight"] = checkpoint["model.diffusion_model.time_embed.0.weight"]403    new_checkpoint["time_embedding.linear_1.bias"] = checkpoint["model.diffusion_model.time_embed.0.bias"]404    new_checkpoint["time_embedding.linear_2.weight"] = checkpoint["model.diffusion_model.time_embed.2.weight"]405    new_checkpoint["time_embedding.linear_2.bias"] = checkpoint["model.diffusion_model.time_embed.2.bias"]406 407    new_checkpoint["conv_in.weight"] = unet_state_dict["input_blocks.0.0.weight"]408    new_checkpoint["conv_in.bias"] = unet_state_dict["input_blocks.0.0.bias"]409 410    new_checkpoint["conv_norm_out.weight"] = unet_state_dict["out.0.weight"]411    new_checkpoint["conv_norm_out.bias"] = unet_state_dict["out.0.bias"]412    new_checkpoint["conv_out.weight"] = unet_state_dict["out.2.weight"]413    new_checkpoint["conv_out.bias"] = unet_state_dict["out.2.bias"]414 415    # Retrieves the keys for the input blocks only416    num_input_blocks = len({".".join(layer.split(".")[:2]) for layer in unet_state_dict if "input_blocks" in layer})417    input_blocks = {418        layer_id: [key for key in unet_state_dict if f"input_blocks.{layer_id}" in key]419        for layer_id in range(num_input_blocks)420    }421 422    # Retrieves the keys for the middle blocks only423    num_middle_blocks = len({".".join(layer.split(".")[:2]) for layer in unet_state_dict if "middle_block" in layer})424    middle_blocks = {425        layer_id: [key for key in unet_state_dict if f"middle_block.{layer_id}" in key]426        for layer_id in range(num_middle_blocks)427    }428 429    # Retrieves the keys for the output blocks only430    num_output_blocks = len({".".join(layer.split(".")[:2]) for layer in unet_state_dict if "output_blocks" in layer})431    output_blocks = {432        layer_id: [key for key in unet_state_dict if f"output_blocks.{layer_id}" in key]433        for layer_id in range(num_output_blocks)434    }435 436    for i in range(1, num_input_blocks):437        block_id = (i - 1) // (config["layers_per_block"] + 1)438        layer_in_block_id = (i - 1) % (config["layers_per_block"] + 1)439 440        resnets = [441            key for key in input_blocks[i] if f"input_blocks.{i}.0" in key and f"input_blocks.{i}.0.op" not in key442        ]443        attentions = [key for key in input_blocks[i] if f"input_blocks.{i}.1" in key]444 445        if f"input_blocks.{i}.0.op.weight" in unet_state_dict:446            new_checkpoint[f"down_blocks.{block_id}.downsamplers.0.conv.weight"] = unet_state_dict.pop(447                f"input_blocks.{i}.0.op.weight"448            )449            new_checkpoint[f"down_blocks.{block_id}.downsamplers.0.conv.bias"] = unet_state_dict.pop(450                f"input_blocks.{i}.0.op.bias"451            )452        elif f"input_blocks.{i}.0.weight" in unet_state_dict:453            # text_unet uses linear layers in place of downsamplers454            shape = unet_state_dict[f"input_blocks.{i}.0.weight"].shape455            if shape[0] != shape[1]:456                continue457            new_checkpoint[f"down_blocks.{block_id}.downsamplers.0.weight"] = unet_state_dict.pop(458                f"input_blocks.{i}.0.weight"459            )460            new_checkpoint[f"down_blocks.{block_id}.downsamplers.0.bias"] = unet_state_dict.pop(461                f"input_blocks.{i}.0.bias"462            )463 464        paths = renew_resnet_paths(resnets)465        meta_path = {"old": f"input_blocks.{i}.0", "new": f"down_blocks.{block_id}.resnets.{layer_in_block_id}"}466        assign_to_checkpoint(467            paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config468        )469 470        if len(attentions):471            paths = renew_attention_paths(attentions)472            meta_path = {"old": f"input_blocks.{i}.1", "new": f"down_blocks.{block_id}.attentions.{layer_in_block_id}"}473            assign_to_checkpoint(474                paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config475            )476 477    resnet_0 = middle_blocks[0]478    attentions = middle_blocks[1]479    resnet_1 = middle_blocks[2]480 481    resnet_0_paths = renew_resnet_paths(resnet_0)482    assign_to_checkpoint(resnet_0_paths, new_checkpoint, unet_state_dict, config=config)483 484    resnet_1_paths = renew_resnet_paths(resnet_1)485    assign_to_checkpoint(resnet_1_paths, new_checkpoint, unet_state_dict, config=config)486 487    attentions_paths = renew_attention_paths(attentions)488    meta_path = {"old": "middle_block.1", "new": "mid_block.attentions.0"}489    assign_to_checkpoint(490        attentions_paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config491    )492 493    for i in range(num_output_blocks):494        block_id = i // (config["layers_per_block"] + 1)495        layer_in_block_id = i % (config["layers_per_block"] + 1)496        output_block_layers = [shave_segments(name, 2) for name in output_blocks[i]]497        output_block_list = {}498 499        for layer in output_block_layers:500            layer_id, layer_name = layer.split(".")[0], shave_segments(layer, 1)501            if layer_id in output_block_list:502                output_block_list[layer_id].append(layer_name)503            else:504                output_block_list[layer_id] = [layer_name]505 506        if len(output_block_list) > 1:507            resnets = [key for key in output_blocks[i] if f"output_blocks.{i}.0" in key]508            attentions = [key for key in output_blocks[i] if f"output_blocks.{i}.1" in key]509 510            paths = renew_resnet_paths(resnets)511 512            meta_path = {"old": f"output_blocks.{i}.0", "new": f"up_blocks.{block_id}.resnets.{layer_in_block_id}"}513            assign_to_checkpoint(514                paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config515            )516 517            if ["conv.weight", "conv.bias"] in output_block_list.values():518                index = list(output_block_list.values()).index(["conv.weight", "conv.bias"])519                new_checkpoint[f"up_blocks.{block_id}.upsamplers.0.conv.weight"] = unet_state_dict[520                    f"output_blocks.{i}.{index}.conv.weight"521                ]522                new_checkpoint[f"up_blocks.{block_id}.upsamplers.0.conv.bias"] = unet_state_dict[523                    f"output_blocks.{i}.{index}.conv.bias"524                ]525                # Clear attentions as they have been attributed above.526                if len(attentions) == 2:527                    attentions = []528            elif f"output_blocks.{i}.1.weight" in unet_state_dict:529                # text_unet uses linear layers in place of upsamplers530                shape = unet_state_dict[f"output_blocks.{i}.1.weight"].shape531                if shape[0] != shape[1]:532                    continue533                new_checkpoint[f"up_blocks.{block_id}.upsamplers.0.weight"] = unet_state_dict.pop(534                    f"output_blocks.{i}.1.weight"535                )536                new_checkpoint[f"up_blocks.{block_id}.upsamplers.0.bias"] = unet_state_dict.pop(537                    f"output_blocks.{i}.1.bias"538                )539                # Clear attentions as they have been attributed above.540                if len(attentions) == 2:541                    attentions = []542            elif f"output_blocks.{i}.2.weight" in unet_state_dict:543                # text_unet uses linear layers in place of upsamplers544                shape = unet_state_dict[f"output_blocks.{i}.2.weight"].shape545                if shape[0] != shape[1]:546                    continue547                new_checkpoint[f"up_blocks.{block_id}.upsamplers.0.weight"] = unet_state_dict.pop(548                    f"output_blocks.{i}.2.weight"549                )550                new_checkpoint[f"up_blocks.{block_id}.upsamplers.0.bias"] = unet_state_dict.pop(551                    f"output_blocks.{i}.2.bias"552                )553 554            if len(attentions):555                paths = renew_attention_paths(attentions)556                meta_path = {557                    "old": f"output_blocks.{i}.1",558                    "new": f"up_blocks.{block_id}.attentions.{layer_in_block_id}",559                }560                assign_to_checkpoint(561                    paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config562                )563        else:564            resnet_0_paths = renew_resnet_paths(output_block_layers, n_shave_prefix_segments=1)565            for path in resnet_0_paths:566                old_path = ".".join(["output_blocks", str(i), path["old"]])567                new_path = ".".join(["up_blocks", str(block_id), "resnets", str(layer_in_block_id), path["new"]])568 569                new_checkpoint[new_path] = unet_state_dict[old_path]570 571    return new_checkpoint572 573 574def convert_vd_vae_checkpoint(checkpoint, config):575    # extract state dict for VAE576    vae_state_dict = {}577    keys = list(checkpoint.keys())578    for key in keys:579        vae_state_dict[key] = checkpoint.get(key)580 581    new_checkpoint = {}582 583    new_checkpoint["encoder.conv_in.weight"] = vae_state_dict["encoder.conv_in.weight"]584    new_checkpoint["encoder.conv_in.bias"] = vae_state_dict["encoder.conv_in.bias"]585    new_checkpoint["encoder.conv_out.weight"] = vae_state_dict["encoder.conv_out.weight"]586    new_checkpoint["encoder.conv_out.bias"] = vae_state_dict["encoder.conv_out.bias"]587    new_checkpoint["encoder.conv_norm_out.weight"] = vae_state_dict["encoder.norm_out.weight"]588    new_checkpoint["encoder.conv_norm_out.bias"] = vae_state_dict["encoder.norm_out.bias"]589 590    new_checkpoint["decoder.conv_in.weight"] = vae_state_dict["decoder.conv_in.weight"]591    new_checkpoint["decoder.conv_in.bias"] = vae_state_dict["decoder.conv_in.bias"]592    new_checkpoint["decoder.conv_out.weight"] = vae_state_dict["decoder.conv_out.weight"]593    new_checkpoint["decoder.conv_out.bias"] = vae_state_dict["decoder.conv_out.bias"]594    new_checkpoint["decoder.conv_norm_out.weight"] = vae_state_dict["decoder.norm_out.weight"]595    new_checkpoint["decoder.conv_norm_out.bias"] = vae_state_dict["decoder.norm_out.bias"]596 597    new_checkpoint["quant_conv.weight"] = vae_state_dict["quant_conv.weight"]598    new_checkpoint["quant_conv.bias"] = vae_state_dict["quant_conv.bias"]599    new_checkpoint["post_quant_conv.weight"] = vae_state_dict["post_quant_conv.weight"]600    new_checkpoint["post_quant_conv.bias"] = vae_state_dict["post_quant_conv.bias"]601 602    # Retrieves the keys for the encoder down blocks only603    num_down_blocks = len({".".join(layer.split(".")[:3]) for layer in vae_state_dict if "encoder.down" in layer})604    down_blocks = {605        layer_id: [key for key in vae_state_dict if f"down.{layer_id}" in key] for layer_id in range(num_down_blocks)606    }607 608    # Retrieves the keys for the decoder up blocks only609    num_up_blocks = len({".".join(layer.split(".")[:3]) for layer in vae_state_dict if "decoder.up" in layer})610    up_blocks = {611        layer_id: [key for key in vae_state_dict if f"up.{layer_id}" in key] for layer_id in range(num_up_blocks)612    }613 614    for i in range(num_down_blocks):615        resnets = [key for key in down_blocks[i] if f"down.{i}" in key and f"down.{i}.downsample" not in key]616 617        if f"encoder.down.{i}.downsample.conv.weight" in vae_state_dict:618            new_checkpoint[f"encoder.down_blocks.{i}.downsamplers.0.conv.weight"] = vae_state_dict.pop(619                f"encoder.down.{i}.downsample.conv.weight"620            )621            new_checkpoint[f"encoder.down_blocks.{i}.downsamplers.0.conv.bias"] = vae_state_dict.pop(622                f"encoder.down.{i}.downsample.conv.bias"623            )624 625        paths = renew_vae_resnet_paths(resnets)626        meta_path = {"old": f"down.{i}.block", "new": f"down_blocks.{i}.resnets"}627        assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)628 629    mid_resnets = [key for key in vae_state_dict if "encoder.mid.block" in key]630    num_mid_res_blocks = 2631    for i in range(1, num_mid_res_blocks + 1):632        resnets = [key for key in mid_resnets if f"encoder.mid.block_{i}" in key]633 634        paths = renew_vae_resnet_paths(resnets)635        meta_path = {"old": f"mid.block_{i}", "new": f"mid_block.resnets.{i - 1}"}636        assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)637 638    mid_attentions = [key for key in vae_state_dict if "encoder.mid.attn" in key]639    paths = renew_vae_attention_paths(mid_attentions)640    meta_path = {"old": "mid.attn_1", "new": "mid_block.attentions.0"}641    assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)642    conv_attn_to_linear(new_checkpoint)643 644    for i in range(num_up_blocks):645        block_id = num_up_blocks - 1 - i646        resnets = [647            key for key in up_blocks[block_id] if f"up.{block_id}" in key and f"up.{block_id}.upsample" not in key648        ]649 650        if f"decoder.up.{block_id}.upsample.conv.weight" in vae_state_dict:651            new_checkpoint[f"decoder.up_blocks.{i}.upsamplers.0.conv.weight"] = vae_state_dict[652                f"decoder.up.{block_id}.upsample.conv.weight"653            ]654            new_checkpoint[f"decoder.up_blocks.{i}.upsamplers.0.conv.bias"] = vae_state_dict[655                f"decoder.up.{block_id}.upsample.conv.bias"656            ]657 658        paths = renew_vae_resnet_paths(resnets)659        meta_path = {"old": f"up.{block_id}.block", "new": f"up_blocks.{i}.resnets"}660        assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)661 662    mid_resnets = [key for key in vae_state_dict if "decoder.mid.block" in key]663    num_mid_res_blocks = 2664    for i in range(1, num_mid_res_blocks + 1):665        resnets = [key for key in mid_resnets if f"decoder.mid.block_{i}" in key]666 667        paths = renew_vae_resnet_paths(resnets)668        meta_path = {"old": f"mid.block_{i}", "new": f"mid_block.resnets.{i - 1}"}669        assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)670 671    mid_attentions = [key for key in vae_state_dict if "decoder.mid.attn" in key]672    paths = renew_vae_attention_paths(mid_attentions)673    meta_path = {"old": "mid.attn_1", "new": "mid_block.attentions.0"}674    assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)675    conv_attn_to_linear(new_checkpoint)676    return new_checkpoint677 678 679if __name__ == "__main__":680    parser = argparse.ArgumentParser()681 682    parser.add_argument(683        "--unet_checkpoint_path", default=None, type=str, required=False, help="Path to the checkpoint to convert."684    )685    parser.add_argument(686        "--vae_checkpoint_path", default=None, type=str, required=False, help="Path to the checkpoint to convert."687    )688    parser.add_argument(689        "--optimus_checkpoint_path", default=None, type=str, required=False, help="Path to the checkpoint to convert."690    )691    parser.add_argument(692        "--scheduler_type",693        default="pndm",694        type=str,695        help="Type of scheduler to use. Should be one of ['pndm', 'lms', 'ddim', 'euler', 'euler-ancestral', 'dpm']",696    )697    parser.add_argument(698        "--extract_ema",699        action="store_true",700        help=(701            "Only relevant for checkpoints that have both EMA and non-EMA weights. Whether to extract the EMA weights"702            " or not. Defaults to `False`. Add `--extract_ema` to extract the EMA weights. EMA weights usually yield"703            " higher quality images for inference. Non-EMA weights are usually better to continue fine-tuning."704        ),705    )706    parser.add_argument("--dump_path", default=None, type=str, required=True, help="Path to the output model.")707 708    args = parser.parse_args()709 710    scheduler_config = SCHEDULER_CONFIG711 712    num_train_timesteps = scheduler_config.timesteps713    beta_start = scheduler_config.beta_linear_start714    beta_end = scheduler_config.beta_linear_end715    if args.scheduler_type == "pndm":716        scheduler = PNDMScheduler(717            beta_end=beta_end,718            beta_schedule="scaled_linear",719            beta_start=beta_start,720            num_train_timesteps=num_train_timesteps,721            skip_prk_steps=True,722            steps_offset=1,723        )724    elif args.scheduler_type == "lms":725        scheduler = LMSDiscreteScheduler(beta_start=beta_start, beta_end=beta_end, beta_schedule="scaled_linear")726    elif args.scheduler_type == "euler":727        scheduler = EulerDiscreteScheduler(beta_start=beta_start, beta_end=beta_end, beta_schedule="scaled_linear")728    elif args.scheduler_type == "euler-ancestral":729        scheduler = EulerAncestralDiscreteScheduler(730            beta_start=beta_start, beta_end=beta_end, beta_schedule="scaled_linear"731        )732    elif args.scheduler_type == "dpm":733        scheduler = DPMSolverMultistepScheduler(734            beta_start=beta_start, beta_end=beta_end, beta_schedule="scaled_linear"735        )736    elif args.scheduler_type == "ddim":737        scheduler = DDIMScheduler(738            beta_start=beta_start,739            beta_end=beta_end,740            beta_schedule="scaled_linear",741            clip_sample=False,742            set_alpha_to_one=False,743            steps_offset=1,744        )745    else:746        raise ValueError(f"Scheduler of type {args.scheduler_type} doesn't exist!")747 748    # Convert the UNet2DConditionModel models.749    if args.unet_checkpoint_path is not None:750        # image UNet751        image_unet_config = create_image_unet_diffusers_config(IMAGE_UNET_CONFIG)752        checkpoint = torch.load(args.unet_checkpoint_path)753        converted_image_unet_checkpoint = convert_vd_unet_checkpoint(754            checkpoint, image_unet_config, unet_key="model.diffusion_model.unet_image.", extract_ema=args.extract_ema755        )756        image_unet = UNet2DConditionModel(**image_unet_config)757        image_unet.load_state_dict(converted_image_unet_checkpoint)758 759        # text UNet760        text_unet_config = create_text_unet_diffusers_config(TEXT_UNET_CONFIG)761        converted_text_unet_checkpoint = convert_vd_unet_checkpoint(762            checkpoint, text_unet_config, unet_key="model.diffusion_model.unet_text.", extract_ema=args.extract_ema763        )764        text_unet = UNetFlatConditionModel(**text_unet_config)765        text_unet.load_state_dict(converted_text_unet_checkpoint)766 767    # Convert the VAE model.768    if args.vae_checkpoint_path is not None:769        vae_config = create_vae_diffusers_config(AUTOENCODER_CONFIG)770        checkpoint = torch.load(args.vae_checkpoint_path)771        converted_vae_checkpoint = convert_vd_vae_checkpoint(checkpoint, vae_config)772 773        vae = AutoencoderKL(**vae_config)774        vae.load_state_dict(converted_vae_checkpoint)775 776    tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14")777    image_feature_extractor = CLIPImageProcessor.from_pretrained("openai/clip-vit-large-patch14")778    text_encoder = CLIPTextModelWithProjection.from_pretrained("openai/clip-vit-large-patch14")779    image_encoder = CLIPVisionModelWithProjection.from_pretrained("openai/clip-vit-large-patch14")780 781    pipe = VersatileDiffusionPipeline(782        scheduler=scheduler,783        tokenizer=tokenizer,784        image_feature_extractor=image_feature_extractor,785        text_encoder=text_encoder,786        image_encoder=image_encoder,787        image_unet=image_unet,788        text_unet=text_unet,789        vae=vae,790    )791    pipe.save_pretrained(args.dump_path)792