Spaces:
Running on Zero
Running on Zero
| # adapted from https://github.com/Stability-AI/stable-audio-tools/blob/main/stable_audio_tools/models/dit.py | |
| import typing as tp | |
| import math | |
| import torch | |
| from einops import rearrange | |
| from torch import nn | |
| from torch.nn import functional as F | |
| class FourierFeatures(nn.Module): | |
| def __init__(self, in_features, out_features, std=1.): | |
| super().__init__() | |
| assert out_features % 2 == 0 | |
| self.weight = nn.Parameter(torch.randn( | |
| [out_features // 2, in_features]) * std) | |
| def forward(self, input): | |
| f = 2 * math.pi * input @ self.weight.T | |
| return torch.cat([f.cos(), f.sin()], dim=-1) | |
| class OneHotPositionalEmbedding(nn.Module): | |
| def __init__(self, max_seq_len): | |
| super().__init__() | |
| self.max_seq_len = max_seq_len | |
| def forward(self, x, pos=None, seq_start_pos=None): | |
| seq_len, device = x.shape[1], x.device | |
| assert seq_len <= self.max_seq_len, f'you are passing in a sequence length of {seq_len} but your one-hot positional embedding has a max sequence length of {self.max_seq_len}' | |
| if pos is None: | |
| pos = torch.arange(seq_len, device=device) | |
| if seq_start_pos is not None: | |
| pos = (pos - seq_start_pos[..., None]).clamp(min=0) | |
| pos_emb = F.one_hot(pos, num_classes=self.max_seq_len).to(x.dtype) | |
| return pos_emb | |
| class DiffusionTransformer(nn.Module): | |
| def __init__(self, | |
| io_channels=32, | |
| patch_size=1, | |
| embed_dim=768, | |
| cond_token_dim=0, | |
| cond_token_proj_dim=64, | |
| project_cond_tokens=False, | |
| global_cond_dim=0, | |
| project_global_cond=True, | |
| input_concat_dim=0, | |
| prepend_cond_dim=0, | |
| depth=12, | |
| num_heads=8, | |
| transformer_type: tp.Literal["x-transformers", "continuous_transformer"] = "x-transformers", | |
| global_cond_type: tp.Literal["prepend", "adaLN"] = "prepend", | |
| timestep_cond_type: tp.Literal["global", "input_concat"] = "global", | |
| timestep_embed_dim=None, | |
| pos_emb_strategy="concatenation", | |
| pos_emb_dim=None, | |
| pos_emb_type="one-hot", | |
| pos_emb_crossattn_strategy="concatenation", | |
| pos_emb_crossattn_dim=None, | |
| pos_emb_crossattn_type="one-hot", | |
| use_taxonomy_in_pos_emb=True, | |
| max_num_tracks=14,#used for one-hot positional embeddings | |
| **kwargs): | |
| super().__init__() | |
| self.cond_token_dim = cond_token_dim | |
| # Timestep embeddings | |
| self.timestep_cond_type = timestep_cond_type | |
| timestep_features_dim = 256 | |
| self.timestep_features = FourierFeatures(1, timestep_features_dim) | |
| if timestep_cond_type == "global": | |
| timestep_embed_dim = embed_dim | |
| elif timestep_cond_type == "input_concat": | |
| assert timestep_embed_dim is not None, "timestep_embed_dim must be specified if timestep_cond_type is input_concat" | |
| input_concat_dim += timestep_embed_dim | |
| self.to_timestep_embed = nn.Sequential( | |
| nn.Linear(timestep_features_dim, timestep_embed_dim, bias=True), | |
| nn.SiLU(), | |
| nn.Linear(timestep_embed_dim, timestep_embed_dim, bias=True), | |
| ) | |
| self.project_cond_tokens = project_cond_tokens | |
| if cond_token_dim > 0: | |
| # Conditioning tokens | |
| if self.project_cond_tokens: | |
| self.to_cond_embed = nn.Sequential( | |
| nn.Linear(cond_token_dim, cond_token_proj_dim, bias=False), | |
| nn.SiLU(), | |
| nn.Linear(cond_token_proj_dim, cond_token_proj_dim, bias=False) | |
| ) | |
| cond_embed_dim = cond_token_proj_dim | |
| else: | |
| cond_embed_dim = cond_token_dim | |
| else: | |
| cond_embed_dim = 0 | |
| if global_cond_dim > 0: | |
| # Global conditioning | |
| global_embed_dim = global_cond_dim if not project_global_cond else embed_dim | |
| self.to_global_embed = nn.Sequential( | |
| nn.Linear(global_cond_dim, global_embed_dim, bias=False), | |
| nn.SiLU(), | |
| nn.Linear(global_embed_dim, global_embed_dim, bias=False) | |
| ) | |
| if prepend_cond_dim > 0: | |
| # Prepend conditioning | |
| self.to_prepend_embed = nn.Sequential( | |
| nn.Linear(prepend_cond_dim, embed_dim, bias=False), | |
| nn.SiLU(), | |
| nn.Linear(embed_dim, embed_dim, bias=False) | |
| ) | |
| self.input_concat_dim = input_concat_dim | |
| dim_in = io_channels + self.input_concat_dim | |
| self.patch_size = patch_size | |
| # Transformer | |
| self.transformer_type = transformer_type | |
| self.global_cond_type = global_cond_type | |
| if pos_emb_strategy == "concatenation": | |
| assert pos_emb_dim is not None, "pos_emb_dim must be specified if pos_emb_strategy is concatenation" | |
| if pos_emb_type == "one-hot": | |
| # One-hot positional embeddings | |
| self.pos_emb = OneHotPositionalEmbedding(pos_emb_dim-max_num_tracks) | |
| self.extra_dim = pos_emb_dim | |
| def concat_pos_emb(x, pos=None, seq_start_pos=None, taxonomy=None): | |
| B, N, T, C = x.shape | |
| pos_emb = self.pos_emb(x.view(-1,x.shape[-2], x.shape[-1]), pos=pos, seq_start_pos=seq_start_pos) | |
| assert pos_emb.shape[-1] == pos_emb_dim-max_num_tracks, f"pos_emb shape mismatch: {pos_emb.shape[-1]} != {pos_emb_dim}" | |
| assert pos_emb.shape[-2] == T, f"pos_emb sequence length mismatch: {pos_emb.shape[-2]} != {x.shape[-2]}" | |
| pos_emb=pos_emb.unsqueeze(0).unsqueeze(0).expand(B,N,T,-1) | |
| assert pos_emb.ndim == 4, f"pos_emb must be 2D or 3D, got {pos_emb.ndim}" | |
| assert pos_emb.shape[0] == x.shape[0], f"pos_emb batch size mismatch: {pos_emb.shape[0]} != {x.shape[0]}" | |
| pos_emb_track=torch.zeros((B, N, T, max_num_tracks), device=x.device, dtype=x.dtype) | |
| for i in range(B): | |
| for j in range(N): | |
| if use_taxonomy_in_pos_emb: | |
| raise NotImplementedError("use_taxonomy_in_pos_emb is not implemented for pos_emb_type 'one-hot'") | |
| assert taxonomy is not None, "taxonomy must be provided if use_taxonomy_in_pos_emb is True" | |
| if taxonomy[i][j]=="92": | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([0], device=x.device), num_classes=3).to(x.dtype).expand(T, -1) | |
| elif taxonomy[i][j]=="2": | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([1], device=x.device), num_classes=3).to(x.dtype).expand(T, -1) | |
| elif taxonomy[i][j]=="11": | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([2], device=x.device), num_classes=3).to(x.dtype).expand(T, -1) | |
| else: | |
| if j >= max_num_tracks: | |
| j= j% max_num_tracks | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([j], device=x.device), num_classes=max_num_tracks).to(x.dtype).expand(T, -1) | |
| return torch.cat((x, pos_emb, pos_emb_track), dim=-1) | |
| self.pos_emb_fn = concat_pos_emb | |
| self.remove_pos_emb = lambda x: x[..., :-pos_emb_dim] if pos_emb_dim > 0 else x | |
| else: | |
| raise ValueError(f"Unknown pos_emb_type: {pos_emb_type}") | |
| else: | |
| raise ValueError(f"Unknown pos_emb_strategy: {pos_emb_strategy}") | |
| if pos_emb_crossattn_strategy == "concatenation": | |
| assert pos_emb_crossattn_dim is not None, "pos_emb_crossattn_dim must be specified if pos_emb_crossattn_strategy is concatenation" | |
| if pos_emb_crossattn_type == "one-hot": | |
| # One-hot positional embeddings for cross-attention | |
| self.pos_emb_crossattn = OneHotPositionalEmbedding(pos_emb_crossattn_dim-max_num_tracks) | |
| self.crossattn_extra_dim = pos_emb_crossattn_dim | |
| if not self.project_cond_tokens: | |
| def concat_pos_emb_crossattn(x, pos=None, seq_start_pos=None, taxonomy=None): | |
| B, N, T, C = x.shape | |
| pos_emb = self.pos_emb_crossattn(x.view(-1, T,C), pos=pos, seq_start_pos=seq_start_pos) | |
| assert pos_emb.shape[-1] == pos_emb_crossattn_dim-max_num_tracks, f"pos_emb shape mismatch: {pos_emb.shape[-1]} != {pos_emb_crossattn_dim}" | |
| assert pos_emb.shape[-2] == T, f"pos_emb sequence length mismatch: {pos_emb.shape[-2]} != {x.shape[-2]}" | |
| pos_emb=pos_emb.unsqueeze(0).unsqueeze(0).expand(B,N,T,-1) | |
| #if pos_emb.ndim == 3: | |
| assert pos_emb.ndim == 4, f"pos_emb must be 2D or 3D, got {pos_emb.ndim}" | |
| assert pos_emb.shape[0] == x.shape[0], f"pos_emb batch size mismatch: {pos_emb.shape[0]} != {x.shape[0]}" | |
| pos_emb_track=torch.zeros((B, N, T, max_num_tracks), device=x.device, dtype=x.dtype) | |
| for i in range(B): | |
| for j in range(N): | |
| if use_taxonomy_in_pos_emb: | |
| raise NotImplementedError("use_taxonomy_in_pos_emb is not implemented for pos_emb_crossattn_type 'one-hot'") | |
| assert taxonomy is not None, "taxonomy must be provided if use_taxonomy_in_pos_emb is True" | |
| if taxonomy[i][j]=="92": | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([0], device=x.device), num_classes=3).to(x.dtype).expand(T, -1) | |
| elif taxonomy[i][j]=="2": | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([1], device=x.device), num_classes=3).to(x.dtype).expand(T, -1) | |
| elif taxonomy[i][j]=="11": | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([2], device=x.device), num_classes=3).to(x.dtype).expand(T, -1) | |
| else: | |
| if j >= max_num_tracks: | |
| j= j% max_num_tracks | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([j], device=x.device), num_classes=max_num_tracks).to(x.dtype).expand(T, -1) | |
| return torch.cat((x, pos_emb, pos_emb_track), dim=-1) | |
| else: | |
| def concat_pos_emb_crossattn(x, pos=None, seq_start_pos=None, taxonomy=None): | |
| #print("x shape",x.shape) | |
| B, N, T, C = x.shape | |
| assert T*C== cond_token_dim, f"cond_token_proj_dim must match T*C, got {cond_token_dim} != {T*C}" | |
| #rehape to B, N, 1, T*C | |
| x= rearrange(x, "b n t c -> b n 1 (t c)") | |
| #pos_emb = self.pos_emb_crossattn(x.view(-1, T,C), pos=pos, seq_start_pos=seq_start_pos) | |
| #assert pos_emb.shape[-1] == pos_emb_crossattn_dim-3, f"pos_emb shape mismatch: {pos_emb.shape[-1]} != {pos_emb_crossattn_dim}" | |
| #assert pos_emb.shape[-2] == T, f"pos_emb sequence length mismatch: {pos_emb.shape[-2]} != {x.shape[-2]}" | |
| #pos_emb=pos_emb.unsqueeze(0).unsqueeze(0).expand(B,N,T,-1) | |
| #if pos_emb.ndim == 3: | |
| #assert pos_emb.ndim == 4, f"pos_emb must be 2D or 3D, got {pos_emb.ndim}" | |
| #assert pos_emb.shape[0] == x.shape[0], f"pos_emb batch size mismatch: {pos_emb.shape[0]} != {x.shape[0]}" | |
| x=rearrange(x, "b n 1 c -> (b n) 1 c") | |
| x=self.to_cond_embed(x) | |
| x=rearrange(x, "(b n) 1 c -> b n 1 c", b=B, n=N) | |
| pos_emb_track=torch.zeros((B, N, 1, pos_emb_crossattn_dim), device=x.device, dtype=x.dtype) | |
| for i in range(B): | |
| for j in range(N): | |
| if use_taxonomy_in_pos_emb: | |
| assert taxonomy is not None, "taxonomy must be provided if use_taxonomy_in_pos_emb is True" | |
| if taxonomy[i][j]=="92": | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([0], device=x.device), num_classes=pos_emb_crossattn_dim).to(x.dtype) | |
| elif taxonomy[i][j]=="2": | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([1], device=x.device), num_classes=pos_emb_crossattn_dim).to(x.dtype) | |
| elif taxonomy[i][j]=="11": | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([2], device=x.device), num_classes=pos_emb_crossattn_dim).to(x.dtype) | |
| else: | |
| pos_emb_track[i, j, :, :]= F.one_hot(torch.tensor([j], device=x.device), num_classes=pos_emb_crossattn_dim).to(x.dtype) | |
| return torch.cat((x, pos_emb_track), dim=-1) | |
| self.pos_emb_crossattn_fn = concat_pos_emb_crossattn | |
| else: | |
| raise ValueError(f"Unknown pos_emb_type: {pos_emb_crossattn_type}") | |
| global_dim = None | |
| if self.global_cond_type == "adaLN": | |
| # The global conditioning is projected to the embed_dim already at this point | |
| global_dim = embed_dim | |
| from networks.transformer import ContinuousTransformer | |
| self.transformer = ContinuousTransformer( | |
| dim=embed_dim, | |
| depth=depth, | |
| num_heads= num_heads, | |
| dim_in=dim_in + pos_emb_dim, | |
| dim_out=io_channels , | |
| cross_attend = cond_token_dim > 0, | |
| cond_token_dim = cond_embed_dim + pos_emb_crossattn_dim, | |
| global_cond_dim=global_dim, | |
| **kwargs | |
| ) | |
| self.preprocess_conv = nn.Conv1d(dim_in, dim_in, 1, bias=False) | |
| nn.init.zeros_(self.preprocess_conv.weight) | |
| self.postprocess_conv = nn.Conv1d(io_channels, io_channels, 1, bias=False) | |
| nn.init.zeros_(self.postprocess_conv.weight) | |
| def _forward( | |
| self, | |
| x, | |
| t, | |
| mask=None, | |
| cross_attn_cond=None, | |
| cross_attn_cond_mask=None, | |
| input_concat_cond=None, | |
| global_embed=None, | |
| prepend_cond=None, | |
| prepend_cond_mask=None, | |
| return_info=False, | |
| **kwargs): | |
| t=t.squeeze(1) | |
| #if cross_attn_cond is not None: | |
| # cross_attn_cond = self.to_cond_embed(cross_attn_cond) | |
| if global_embed is not None: | |
| # Project the global conditioning to the embedding dimension | |
| global_embed = self.to_global_embed(global_embed) | |
| prepend_inputs = None | |
| prepend_mask = None | |
| prepend_length = 0 | |
| if prepend_cond is not None: | |
| # Project the prepend conditioning to the embedding dimension | |
| prepend_cond = self.to_prepend_embed(prepend_cond) | |
| prepend_inputs = prepend_cond | |
| if prepend_cond_mask is not None: | |
| prepend_mask = prepend_cond_mask | |
| # Get the batch of timestep embeddings | |
| timestep_embed = self.to_timestep_embed(self.timestep_features(t[:, None])) # (b, embed_dim) | |
| # Timestep embedding is considered a global embedding. Add to the global conditioning if it exists | |
| if self.timestep_cond_type == "global": | |
| if global_embed is not None: | |
| global_embed = global_embed + timestep_embed | |
| else: | |
| global_embed = timestep_embed | |
| elif self.timestep_cond_type == "input_concat": | |
| x = torch.cat([x, timestep_embed.unsqueeze(1).expand(-1, -1, x.shape[2])], dim=1) | |
| # Add the global_embed to the prepend inputs if there is no global conditioning support in the transformer | |
| if self.global_cond_type == "prepend" and global_embed is not None: | |
| if prepend_inputs is None: | |
| # Prepend inputs are just the global embed, and the mask is all ones | |
| prepend_inputs = global_embed.unsqueeze(1) | |
| prepend_mask = torch.ones((x.shape[0], 1), device=x.device, dtype=torch.bool) | |
| else: | |
| # Prepend inputs are the prepend conditioning + the global embed | |
| prepend_inputs = torch.cat([prepend_inputs, global_embed.unsqueeze(1)], dim=1) | |
| prepend_mask = torch.cat([prepend_mask, torch.ones((x.shape[0], 1), device=x.device, dtype=torch.bool)], dim=1) | |
| prepend_length = prepend_inputs.shape[1] | |
| extra_args = {} | |
| if self.global_cond_type == "adaLN": | |
| extra_args["global_cond"] = global_embed | |
| output = self.transformer(x, prepend_embeds=prepend_inputs, context=cross_attn_cond, context_mask=cross_attn_cond_mask, mask=mask, prepend_mask=prepend_mask, return_info=return_info, **extra_args, **kwargs) | |
| if return_info: | |
| output, info = output | |
| output=output[:,prepend_length:,:] | |
| if return_info: | |
| return output, info | |
| return output | |
| def forward( | |
| self, | |
| x, | |
| t, | |
| cross_attn_cond=None, | |
| cross_attn_cond_mask=None, | |
| input_concat_cond=None, | |
| global_embed=None, | |
| taxonomy=None, | |
| mask=None, | |
| return_info=False, | |
| **kwargs): | |
| model_dtype = next(self.parameters()).dtype | |
| x = x.to(model_dtype) | |
| t = t.to(model_dtype) | |
| if cross_attn_cond is not None: | |
| cross_attn_cond = cross_attn_cond.to(model_dtype) | |
| if input_concat_cond is not None: | |
| input_concat_cond = input_concat_cond.to(model_dtype) | |
| # Interpolate input_concat_cond to the same length as x | |
| assert input_concat_cond.ndim == 4, f"input_concat_cond must be 4D, got {input_concat_cond.ndim}" | |
| assert input_concat_cond.shape[0] == x.shape[0] | |
| assert input_concat_cond.shape[1] == x.shape[1] | |
| assert input_concat_cond.shape[-1] == x.shape[-1] | |
| assert input_concat_cond.shape[-2] == self.input_concat_dim, f"input_concat_cond shape mismatch: {input_concat_cond.shape[-2]} != {self.input_concat_dim}" | |
| x = torch.cat([x, input_concat_cond], dim=-2) | |
| if global_embed is not None: | |
| global_embed = global_embed.to(model_dtype) | |
| if cross_attn_cond_mask is not None: | |
| cross_attn_cond_mask = cross_attn_cond_mask.bool() | |
| #cross_attn_cond_mask = None # Temporarily disabling conditioning masks due to kernel issue for flash attention | |
| orig_shape = x.shape | |
| x= rearrange(x, "b n c t -> (b n) c t") | |
| x = self.preprocess_conv(x) + x | |
| x=x.view(orig_shape) | |
| x= rearrange(x, "b n c t -> b n t c") | |
| #shape of contecxt is already [B, N, T, C] so no need to rearrange | |
| orig_shape = x.shape | |
| x= self.pos_emb_fn(x, taxonomy=taxonomy) | |
| cross_attn_cond= self.pos_emb_crossattn_fn(cross_attn_cond, taxonomy=taxonomy) | |
| x=rearrange(x, "b n t c -> b (n t) c") | |
| cross_attn_cond_orig_shape = cross_attn_cond.shape | |
| cross_attn_cond = rearrange(cross_attn_cond, "b n t c -> b (n t) c") | |
| # rehape to [B, N \times T, C] for the transformer | |
| # mask has shape [B, N ], I need to expand it to [B, N, T] for the convolution | |
| mask= mask.unsqueeze(-1).expand(orig_shape[0], orig_shape[1], orig_shape[2]) | |
| mask= rearrange(mask, "b n t -> b (n t)") | |
| cross_attn_cond_mask = cross_attn_cond_mask.unsqueeze(-1).expand(cross_attn_cond_orig_shape[0], cross_attn_cond_orig_shape[1], cross_attn_cond_orig_shape[2]) | |
| cross_attn_cond_mask = rearrange(cross_attn_cond_mask, "b n t -> b (n t)") | |
| out= self._forward( | |
| x, | |
| t, | |
| cross_attn_cond=cross_attn_cond, | |
| cross_attn_cond_mask=cross_attn_cond_mask, | |
| input_concat_cond=input_concat_cond, | |
| global_embed=global_embed, | |
| mask=mask, | |
| return_info=return_info, | |
| **kwargs | |
| ) | |
| #print("out shape", out.shape) | |
| out = rearrange(out, "b t c -> b c t") | |
| out= self.postprocess_conv(out) + out | |
| out = rearrange(out, "b c t -> b t c") | |
| #print("out shape after postprocess", out.shape) | |
| #now we reshape... | |
| out = rearrange(out, "b (n t) c -> b n t c", n=orig_shape[1], t=orig_shape[2]) | |
| out=rearrange(out, "b n t c -> b n c t") | |
| return out |