mirror of
https://github.com/Comfy-Org/ComfyUI.git
synced 2026-08-25 18:32:35 +08:00
214 lines
9.1 KiB
Python
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
|