multimodalart/EchoMimic-zero
8
1# Adapted from https://github.com/guoyww/AnimateDiff/blob/main/animatediff/models/unet_blocks.py2 3from collections import OrderedDict4from dataclasses import dataclass5from os import PathLike6from pathlib import Path7from typing import Dict, List, Optional, Tuple, Union8 9import torch10import torch.nn as nn11import torch.utils.checkpoint12from diffusers.configuration_utils import ConfigMixin, register_to_config13from diffusers.models.attention_processor import AttentionProcessor14from diffusers.models.embeddings import TimestepEmbedding, Timesteps15from diffusers.models.modeling_utils import ModelMixin16from diffusers.utils import SAFETENSORS_WEIGHTS_NAME, WEIGHTS_NAME, BaseOutput, logging17from safetensors.torch import load_file18 19from .resnet import InflatedConv3d, InflatedGroupNorm20from .unet_3d_blocks import UNetMidBlock3DCrossAttn, get_down_block, get_up_block21 22logger = logging.get_logger(__name__) # pylint: disable=invalid-name23 24 25@dataclass26class UNet3DConditionOutput(BaseOutput):27 sample: torch.FloatTensor28 29 30class UNet3DConditionModel(ModelMixin, ConfigMixin):31 _supports_gradient_checkpointing = True32 33 @register_to_config34 def __init__(35 self,36 sample_size: Optional[int] = None,37 in_channels: int = 4,38 out_channels: int = 4,39 center_input_sample: bool = False,40 flip_sin_to_cos: bool = True,41 freq_shift: int = 0,42 down_block_types: Tuple[str] = (43 "CrossAttnDownBlock3D",44 "CrossAttnDownBlock3D",45 "CrossAttnDownBlock3D",46 "DownBlock3D",47 ),48 mid_block_type: str = "UNetMidBlock3DCrossAttn",49 up_block_types: Tuple[str] = (50 "UpBlock3D",51 "CrossAttnUpBlock3D",52 "CrossAttnUpBlock3D",53 "CrossAttnUpBlock3D",54 ),55 only_cross_attention: Union[bool, Tuple[bool]] = False,56 block_out_channels: Tuple[int] = (320, 640, 1280, 1280),57 layers_per_block: int = 2,58 downsample_padding: int = 1,59 mid_block_scale_factor: float = 1,60 act_fn: str = "silu",61 norm_num_groups: int = 32,62 norm_eps: float = 1e-5,63 cross_attention_dim: int = 1280,64 attention_head_dim: Union[int, Tuple[int]] = 8,65 dual_cross_attention: bool = False,66 use_linear_projection: bool = False,67 class_embed_type: Optional[str] = None,68 num_class_embeds: Optional[int] = None,69 upcast_attention: bool = False,70 resnet_time_scale_shift: str = "default",71 use_inflated_groupnorm=False,72 # Additional73 use_motion_module=False,74 motion_module_resolutions=(1, 2, 4, 8),75 motion_module_mid_block=False,76 motion_module_decoder_only=False,77 motion_module_type=None,78 motion_module_kwargs={},79 unet_use_cross_frame_attention=None,80 unet_use_temporal_attention=None,81 ):82 super().__init__()83 84 self.sample_size = sample_size85 time_embed_dim = block_out_channels[0] * 486 87 # input88 self.conv_in = InflatedConv3d(89 in_channels, block_out_channels[0], kernel_size=3, padding=(1, 1)90 )91 92 # time93 self.time_proj = Timesteps(block_out_channels[0], flip_sin_to_cos, freq_shift)94 timestep_input_dim = block_out_channels[0]95 96 self.time_embedding = TimestepEmbedding(timestep_input_dim, time_embed_dim)97 98 # class embedding99 if class_embed_type is None and num_class_embeds is not None:100 self.class_embedding = nn.Embedding(num_class_embeds, time_embed_dim)101 elif class_embed_type == "timestep":102 self.class_embedding = TimestepEmbedding(timestep_input_dim, time_embed_dim)103 elif class_embed_type == "identity":104 self.class_embedding = nn.Identity(time_embed_dim, time_embed_dim)105 else:106 self.class_embedding = None107 108 self.down_blocks = nn.ModuleList([])109 self.mid_block = None110 self.up_blocks = nn.ModuleList([])111 112 if isinstance(only_cross_attention, bool):113 only_cross_attention = [only_cross_attention] * len(down_block_types)114 115 if isinstance(attention_head_dim, int):116 attention_head_dim = (attention_head_dim,) * len(down_block_types)117 118 # down119 output_channel = block_out_channels[0]120 for i, down_block_type in enumerate(down_block_types):121 res = 2**i122 input_channel = output_channel123 output_channel = block_out_channels[i]124 is_final_block = i == len(block_out_channels) - 1125 126 down_block = get_down_block(127 down_block_type,128 num_layers=layers_per_block,129 in_channels=input_channel,130 out_channels=output_channel,131 temb_channels=time_embed_dim,132 add_downsample=not is_final_block,133 resnet_eps=norm_eps,134 resnet_act_fn=act_fn,135 resnet_groups=norm_num_groups,136 cross_attention_dim=cross_attention_dim,137 attn_num_head_channels=attention_head_dim[i],138 downsample_padding=downsample_padding,139 dual_cross_attention=dual_cross_attention,140 use_linear_projection=use_linear_projection,141 only_cross_attention=only_cross_attention[i],142 upcast_attention=upcast_attention,143 resnet_time_scale_shift=resnet_time_scale_shift,144 unet_use_cross_frame_attention=unet_use_cross_frame_attention,145 unet_use_temporal_attention=unet_use_temporal_attention,146 use_inflated_groupnorm=use_inflated_groupnorm,147 use_motion_module=use_motion_module148 and (res in motion_module_resolutions)149 and (not motion_module_decoder_only),150 motion_module_type=motion_module_type,151 motion_module_kwargs=motion_module_kwargs,152 )153 self.down_blocks.append(down_block)154 155 # mid156 if mid_block_type == "UNetMidBlock3DCrossAttn":157 self.mid_block = UNetMidBlock3DCrossAttn(158 in_channels=block_out_channels[-1],159 temb_channels=time_embed_dim,160 resnet_eps=norm_eps,161 resnet_act_fn=act_fn,162 output_scale_factor=mid_block_scale_factor,163 resnet_time_scale_shift=resnet_time_scale_shift,164 cross_attention_dim=cross_attention_dim,165 attn_num_head_channels=attention_head_dim[-1],166 resnet_groups=norm_num_groups,167 dual_cross_attention=dual_cross_attention,168 use_linear_projection=use_linear_projection,169 upcast_attention=upcast_attention,170 unet_use_cross_frame_attention=unet_use_cross_frame_attention,171 unet_use_temporal_attention=unet_use_temporal_attention,172 use_inflated_groupnorm=use_inflated_groupnorm,173 use_motion_module=use_motion_module and motion_module_mid_block,174 motion_module_type=motion_module_type,175 motion_module_kwargs=motion_module_kwargs,176 )177 else:178 raise ValueError(f"unknown mid_block_type : {mid_block_type}")179 180 # count how many layers upsample the videos181 self.num_upsamplers = 0182 183 # up184 reversed_block_out_channels = list(reversed(block_out_channels))185 reversed_attention_head_dim = list(reversed(attention_head_dim))186 only_cross_attention = list(reversed(only_cross_attention))187 output_channel = reversed_block_out_channels[0]188 for i, up_block_type in enumerate(up_block_types):189 res = 2 ** (3 - i)190 is_final_block = i == len(block_out_channels) - 1191 192 prev_output_channel = output_channel193 output_channel = reversed_block_out_channels[i]194 input_channel = reversed_block_out_channels[195 min(i + 1, len(block_out_channels) - 1)196 ]197 198 # add upsample block for all BUT final layer199 if not is_final_block:200 add_upsample = True201 self.num_upsamplers += 1202 else:203 add_upsample = False204 205 up_block = get_up_block(206 up_block_type,207 num_layers=layers_per_block + 1,208 in_channels=input_channel,209 out_channels=output_channel,210 prev_output_channel=prev_output_channel,211 temb_channels=time_embed_dim,212 add_upsample=add_upsample,213 resnet_eps=norm_eps,214 resnet_act_fn=act_fn,215 resnet_groups=norm_num_groups,216 cross_attention_dim=cross_attention_dim,217 attn_num_head_channels=reversed_attention_head_dim[i],218 dual_cross_attention=dual_cross_attention,219 use_linear_projection=use_linear_projection,220 only_cross_attention=only_cross_attention[i],221 upcast_attention=upcast_attention,222 resnet_time_scale_shift=resnet_time_scale_shift,223 unet_use_cross_frame_attention=unet_use_cross_frame_attention,224 unet_use_temporal_attention=unet_use_temporal_attention,225 use_inflated_groupnorm=use_inflated_groupnorm,226 use_motion_module=use_motion_module227 and (res in motion_module_resolutions),228 motion_module_type=motion_module_type,229 motion_module_kwargs=motion_module_kwargs,230 )231 self.up_blocks.append(up_block)232 prev_output_channel = output_channel233 234 # out235 if use_inflated_groupnorm:236 self.conv_norm_out = InflatedGroupNorm(237 num_channels=block_out_channels[0],238 num_groups=norm_num_groups,239 eps=norm_eps,240 )241 else:242 self.conv_norm_out = nn.GroupNorm(243 num_channels=block_out_channels[0],244 num_groups=norm_num_groups,245 eps=norm_eps,246 )247 self.conv_act = nn.SiLU()248 self.conv_out = InflatedConv3d(249 block_out_channels[0], out_channels, kernel_size=3, padding=1250 )251 252 @property253 # Copied from diffusers.models.unet_2d_condition.UNet2DConditionModel.attn_processors254 def attn_processors(self) -> Dict[str, AttentionProcessor]:255 r"""256 Returns:257 `dict` of attention processors: A dictionary containing all attention processors used in the model with258 indexed by its weight name.259 """260 # set recursively261 processors = {}262 263 def fn_recursive_add_processors(264 name: str,265 module: torch.nn.Module,266 processors: Dict[str, AttentionProcessor],267 ):268 if hasattr(module, "set_processor"):269 processors[f"{name}.processor"] = module.processor270 271 for sub_name, child in module.named_children():272 if "temporal_transformer" not in sub_name:273 fn_recursive_add_processors(f"{name}.{sub_name}", child, processors)274 275 return processors276 277 for name, module in self.named_children():278 if "temporal_transformer" not in name:279 fn_recursive_add_processors(name, module, processors)280 281 return processors282 283 def set_attention_slice(self, slice_size):284 r"""285 Enable sliced attention computation.286 287 When this option is enabled, the attention module will split the input tensor in slices, to compute attention288 in several steps. This is useful to save some memory in exchange for a small speed decrease.289 290 Args:291 slice_size (`str` or `int` or `list(int)`, *optional*, defaults to `"auto"`):292 When `"auto"`, halves the input to the attention heads, so attention will be computed in two steps. If293 `"max"`, maxium amount of memory will be saved by running only one slice at a time. If a number is294 provided, uses as many slices as `attention_head_dim // slice_size`. In this case, `attention_head_dim`295 must be a multiple of `slice_size`.296 """297 sliceable_head_dims = []298 299 def fn_recursive_retrieve_slicable_dims(module: torch.nn.Module):300 if hasattr(module, "set_attention_slice"):301 sliceable_head_dims.append(module.sliceable_head_dim)302 303 for child in module.children():304 fn_recursive_retrieve_slicable_dims(child)305 306 # retrieve number of attention layers307 for module in self.children():308 fn_recursive_retrieve_slicable_dims(module)309 310 num_slicable_layers = len(sliceable_head_dims)311 312 if slice_size == "auto":313 # half the attention head size is usually a good trade-off between314 # speed and memory315 slice_size = [dim // 2 for dim in sliceable_head_dims]316 elif slice_size == "max":317 # make smallest slice possible318 slice_size = num_slicable_layers * [1]319 320 slice_size = (321 num_slicable_layers * [slice_size]322 if not isinstance(slice_size, list)323 else slice_size324 )325 326 if len(slice_size) != len(sliceable_head_dims):327 raise ValueError(328 f"You have provided {len(slice_size)}, but {self.config} has {len(sliceable_head_dims)} different"329 f" attention layers. Make sure to match `len(slice_size)` to be {len(sliceable_head_dims)}."330 )331 332 for i in range(len(slice_size)):333 size = slice_size[i]334 dim = sliceable_head_dims[i]335 if size is not None and size > dim:336 raise ValueError(f"size {size} has to be smaller or equal to {dim}.")337 338 # Recursively walk through all the children.339 # Any children which exposes the set_attention_slice method340 # gets the message341 def fn_recursive_set_attention_slice(342 module: torch.nn.Module, slice_size: List[int]343 ):344 if hasattr(module, "set_attention_slice"):345 module.set_attention_slice(slice_size.pop())346 347 for child in module.children():348 fn_recursive_set_attention_slice(child, slice_size)349 350 reversed_slice_size = list(reversed(slice_size))351 for module in self.children():352 fn_recursive_set_attention_slice(module, reversed_slice_size)353 354 def _set_gradient_checkpointing(self, module, value=False):355 if hasattr(module, "gradient_checkpointing"):356 module.gradient_checkpointing = value357 358 # Copied from diffusers.models.unet_2d_condition.UNet2DConditionModel.set_attn_processor359 def set_attn_processor(360 self, processor: Union[AttentionProcessor, Dict[str, AttentionProcessor]]361 ):362 r"""363 Sets the attention processor to use to compute attention.364 365 Parameters:366 processor (`dict` of `AttentionProcessor` or only `AttentionProcessor`):367 The instantiated processor class or a dictionary of processor classes that will be set as the processor368 for **all** `Attention` layers.369 370 If `processor` is a dict, the key needs to define the path to the corresponding cross attention371 processor. This is strongly recommended when setting trainable attention processors.372 373 """374 count = len(self.attn_processors.keys())375 376 if isinstance(processor, dict) and len(processor) != count:377 raise ValueError(378 f"A dict of processors was passed, but the number of processors {len(processor)} does not match the"379 f" number of attention layers: {count}. Please make sure to pass {count} processor classes."380 )381 382 def fn_recursive_attn_processor(name: str, module: torch.nn.Module, processor):383 if hasattr(module, "set_processor"):384 if not isinstance(processor, dict):385 module.set_processor(processor)386 else:387 module.set_processor(processor.pop(f"{name}.processor"))388 389 for sub_name, child in module.named_children():390 if "temporal_transformer" not in sub_name:391 fn_recursive_attn_processor(f"{name}.{sub_name}", child, processor)392 393 for name, module in self.named_children():394 if "temporal_transformer" not in name:395 fn_recursive_attn_processor(name, module, processor)396 397 def forward(398 self,399 sample: torch.FloatTensor,400 timestep: Union[torch.Tensor, float, int],401 encoder_hidden_states: torch.Tensor,402 class_labels: Optional[torch.Tensor] = None,403 pose_cond_fea: Optional[torch.Tensor] = None,404 attention_mask: Optional[torch.Tensor] = None,405 down_block_additional_residuals: Optional[Tuple[torch.Tensor]] = None,406 mid_block_additional_residual: Optional[torch.Tensor] = None,407 return_dict: bool = True,408 ) -> Union[UNet3DConditionOutput, Tuple]:409 r"""410 Args:411 sample (`torch.FloatTensor`): (batch, channel, height, width) noisy inputs tensor412 timestep (`torch.FloatTensor` or `float` or `int`): (batch) timesteps413 encoder_hidden_states (`torch.FloatTensor`): (batch, sequence_length, feature_dim) encoder hidden states414 return_dict (`bool`, *optional*, defaults to `True`):415 Whether or not to return a [`models.unet_2d_condition.UNet2DConditionOutput`] instead of a plain tuple.416 417 Returns:418 [`~models.unet_2d_condition.UNet2DConditionOutput`] or `tuple`:419 [`~models.unet_2d_condition.UNet2DConditionOutput`] if `return_dict` is True, otherwise a `tuple`. When420 returning a tuple, the first element is the sample tensor.421 """422 # By default samples have to be AT least a multiple of the overall upsampling factor.423 # The overall upsampling factor is equal to 2 ** (# num of upsampling layears).424 # However, the upsampling interpolation output size can be forced to fit any upsampling size425 # on the fly if necessary.426 default_overall_up_factor = 2**self.num_upsamplers427 428 # upsample size should be forwarded when sample is not a multiple of `default_overall_up_factor`429 forward_upsample_size = False430 upsample_size = None431 432 if any(s % default_overall_up_factor != 0 for s in sample.shape[-2:]):433 logger.info("Forward upsample size to force interpolation output size.")434 forward_upsample_size = True435 436 # prepare attention_mask437 if attention_mask is not None:438 attention_mask = (1 - attention_mask.to(sample.dtype)) * -10000.0439 attention_mask = attention_mask.unsqueeze(1)440 441 # center input if necessary442 if self.config.center_input_sample:443 sample = 2 * sample - 1.0444 445 # time446 timesteps = timestep447 if not torch.is_tensor(timesteps):448 # This would be a good case for the `match` statement (Python 3.10+)449 is_mps = sample.device.type == "mps"450 if isinstance(timestep, float):451 dtype = torch.float32 if is_mps else torch.float64452 else:453 dtype = torch.int32 if is_mps else torch.int64454 timesteps = torch.tensor([timesteps], dtype=dtype, device=sample.device)455 elif len(timesteps.shape) == 0:456 timesteps = timesteps[None].to(sample.device)457 458 # broadcast to batch dimension in a way that's compatible with ONNX/Core ML459 timesteps = timesteps.expand(sample.shape[0])460 461 t_emb = self.time_proj(timesteps)462 463 # timesteps does not contain any weights and will always return f32 tensors464 # but time_embedding might actually be running in fp16. so we need to cast here.465 # there might be better ways to encapsulate this.466 t_emb = t_emb.to(dtype=self.dtype)467 emb = self.time_embedding(t_emb)468 469 if self.class_embedding is not None:470 if class_labels is None:471 raise ValueError(472 "class_labels should be provided when num_class_embeds > 0"473 )474 475 if self.config.class_embed_type == "timestep":476 class_labels = self.time_proj(class_labels)477 478 class_emb = self.class_embedding(class_labels).to(dtype=self.dtype)479 emb = emb + class_emb480 481 # pre-process482 sample = self.conv_in(sample)483 if pose_cond_fea is not None:484 sample = sample + pose_cond_fea485 486 # down487 down_block_res_samples = (sample,)488 for downsample_block in self.down_blocks:489 if (490 hasattr(downsample_block, "has_cross_attention")491 and downsample_block.has_cross_attention492 ):493 sample, res_samples = downsample_block(494 hidden_states=sample,495 temb=emb,496 encoder_hidden_states=encoder_hidden_states,497 attention_mask=attention_mask,498 )499 else:500 sample, res_samples = downsample_block(501 hidden_states=sample,502 temb=emb,503 encoder_hidden_states=encoder_hidden_states,504 )505 506 down_block_res_samples += res_samples507 508 if down_block_additional_residuals is not None:509 new_down_block_res_samples = ()510 511 for down_block_res_sample, down_block_additional_residual in zip(512 down_block_res_samples, down_block_additional_residuals513 ):514 down_block_res_sample = (515 down_block_res_sample + down_block_additional_residual516 )517 new_down_block_res_samples += (down_block_res_sample,)518 519 down_block_res_samples = new_down_block_res_samples520 521 # mid522 sample = self.mid_block(523 sample,524 emb,525 encoder_hidden_states=encoder_hidden_states,526 attention_mask=attention_mask,527 )528 529 if mid_block_additional_residual is not None:530 sample = sample + mid_block_additional_residual531 532 # up533 for i, upsample_block in enumerate(self.up_blocks):534 is_final_block = i == len(self.up_blocks) - 1535 536 res_samples = down_block_res_samples[-len(upsample_block.resnets) :]537 down_block_res_samples = down_block_res_samples[538 : -len(upsample_block.resnets)539 ]540 541 # if we have not reached the final block and need to forward the542 # upsample size, we do it here543 if not is_final_block and forward_upsample_size:544 upsample_size = down_block_res_samples[-1].shape[2:]545 546 if (547 hasattr(upsample_block, "has_cross_attention")548 and upsample_block.has_cross_attention549 ):550 sample = upsample_block(551 hidden_states=sample,552 temb=emb,553 res_hidden_states_tuple=res_samples,554 encoder_hidden_states=encoder_hidden_states,555 upsample_size=upsample_size,556 attention_mask=attention_mask,557 )558 else:559 sample = upsample_block(560 hidden_states=sample,561 temb=emb,562 res_hidden_states_tuple=res_samples,563 upsample_size=upsample_size,564 encoder_hidden_states=encoder_hidden_states,565 )566 567 # post-process568 sample = self.conv_norm_out(sample)569 sample = self.conv_act(sample)570 sample = self.conv_out(sample)571 572 if not return_dict:573 return (sample,)574 575 return UNet3DConditionOutput(sample=sample)576 577 @classmethod578 def from_pretrained_2d(579 cls,580 pretrained_model_path: PathLike,581 motion_module_path: PathLike,582 subfolder=None,583 unet_additional_kwargs=None,584 mm_zero_proj_out=False,585 ):586 pretrained_model_path = Path(pretrained_model_path)587 motion_module_path = Path(motion_module_path)588 if subfolder is not None:589 pretrained_model_path = pretrained_model_path.joinpath(subfolder)590 logger.info(591 f"loaded temporal unet's pretrained weights from {pretrained_model_path} ..."592 )593 594 config_file = pretrained_model_path / "config.json"595 if not (config_file.exists() and config_file.is_file()):596 raise RuntimeError(f"{config_file} does not exist or is not a file")597 598 unet_config = cls.load_config(config_file)599 unet_config["_class_name"] = cls.__name__600 unet_config["down_block_types"] = [601 "CrossAttnDownBlock3D",602 "CrossAttnDownBlock3D",603 "CrossAttnDownBlock3D",604 "DownBlock3D",605 ]606 unet_config["up_block_types"] = [607 "UpBlock3D",608 "CrossAttnUpBlock3D",609 "CrossAttnUpBlock3D",610 "CrossAttnUpBlock3D",611 ]612 unet_config["mid_block_type"] = "UNetMidBlock3DCrossAttn"613 614 model = cls.from_config(unet_config, **unet_additional_kwargs)615 # load the vanilla weights616 if pretrained_model_path.joinpath(SAFETENSORS_WEIGHTS_NAME).exists():617 logger.debug(618 f"loading safeTensors weights from {pretrained_model_path} ..."619 )620 state_dict = load_file(621 pretrained_model_path.joinpath(SAFETENSORS_WEIGHTS_NAME), device="cpu"622 )623 624 elif pretrained_model_path.joinpath(WEIGHTS_NAME).exists():625 logger.debug(f"loading weights from {pretrained_model_path} ...")626 state_dict = torch.load(627 pretrained_model_path.joinpath(WEIGHTS_NAME),628 map_location="cpu",629 weights_only=True,630 )631 else:632 raise FileNotFoundError(f"no weights file found in {pretrained_model_path}")633 634 # load the motion module weights635 if motion_module_path.exists() and motion_module_path.is_file():636 if motion_module_path.suffix.lower() in [".pth", ".pt", ".ckpt"]:637 logger.info(f"Load motion module params from {motion_module_path}")638 motion_state_dict = torch.load(639 motion_module_path, map_location="cpu", weights_only=True640 )641 elif motion_module_path.suffix.lower() == ".safetensors":642 motion_state_dict = load_file(motion_module_path, device="cpu")643 else:644 raise RuntimeError(645 f"unknown file format for motion module weights: {motion_module_path.suffix}"646 )647 if mm_zero_proj_out:648 logger.info(f"Zero initialize proj_out layers in motion module...")649 new_motion_state_dict = OrderedDict()650 for k in motion_state_dict:651 if "proj_out" in k:652 continue653 new_motion_state_dict[k] = motion_state_dict[k]654 motion_state_dict = new_motion_state_dict655 656 # merge the state dicts657 state_dict.update(motion_state_dict)658 659 # load the weights into the model660 m, u = model.load_state_dict(state_dict, strict=False)661 logger.debug(f"### missing keys: {len(m)}; \n### unexpected keys: {len(u)};")662 663 params = [664 p.numel() if "temporal" in n else 0 for n, p in model.named_parameters()665 ]666 logger.info(f"Loaded {sum(params) / 1e6}M-parameter motion module")667 668 return model669 