Files
ComfyUI/comfy/ldm/minimax_music/dit.py

214 lines
9.1 KiB
Python

import math
import torch
from torch import nn
import comfy.model_management
import comfy.ops
import comfy.quant_ops
from comfy.ldm.modules.attention import optimized_attention_for_device
MAX_CONDITION_FRAMES = 200
CONDITION_HOP_FRAMES = 100
def latent_length(audio_frames):
return max(1, int(audio_frames * 44100 / 24000 * 960 / 512))
class FourierFeatures(nn.Module):
def __init__(self, in_features, out_features, dtype, device):
super().__init__()
self.weight = nn.Parameter(torch.empty(out_features // 2, in_features, dtype=dtype, device=device))
def forward(self, value):
weight = comfy.ops.cast_to_input(self.weight, value)
features = 2.0 * math.pi * value @ weight.T
return torch.cat((features.cos(), features.sin()), dim=-1)
class LayerNorm(nn.Module):
def __init__(self, dim, dtype, device):
super().__init__()
self.gamma = nn.Parameter(torch.empty(dim, dtype=dtype, device=device))
self.register_buffer("beta", torch.empty(dim, dtype=dtype, device=device))
def forward(self, x):
return torch.nn.functional.layer_norm(
x,
(x.shape[-1],),
comfy.ops.cast_to_input(self.gamma, x),
comfy.ops.cast_to_input(self.beta, x),
)
class RotaryEmbedding(nn.Module):
def __init__(self, dim, dtype, device):
super().__init__()
self.register_buffer("inv_freq", torch.empty(dim // 2, dtype=dtype, device=device))
def forward_from_seq_len(self, length, device, dtype):
positions = torch.arange(length, device=device, dtype=torch.float32)
frequencies = torch.outer(positions, comfy.ops.cast_to_input(self.inv_freq, positions))
frequencies = frequencies.to(dtype)
cos, sin = frequencies.cos(), frequencies.sin()
return torch.stack((cos, -sin, sin, cos), dim=-1).reshape(1, 1, length, frequencies.shape[-1], 2, 2)
def _apply_rope(x, rotation_matrix):
x_dtype = x.dtype
x = x.reshape(*x.shape[:-1], 2, -1).movedim(-2, -1).unsqueeze(-2).to(rotation_matrix.dtype)
x = rotation_matrix[..., 0] * x[..., 0] + rotation_matrix[..., 1] * x[..., 1]
return x.movedim(-1, -2).flatten(-2).to(x_dtype)
class Attention(nn.Module):
def __init__(self, dim, dim_heads, dtype, device, operations):
super().__init__()
self.num_heads = dim // dim_heads
self.dim_heads = dim_heads
self.to_qkv = operations.Linear(dim, dim * 3, bias=False, dtype=dtype, device=device)
self.to_out = operations.Linear(dim, dim, bias=False, dtype=dtype, device=device)
def forward(self, x, rotation_matrix):
batch, length, dim = x.shape
q, k, v = self.to_qkv(x).chunk(3, dim=-1)
q = q.reshape(batch, length, self.num_heads, self.dim_heads).transpose(1, 2)
k = k.reshape(batch, length, self.num_heads, self.dim_heads).transpose(1, 2)
v = v.reshape(batch, length, self.num_heads, self.dim_heads).transpose(1, 2)
rotary_dims = rotation_matrix.shape[-3] * 2
if comfy.model_management.in_training:
q = torch.cat((_apply_rope(q[..., :rotary_dims], rotation_matrix), q[..., rotary_dims:]), dim=-1)
k = torch.cat((_apply_rope(k[..., :rotary_dims], rotation_matrix), k[..., rotary_dims:]), dim=-1)
else:
rotated_q, rotated_k = comfy.quant_ops.ck.apply_rope_split_half(q[..., :rotary_dims], k[..., :rotary_dims], rotation_matrix)
q = torch.cat((rotated_q, q[..., rotary_dims:]), dim=-1)
k = torch.cat((rotated_k, k[..., rotary_dims:]), dim=-1)
attention = optimized_attention_for_device(q.device)
out = attention(q, k, v, self.num_heads, skip_reshape=True)
return self.to_out(out)
class GLU(nn.Module):
def __init__(self, dim, inner_dim, dtype, device, operations):
super().__init__()
self.proj = operations.Linear(dim, inner_dim * 2, dtype=dtype, device=device)
def forward(self, x):
value, gate = self.proj(x).chunk(2, dim=-1)
return value * torch.nn.functional.silu(gate)
class FeedForward(nn.Module):
def __init__(self, dim, inner_dim, dtype, device, operations):
super().__init__()
self.ff = nn.Sequential(
GLU(dim, inner_dim, dtype, device, operations),
nn.Identity(),
operations.Linear(inner_dim, dim, dtype=dtype, device=device),
)
def forward(self, x):
return self.ff(x)
class TransformerBlock(nn.Module):
def __init__(self, dim, dim_heads, inner_dim, dtype, device, operations):
super().__init__()
self.pre_norm = LayerNorm(dim, dtype, device)
self.self_attn = Attention(dim, dim_heads, dtype, device, operations)
self.ff_norm = LayerNorm(dim, dtype, device)
self.ff = FeedForward(dim, inner_dim, dtype, device, operations)
def forward(self, x, rotation_matrix):
x = x + self.self_attn(self.pre_norm(x), rotation_matrix)
return x + self.ff(self.ff_norm(x))
class ContinuousTransformer(nn.Module):
def __init__(self, dtype, device, operations):
super().__init__()
self.project_in = operations.Linear(2304, 2048, bias=False, dtype=dtype, device=device)
self.project_out = operations.Linear(2048, 128, bias=False, dtype=dtype, device=device)
self.rotary_pos_emb = RotaryEmbedding(32, dtype, device)
self.layers = nn.ModuleList([
TransformerBlock(2048, 64, 8192, dtype, device, operations)
for _ in range(36)
])
def forward(self, x, timestep_embedding):
x = self.project_in(x)
x = torch.cat((timestep_embedding.unsqueeze(1), x), dim=1)
rotation_matrix = self.rotary_pos_emb.forward_from_seq_len(x.shape[1], x.device, x.dtype)
for layer in self.layers:
x = layer(x, rotation_matrix)
return self.project_out(x[:, 1:])
class DiffusionTransformer(nn.Module):
def __init__(self, dtype, device, operations):
super().__init__()
self.transformer = ContinuousTransformer(dtype, device, operations)
self.timestep_features = FourierFeatures(1, 256, dtype, device)
self.to_timestep_embed = nn.Sequential(
operations.Linear(256, 2048, dtype=dtype, device=device),
nn.SiLU(),
operations.Linear(2048, 2048, dtype=dtype, device=device),
)
self.preprocess_conv = operations.Conv1d(2304, 2304, 1, bias=False, dtype=dtype, device=device)
self.postprocess_conv = operations.Conv1d(128, 128, 1, bias=False, dtype=dtype, device=device)
def forward(self, x, timestep, condition):
full = torch.cat((x, torch.zeros_like(x), condition), dim=1)
full = self.preprocess_conv(full) + full
timestep_features = self.timestep_features(timestep[:, None]).to(dtype=x.dtype)
timestep_embedding = self.to_timestep_embed(timestep_features)
out = self.transformer(full.transpose(1, 2), timestep_embedding).transpose(1, 2)
return self.postprocess_conv(out) + out
class MiniMaxMusic3DiT(nn.Module):
def __init__(self, dtype=None, device=None, operations=None, **kwargs):
super().__init__()
self.dtype = dtype
self.latent_conditioners = nn.Sequential(
operations.Conv1d(4096, 2048, kernel_size=3, padding=1, dtype=dtype, device=device)
)
self.diffusion_transformer = DiffusionTransformer(dtype, device, operations)
self.cond_layer_logits = nn.Parameter(torch.empty(8, dtype=dtype, device=device))
self.cond_layer_scale = nn.Parameter(torch.empty(1, dtype=dtype, device=device))
def aligned_condition(self, hidden):
frames = hidden.shape[1]
hidden = hidden.transpose(1, 2).reshape(hidden.shape[0], 8, 4096, frames)
weights = torch.softmax(comfy.ops.cast_to_input(self.cond_layer_logits, hidden), dim=0)
hidden = torch.einsum("blht,l->bht", hidden, weights)
hidden = comfy.ops.cast_to_input(self.cond_layer_scale, hidden) * hidden
condition = self.latent_conditioners(hidden)
return torch.nn.functional.interpolate(condition, size=latent_length(frames), mode="nearest")
def forward(self, x, timestep, context, conditioning_scale, **kwargs):
condition = self.aligned_condition(context)
condition = condition * conditioning_scale[:, :1, :1]
if condition.shape[-1] < x.shape[-1]:
condition = torch.nn.functional.pad(condition, (0, x.shape[-1] - condition.shape[-1]))
else:
condition = condition[..., :x.shape[-1]]
window = latent_length(MAX_CONDITION_FRAMES)
if x.shape[-1] <= window:
return -self.diffusion_transformer(x, timestep, condition)
output = torch.zeros_like(x)
count = torch.zeros((1, 1, x.shape[-1]), device=x.device, dtype=x.dtype)
hop = latent_length(CONDITION_HOP_FRAMES)
start = 0
while start < x.shape[-1]:
end = min(start + window, x.shape[-1])
output[..., start:end] -= self.diffusion_transformer(x[..., start:end], timestep, condition[..., start:end])
count[..., start:end] += 1
if end == x.shape[-1]:
break
start += hop
return output / count