CoolFace
Apppublic

tsi-org/tango

sourceHugging Faceupdated 3y agoView on Hugging Face
0likes
convert_ms_text_to_video_to_diffusers.py429 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 LDM checkpoints. """16 17import argparse18 19import torch20 21from diffusers import UNet3DConditionModel22 23 24def assign_to_checkpoint(25    paths, checkpoint, old_checkpoint, attention_paths_to_split=None, additional_replacements=None, config=None26):27    """28    This does the final conversion step: take locally converted weights and apply a global renaming to them. It splits29    attention layers, and takes into account additional replacements that may arise.30 31    Assigns the weights to the new checkpoint.32    """33    assert isinstance(paths, list), "Paths should be a list of dicts containing 'old' and 'new' keys."34 35    # Splits the attention layers into three variables.36    if attention_paths_to_split is not None:37        for path, path_map in attention_paths_to_split.items():38            old_tensor = old_checkpoint[path]39            channels = old_tensor.shape[0] // 340 41            target_shape = (-1, channels) if len(old_tensor.shape) == 3 else (-1)42 43            num_heads = old_tensor.shape[0] // config["num_head_channels"] // 344 45            old_tensor = old_tensor.reshape((num_heads, 3 * channels // num_heads) + old_tensor.shape[1:])46            query, key, value = old_tensor.split(channels // num_heads, dim=1)47 48            checkpoint[path_map["query"]] = query.reshape(target_shape)49            checkpoint[path_map["key"]] = key.reshape(target_shape)50            checkpoint[path_map["value"]] = value.reshape(target_shape)51 52    for path in paths:53        new_path = path["new"]54 55        # These have already been assigned56        if attention_paths_to_split is not None and new_path in attention_paths_to_split:57            continue58 59        if additional_replacements is not None:60            for replacement in additional_replacements:61                new_path = new_path.replace(replacement["old"], replacement["new"])62 63        # proj_attn.weight has to be converted from conv 1D to linear64        weight = old_checkpoint[path["old"]]65        names = ["proj_attn.weight"]66        names_2 = ["proj_out.weight", "proj_in.weight"]67        if any(k in new_path for k in names):68            checkpoint[new_path] = weight[:, :, 0]69        elif any(k in new_path for k in names_2) and len(weight.shape) > 2 and ".attentions." not in new_path:70            checkpoint[new_path] = weight[:, :, 0]71        else:72            checkpoint[new_path] = weight73 74 75def renew_attention_paths(old_list, n_shave_prefix_segments=0):76    """77    Updates paths inside attentions to the new naming scheme (local renaming)78    """79    mapping = []80    for old_item in old_list:81        new_item = old_item82 83        #         new_item = new_item.replace('norm.weight', 'group_norm.weight')84        #         new_item = new_item.replace('norm.bias', 'group_norm.bias')85 86        #         new_item = new_item.replace('proj_out.weight', 'proj_attn.weight')87        #         new_item = new_item.replace('proj_out.bias', 'proj_attn.bias')88 89        #         new_item = shave_segments(new_item, n_shave_prefix_segments=n_shave_prefix_segments)90 91        mapping.append({"old": old_item, "new": new_item})92 93    return mapping94 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_temp_conv_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        mapping.append({"old": old_item, "new": old_item})113 114    return mapping115 116 117def renew_resnet_paths(old_list, n_shave_prefix_segments=0):118    """119    Updates paths inside resnets to the new naming scheme (local renaming)120    """121    mapping = []122    for old_item in old_list:123        new_item = old_item.replace("in_layers.0", "norm1")124        new_item = new_item.replace("in_layers.2", "conv1")125 126        new_item = new_item.replace("out_layers.0", "norm2")127        new_item = new_item.replace("out_layers.3", "conv2")128 129        new_item = new_item.replace("emb_layers.1", "time_emb_proj")130        new_item = new_item.replace("skip_connection", "conv_shortcut")131 132        new_item = shave_segments(new_item, n_shave_prefix_segments=n_shave_prefix_segments)133 134        if "temopral_conv" not in old_item:135            mapping.append({"old": old_item, "new": new_item})136 137    return mapping138 139 140def convert_ldm_unet_checkpoint(checkpoint, config, path=None, extract_ema=False):141    """142    Takes a state dict and a config, and returns a converted checkpoint.143    """144 145    # extract state_dict for UNet146    unet_state_dict = {}147    keys = list(checkpoint.keys())148 149    unet_key = "model.diffusion_model."150 151    # at least a 100 parameters have to start with `model_ema` in order for the checkpoint to be EMA152    if sum(k.startswith("model_ema") for k in keys) > 100 and extract_ema:153        print(f"Checkpoint {path} has both EMA and non-EMA weights.")154        print(155            "In this conversion only the EMA weights are extracted. If you want to instead extract the non-EMA"156            " weights (useful to continue fine-tuning), please make sure to remove the `--extract_ema` flag."157        )158        for key in keys:159            if key.startswith("model.diffusion_model"):160                flat_ema_key = "model_ema." + "".join(key.split(".")[1:])161                unet_state_dict[key.replace(unet_key, "")] = checkpoint.pop(flat_ema_key)162    else:163        if sum(k.startswith("model_ema") for k in keys) > 100:164            print(165                "In this conversion only the non-EMA weights are extracted. If you want to instead extract the EMA"166                " weights (usually better for inference), please make sure to add the `--extract_ema` flag."167            )168 169        for key in keys:170            unet_state_dict[key.replace(unet_key, "")] = checkpoint.pop(key)171 172    new_checkpoint = {}173 174    new_checkpoint["time_embedding.linear_1.weight"] = unet_state_dict["time_embed.0.weight"]175    new_checkpoint["time_embedding.linear_1.bias"] = unet_state_dict["time_embed.0.bias"]176    new_checkpoint["time_embedding.linear_2.weight"] = unet_state_dict["time_embed.2.weight"]177    new_checkpoint["time_embedding.linear_2.bias"] = unet_state_dict["time_embed.2.bias"]178 179    if config["class_embed_type"] is None:180        # No parameters to port181        ...182    elif config["class_embed_type"] == "timestep" or config["class_embed_type"] == "projection":183        new_checkpoint["class_embedding.linear_1.weight"] = unet_state_dict["label_emb.0.0.weight"]184        new_checkpoint["class_embedding.linear_1.bias"] = unet_state_dict["label_emb.0.0.bias"]185        new_checkpoint["class_embedding.linear_2.weight"] = unet_state_dict["label_emb.0.2.weight"]186        new_checkpoint["class_embedding.linear_2.bias"] = unet_state_dict["label_emb.0.2.bias"]187    else:188        raise NotImplementedError(f"Not implemented `class_embed_type`: {config['class_embed_type']}")189 190    new_checkpoint["conv_in.weight"] = unet_state_dict["input_blocks.0.0.weight"]191    new_checkpoint["conv_in.bias"] = unet_state_dict["input_blocks.0.0.bias"]192 193    first_temp_attention = [v for v in unet_state_dict if v.startswith("input_blocks.0.1")]194    paths = renew_attention_paths(first_temp_attention)195    meta_path = {"old": "input_blocks.0.1", "new": "transformer_in"}196    assign_to_checkpoint(paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config)197 198    new_checkpoint["conv_norm_out.weight"] = unet_state_dict["out.0.weight"]199    new_checkpoint["conv_norm_out.bias"] = unet_state_dict["out.0.bias"]200    new_checkpoint["conv_out.weight"] = unet_state_dict["out.2.weight"]201    new_checkpoint["conv_out.bias"] = unet_state_dict["out.2.bias"]202 203    # Retrieves the keys for the input blocks only204    num_input_blocks = len({".".join(layer.split(".")[:2]) for layer in unet_state_dict if "input_blocks" in layer})205    input_blocks = {206        layer_id: [key for key in unet_state_dict if f"input_blocks.{layer_id}" in key]207        for layer_id in range(num_input_blocks)208    }209 210    # Retrieves the keys for the middle blocks only211    num_middle_blocks = len({".".join(layer.split(".")[:2]) for layer in unet_state_dict if "middle_block" in layer})212    middle_blocks = {213        layer_id: [key for key in unet_state_dict if f"middle_block.{layer_id}" in key]214        for layer_id in range(num_middle_blocks)215    }216 217    # Retrieves the keys for the output blocks only218    num_output_blocks = len({".".join(layer.split(".")[:2]) for layer in unet_state_dict if "output_blocks" in layer})219    output_blocks = {220        layer_id: [key for key in unet_state_dict if f"output_blocks.{layer_id}" in key]221        for layer_id in range(num_output_blocks)222    }223 224    for i in range(1, num_input_blocks):225        block_id = (i - 1) // (config["layers_per_block"] + 1)226        layer_in_block_id = (i - 1) % (config["layers_per_block"] + 1)227 228        resnets = [229            key for key in input_blocks[i] if f"input_blocks.{i}.0" in key and f"input_blocks.{i}.0.op" not in key230        ]231        attentions = [key for key in input_blocks[i] if f"input_blocks.{i}.1" in key]232        temp_attentions = [key for key in input_blocks[i] if f"input_blocks.{i}.2" in key]233 234        if f"input_blocks.{i}.op.weight" in unet_state_dict:235            new_checkpoint[f"down_blocks.{block_id}.downsamplers.0.conv.weight"] = unet_state_dict.pop(236                f"input_blocks.{i}.op.weight"237            )238            new_checkpoint[f"down_blocks.{block_id}.downsamplers.0.conv.bias"] = unet_state_dict.pop(239                f"input_blocks.{i}.op.bias"240            )241 242        paths = renew_resnet_paths(resnets)243        meta_path = {"old": f"input_blocks.{i}.0", "new": f"down_blocks.{block_id}.resnets.{layer_in_block_id}"}244        assign_to_checkpoint(245            paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config246        )247 248        temporal_convs = [key for key in resnets if "temopral_conv" in key]249        paths = renew_temp_conv_paths(temporal_convs)250        meta_path = {251            "old": f"input_blocks.{i}.0.temopral_conv",252            "new": f"down_blocks.{block_id}.temp_convs.{layer_in_block_id}",253        }254        assign_to_checkpoint(255            paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config256        )257 258        if len(attentions):259            paths = renew_attention_paths(attentions)260            meta_path = {"old": f"input_blocks.{i}.1", "new": f"down_blocks.{block_id}.attentions.{layer_in_block_id}"}261            assign_to_checkpoint(262                paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config263            )264 265        if len(temp_attentions):266            paths = renew_attention_paths(temp_attentions)267            meta_path = {268                "old": f"input_blocks.{i}.2",269                "new": f"down_blocks.{block_id}.temp_attentions.{layer_in_block_id}",270            }271            assign_to_checkpoint(272                paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config273            )274 275    resnet_0 = middle_blocks[0]276    temporal_convs_0 = [key for key in resnet_0 if "temopral_conv" in key]277    attentions = middle_blocks[1]278    temp_attentions = middle_blocks[2]279    resnet_1 = middle_blocks[3]280    temporal_convs_1 = [key for key in resnet_1 if "temopral_conv" in key]281 282    resnet_0_paths = renew_resnet_paths(resnet_0)283    meta_path = {"old": "middle_block.0", "new": "mid_block.resnets.0"}284    assign_to_checkpoint(285        resnet_0_paths, new_checkpoint, unet_state_dict, config=config, additional_replacements=[meta_path]286    )287 288    temp_conv_0_paths = renew_temp_conv_paths(temporal_convs_0)289    meta_path = {"old": "middle_block.0.temopral_conv", "new": "mid_block.temp_convs.0"}290    assign_to_checkpoint(291        temp_conv_0_paths, new_checkpoint, unet_state_dict, config=config, additional_replacements=[meta_path]292    )293 294    resnet_1_paths = renew_resnet_paths(resnet_1)295    meta_path = {"old": "middle_block.3", "new": "mid_block.resnets.1"}296    assign_to_checkpoint(297        resnet_1_paths, new_checkpoint, unet_state_dict, config=config, additional_replacements=[meta_path]298    )299 300    temp_conv_1_paths = renew_temp_conv_paths(temporal_convs_1)301    meta_path = {"old": "middle_block.3.temopral_conv", "new": "mid_block.temp_convs.1"}302    assign_to_checkpoint(303        temp_conv_1_paths, new_checkpoint, unet_state_dict, config=config, additional_replacements=[meta_path]304    )305 306    attentions_paths = renew_attention_paths(attentions)307    meta_path = {"old": "middle_block.1", "new": "mid_block.attentions.0"}308    assign_to_checkpoint(309        attentions_paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config310    )311 312    temp_attentions_paths = renew_attention_paths(temp_attentions)313    meta_path = {"old": "middle_block.2", "new": "mid_block.temp_attentions.0"}314    assign_to_checkpoint(315        temp_attentions_paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config316    )317 318    for i in range(num_output_blocks):319        block_id = i // (config["layers_per_block"] + 1)320        layer_in_block_id = i % (config["layers_per_block"] + 1)321        output_block_layers = [shave_segments(name, 2) for name in output_blocks[i]]322        output_block_list = {}323 324        for layer in output_block_layers:325            layer_id, layer_name = layer.split(".")[0], shave_segments(layer, 1)326            if layer_id in output_block_list:327                output_block_list[layer_id].append(layer_name)328            else:329                output_block_list[layer_id] = [layer_name]330 331        if len(output_block_list) > 1:332            resnets = [key for key in output_blocks[i] if f"output_blocks.{i}.0" in key]333            attentions = [key for key in output_blocks[i] if f"output_blocks.{i}.1" in key]334            temp_attentions = [key for key in output_blocks[i] if f"output_blocks.{i}.2" in key]335 336            resnet_0_paths = renew_resnet_paths(resnets)337            paths = renew_resnet_paths(resnets)338 339            meta_path = {"old": f"output_blocks.{i}.0", "new": f"up_blocks.{block_id}.resnets.{layer_in_block_id}"}340            assign_to_checkpoint(341                paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config342            )343 344            temporal_convs = [key for key in resnets if "temopral_conv" in key]345            paths = renew_temp_conv_paths(temporal_convs)346            meta_path = {347                "old": f"output_blocks.{i}.0.temopral_conv",348                "new": f"up_blocks.{block_id}.temp_convs.{layer_in_block_id}",349            }350            assign_to_checkpoint(351                paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config352            )353 354            output_block_list = {k: sorted(v) for k, v in output_block_list.items()}355            if ["conv.bias", "conv.weight"] in output_block_list.values():356                index = list(output_block_list.values()).index(["conv.bias", "conv.weight"])357                new_checkpoint[f"up_blocks.{block_id}.upsamplers.0.conv.weight"] = unet_state_dict[358                    f"output_blocks.{i}.{index}.conv.weight"359                ]360                new_checkpoint[f"up_blocks.{block_id}.upsamplers.0.conv.bias"] = unet_state_dict[361                    f"output_blocks.{i}.{index}.conv.bias"362                ]363 364                # Clear attentions as they have been attributed above.365                if len(attentions) == 2:366                    attentions = []367 368            if len(attentions):369                paths = renew_attention_paths(attentions)370                meta_path = {371                    "old": f"output_blocks.{i}.1",372                    "new": f"up_blocks.{block_id}.attentions.{layer_in_block_id}",373                }374                assign_to_checkpoint(375                    paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config376                )377 378            if len(temp_attentions):379                paths = renew_attention_paths(temp_attentions)380                meta_path = {381                    "old": f"output_blocks.{i}.2",382                    "new": f"up_blocks.{block_id}.temp_attentions.{layer_in_block_id}",383                }384                assign_to_checkpoint(385                    paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config386                )387        else:388            resnet_0_paths = renew_resnet_paths(output_block_layers, n_shave_prefix_segments=1)389            for path in resnet_0_paths:390                old_path = ".".join(["output_blocks", str(i), path["old"]])391                new_path = ".".join(["up_blocks", str(block_id), "resnets", str(layer_in_block_id), path["new"]])392                new_checkpoint[new_path] = unet_state_dict[old_path]393 394            temopral_conv_paths = [l for l in output_block_layers if "temopral_conv" in l]395            for path in temopral_conv_paths:396                pruned_path = path.split("temopral_conv.")[-1]397                old_path = ".".join(["output_blocks", str(i), str(block_id), "temopral_conv", pruned_path])398                new_path = ".".join(["up_blocks", str(block_id), "temp_convs", str(layer_in_block_id), pruned_path])399                new_checkpoint[new_path] = unet_state_dict[old_path]400 401    return new_checkpoint402 403 404if __name__ == "__main__":405    parser = argparse.ArgumentParser()406 407    parser.add_argument(408        "--checkpoint_path", default=None, type=str, required=True, help="Path to the checkpoint to convert."409    )410    parser.add_argument("--dump_path", default=None, type=str, required=True, help="Path to the output model.")411    args = parser.parse_args()412 413    unet_checkpoint = torch.load(args.checkpoint_path, map_location="cpu")414    unet = UNet3DConditionModel()415 416    converted_ckpt = convert_ldm_unet_checkpoint(unet_checkpoint, unet.config)417 418    diff_0 = set(unet.state_dict().keys()) - set(converted_ckpt.keys())419    diff_1 = set(converted_ckpt.keys()) - set(unet.state_dict().keys())420 421    assert len(diff_0) == len(diff_1) == 0, "Converted weights don't match"422 423    # load state_dict424    unet.load_state_dict(converted_ckpt)425 426    unet.save_pretrained(args.dump_path)427 428    # -- finish converting the unet --429