fred-dev/comfy_ui_ali
0
1"""2 This file is part of ComfyUI.3 Copyright (C) 2024 Comfy4 5 This program is free software: you can redistribute it and/or modify6 it under the terms of the GNU General Public License as published by7 the Free Software Foundation, either version 3 of the License, or8 (at your option) any later version.9 10 This program is distributed in the hope that it will be useful,11 but WITHOUT ANY WARRANTY; without even the implied warranty of12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13 GNU General Public License for more details.14 15 You should have received a copy of the GNU General Public License16 along with this program. If not, see <https://www.gnu.org/licenses/>.17"""18 19 20import torch21import math22import struct23import comfy.checkpoint_pickle24import safetensors.torch25import numpy as np26from PIL import Image27import logging28import itertools29from torch.nn.functional import interpolate30from einops import rearrange31 32ALWAYS_SAFE_LOAD = False33if hasattr(torch.serialization, "add_safe_globals"): # TODO: this was added in pytorch 2.4, the unsafe path should be removed once earlier versions are deprecated34 class ModelCheckpoint:35 pass36 ModelCheckpoint.__module__ = "pytorch_lightning.callbacks.model_checkpoint"37 38 from numpy.core.multiarray import scalar39 from numpy import dtype40 from numpy.dtypes import Float64DType41 from _codecs import encode42 43 torch.serialization.add_safe_globals([ModelCheckpoint, scalar, dtype, Float64DType, encode])44 ALWAYS_SAFE_LOAD = True45 logging.info("Checkpoint files will always be loaded safely.")46else:47 logging.info("Warning, you are using an old pytorch version and some ckpt/pt files might be loaded unsafely. Upgrading to 2.4 or above is recommended.")48 49def load_torch_file(ckpt, safe_load=False, device=None, return_metadata=False):50 if device is None:51 device = torch.device("cpu")52 metadata = None53 if ckpt.lower().endswith(".safetensors") or ckpt.lower().endswith(".sft"):54 try:55 with safetensors.safe_open(ckpt, framework="pt", device=device.type) as f:56 sd = {}57 for k in f.keys():58 sd[k] = f.get_tensor(k)59 if return_metadata:60 metadata = f.metadata()61 except Exception as e:62 if len(e.args) > 0:63 message = e.args[0]64 if "HeaderTooLarge" in message:65 raise ValueError("{}\n\nFile path: {}\n\nThe safetensors file is corrupt or invalid. Make sure this is actually a safetensors file and not a ckpt or pt or other filetype.".format(message, ckpt))66 if "MetadataIncompleteBuffer" in message:67 raise ValueError("{}\n\nFile path: {}\n\nThe safetensors file is corrupt/incomplete. Check the file size and make sure you have copied/downloaded it correctly.".format(message, ckpt))68 raise e69 else:70 if safe_load or ALWAYS_SAFE_LOAD:71 pl_sd = torch.load(ckpt, map_location=device, weights_only=True)72 else:73 pl_sd = torch.load(ckpt, map_location=device, pickle_module=comfy.checkpoint_pickle)74 if "global_step" in pl_sd:75 logging.debug(f"Global Step: {pl_sd['global_step']}")76 if "state_dict" in pl_sd:77 sd = pl_sd["state_dict"]78 else:79 if len(pl_sd) == 1:80 key = list(pl_sd.keys())[0]81 sd = pl_sd[key]82 if not isinstance(sd, dict):83 sd = pl_sd84 else:85 sd = pl_sd86 return (sd, metadata) if return_metadata else sd87 88def save_torch_file(sd, ckpt, metadata=None):89 if metadata is not None:90 safetensors.torch.save_file(sd, ckpt, metadata=metadata)91 else:92 safetensors.torch.save_file(sd, ckpt)93 94def calculate_parameters(sd, prefix=""):95 params = 096 for k in sd.keys():97 if k.startswith(prefix):98 w = sd[k]99 params += w.nelement()100 return params101 102def weight_dtype(sd, prefix=""):103 dtypes = {}104 for k in sd.keys():105 if k.startswith(prefix):106 w = sd[k]107 dtypes[w.dtype] = dtypes.get(w.dtype, 0) + w.numel()108 109 if len(dtypes) == 0:110 return None111 112 return max(dtypes, key=dtypes.get)113 114def state_dict_key_replace(state_dict, keys_to_replace):115 for x in keys_to_replace:116 if x in state_dict:117 state_dict[keys_to_replace[x]] = state_dict.pop(x)118 return state_dict119 120def state_dict_prefix_replace(state_dict, replace_prefix, filter_keys=False):121 if filter_keys:122 out = {}123 else:124 out = state_dict125 for rp in replace_prefix:126 replace = list(map(lambda a: (a, "{}{}".format(replace_prefix[rp], a[len(rp):])), filter(lambda a: a.startswith(rp), state_dict.keys())))127 for x in replace:128 w = state_dict.pop(x[0])129 out[x[1]] = w130 return out131 132 133def transformers_convert(sd, prefix_from, prefix_to, number):134 keys_to_replace = {135 "{}positional_embedding": "{}embeddings.position_embedding.weight",136 "{}token_embedding.weight": "{}embeddings.token_embedding.weight",137 "{}ln_final.weight": "{}final_layer_norm.weight",138 "{}ln_final.bias": "{}final_layer_norm.bias",139 }140 141 for k in keys_to_replace:142 x = k.format(prefix_from)143 if x in sd:144 sd[keys_to_replace[k].format(prefix_to)] = sd.pop(x)145 146 resblock_to_replace = {147 "ln_1": "layer_norm1",148 "ln_2": "layer_norm2",149 "mlp.c_fc": "mlp.fc1",150 "mlp.c_proj": "mlp.fc2",151 "attn.out_proj": "self_attn.out_proj",152 }153 154 for resblock in range(number):155 for x in resblock_to_replace:156 for y in ["weight", "bias"]:157 k = "{}transformer.resblocks.{}.{}.{}".format(prefix_from, resblock, x, y)158 k_to = "{}encoder.layers.{}.{}.{}".format(prefix_to, resblock, resblock_to_replace[x], y)159 if k in sd:160 sd[k_to] = sd.pop(k)161 162 for y in ["weight", "bias"]:163 k_from = "{}transformer.resblocks.{}.attn.in_proj_{}".format(prefix_from, resblock, y)164 if k_from in sd:165 weights = sd.pop(k_from)166 shape_from = weights.shape[0] // 3167 for x in range(3):168 p = ["self_attn.q_proj", "self_attn.k_proj", "self_attn.v_proj"]169 k_to = "{}encoder.layers.{}.{}.{}".format(prefix_to, resblock, p[x], y)170 sd[k_to] = weights[shape_from*x:shape_from*(x + 1)]171 172 return sd173 174def clip_text_transformers_convert(sd, prefix_from, prefix_to):175 sd = transformers_convert(sd, prefix_from, "{}text_model.".format(prefix_to), 32)176 177 tp = "{}text_projection.weight".format(prefix_from)178 if tp in sd:179 sd["{}text_projection.weight".format(prefix_to)] = sd.pop(tp)180 181 tp = "{}text_projection".format(prefix_from)182 if tp in sd:183 sd["{}text_projection.weight".format(prefix_to)] = sd.pop(tp).transpose(0, 1).contiguous()184 return sd185 186 187UNET_MAP_ATTENTIONS = {188 "proj_in.weight",189 "proj_in.bias",190 "proj_out.weight",191 "proj_out.bias",192 "norm.weight",193 "norm.bias",194}195 196TRANSFORMER_BLOCKS = {197 "norm1.weight",198 "norm1.bias",199 "norm2.weight",200 "norm2.bias",201 "norm3.weight",202 "norm3.bias",203 "attn1.to_q.weight",204 "attn1.to_k.weight",205 "attn1.to_v.weight",206 "attn1.to_out.0.weight",207 "attn1.to_out.0.bias",208 "attn2.to_q.weight",209 "attn2.to_k.weight",210 "attn2.to_v.weight",211 "attn2.to_out.0.weight",212 "attn2.to_out.0.bias",213 "ff.net.0.proj.weight",214 "ff.net.0.proj.bias",215 "ff.net.2.weight",216 "ff.net.2.bias",217}218 219UNET_MAP_RESNET = {220 "in_layers.2.weight": "conv1.weight",221 "in_layers.2.bias": "conv1.bias",222 "emb_layers.1.weight": "time_emb_proj.weight",223 "emb_layers.1.bias": "time_emb_proj.bias",224 "out_layers.3.weight": "conv2.weight",225 "out_layers.3.bias": "conv2.bias",226 "skip_connection.weight": "conv_shortcut.weight",227 "skip_connection.bias": "conv_shortcut.bias",228 "in_layers.0.weight": "norm1.weight",229 "in_layers.0.bias": "norm1.bias",230 "out_layers.0.weight": "norm2.weight",231 "out_layers.0.bias": "norm2.bias",232}233 234UNET_MAP_BASIC = {235 ("label_emb.0.0.weight", "class_embedding.linear_1.weight"),236 ("label_emb.0.0.bias", "class_embedding.linear_1.bias"),237 ("label_emb.0.2.weight", "class_embedding.linear_2.weight"),238 ("label_emb.0.2.bias", "class_embedding.linear_2.bias"),239 ("label_emb.0.0.weight", "add_embedding.linear_1.weight"),240 ("label_emb.0.0.bias", "add_embedding.linear_1.bias"),241 ("label_emb.0.2.weight", "add_embedding.linear_2.weight"),242 ("label_emb.0.2.bias", "add_embedding.linear_2.bias"),243 ("input_blocks.0.0.weight", "conv_in.weight"),244 ("input_blocks.0.0.bias", "conv_in.bias"),245 ("out.0.weight", "conv_norm_out.weight"),246 ("out.0.bias", "conv_norm_out.bias"),247 ("out.2.weight", "conv_out.weight"),248 ("out.2.bias", "conv_out.bias"),249 ("time_embed.0.weight", "time_embedding.linear_1.weight"),250 ("time_embed.0.bias", "time_embedding.linear_1.bias"),251 ("time_embed.2.weight", "time_embedding.linear_2.weight"),252 ("time_embed.2.bias", "time_embedding.linear_2.bias")253}254 255def unet_to_diffusers(unet_config):256 if "num_res_blocks" not in unet_config:257 return {}258 num_res_blocks = unet_config["num_res_blocks"]259 channel_mult = unet_config["channel_mult"]260 transformer_depth = unet_config["transformer_depth"][:]261 transformer_depth_output = unet_config["transformer_depth_output"][:]262 num_blocks = len(channel_mult)263 264 transformers_mid = unet_config.get("transformer_depth_middle", None)265 266 diffusers_unet_map = {}267 for x in range(num_blocks):268 n = 1 + (num_res_blocks[x] + 1) * x269 for i in range(num_res_blocks[x]):270 for b in UNET_MAP_RESNET:271 diffusers_unet_map["down_blocks.{}.resnets.{}.{}".format(x, i, UNET_MAP_RESNET[b])] = "input_blocks.{}.0.{}".format(n, b)272 num_transformers = transformer_depth.pop(0)273 if num_transformers > 0:274 for b in UNET_MAP_ATTENTIONS:275 diffusers_unet_map["down_blocks.{}.attentions.{}.{}".format(x, i, b)] = "input_blocks.{}.1.{}".format(n, b)276 for t in range(num_transformers):277 for b in TRANSFORMER_BLOCKS:278 diffusers_unet_map["down_blocks.{}.attentions.{}.transformer_blocks.{}.{}".format(x, i, t, b)] = "input_blocks.{}.1.transformer_blocks.{}.{}".format(n, t, b)279 n += 1280 for k in ["weight", "bias"]:281 diffusers_unet_map["down_blocks.{}.downsamplers.0.conv.{}".format(x, k)] = "input_blocks.{}.0.op.{}".format(n, k)282 283 i = 0284 for b in UNET_MAP_ATTENTIONS:285 diffusers_unet_map["mid_block.attentions.{}.{}".format(i, b)] = "middle_block.1.{}".format(b)286 for t in range(transformers_mid):287 for b in TRANSFORMER_BLOCKS:288 diffusers_unet_map["mid_block.attentions.{}.transformer_blocks.{}.{}".format(i, t, b)] = "middle_block.1.transformer_blocks.{}.{}".format(t, b)289 290 for i, n in enumerate([0, 2]):291 for b in UNET_MAP_RESNET:292 diffusers_unet_map["mid_block.resnets.{}.{}".format(i, UNET_MAP_RESNET[b])] = "middle_block.{}.{}".format(n, b)293 294 num_res_blocks = list(reversed(num_res_blocks))295 for x in range(num_blocks):296 n = (num_res_blocks[x] + 1) * x297 l = num_res_blocks[x] + 1298 for i in range(l):299 c = 0300 for b in UNET_MAP_RESNET:301 diffusers_unet_map["up_blocks.{}.resnets.{}.{}".format(x, i, UNET_MAP_RESNET[b])] = "output_blocks.{}.0.{}".format(n, b)302 c += 1303 num_transformers = transformer_depth_output.pop()304 if num_transformers > 0:305 c += 1306 for b in UNET_MAP_ATTENTIONS:307 diffusers_unet_map["up_blocks.{}.attentions.{}.{}".format(x, i, b)] = "output_blocks.{}.1.{}".format(n, b)308 for t in range(num_transformers):309 for b in TRANSFORMER_BLOCKS:310 diffusers_unet_map["up_blocks.{}.attentions.{}.transformer_blocks.{}.{}".format(x, i, t, b)] = "output_blocks.{}.1.transformer_blocks.{}.{}".format(n, t, b)311 if i == l - 1:312 for k in ["weight", "bias"]:313 diffusers_unet_map["up_blocks.{}.upsamplers.0.conv.{}".format(x, k)] = "output_blocks.{}.{}.conv.{}".format(n, c, k)314 n += 1315 316 for k in UNET_MAP_BASIC:317 diffusers_unet_map[k[1]] = k[0]318 319 return diffusers_unet_map320 321def swap_scale_shift(weight):322 shift, scale = weight.chunk(2, dim=0)323 new_weight = torch.cat([scale, shift], dim=0)324 return new_weight325 326MMDIT_MAP_BASIC = {327 ("context_embedder.bias", "context_embedder.bias"),328 ("context_embedder.weight", "context_embedder.weight"),329 ("t_embedder.mlp.0.bias", "time_text_embed.timestep_embedder.linear_1.bias"),330 ("t_embedder.mlp.0.weight", "time_text_embed.timestep_embedder.linear_1.weight"),331 ("t_embedder.mlp.2.bias", "time_text_embed.timestep_embedder.linear_2.bias"),332 ("t_embedder.mlp.2.weight", "time_text_embed.timestep_embedder.linear_2.weight"),333 ("x_embedder.proj.bias", "pos_embed.proj.bias"),334 ("x_embedder.proj.weight", "pos_embed.proj.weight"),335 ("y_embedder.mlp.0.bias", "time_text_embed.text_embedder.linear_1.bias"),336 ("y_embedder.mlp.0.weight", "time_text_embed.text_embedder.linear_1.weight"),337 ("y_embedder.mlp.2.bias", "time_text_embed.text_embedder.linear_2.bias"),338 ("y_embedder.mlp.2.weight", "time_text_embed.text_embedder.linear_2.weight"),339 ("pos_embed", "pos_embed.pos_embed"),340 ("final_layer.adaLN_modulation.1.bias", "norm_out.linear.bias", swap_scale_shift),341 ("final_layer.adaLN_modulation.1.weight", "norm_out.linear.weight", swap_scale_shift),342 ("final_layer.linear.bias", "proj_out.bias"),343 ("final_layer.linear.weight", "proj_out.weight"),344}345 346MMDIT_MAP_BLOCK = {347 ("context_block.adaLN_modulation.1.bias", "norm1_context.linear.bias"),348 ("context_block.adaLN_modulation.1.weight", "norm1_context.linear.weight"),349 ("context_block.attn.proj.bias", "attn.to_add_out.bias"),350 ("context_block.attn.proj.weight", "attn.to_add_out.weight"),351 ("context_block.mlp.fc1.bias", "ff_context.net.0.proj.bias"),352 ("context_block.mlp.fc1.weight", "ff_context.net.0.proj.weight"),353 ("context_block.mlp.fc2.bias", "ff_context.net.2.bias"),354 ("context_block.mlp.fc2.weight", "ff_context.net.2.weight"),355 ("context_block.attn.ln_q.weight", "attn.norm_added_q.weight"),356 ("context_block.attn.ln_k.weight", "attn.norm_added_k.weight"),357 ("x_block.adaLN_modulation.1.bias", "norm1.linear.bias"),358 ("x_block.adaLN_modulation.1.weight", "norm1.linear.weight"),359 ("x_block.attn.proj.bias", "attn.to_out.0.bias"),360 ("x_block.attn.proj.weight", "attn.to_out.0.weight"),361 ("x_block.attn.ln_q.weight", "attn.norm_q.weight"),362 ("x_block.attn.ln_k.weight", "attn.norm_k.weight"),363 ("x_block.attn2.proj.bias", "attn2.to_out.0.bias"),364 ("x_block.attn2.proj.weight", "attn2.to_out.0.weight"),365 ("x_block.attn2.ln_q.weight", "attn2.norm_q.weight"),366 ("x_block.attn2.ln_k.weight", "attn2.norm_k.weight"),367 ("x_block.mlp.fc1.bias", "ff.net.0.proj.bias"),368 ("x_block.mlp.fc1.weight", "ff.net.0.proj.weight"),369 ("x_block.mlp.fc2.bias", "ff.net.2.bias"),370 ("x_block.mlp.fc2.weight", "ff.net.2.weight"),371}372 373def mmdit_to_diffusers(mmdit_config, output_prefix=""):374 key_map = {}375 376 depth = mmdit_config.get("depth", 0)377 num_blocks = mmdit_config.get("num_blocks", depth)378 for i in range(num_blocks):379 block_from = "transformer_blocks.{}".format(i)380 block_to = "{}joint_blocks.{}".format(output_prefix, i)381 382 offset = depth * 64383 384 for end in ("weight", "bias"):385 k = "{}.attn.".format(block_from)386 qkv = "{}.x_block.attn.qkv.{}".format(block_to, end)387 key_map["{}to_q.{}".format(k, end)] = (qkv, (0, 0, offset))388 key_map["{}to_k.{}".format(k, end)] = (qkv, (0, offset, offset))389 key_map["{}to_v.{}".format(k, end)] = (qkv, (0, offset * 2, offset))390 391 qkv = "{}.context_block.attn.qkv.{}".format(block_to, end)392 key_map["{}add_q_proj.{}".format(k, end)] = (qkv, (0, 0, offset))393 key_map["{}add_k_proj.{}".format(k, end)] = (qkv, (0, offset, offset))394 key_map["{}add_v_proj.{}".format(k, end)] = (qkv, (0, offset * 2, offset))395 396 k = "{}.attn2.".format(block_from)397 qkv = "{}.x_block.attn2.qkv.{}".format(block_to, end)398 key_map["{}to_q.{}".format(k, end)] = (qkv, (0, 0, offset))399 key_map["{}to_k.{}".format(k, end)] = (qkv, (0, offset, offset))400 key_map["{}to_v.{}".format(k, end)] = (qkv, (0, offset * 2, offset))401 402 for k in MMDIT_MAP_BLOCK:403 key_map["{}.{}".format(block_from, k[1])] = "{}.{}".format(block_to, k[0])404 405 map_basic = MMDIT_MAP_BASIC.copy()406 map_basic.add(("joint_blocks.{}.context_block.adaLN_modulation.1.bias".format(depth - 1), "transformer_blocks.{}.norm1_context.linear.bias".format(depth - 1), swap_scale_shift))407 map_basic.add(("joint_blocks.{}.context_block.adaLN_modulation.1.weight".format(depth - 1), "transformer_blocks.{}.norm1_context.linear.weight".format(depth - 1), swap_scale_shift))408 409 for k in map_basic:410 if len(k) > 2:411 key_map[k[1]] = ("{}{}".format(output_prefix, k[0]), None, k[2])412 else:413 key_map[k[1]] = "{}{}".format(output_prefix, k[0])414 415 return key_map416 417PIXART_MAP_BASIC = {418 ("csize_embedder.mlp.0.weight", "adaln_single.emb.resolution_embedder.linear_1.weight"),419 ("csize_embedder.mlp.0.bias", "adaln_single.emb.resolution_embedder.linear_1.bias"),420 ("csize_embedder.mlp.2.weight", "adaln_single.emb.resolution_embedder.linear_2.weight"),421 ("csize_embedder.mlp.2.bias", "adaln_single.emb.resolution_embedder.linear_2.bias"),422 ("ar_embedder.mlp.0.weight", "adaln_single.emb.aspect_ratio_embedder.linear_1.weight"),423 ("ar_embedder.mlp.0.bias", "adaln_single.emb.aspect_ratio_embedder.linear_1.bias"),424 ("ar_embedder.mlp.2.weight", "adaln_single.emb.aspect_ratio_embedder.linear_2.weight"),425 ("ar_embedder.mlp.2.bias", "adaln_single.emb.aspect_ratio_embedder.linear_2.bias"),426 ("x_embedder.proj.weight", "pos_embed.proj.weight"),427 ("x_embedder.proj.bias", "pos_embed.proj.bias"),428 ("y_embedder.y_embedding", "caption_projection.y_embedding"),429 ("y_embedder.y_proj.fc1.weight", "caption_projection.linear_1.weight"),430 ("y_embedder.y_proj.fc1.bias", "caption_projection.linear_1.bias"),431 ("y_embedder.y_proj.fc2.weight", "caption_projection.linear_2.weight"),432 ("y_embedder.y_proj.fc2.bias", "caption_projection.linear_2.bias"),433 ("t_embedder.mlp.0.weight", "adaln_single.emb.timestep_embedder.linear_1.weight"),434 ("t_embedder.mlp.0.bias", "adaln_single.emb.timestep_embedder.linear_1.bias"),435 ("t_embedder.mlp.2.weight", "adaln_single.emb.timestep_embedder.linear_2.weight"),436 ("t_embedder.mlp.2.bias", "adaln_single.emb.timestep_embedder.linear_2.bias"),437 ("t_block.1.weight", "adaln_single.linear.weight"),438 ("t_block.1.bias", "adaln_single.linear.bias"),439 ("final_layer.linear.weight", "proj_out.weight"),440 ("final_layer.linear.bias", "proj_out.bias"),441 ("final_layer.scale_shift_table", "scale_shift_table"),442}443 444PIXART_MAP_BLOCK = {445 ("scale_shift_table", "scale_shift_table"),446 ("attn.proj.weight", "attn1.to_out.0.weight"),447 ("attn.proj.bias", "attn1.to_out.0.bias"),448 ("mlp.fc1.weight", "ff.net.0.proj.weight"),449 ("mlp.fc1.bias", "ff.net.0.proj.bias"),450 ("mlp.fc2.weight", "ff.net.2.weight"),451 ("mlp.fc2.bias", "ff.net.2.bias"),452 ("cross_attn.proj.weight" ,"attn2.to_out.0.weight"),453 ("cross_attn.proj.bias" ,"attn2.to_out.0.bias"),454}455 456def pixart_to_diffusers(mmdit_config, output_prefix=""):457 key_map = {}458 459 depth = mmdit_config.get("depth", 0)460 offset = mmdit_config.get("hidden_size", 1152)461 462 for i in range(depth):463 block_from = "transformer_blocks.{}".format(i)464 block_to = "{}blocks.{}".format(output_prefix, i)465 466 for end in ("weight", "bias"):467 s = "{}.attn1.".format(block_from)468 qkv = "{}.attn.qkv.{}".format(block_to, end)469 key_map["{}to_q.{}".format(s, end)] = (qkv, (0, 0, offset))470 key_map["{}to_k.{}".format(s, end)] = (qkv, (0, offset, offset))471 key_map["{}to_v.{}".format(s, end)] = (qkv, (0, offset * 2, offset))472 473 s = "{}.attn2.".format(block_from)474 q = "{}.cross_attn.q_linear.{}".format(block_to, end)475 kv = "{}.cross_attn.kv_linear.{}".format(block_to, end)476 477 key_map["{}to_q.{}".format(s, end)] = q478 key_map["{}to_k.{}".format(s, end)] = (kv, (0, 0, offset))479 key_map["{}to_v.{}".format(s, end)] = (kv, (0, offset, offset))480 481 for k in PIXART_MAP_BLOCK:482 key_map["{}.{}".format(block_from, k[1])] = "{}.{}".format(block_to, k[0])483 484 for k in PIXART_MAP_BASIC:485 key_map[k[1]] = "{}{}".format(output_prefix, k[0])486 487 return key_map488 489def auraflow_to_diffusers(mmdit_config, output_prefix=""):490 n_double_layers = mmdit_config.get("n_double_layers", 0)491 n_layers = mmdit_config.get("n_layers", 0)492 493 key_map = {}494 for i in range(n_layers):495 if i < n_double_layers:496 index = i497 prefix_from = "joint_transformer_blocks"498 prefix_to = "{}double_layers".format(output_prefix)499 block_map = {500 "attn.to_q.weight": "attn.w2q.weight",501 "attn.to_k.weight": "attn.w2k.weight",502 "attn.to_v.weight": "attn.w2v.weight",503 "attn.to_out.0.weight": "attn.w2o.weight",504 "attn.add_q_proj.weight": "attn.w1q.weight",505 "attn.add_k_proj.weight": "attn.w1k.weight",506 "attn.add_v_proj.weight": "attn.w1v.weight",507 "attn.to_add_out.weight": "attn.w1o.weight",508 "ff.linear_1.weight": "mlpX.c_fc1.weight",509 "ff.linear_2.weight": "mlpX.c_fc2.weight",510 "ff.out_projection.weight": "mlpX.c_proj.weight",511 "ff_context.linear_1.weight": "mlpC.c_fc1.weight",512 "ff_context.linear_2.weight": "mlpC.c_fc2.weight",513 "ff_context.out_projection.weight": "mlpC.c_proj.weight",514 "norm1.linear.weight": "modX.1.weight",515 "norm1_context.linear.weight": "modC.1.weight",516 }517 else:518 index = i - n_double_layers519 prefix_from = "single_transformer_blocks"520 prefix_to = "{}single_layers".format(output_prefix)521 522 block_map = {523 "attn.to_q.weight": "attn.w1q.weight",524 "attn.to_k.weight": "attn.w1k.weight",525 "attn.to_v.weight": "attn.w1v.weight",526 "attn.to_out.0.weight": "attn.w1o.weight",527 "norm1.linear.weight": "modCX.1.weight",528 "ff.linear_1.weight": "mlp.c_fc1.weight",529 "ff.linear_2.weight": "mlp.c_fc2.weight",530 "ff.out_projection.weight": "mlp.c_proj.weight"531 }532 533 for k in block_map:534 key_map["{}.{}.{}".format(prefix_from, index, k)] = "{}.{}.{}".format(prefix_to, index, block_map[k])535 536 MAP_BASIC = {537 ("positional_encoding", "pos_embed.pos_embed"),538 ("register_tokens", "register_tokens"),539 ("t_embedder.mlp.0.weight", "time_step_proj.linear_1.weight"),540 ("t_embedder.mlp.0.bias", "time_step_proj.linear_1.bias"),541 ("t_embedder.mlp.2.weight", "time_step_proj.linear_2.weight"),542 ("t_embedder.mlp.2.bias", "time_step_proj.linear_2.bias"),543 ("cond_seq_linear.weight", "context_embedder.weight"),544 ("init_x_linear.weight", "pos_embed.proj.weight"),545 ("init_x_linear.bias", "pos_embed.proj.bias"),546 ("final_linear.weight", "proj_out.weight"),547 ("modF.1.weight", "norm_out.linear.weight", swap_scale_shift),548 }549 550 for k in MAP_BASIC:551 if len(k) > 2:552 key_map[k[1]] = ("{}{}".format(output_prefix, k[0]), None, k[2])553 else:554 key_map[k[1]] = "{}{}".format(output_prefix, k[0])555 556 return key_map557 558def flux_to_diffusers(mmdit_config, output_prefix=""):559 n_double_layers = mmdit_config.get("depth", 0)560 n_single_layers = mmdit_config.get("depth_single_blocks", 0)561 hidden_size = mmdit_config.get("hidden_size", 0)562 563 key_map = {}564 for index in range(n_double_layers):565 prefix_from = "transformer_blocks.{}".format(index)566 prefix_to = "{}double_blocks.{}".format(output_prefix, index)567 568 for end in ("weight", "bias"):569 k = "{}.attn.".format(prefix_from)570 qkv = "{}.img_attn.qkv.{}".format(prefix_to, end)571 key_map["{}to_q.{}".format(k, end)] = (qkv, (0, 0, hidden_size))572 key_map["{}to_k.{}".format(k, end)] = (qkv, (0, hidden_size, hidden_size))573 key_map["{}to_v.{}".format(k, end)] = (qkv, (0, hidden_size * 2, hidden_size))574 575 k = "{}.attn.".format(prefix_from)576 qkv = "{}.txt_attn.qkv.{}".format(prefix_to, end)577 key_map["{}add_q_proj.{}".format(k, end)] = (qkv, (0, 0, hidden_size))578 key_map["{}add_k_proj.{}".format(k, end)] = (qkv, (0, hidden_size, hidden_size))579 key_map["{}add_v_proj.{}".format(k, end)] = (qkv, (0, hidden_size * 2, hidden_size))580 581 block_map = {582 "attn.to_out.0.weight": "img_attn.proj.weight",583 "attn.to_out.0.bias": "img_attn.proj.bias",584 "norm1.linear.weight": "img_mod.lin.weight",585 "norm1.linear.bias": "img_mod.lin.bias",586 "norm1_context.linear.weight": "txt_mod.lin.weight",587 "norm1_context.linear.bias": "txt_mod.lin.bias",588 "attn.to_add_out.weight": "txt_attn.proj.weight",589 "attn.to_add_out.bias": "txt_attn.proj.bias",590 "ff.net.0.proj.weight": "img_mlp.0.weight",591 "ff.net.0.proj.bias": "img_mlp.0.bias",592 "ff.net.2.weight": "img_mlp.2.weight",593 "ff.net.2.bias": "img_mlp.2.bias",594 "ff_context.net.0.proj.weight": "txt_mlp.0.weight",595 "ff_context.net.0.proj.bias": "txt_mlp.0.bias",596 "ff_context.net.2.weight": "txt_mlp.2.weight",597 "ff_context.net.2.bias": "txt_mlp.2.bias",598 "attn.norm_q.weight": "img_attn.norm.query_norm.scale",599 "attn.norm_k.weight": "img_attn.norm.key_norm.scale",600 "attn.norm_added_q.weight": "txt_attn.norm.query_norm.scale",601 "attn.norm_added_k.weight": "txt_attn.norm.key_norm.scale",602 }603 604 for k in block_map:605 key_map["{}.{}".format(prefix_from, k)] = "{}.{}".format(prefix_to, block_map[k])606 607 for index in range(n_single_layers):608 prefix_from = "single_transformer_blocks.{}".format(index)609 prefix_to = "{}single_blocks.{}".format(output_prefix, index)610 611 for end in ("weight", "bias"):612 k = "{}.attn.".format(prefix_from)613 qkv = "{}.linear1.{}".format(prefix_to, end)614 key_map["{}to_q.{}".format(k, end)] = (qkv, (0, 0, hidden_size))615 key_map["{}to_k.{}".format(k, end)] = (qkv, (0, hidden_size, hidden_size))616 key_map["{}to_v.{}".format(k, end)] = (qkv, (0, hidden_size * 2, hidden_size))617 key_map["{}.proj_mlp.{}".format(prefix_from, end)] = (qkv, (0, hidden_size * 3, hidden_size * 4))618 619 block_map = {620 "norm.linear.weight": "modulation.lin.weight",621 "norm.linear.bias": "modulation.lin.bias",622 "proj_out.weight": "linear2.weight",623 "proj_out.bias": "linear2.bias",624 "attn.norm_q.weight": "norm.query_norm.scale",625 "attn.norm_k.weight": "norm.key_norm.scale",626 }627 628 for k in block_map:629 key_map["{}.{}".format(prefix_from, k)] = "{}.{}".format(prefix_to, block_map[k])630 631 MAP_BASIC = {632 ("final_layer.linear.bias", "proj_out.bias"),633 ("final_layer.linear.weight", "proj_out.weight"),634 ("img_in.bias", "x_embedder.bias"),635 ("img_in.weight", "x_embedder.weight"),636 ("time_in.in_layer.bias", "time_text_embed.timestep_embedder.linear_1.bias"),637 ("time_in.in_layer.weight", "time_text_embed.timestep_embedder.linear_1.weight"),638 ("time_in.out_layer.bias", "time_text_embed.timestep_embedder.linear_2.bias"),639 ("time_in.out_layer.weight", "time_text_embed.timestep_embedder.linear_2.weight"),640 ("txt_in.bias", "context_embedder.bias"),641 ("txt_in.weight", "context_embedder.weight"),642 ("vector_in.in_layer.bias", "time_text_embed.text_embedder.linear_1.bias"),643 ("vector_in.in_layer.weight", "time_text_embed.text_embedder.linear_1.weight"),644 ("vector_in.out_layer.bias", "time_text_embed.text_embedder.linear_2.bias"),645 ("vector_in.out_layer.weight", "time_text_embed.text_embedder.linear_2.weight"),646 ("guidance_in.in_layer.bias", "time_text_embed.guidance_embedder.linear_1.bias"),647 ("guidance_in.in_layer.weight", "time_text_embed.guidance_embedder.linear_1.weight"),648 ("guidance_in.out_layer.bias", "time_text_embed.guidance_embedder.linear_2.bias"),649 ("guidance_in.out_layer.weight", "time_text_embed.guidance_embedder.linear_2.weight"),650 ("final_layer.adaLN_modulation.1.bias", "norm_out.linear.bias", swap_scale_shift),651 ("final_layer.adaLN_modulation.1.weight", "norm_out.linear.weight", swap_scale_shift),652 ("pos_embed_input.bias", "controlnet_x_embedder.bias"),653 ("pos_embed_input.weight", "controlnet_x_embedder.weight"),654 }655 656 for k in MAP_BASIC:657 if len(k) > 2:658 key_map[k[1]] = ("{}{}".format(output_prefix, k[0]), None, k[2])659 else:660 key_map[k[1]] = "{}{}".format(output_prefix, k[0])661 662 return key_map663 664def repeat_to_batch_size(tensor, batch_size, dim=0):665 if tensor.shape[dim] > batch_size:666 return tensor.narrow(dim, 0, batch_size)667 elif tensor.shape[dim] < batch_size:668 return tensor.repeat(dim * [1] + [math.ceil(batch_size / tensor.shape[dim])] + [1] * (len(tensor.shape) - 1 - dim)).narrow(dim, 0, batch_size)669 return tensor670 671def resize_to_batch_size(tensor, batch_size):672 in_batch_size = tensor.shape[0]673 if in_batch_size == batch_size:674 return tensor675 676 if batch_size <= 1:677 return tensor[:batch_size]678 679 output = torch.empty([batch_size] + list(tensor.shape)[1:], dtype=tensor.dtype, device=tensor.device)680 if batch_size < in_batch_size:681 scale = (in_batch_size - 1) / (batch_size - 1)682 for i in range(batch_size):683 output[i] = tensor[min(round(i * scale), in_batch_size - 1)]684 else:685 scale = in_batch_size / batch_size686 for i in range(batch_size):687 output[i] = tensor[min(math.floor((i + 0.5) * scale), in_batch_size - 1)]688 689 return output690 691def convert_sd_to(state_dict, dtype):692 keys = list(state_dict.keys())693 for k in keys:694 state_dict[k] = state_dict[k].to(dtype)695 return state_dict696 697def safetensors_header(safetensors_path, max_size=100*1024*1024):698 with open(safetensors_path, "rb") as f:699 header = f.read(8)700 length_of_header = struct.unpack('<Q', header)[0]701 if length_of_header > max_size:702 return None703 return f.read(length_of_header)704 705def set_attr(obj, attr, value):706 attrs = attr.split(".")707 for name in attrs[:-1]:708 obj = getattr(obj, name)709 prev = getattr(obj, attrs[-1])710 setattr(obj, attrs[-1], value)711 return prev712 713def set_attr_param(obj, attr, value):714 return set_attr(obj, attr, torch.nn.Parameter(value, requires_grad=False))715 716def copy_to_param(obj, attr, value):717 # inplace update tensor instead of replacing it718 attrs = attr.split(".")719 for name in attrs[:-1]:720 obj = getattr(obj, name)721 prev = getattr(obj, attrs[-1])722 prev.data.copy_(value)723 724def get_attr(obj, attr: str):725 """Retrieves a nested attribute from an object using dot notation.726 727 Args:728 obj: The object to get the attribute from729 attr (str): The attribute path using dot notation (e.g. "model.layer.weight")730 731 Returns:732 The value of the requested attribute733 734 Example:735 model = MyModel()736 weight = get_attr(model, "layer1.conv.weight")737 # Equivalent to: model.layer1.conv.weight738 739 Important:740 Always prefer `comfy.model_patcher.ModelPatcher.get_model_object` when741 accessing nested model objects under `ModelPatcher.model`.742 """743 attrs = attr.split(".")744 for name in attrs:745 obj = getattr(obj, name)746 return obj747 748def bislerp(samples, width, height):749 def slerp(b1, b2, r):750 '''slerps batches b1, b2 according to ratio r, batches should be flat e.g. NxC'''751 752 c = b1.shape[-1]753 754 #norms755 b1_norms = torch.norm(b1, dim=-1, keepdim=True)756 b2_norms = torch.norm(b2, dim=-1, keepdim=True)757 758 #normalize759 b1_normalized = b1 / b1_norms760 b2_normalized = b2 / b2_norms761 762 #zero when norms are zero763 b1_normalized[b1_norms.expand(-1,c) == 0.0] = 0.0764 b2_normalized[b2_norms.expand(-1,c) == 0.0] = 0.0765 766 #slerp767 dot = (b1_normalized*b2_normalized).sum(1)768 omega = torch.acos(dot)769 so = torch.sin(omega)770 771 #technically not mathematically correct, but more pleasing?772 res = (torch.sin((1.0-r.squeeze(1))*omega)/so).unsqueeze(1)*b1_normalized + (torch.sin(r.squeeze(1)*omega)/so).unsqueeze(1) * b2_normalized773 res *= (b1_norms * (1.0-r) + b2_norms * r).expand(-1,c)774 775 #edge cases for same or polar opposites776 res[dot > 1 - 1e-5] = b1[dot > 1 - 1e-5]777 res[dot < 1e-5 - 1] = (b1 * (1.0-r) + b2 * r)[dot < 1e-5 - 1]778 return res779 780 def generate_bilinear_data(length_old, length_new, device):781 coords_1 = torch.arange(length_old, dtype=torch.float32, device=device).reshape((1,1,1,-1))782 coords_1 = torch.nn.functional.interpolate(coords_1, size=(1, length_new), mode="bilinear")783 ratios = coords_1 - coords_1.floor()784 coords_1 = coords_1.to(torch.int64)785 786 coords_2 = torch.arange(length_old, dtype=torch.float32, device=device).reshape((1,1,1,-1)) + 1787 coords_2[:,:,:,-1] -= 1788 coords_2 = torch.nn.functional.interpolate(coords_2, size=(1, length_new), mode="bilinear")789 coords_2 = coords_2.to(torch.int64)790 return ratios, coords_1, coords_2791 792 orig_dtype = samples.dtype793 samples = samples.float()794 n,c,h,w = samples.shape795 h_new, w_new = (height, width)796 797 #linear w798 ratios, coords_1, coords_2 = generate_bilinear_data(w, w_new, samples.device)799 coords_1 = coords_1.expand((n, c, h, -1))800 coords_2 = coords_2.expand((n, c, h, -1))801 ratios = ratios.expand((n, 1, h, -1))802 803 pass_1 = samples.gather(-1,coords_1).movedim(1, -1).reshape((-1,c))804 pass_2 = samples.gather(-1,coords_2).movedim(1, -1).reshape((-1,c))805 ratios = ratios.movedim(1, -1).reshape((-1,1))806 807 result = slerp(pass_1, pass_2, ratios)808 result = result.reshape(n, h, w_new, c).movedim(-1, 1)809 810 #linear h811 ratios, coords_1, coords_2 = generate_bilinear_data(h, h_new, samples.device)812 coords_1 = coords_1.reshape((1,1,-1,1)).expand((n, c, -1, w_new))813 coords_2 = coords_2.reshape((1,1,-1,1)).expand((n, c, -1, w_new))814 ratios = ratios.reshape((1,1,-1,1)).expand((n, 1, -1, w_new))815 816 pass_1 = result.gather(-2,coords_1).movedim(1, -1).reshape((-1,c))817 pass_2 = result.gather(-2,coords_2).movedim(1, -1).reshape((-1,c))818 ratios = ratios.movedim(1, -1).reshape((-1,1))819 820 result = slerp(pass_1, pass_2, ratios)821 result = result.reshape(n, h_new, w_new, c).movedim(-1, 1)822 return result.to(orig_dtype)823 824def lanczos(samples, width, height):825 images = [Image.fromarray(np.clip(255. * image.movedim(0, -1).cpu().numpy(), 0, 255).astype(np.uint8)) for image in samples]826 images = [image.resize((width, height), resample=Image.Resampling.LANCZOS) for image in images]827 images = [torch.from_numpy(np.array(image).astype(np.float32) / 255.0).movedim(-1, 0) for image in images]828 result = torch.stack(images)829 return result.to(samples.device, samples.dtype)830 831def common_upscale(samples, width, height, upscale_method, crop):832 orig_shape = tuple(samples.shape)833 if len(orig_shape) > 4:834 samples = samples.reshape(samples.shape[0], samples.shape[1], -1, samples.shape[-2], samples.shape[-1])835 samples = samples.movedim(2, 1)836 samples = samples.reshape(-1, orig_shape[1], orig_shape[-2], orig_shape[-1])837 if crop == "center":838 old_width = samples.shape[-1]839 old_height = samples.shape[-2]840 old_aspect = old_width / old_height841 new_aspect = width / height842 x = 0843 y = 0844 if old_aspect > new_aspect:845 x = round((old_width - old_width * (new_aspect / old_aspect)) / 2)846 elif old_aspect < new_aspect:847 y = round((old_height - old_height * (old_aspect / new_aspect)) / 2)848 s = samples.narrow(-2, y, old_height - y * 2).narrow(-1, x, old_width - x * 2)849 else:850 s = samples851 852 if upscale_method == "bislerp":853 out = bislerp(s, width, height)854 elif upscale_method == "lanczos":855 out = lanczos(s, width, height)856 else:857 out = torch.nn.functional.interpolate(s, size=(height, width), mode=upscale_method)858 859 if len(orig_shape) == 4:860 return out861 862 out = out.reshape((orig_shape[0], -1, orig_shape[1]) + (height, width))863 return out.movedim(2, 1).reshape(orig_shape[:-2] + (height, width))864 865def get_tiled_scale_steps(width, height, tile_x, tile_y, overlap):866 rows = 1 if height <= tile_y else math.ceil((height - overlap) / (tile_y - overlap))867 cols = 1 if width <= tile_x else math.ceil((width - overlap) / (tile_x - overlap))868 return rows * cols869 870@torch.inference_mode()871def tiled_scale_multidim(samples, function, tile=(64, 64), overlap=8, upscale_amount=4, out_channels=3, output_device="cpu", downscale=False, index_formulas=None, pbar=None):872 dims = len(tile)873 874 if not (isinstance(upscale_amount, (tuple, list))):875 upscale_amount = [upscale_amount] * dims876 877 if not (isinstance(overlap, (tuple, list))):878 overlap = [overlap] * dims879 880 if index_formulas is None:881 index_formulas = upscale_amount882 883 if not (isinstance(index_formulas, (tuple, list))):884 index_formulas = [index_formulas] * dims885 886 def get_upscale(dim, val):887 up = upscale_amount[dim]888 if callable(up):889 return up(val)890 else:891 return up * val892 893 def get_downscale(dim, val):894 up = upscale_amount[dim]895 if callable(up):896 return up(val)897 else:898 return val / up899 900 def get_upscale_pos(dim, val):901 up = index_formulas[dim]902 if callable(up):903 return up(val)904 else:905 return up * val906 907 def get_downscale_pos(dim, val):908 up = index_formulas[dim]909 if callable(up):910 return up(val)911 else:912 return val / up913 914 if downscale:915 get_scale = get_downscale916 get_pos = get_downscale_pos917 else:918 get_scale = get_upscale919 get_pos = get_upscale_pos920 921 def mult_list_upscale(a):922 out = []923 for i in range(len(a)):924 out.append(round(get_scale(i, a[i])))925 return out926 927 output = torch.empty([samples.shape[0], out_channels] + mult_list_upscale(samples.shape[2:]), device=output_device)928 929 for b in range(samples.shape[0]):930 s = samples[b:b+1]931 932 # handle entire input fitting in a single tile933 if all(s.shape[d+2] <= tile[d] for d in range(dims)):934 output[b:b+1] = function(s).to(output_device)935 if pbar is not None:936 pbar.update(1)937 continue938 939 out = torch.zeros([s.shape[0], out_channels] + mult_list_upscale(s.shape[2:]), device=output_device)940 out_div = torch.zeros([s.shape[0], out_channels] + mult_list_upscale(s.shape[2:]), device=output_device)941 942 positions = [range(0, s.shape[d+2] - overlap[d], tile[d] - overlap[d]) if s.shape[d+2] > tile[d] else [0] for d in range(dims)]943 944 for it in itertools.product(*positions):945 s_in = s946 upscaled = []947 948 for d in range(dims):949 pos = max(0, min(s.shape[d + 2] - overlap[d], it[d]))950 l = min(tile[d], s.shape[d + 2] - pos)951 s_in = s_in.narrow(d + 2, pos, l)952 upscaled.append(round(get_pos(d, pos)))953 954 ps = function(s_in).to(output_device)955 mask = torch.ones_like(ps)956 957 for d in range(2, dims + 2):958 feather = round(get_scale(d - 2, overlap[d - 2]))959 if feather >= mask.shape[d]:960 continue961 for t in range(feather):962 a = (t + 1) / feather963 mask.narrow(d, t, 1).mul_(a)964 mask.narrow(d, mask.shape[d] - 1 - t, 1).mul_(a)965 966 o = out967 o_d = out_div968 for d in range(dims):969 o = o.narrow(d + 2, upscaled[d], mask.shape[d + 2])970 o_d = o_d.narrow(d + 2, upscaled[d], mask.shape[d + 2])971 972 o.add_(ps * mask)973 o_d.add_(mask)974 975 if pbar is not None:976 pbar.update(1)977 978 output[b:b+1] = out/out_div979 return output980 981def tiled_scale(samples, function, tile_x=64, tile_y=64, overlap = 8, upscale_amount = 4, out_channels = 3, output_device="cpu", pbar = None):982 return tiled_scale_multidim(samples, function, (tile_y, tile_x), overlap=overlap, upscale_amount=upscale_amount, out_channels=out_channels, output_device=output_device, pbar=pbar)983 984PROGRESS_BAR_ENABLED = True985def set_progress_bar_enabled(enabled):986 global PROGRESS_BAR_ENABLED987 PROGRESS_BAR_ENABLED = enabled988 989PROGRESS_BAR_HOOK = None990def set_progress_bar_global_hook(function):991 global PROGRESS_BAR_HOOK992 PROGRESS_BAR_HOOK = function993 994class ProgressBar:995 def __init__(self, total):996 global PROGRESS_BAR_HOOK997 self.total = total998 self.current = 0999 self.hook = PROGRESS_BAR_HOOK1000 1001 def update_absolute(self, value, total=None, preview=None):1002 if total is not None:1003 self.total = total1004 if value > self.total:1005 value = self.total1006 self.current = value1007 if self.hook is not None:1008 self.hook(self.current, self.total, preview)1009 1010 def update(self, value):1011 self.update_absolute(self.current + value)1012 1013def reshape_mask(input_mask, output_shape):1014 dims = len(output_shape) - 21015 1016 if dims == 1:1017 scale_mode = "linear"1018 1019 if dims == 2:1020 input_mask = input_mask.reshape((-1, 1, input_mask.shape[-2], input_mask.shape[-1]))1021 scale_mode = "bilinear"1022 1023 if dims == 3:1024 if len(input_mask.shape) < 5:1025 input_mask = input_mask.reshape((1, 1, -1, input_mask.shape[-2], input_mask.shape[-1]))1026 scale_mode = "trilinear"1027 1028 mask = torch.nn.functional.interpolate(input_mask, size=output_shape[2:], mode=scale_mode)1029 if mask.shape[1] < output_shape[1]:1030 mask = mask.repeat((1, output_shape[1]) + (1,) * dims)[:,:output_shape[1]]1031 mask = repeat_to_batch_size(mask, output_shape[0])1032 return mask1033 1034def upscale_dit_mask(mask: torch.Tensor, img_size_in, img_size_out):1035 hi, wi = img_size_in1036 ho, wo = img_size_out1037 # if it's already the correct size, no need to do anything1038 if (hi, wi) == (ho, wo):1039 return mask1040 if mask.ndim == 2:1041 mask = mask.unsqueeze(0)1042 if mask.ndim != 3:1043 raise ValueError(f"Got a mask of shape {list(mask.shape)}, expected [b, q, k] or [q, k]")1044 txt_tokens = mask.shape[1] - (hi * wi)1045 # quadrants of the mask1046 txt_to_txt = mask[:, :txt_tokens, :txt_tokens]1047 txt_to_img = mask[:, :txt_tokens, txt_tokens:]1048 img_to_img = mask[:, txt_tokens:, txt_tokens:]1049 img_to_txt = mask[:, txt_tokens:, :txt_tokens]1050 1051 # convert to 1d x 2d, interpolate, then back to 1d x 1d1052 txt_to_img = rearrange (txt_to_img, "b t (h w) -> b t h w", h=hi, w=wi)1053 txt_to_img = interpolate(txt_to_img, size=img_size_out, mode="bilinear")1054 txt_to_img = rearrange (txt_to_img, "b t h w -> b t (h w)")1055 # this one is hard because we have to do it twice1056 # convert to 1d x 2d, interpolate, then to 2d x 1d, interpolate, then 1d x 1d1057 img_to_img = rearrange (img_to_img, "b hw (h w) -> b hw h w", h=hi, w=wi)1058 img_to_img = interpolate(img_to_img, size=img_size_out, mode="bilinear")1059 img_to_img = rearrange (img_to_img, "b (hk wk) hq wq -> b (hq wq) hk wk", hk=hi, wk=wi)1060 img_to_img = interpolate(img_to_img, size=img_size_out, mode="bilinear")1061 img_to_img = rearrange (img_to_img, "b (hq wq) hk wk -> b (hk wk) (hq wq)", hq=ho, wq=wo)1062 # convert to 2d x 1d, interpolate, then back to 1d x 1d1063 img_to_txt = rearrange (img_to_txt, "b (h w) t -> b t h w", h=hi, w=wi)1064 img_to_txt = interpolate(img_to_txt, size=img_size_out, mode="bilinear")1065 img_to_txt = rearrange (img_to_txt, "b t h w -> b (h w) t")1066 1067 # reassemble the mask from blocks1068 out = torch.cat([1069 torch.cat([txt_to_txt, txt_to_img], dim=2),1070 torch.cat([img_to_txt, img_to_img], dim=2)],1071 dim=11072 )1073 return out1074 