tsi-org/tango
0
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 AudioLDM checkpoints."""16 17import argparse18import re19 20import torch21from transformers import (22 AutoTokenizer,23 ClapTextConfig,24 ClapTextModelWithProjection,25 SpeechT5HifiGan,26 SpeechT5HifiGanConfig,27)28 29from diffusers import (30 AudioLDMPipeline,31 AutoencoderKL,32 DDIMScheduler,33 DPMSolverMultistepScheduler,34 EulerAncestralDiscreteScheduler,35 EulerDiscreteScheduler,36 HeunDiscreteScheduler,37 LMSDiscreteScheduler,38 PNDMScheduler,39 UNet2DConditionModel,40)41from diffusers.utils import is_omegaconf_available, is_safetensors_available42from diffusers.utils.import_utils import BACKENDS_MAPPING43 44 45# Copied from diffusers.pipelines.stable_diffusion.convert_from_ckpt.shave_segments46def shave_segments(path, n_shave_prefix_segments=1):47 """48 Removes segments. Positive values shave the first segments, negative shave the last segments.49 """50 if n_shave_prefix_segments >= 0:51 return ".".join(path.split(".")[n_shave_prefix_segments:])52 else:53 return ".".join(path.split(".")[:n_shave_prefix_segments])54 55 56# Copied from diffusers.pipelines.stable_diffusion.convert_from_ckpt.renew_resnet_paths57def renew_resnet_paths(old_list, n_shave_prefix_segments=0):58 """59 Updates paths inside resnets to the new naming scheme (local renaming)60 """61 mapping = []62 for old_item in old_list:63 new_item = old_item.replace("in_layers.0", "norm1")64 new_item = new_item.replace("in_layers.2", "conv1")65 66 new_item = new_item.replace("out_layers.0", "norm2")67 new_item = new_item.replace("out_layers.3", "conv2")68 69 new_item = new_item.replace("emb_layers.1", "time_emb_proj")70 new_item = new_item.replace("skip_connection", "conv_shortcut")71 72 new_item = shave_segments(new_item, n_shave_prefix_segments=n_shave_prefix_segments)73 74 mapping.append({"old": old_item, "new": new_item})75 76 return mapping77 78 79# Copied from diffusers.pipelines.stable_diffusion.convert_from_ckpt.renew_vae_resnet_paths80def renew_vae_resnet_paths(old_list, n_shave_prefix_segments=0):81 """82 Updates paths inside resnets to the new naming scheme (local renaming)83 """84 mapping = []85 for old_item in old_list:86 new_item = old_item87 88 new_item = new_item.replace("nin_shortcut", "conv_shortcut")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 96# Copied from diffusers.pipelines.stable_diffusion.convert_from_ckpt.renew_attention_paths97def renew_attention_paths(old_list):98 """99 Updates paths inside attentions to the new naming scheme (local renaming)100 """101 mapping = []102 for old_item in old_list:103 new_item = old_item104 105 # new_item = new_item.replace('norm.weight', 'group_norm.weight')106 # new_item = new_item.replace('norm.bias', 'group_norm.bias')107 108 # new_item = new_item.replace('proj_out.weight', 'proj_attn.weight')109 # new_item = new_item.replace('proj_out.bias', 'proj_attn.bias')110 111 # new_item = shave_segments(new_item, n_shave_prefix_segments=n_shave_prefix_segments)112 113 mapping.append({"old": old_item, "new": new_item})114 115 return mapping116 117 118# Copied from diffusers.pipelines.stable_diffusion.convert_from_ckpt.renew_vae_attention_paths119def renew_vae_attention_paths(old_list, n_shave_prefix_segments=0):120 """121 Updates paths inside attentions to the new naming scheme (local renaming)122 """123 mapping = []124 for old_item in old_list:125 new_item = old_item126 127 new_item = new_item.replace("norm.weight", "group_norm.weight")128 new_item = new_item.replace("norm.bias", "group_norm.bias")129 130 new_item = new_item.replace("q.weight", "query.weight")131 new_item = new_item.replace("q.bias", "query.bias")132 133 new_item = new_item.replace("k.weight", "key.weight")134 new_item = new_item.replace("k.bias", "key.bias")135 136 new_item = new_item.replace("v.weight", "value.weight")137 new_item = new_item.replace("v.bias", "value.bias")138 139 new_item = new_item.replace("proj_out.weight", "proj_attn.weight")140 new_item = new_item.replace("proj_out.bias", "proj_attn.bias")141 142 new_item = shave_segments(new_item, n_shave_prefix_segments=n_shave_prefix_segments)143 144 mapping.append({"old": old_item, "new": new_item})145 146 return mapping147 148 149# Copied from diffusers.pipelines.stable_diffusion.convert_from_ckpt.assign_to_checkpoint150def assign_to_checkpoint(151 paths, checkpoint, old_checkpoint, attention_paths_to_split=None, additional_replacements=None, config=None152):153 """154 This does the final conversion step: take locally converted weights and apply a global renaming to them. It splits155 attention layers, and takes into account additional replacements that may arise.156 157 Assigns the weights to the new checkpoint.158 """159 assert isinstance(paths, list), "Paths should be a list of dicts containing 'old' and 'new' keys."160 161 # Splits the attention layers into three variables.162 if attention_paths_to_split is not None:163 for path, path_map in attention_paths_to_split.items():164 old_tensor = old_checkpoint[path]165 channels = old_tensor.shape[0] // 3166 167 target_shape = (-1, channels) if len(old_tensor.shape) == 3 else (-1)168 169 num_heads = old_tensor.shape[0] // config["num_head_channels"] // 3170 171 old_tensor = old_tensor.reshape((num_heads, 3 * channels // num_heads) + old_tensor.shape[1:])172 query, key, value = old_tensor.split(channels // num_heads, dim=1)173 174 checkpoint[path_map["query"]] = query.reshape(target_shape)175 checkpoint[path_map["key"]] = key.reshape(target_shape)176 checkpoint[path_map["value"]] = value.reshape(target_shape)177 178 for path in paths:179 new_path = path["new"]180 181 # These have already been assigned182 if attention_paths_to_split is not None and new_path in attention_paths_to_split:183 continue184 185 # Global renaming happens here186 new_path = new_path.replace("middle_block.0", "mid_block.resnets.0")187 new_path = new_path.replace("middle_block.1", "mid_block.attentions.0")188 new_path = new_path.replace("middle_block.2", "mid_block.resnets.1")189 190 if additional_replacements is not None:191 for replacement in additional_replacements:192 new_path = new_path.replace(replacement["old"], replacement["new"])193 194 # proj_attn.weight has to be converted from conv 1D to linear195 if "proj_attn.weight" in new_path:196 checkpoint[new_path] = old_checkpoint[path["old"]][:, :, 0]197 else:198 checkpoint[new_path] = old_checkpoint[path["old"]]199 200 201# Copied from diffusers.pipelines.stable_diffusion.convert_from_ckpt.conv_attn_to_linear202def conv_attn_to_linear(checkpoint):203 keys = list(checkpoint.keys())204 attn_keys = ["query.weight", "key.weight", "value.weight"]205 for key in keys:206 if ".".join(key.split(".")[-2:]) in attn_keys:207 if checkpoint[key].ndim > 2:208 checkpoint[key] = checkpoint[key][:, :, 0, 0]209 elif "proj_attn.weight" in key:210 if checkpoint[key].ndim > 2:211 checkpoint[key] = checkpoint[key][:, :, 0]212 213 214def create_unet_diffusers_config(original_config, image_size: int):215 """216 Creates a UNet config for diffusers based on the config of the original AudioLDM model.217 """218 unet_params = original_config.model.params.unet_config.params219 vae_params = original_config.model.params.first_stage_config.params.ddconfig220 221 block_out_channels = [unet_params.model_channels * mult for mult in unet_params.channel_mult]222 223 down_block_types = []224 resolution = 1225 for i in range(len(block_out_channels)):226 block_type = "CrossAttnDownBlock2D" if resolution in unet_params.attention_resolutions else "DownBlock2D"227 down_block_types.append(block_type)228 if i != len(block_out_channels) - 1:229 resolution *= 2230 231 up_block_types = []232 for i in range(len(block_out_channels)):233 block_type = "CrossAttnUpBlock2D" if resolution in unet_params.attention_resolutions else "UpBlock2D"234 up_block_types.append(block_type)235 resolution //= 2236 237 vae_scale_factor = 2 ** (len(vae_params.ch_mult) - 1)238 239 cross_attention_dim = (240 unet_params.cross_attention_dim if "cross_attention_dim" in unet_params else block_out_channels241 )242 243 class_embed_type = "simple_projection" if "extra_film_condition_dim" in unet_params else None244 projection_class_embeddings_input_dim = (245 unet_params.extra_film_condition_dim if "extra_film_condition_dim" in unet_params else None246 )247 class_embeddings_concat = unet_params.extra_film_use_concat if "extra_film_use_concat" in unet_params else None248 249 config = {250 "sample_size": image_size // vae_scale_factor,251 "in_channels": unet_params.in_channels,252 "out_channels": unet_params.out_channels,253 "down_block_types": tuple(down_block_types),254 "up_block_types": tuple(up_block_types),255 "block_out_channels": tuple(block_out_channels),256 "layers_per_block": unet_params.num_res_blocks,257 "cross_attention_dim": cross_attention_dim,258 "class_embed_type": class_embed_type,259 "projection_class_embeddings_input_dim": projection_class_embeddings_input_dim,260 "class_embeddings_concat": class_embeddings_concat,261 }262 263 return config264 265 266# Adapted from diffusers.pipelines.stable_diffusion.convert_from_ckpt.create_vae_diffusers_config267def create_vae_diffusers_config(original_config, checkpoint, image_size: int):268 """269 Creates a VAE config for diffusers based on the config of the original AudioLDM model. Compared to the original270 Stable Diffusion conversion, this function passes a *learnt* VAE scaling factor to the diffusers VAE.271 """272 vae_params = original_config.model.params.first_stage_config.params.ddconfig273 _ = original_config.model.params.first_stage_config.params.embed_dim274 275 block_out_channels = [vae_params.ch * mult for mult in vae_params.ch_mult]276 down_block_types = ["DownEncoderBlock2D"] * len(block_out_channels)277 up_block_types = ["UpDecoderBlock2D"] * len(block_out_channels)278 279 scaling_factor = checkpoint["scale_factor"] if "scale_by_std" in original_config.model.params else 0.18215280 281 config = {282 "sample_size": image_size,283 "in_channels": vae_params.in_channels,284 "out_channels": vae_params.out_ch,285 "down_block_types": tuple(down_block_types),286 "up_block_types": tuple(up_block_types),287 "block_out_channels": tuple(block_out_channels),288 "latent_channels": vae_params.z_channels,289 "layers_per_block": vae_params.num_res_blocks,290 "scaling_factor": float(scaling_factor),291 }292 return config293 294 295# Copied from diffusers.pipelines.stable_diffusion.convert_from_ckpt.create_diffusers_schedular296def create_diffusers_schedular(original_config):297 schedular = DDIMScheduler(298 num_train_timesteps=original_config.model.params.timesteps,299 beta_start=original_config.model.params.linear_start,300 beta_end=original_config.model.params.linear_end,301 beta_schedule="scaled_linear",302 )303 return schedular304 305 306# Adapted from diffusers.pipelines.stable_diffusion.convert_from_ckpt.convert_ldm_unet_checkpoint307def convert_ldm_unet_checkpoint(checkpoint, config, path=None, extract_ema=False):308 """309 Takes a state dict and a config, and returns a converted checkpoint. Compared to the original Stable Diffusion310 conversion, this function additionally converts the learnt film embedding linear layer.311 """312 313 # extract state_dict for UNet314 unet_state_dict = {}315 keys = list(checkpoint.keys())316 317 unet_key = "model.diffusion_model."318 # at least a 100 parameters have to start with `model_ema` in order for the checkpoint to be EMA319 if sum(k.startswith("model_ema") for k in keys) > 100 and extract_ema:320 print(f"Checkpoint {path} has both EMA and non-EMA weights.")321 print(322 "In this conversion only the EMA weights are extracted. If you want to instead extract the non-EMA"323 " weights (useful to continue fine-tuning), please make sure to remove the `--extract_ema` flag."324 )325 for key in keys:326 if key.startswith("model.diffusion_model"):327 flat_ema_key = "model_ema." + "".join(key.split(".")[1:])328 unet_state_dict[key.replace(unet_key, "")] = checkpoint.pop(flat_ema_key)329 else:330 if sum(k.startswith("model_ema") for k in keys) > 100:331 print(332 "In this conversion only the non-EMA weights are extracted. If you want to instead extract the EMA"333 " weights (usually better for inference), please make sure to add the `--extract_ema` flag."334 )335 336 for key in keys:337 if key.startswith(unet_key):338 unet_state_dict[key.replace(unet_key, "")] = checkpoint.pop(key)339 340 new_checkpoint = {}341 342 new_checkpoint["time_embedding.linear_1.weight"] = unet_state_dict["time_embed.0.weight"]343 new_checkpoint["time_embedding.linear_1.bias"] = unet_state_dict["time_embed.0.bias"]344 new_checkpoint["time_embedding.linear_2.weight"] = unet_state_dict["time_embed.2.weight"]345 new_checkpoint["time_embedding.linear_2.bias"] = unet_state_dict["time_embed.2.bias"]346 347 new_checkpoint["class_embedding.weight"] = unet_state_dict["film_emb.weight"]348 new_checkpoint["class_embedding.bias"] = unet_state_dict["film_emb.bias"]349 350 new_checkpoint["conv_in.weight"] = unet_state_dict["input_blocks.0.0.weight"]351 new_checkpoint["conv_in.bias"] = unet_state_dict["input_blocks.0.0.bias"]352 353 new_checkpoint["conv_norm_out.weight"] = unet_state_dict["out.0.weight"]354 new_checkpoint["conv_norm_out.bias"] = unet_state_dict["out.0.bias"]355 new_checkpoint["conv_out.weight"] = unet_state_dict["out.2.weight"]356 new_checkpoint["conv_out.bias"] = unet_state_dict["out.2.bias"]357 358 # Retrieves the keys for the input blocks only359 num_input_blocks = len({".".join(layer.split(".")[:2]) for layer in unet_state_dict if "input_blocks" in layer})360 input_blocks = {361 layer_id: [key for key in unet_state_dict if f"input_blocks.{layer_id}" in key]362 for layer_id in range(num_input_blocks)363 }364 365 # Retrieves the keys for the middle blocks only366 num_middle_blocks = len({".".join(layer.split(".")[:2]) for layer in unet_state_dict if "middle_block" in layer})367 middle_blocks = {368 layer_id: [key for key in unet_state_dict if f"middle_block.{layer_id}" in key]369 for layer_id in range(num_middle_blocks)370 }371 372 # Retrieves the keys for the output blocks only373 num_output_blocks = len({".".join(layer.split(".")[:2]) for layer in unet_state_dict if "output_blocks" in layer})374 output_blocks = {375 layer_id: [key for key in unet_state_dict if f"output_blocks.{layer_id}" in key]376 for layer_id in range(num_output_blocks)377 }378 379 for i in range(1, num_input_blocks):380 block_id = (i - 1) // (config["layers_per_block"] + 1)381 layer_in_block_id = (i - 1) % (config["layers_per_block"] + 1)382 383 resnets = [384 key for key in input_blocks[i] if f"input_blocks.{i}.0" in key and f"input_blocks.{i}.0.op" not in key385 ]386 attentions = [key for key in input_blocks[i] if f"input_blocks.{i}.1" in key]387 388 if f"input_blocks.{i}.0.op.weight" in unet_state_dict:389 new_checkpoint[f"down_blocks.{block_id}.downsamplers.0.conv.weight"] = unet_state_dict.pop(390 f"input_blocks.{i}.0.op.weight"391 )392 new_checkpoint[f"down_blocks.{block_id}.downsamplers.0.conv.bias"] = unet_state_dict.pop(393 f"input_blocks.{i}.0.op.bias"394 )395 396 paths = renew_resnet_paths(resnets)397 meta_path = {"old": f"input_blocks.{i}.0", "new": f"down_blocks.{block_id}.resnets.{layer_in_block_id}"}398 assign_to_checkpoint(399 paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config400 )401 402 if len(attentions):403 paths = renew_attention_paths(attentions)404 meta_path = {"old": f"input_blocks.{i}.1", "new": f"down_blocks.{block_id}.attentions.{layer_in_block_id}"}405 assign_to_checkpoint(406 paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config407 )408 409 resnet_0 = middle_blocks[0]410 attentions = middle_blocks[1]411 resnet_1 = middle_blocks[2]412 413 resnet_0_paths = renew_resnet_paths(resnet_0)414 assign_to_checkpoint(resnet_0_paths, new_checkpoint, unet_state_dict, config=config)415 416 resnet_1_paths = renew_resnet_paths(resnet_1)417 assign_to_checkpoint(resnet_1_paths, new_checkpoint, unet_state_dict, config=config)418 419 attentions_paths = renew_attention_paths(attentions)420 meta_path = {"old": "middle_block.1", "new": "mid_block.attentions.0"}421 assign_to_checkpoint(422 attentions_paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config423 )424 425 for i in range(num_output_blocks):426 block_id = i // (config["layers_per_block"] + 1)427 layer_in_block_id = i % (config["layers_per_block"] + 1)428 output_block_layers = [shave_segments(name, 2) for name in output_blocks[i]]429 output_block_list = {}430 431 for layer in output_block_layers:432 layer_id, layer_name = layer.split(".")[0], shave_segments(layer, 1)433 if layer_id in output_block_list:434 output_block_list[layer_id].append(layer_name)435 else:436 output_block_list[layer_id] = [layer_name]437 438 if len(output_block_list) > 1:439 resnets = [key for key in output_blocks[i] if f"output_blocks.{i}.0" in key]440 attentions = [key for key in output_blocks[i] if f"output_blocks.{i}.1" in key]441 442 resnet_0_paths = renew_resnet_paths(resnets)443 paths = renew_resnet_paths(resnets)444 445 meta_path = {"old": f"output_blocks.{i}.0", "new": f"up_blocks.{block_id}.resnets.{layer_in_block_id}"}446 assign_to_checkpoint(447 paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config448 )449 450 output_block_list = {k: sorted(v) for k, v in output_block_list.items()}451 if ["conv.bias", "conv.weight"] in output_block_list.values():452 index = list(output_block_list.values()).index(["conv.bias", "conv.weight"])453 new_checkpoint[f"up_blocks.{block_id}.upsamplers.0.conv.weight"] = unet_state_dict[454 f"output_blocks.{i}.{index}.conv.weight"455 ]456 new_checkpoint[f"up_blocks.{block_id}.upsamplers.0.conv.bias"] = unet_state_dict[457 f"output_blocks.{i}.{index}.conv.bias"458 ]459 460 # Clear attentions as they have been attributed above.461 if len(attentions) == 2:462 attentions = []463 464 if len(attentions):465 paths = renew_attention_paths(attentions)466 meta_path = {467 "old": f"output_blocks.{i}.1",468 "new": f"up_blocks.{block_id}.attentions.{layer_in_block_id}",469 }470 assign_to_checkpoint(471 paths, new_checkpoint, unet_state_dict, additional_replacements=[meta_path], config=config472 )473 else:474 resnet_0_paths = renew_resnet_paths(output_block_layers, n_shave_prefix_segments=1)475 for path in resnet_0_paths:476 old_path = ".".join(["output_blocks", str(i), path["old"]])477 new_path = ".".join(["up_blocks", str(block_id), "resnets", str(layer_in_block_id), path["new"]])478 479 new_checkpoint[new_path] = unet_state_dict[old_path]480 481 return new_checkpoint482 483 484# Copied from diffusers.pipelines.stable_diffusion.convert_from_ckpt.convert_ldm_vae_checkpoint485def convert_ldm_vae_checkpoint(checkpoint, config):486 # extract state dict for VAE487 vae_state_dict = {}488 vae_key = "first_stage_model."489 keys = list(checkpoint.keys())490 for key in keys:491 if key.startswith(vae_key):492 vae_state_dict[key.replace(vae_key, "")] = checkpoint.get(key)493 494 new_checkpoint = {}495 496 new_checkpoint["encoder.conv_in.weight"] = vae_state_dict["encoder.conv_in.weight"]497 new_checkpoint["encoder.conv_in.bias"] = vae_state_dict["encoder.conv_in.bias"]498 new_checkpoint["encoder.conv_out.weight"] = vae_state_dict["encoder.conv_out.weight"]499 new_checkpoint["encoder.conv_out.bias"] = vae_state_dict["encoder.conv_out.bias"]500 new_checkpoint["encoder.conv_norm_out.weight"] = vae_state_dict["encoder.norm_out.weight"]501 new_checkpoint["encoder.conv_norm_out.bias"] = vae_state_dict["encoder.norm_out.bias"]502 503 new_checkpoint["decoder.conv_in.weight"] = vae_state_dict["decoder.conv_in.weight"]504 new_checkpoint["decoder.conv_in.bias"] = vae_state_dict["decoder.conv_in.bias"]505 new_checkpoint["decoder.conv_out.weight"] = vae_state_dict["decoder.conv_out.weight"]506 new_checkpoint["decoder.conv_out.bias"] = vae_state_dict["decoder.conv_out.bias"]507 new_checkpoint["decoder.conv_norm_out.weight"] = vae_state_dict["decoder.norm_out.weight"]508 new_checkpoint["decoder.conv_norm_out.bias"] = vae_state_dict["decoder.norm_out.bias"]509 510 new_checkpoint["quant_conv.weight"] = vae_state_dict["quant_conv.weight"]511 new_checkpoint["quant_conv.bias"] = vae_state_dict["quant_conv.bias"]512 new_checkpoint["post_quant_conv.weight"] = vae_state_dict["post_quant_conv.weight"]513 new_checkpoint["post_quant_conv.bias"] = vae_state_dict["post_quant_conv.bias"]514 515 # Retrieves the keys for the encoder down blocks only516 num_down_blocks = len({".".join(layer.split(".")[:3]) for layer in vae_state_dict if "encoder.down" in layer})517 down_blocks = {518 layer_id: [key for key in vae_state_dict if f"down.{layer_id}" in key] for layer_id in range(num_down_blocks)519 }520 521 # Retrieves the keys for the decoder up blocks only522 num_up_blocks = len({".".join(layer.split(".")[:3]) for layer in vae_state_dict if "decoder.up" in layer})523 up_blocks = {524 layer_id: [key for key in vae_state_dict if f"up.{layer_id}" in key] for layer_id in range(num_up_blocks)525 }526 527 for i in range(num_down_blocks):528 resnets = [key for key in down_blocks[i] if f"down.{i}" in key and f"down.{i}.downsample" not in key]529 530 if f"encoder.down.{i}.downsample.conv.weight" in vae_state_dict:531 new_checkpoint[f"encoder.down_blocks.{i}.downsamplers.0.conv.weight"] = vae_state_dict.pop(532 f"encoder.down.{i}.downsample.conv.weight"533 )534 new_checkpoint[f"encoder.down_blocks.{i}.downsamplers.0.conv.bias"] = vae_state_dict.pop(535 f"encoder.down.{i}.downsample.conv.bias"536 )537 538 paths = renew_vae_resnet_paths(resnets)539 meta_path = {"old": f"down.{i}.block", "new": f"down_blocks.{i}.resnets"}540 assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)541 542 mid_resnets = [key for key in vae_state_dict if "encoder.mid.block" in key]543 num_mid_res_blocks = 2544 for i in range(1, num_mid_res_blocks + 1):545 resnets = [key for key in mid_resnets if f"encoder.mid.block_{i}" in key]546 547 paths = renew_vae_resnet_paths(resnets)548 meta_path = {"old": f"mid.block_{i}", "new": f"mid_block.resnets.{i - 1}"}549 assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)550 551 mid_attentions = [key for key in vae_state_dict if "encoder.mid.attn" in key]552 paths = renew_vae_attention_paths(mid_attentions)553 meta_path = {"old": "mid.attn_1", "new": "mid_block.attentions.0"}554 assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)555 conv_attn_to_linear(new_checkpoint)556 557 for i in range(num_up_blocks):558 block_id = num_up_blocks - 1 - i559 resnets = [560 key for key in up_blocks[block_id] if f"up.{block_id}" in key and f"up.{block_id}.upsample" not in key561 ]562 563 if f"decoder.up.{block_id}.upsample.conv.weight" in vae_state_dict:564 new_checkpoint[f"decoder.up_blocks.{i}.upsamplers.0.conv.weight"] = vae_state_dict[565 f"decoder.up.{block_id}.upsample.conv.weight"566 ]567 new_checkpoint[f"decoder.up_blocks.{i}.upsamplers.0.conv.bias"] = vae_state_dict[568 f"decoder.up.{block_id}.upsample.conv.bias"569 ]570 571 paths = renew_vae_resnet_paths(resnets)572 meta_path = {"old": f"up.{block_id}.block", "new": f"up_blocks.{i}.resnets"}573 assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)574 575 mid_resnets = [key for key in vae_state_dict if "decoder.mid.block" in key]576 num_mid_res_blocks = 2577 for i in range(1, num_mid_res_blocks + 1):578 resnets = [key for key in mid_resnets if f"decoder.mid.block_{i}" in key]579 580 paths = renew_vae_resnet_paths(resnets)581 meta_path = {"old": f"mid.block_{i}", "new": f"mid_block.resnets.{i - 1}"}582 assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)583 584 mid_attentions = [key for key in vae_state_dict if "decoder.mid.attn" in key]585 paths = renew_vae_attention_paths(mid_attentions)586 meta_path = {"old": "mid.attn_1", "new": "mid_block.attentions.0"}587 assign_to_checkpoint(paths, new_checkpoint, vae_state_dict, additional_replacements=[meta_path], config=config)588 conv_attn_to_linear(new_checkpoint)589 return new_checkpoint590 591 592CLAP_KEYS_TO_MODIFY_MAPPING = {593 "text_branch": "text_model",594 "attn": "attention.self",595 "self.proj": "output.dense",596 "attention.self_mask": "attn_mask",597 "mlp.fc1": "intermediate.dense",598 "mlp.fc2": "output.dense",599 "norm1": "layernorm_before",600 "norm2": "layernorm_after",601 "bn0": "batch_norm",602}603 604CLAP_KEYS_TO_IGNORE = ["text_transform"]605 606CLAP_EXPECTED_MISSING_KEYS = ["text_model.embeddings.token_type_ids"]607 608 609def convert_open_clap_checkpoint(checkpoint):610 """611 Takes a state dict and returns a converted CLAP checkpoint.612 """613 # extract state dict for CLAP text embedding model, discarding the audio component614 model_state_dict = {}615 model_key = "cond_stage_model.model.text_"616 keys = list(checkpoint.keys())617 for key in keys:618 if key.startswith(model_key):619 model_state_dict[key.replace(model_key, "text_")] = checkpoint.get(key)620 621 new_checkpoint = {}622 623 sequential_layers_pattern = r".*sequential.(\d+).*"624 text_projection_pattern = r".*_projection.(\d+).*"625 626 for key, value in model_state_dict.items():627 # check if key should be ignored in mapping628 if key.split(".")[0] in CLAP_KEYS_TO_IGNORE:629 continue630 631 # check if any key needs to be modified632 for key_to_modify, new_key in CLAP_KEYS_TO_MODIFY_MAPPING.items():633 if key_to_modify in key:634 key = key.replace(key_to_modify, new_key)635 636 if re.match(sequential_layers_pattern, key):637 # replace sequential layers with list638 sequential_layer = re.match(sequential_layers_pattern, key).group(1)639 640 key = key.replace(f"sequential.{sequential_layer}.", f"layers.{int(sequential_layer)//3}.linear.")641 elif re.match(text_projection_pattern, key):642 projecton_layer = int(re.match(text_projection_pattern, key).group(1))643 644 # Because in CLAP they use `nn.Sequential`...645 transformers_projection_layer = 1 if projecton_layer == 0 else 2646 647 key = key.replace(f"_projection.{projecton_layer}.", f"_projection.linear{transformers_projection_layer}.")648 649 if "audio" and "qkv" in key:650 # split qkv into query key and value651 mixed_qkv = value652 qkv_dim = mixed_qkv.size(0) // 3653 654 query_layer = mixed_qkv[:qkv_dim]655 key_layer = mixed_qkv[qkv_dim : qkv_dim * 2]656 value_layer = mixed_qkv[qkv_dim * 2 :]657 658 new_checkpoint[key.replace("qkv", "query")] = query_layer659 new_checkpoint[key.replace("qkv", "key")] = key_layer660 new_checkpoint[key.replace("qkv", "value")] = value_layer661 else:662 new_checkpoint[key] = value663 664 return new_checkpoint665 666 667def create_transformers_vocoder_config(original_config):668 """669 Creates a config for transformers SpeechT5HifiGan based on the config of the vocoder model.670 """671 vocoder_params = original_config.model.params.vocoder_config.params672 673 config = {674 "model_in_dim": vocoder_params.num_mels,675 "sampling_rate": vocoder_params.sampling_rate,676 "upsample_initial_channel": vocoder_params.upsample_initial_channel,677 "upsample_rates": list(vocoder_params.upsample_rates),678 "upsample_kernel_sizes": list(vocoder_params.upsample_kernel_sizes),679 "resblock_kernel_sizes": list(vocoder_params.resblock_kernel_sizes),680 "resblock_dilation_sizes": [681 list(resblock_dilation) for resblock_dilation in vocoder_params.resblock_dilation_sizes682 ],683 "normalize_before": False,684 }685 686 return config687 688 689def convert_hifigan_checkpoint(checkpoint, config):690 """691 Takes a state dict and config, and returns a converted HiFiGAN vocoder checkpoint.692 """693 # extract state dict for vocoder694 vocoder_state_dict = {}695 vocoder_key = "first_stage_model.vocoder."696 keys = list(checkpoint.keys())697 for key in keys:698 if key.startswith(vocoder_key):699 vocoder_state_dict[key.replace(vocoder_key, "")] = checkpoint.get(key)700 701 # fix upsampler keys, everything else is correct already702 for i in range(len(config.upsample_rates)):703 vocoder_state_dict[f"upsampler.{i}.weight"] = vocoder_state_dict.pop(f"ups.{i}.weight")704 vocoder_state_dict[f"upsampler.{i}.bias"] = vocoder_state_dict.pop(f"ups.{i}.bias")705 706 if not config.normalize_before:707 # if we don't set normalize_before then these variables are unused, so we set them to their initialised values708 vocoder_state_dict["mean"] = torch.zeros(config.model_in_dim)709 vocoder_state_dict["scale"] = torch.ones(config.model_in_dim)710 711 return vocoder_state_dict712 713 714# Adapted from https://huggingface.co/spaces/haoheliu/audioldm-text-to-audio-generation/blob/84a0384742a22bd80c44e903e241f0623e874f1d/audioldm/utils.py#L72-L73715DEFAULT_CONFIG = {716 "model": {717 "params": {718 "linear_start": 0.0015,719 "linear_end": 0.0195,720 "timesteps": 1000,721 "channels": 8,722 "scale_by_std": True,723 "unet_config": {724 "target": "audioldm.latent_diffusion.openaimodel.UNetModel",725 "params": {726 "extra_film_condition_dim": 512,727 "extra_film_use_concat": True,728 "in_channels": 8,729 "out_channels": 8,730 "model_channels": 128,731 "attention_resolutions": [8, 4, 2],732 "num_res_blocks": 2,733 "channel_mult": [1, 2, 3, 5],734 "num_head_channels": 32,735 },736 },737 "first_stage_config": {738 "target": "audioldm.variational_autoencoder.autoencoder.AutoencoderKL",739 "params": {740 "embed_dim": 8,741 "ddconfig": {742 "z_channels": 8,743 "resolution": 256,744 "in_channels": 1,745 "out_ch": 1,746 "ch": 128,747 "ch_mult": [1, 2, 4],748 "num_res_blocks": 2,749 },750 },751 },752 "vocoder_config": {753 "target": "audioldm.first_stage_model.vocoder",754 "params": {755 "upsample_rates": [5, 4, 2, 2, 2],756 "upsample_kernel_sizes": [16, 16, 8, 4, 4],757 "upsample_initial_channel": 1024,758 "resblock_kernel_sizes": [3, 7, 11],759 "resblock_dilation_sizes": [[1, 3, 5], [1, 3, 5], [1, 3, 5]],760 "num_mels": 64,761 "sampling_rate": 16000,762 },763 },764 },765 },766}767 768 769def load_pipeline_from_original_audioldm_ckpt(770 checkpoint_path: str,771 original_config_file: str = None,772 image_size: int = 512,773 prediction_type: str = None,774 extract_ema: bool = False,775 scheduler_type: str = "ddim",776 num_in_channels: int = None,777 device: str = None,778 from_safetensors: bool = False,779) -> AudioLDMPipeline:780 """781 Load an AudioLDM pipeline object from a `.ckpt`/`.safetensors` file and (ideally) a `.yaml` config file.782 783 Although many of the arguments can be automatically inferred, some of these rely on brittle checks against the784 global step count, which will likely fail for models that have undergone further fine-tuning. Therefore, it is785 recommended that you override the default values and/or supply an `original_config_file` wherever possible.786 787 :param checkpoint_path: Path to `.ckpt` file. :param original_config_file: Path to `.yaml` config file788 corresponding to the original architecture.789 If `None`, will be automatically instantiated based on default values.790 :param image_size: The image size that the model was trained on. Use 512 for original AudioLDM checkpoints. :param791 prediction_type: The prediction type that the model was trained on. Use `'epsilon'` for original792 AudioLDM checkpoints.793 :param num_in_channels: The number of input channels. If `None` number of input channels will be automatically794 inferred.795 :param scheduler_type: Type of scheduler to use. Should be one of `["pndm", "lms", "heun", "euler",796 "euler-ancestral", "dpm", "ddim"]`.797 :param extract_ema: Only relevant for checkpoints that have both EMA and non-EMA weights. Whether to extract798 the EMA weights or not. Defaults to `False`. Pass `True` to extract the EMA weights. EMA weights usually799 yield higher quality images for inference. Non-EMA weights are usually better to continue fine-tuning.800 :param device: The device to use. Pass `None` to determine automatically. :param from_safetensors: If801 `checkpoint_path` is in `safetensors` format, load checkpoint with safetensors802 instead of PyTorch.803 :return: An AudioLDMPipeline object representing the passed-in `.ckpt`/`.safetensors` file.804 """805 806 if not is_omegaconf_available():807 raise ValueError(BACKENDS_MAPPING["omegaconf"][1])808 809 from omegaconf import OmegaConf810 811 if from_safetensors:812 if not is_safetensors_available():813 raise ValueError(BACKENDS_MAPPING["safetensors"][1])814 815 from safetensors import safe_open816 817 checkpoint = {}818 with safe_open(checkpoint_path, framework="pt", device="cpu") as f:819 for key in f.keys():820 checkpoint[key] = f.get_tensor(key)821 else:822 if device is None:823 device = "cuda" if torch.cuda.is_available() else "cpu"824 checkpoint = torch.load(checkpoint_path, map_location=device)825 else:826 checkpoint = torch.load(checkpoint_path, map_location=device)827 828 if "state_dict" in checkpoint:829 checkpoint = checkpoint["state_dict"]830 831 if original_config_file is None:832 original_config = DEFAULT_CONFIG833 original_config = OmegaConf.create(original_config)834 else:835 original_config = OmegaConf.load(original_config_file)836 837 if num_in_channels is not None:838 original_config["model"]["params"]["unet_config"]["params"]["in_channels"] = num_in_channels839 840 if (841 "parameterization" in original_config["model"]["params"]842 and original_config["model"]["params"]["parameterization"] == "v"843 ):844 if prediction_type is None:845 prediction_type = "v_prediction"846 else:847 if prediction_type is None:848 prediction_type = "epsilon"849 850 if image_size is None:851 image_size = 512852 853 num_train_timesteps = original_config.model.params.timesteps854 beta_start = original_config.model.params.linear_start855 beta_end = original_config.model.params.linear_end856 857 scheduler = DDIMScheduler(858 beta_end=beta_end,859 beta_schedule="scaled_linear",860 beta_start=beta_start,861 num_train_timesteps=num_train_timesteps,862 steps_offset=1,863 clip_sample=False,864 set_alpha_to_one=False,865 prediction_type=prediction_type,866 )867 # make sure scheduler works correctly with DDIM868 scheduler.register_to_config(clip_sample=False)869 870 if scheduler_type == "pndm":871 config = dict(scheduler.config)872 config["skip_prk_steps"] = True873 scheduler = PNDMScheduler.from_config(config)874 elif scheduler_type == "lms":875 scheduler = LMSDiscreteScheduler.from_config(scheduler.config)876 elif scheduler_type == "heun":877 scheduler = HeunDiscreteScheduler.from_config(scheduler.config)878 elif scheduler_type == "euler":879 scheduler = EulerDiscreteScheduler.from_config(scheduler.config)880 elif scheduler_type == "euler-ancestral":881 scheduler = EulerAncestralDiscreteScheduler.from_config(scheduler.config)882 elif scheduler_type == "dpm":883 scheduler = DPMSolverMultistepScheduler.from_config(scheduler.config)884 elif scheduler_type == "ddim":885 scheduler = scheduler886 else:887 raise ValueError(f"Scheduler of type {scheduler_type} doesn't exist!")888 889 # Convert the UNet2DModel890 unet_config = create_unet_diffusers_config(original_config, image_size=image_size)891 unet = UNet2DConditionModel(**unet_config)892 893 converted_unet_checkpoint = convert_ldm_unet_checkpoint(894 checkpoint, unet_config, path=checkpoint_path, extract_ema=extract_ema895 )896 897 unet.load_state_dict(converted_unet_checkpoint)898 899 # Convert the VAE model900 vae_config = create_vae_diffusers_config(original_config, checkpoint=checkpoint, image_size=image_size)901 converted_vae_checkpoint = convert_ldm_vae_checkpoint(checkpoint, vae_config)902 903 vae = AutoencoderKL(**vae_config)904 vae.load_state_dict(converted_vae_checkpoint)905 906 # Convert the text model907 # AudioLDM uses the same configuration and tokenizer as the original CLAP model908 config = ClapTextConfig.from_pretrained("laion/clap-htsat-unfused")909 tokenizer = AutoTokenizer.from_pretrained("laion/clap-htsat-unfused")910 911 converted_text_model = convert_open_clap_checkpoint(checkpoint)912 text_model = ClapTextModelWithProjection(config)913 914 missing_keys, unexpected_keys = text_model.load_state_dict(converted_text_model, strict=False)915 # we expect not to have token_type_ids in our original state dict so let's ignore them916 missing_keys = list(set(missing_keys) - set(CLAP_EXPECTED_MISSING_KEYS))917 918 if len(unexpected_keys) > 0:919 raise ValueError(f"Unexpected keys when loading CLAP model: {unexpected_keys}")920 921 if len(missing_keys) > 0:922 raise ValueError(f"Missing keys when loading CLAP model: {missing_keys}")923 924 # Convert the vocoder model925 vocoder_config = create_transformers_vocoder_config(original_config)926 vocoder_config = SpeechT5HifiGanConfig(**vocoder_config)927 converted_vocoder_checkpoint = convert_hifigan_checkpoint(checkpoint, vocoder_config)928 929 vocoder = SpeechT5HifiGan(vocoder_config)930 vocoder.load_state_dict(converted_vocoder_checkpoint)931 932 # Instantiate the diffusers pipeline933 pipe = AudioLDMPipeline(934 vae=vae,935 text_encoder=text_model,936 tokenizer=tokenizer,937 unet=unet,938 scheduler=scheduler,939 vocoder=vocoder,940 )941 942 return pipe943 944 945if __name__ == "__main__":946 parser = argparse.ArgumentParser()947 948 parser.add_argument(949 "--checkpoint_path", default=None, type=str, required=True, help="Path to the checkpoint to convert."950 )951 parser.add_argument(952 "--original_config_file",953 default=None,954 type=str,955 help="The YAML config file corresponding to the original architecture.",956 )957 parser.add_argument(958 "--num_in_channels",959 default=None,960 type=int,961 help="The number of input channels. If `None` number of input channels will be automatically inferred.",962 )963 parser.add_argument(964 "--scheduler_type",965 default="ddim",966 type=str,967 help="Type of scheduler to use. Should be one of ['pndm', 'lms', 'ddim', 'euler', 'euler-ancestral', 'dpm']",968 )969 parser.add_argument(970 "--image_size",971 default=None,972 type=int,973 help=("The image size that the model was trained on."),974 )975 parser.add_argument(976 "--prediction_type",977 default=None,978 type=str,979 help=("The prediction type that the model was trained on."),980 )981 parser.add_argument(982 "--extract_ema",983 action="store_true",984 help=(985 "Only relevant for checkpoints that have both EMA and non-EMA weights. Whether to extract the EMA weights"986 " or not. Defaults to `False`. Add `--extract_ema` to extract the EMA weights. EMA weights usually yield"987 " higher quality images for inference. Non-EMA weights are usually better to continue fine-tuning."988 ),989 )990 parser.add_argument(991 "--from_safetensors",992 action="store_true",993 help="If `--checkpoint_path` is in `safetensors` format, load checkpoint with safetensors instead of PyTorch.",994 )995 parser.add_argument(996 "--to_safetensors",997 action="store_true",998 help="Whether to store pipeline in safetensors format or not.",999 )1000 parser.add_argument("--dump_path", default=None, type=str, required=True, help="Path to the output model.")1001 parser.add_argument("--device", type=str, help="Device to use (e.g. cpu, cuda:0, cuda:1, etc.)")1002 args = parser.parse_args()1003 1004 pipe = load_pipeline_from_original_audioldm_ckpt(1005 checkpoint_path=args.checkpoint_path,1006 original_config_file=args.original_config_file,1007 image_size=args.image_size,1008 prediction_type=args.prediction_type,1009 extract_ema=args.extract_ema,1010 scheduler_type=args.scheduler_type,1011 num_in_channels=args.num_in_channels,1012 from_safetensors=args.from_safetensors,1013 device=args.device,1014 )1015 pipe.save_pretrained(args.dump_path, safe_serialization=args.to_safetensors)1016 