- 模型 17/17 文件经镜像全量缓存(gated+token,直连本机不通;sfx.md/setup.md/asset-pipeline.md 镜像结论同步更新) - 修复迁移遗留:stable_audio_3/models/ 源码子包被 .gitignore models/ 规则误伤丢失,从上游恢复并加白名单 - radio:arg_muffled/brake_screech 等叙事件落地(接线原有 L111/L154 零改动)+ phone_ring SYN→SA3 升级;dungeon 13 源 A/B 对齐(RMS 偏差 ≤0.3dB)全量同名替换,SYN 原版备份 tools/asset_fix_backup/sa3_ab_20260902/ - 关键玩法语义达标:echo 距离档 0.83<1.43<2.18<2.98s 严格递增;one-shot 真峰值全 ≤-3dBFS(解码回读法) - check_all_assets 8 游戏全绿(radio 254/254、dungeon 303/303);playtest radio 221/dungeon 1610 全绿
1273 lines
49 KiB
Python
1273 lines
49 KiB
Python
from functools import reduce, partial
|
|
from packaging import version
|
|
import logging
|
|
import math
|
|
|
|
from einops import rearrange, repeat
|
|
from einops.layers.torch import Rearrange
|
|
import torch
|
|
import torch.nn.functional as F
|
|
from torch import nn, einsum
|
|
from torch.amp import autocast
|
|
from torch.nn.utils.parametrizations import weight_norm
|
|
from typing import Callable, Literal, Optional
|
|
try:
|
|
from torch.nn.attention.flex_attention import flex_attention, create_block_mask
|
|
flex_attention_available = True
|
|
except ImportError:
|
|
flex_attention = None
|
|
create_block_mask = None
|
|
flex_attention_available = False
|
|
|
|
try:
|
|
from flash_attn import flash_attn_func, flash_attn_kvpacked_func
|
|
except ImportError as e:
|
|
print(e)
|
|
print('flash_attn not installed, disabling Flash Attention')
|
|
flash_attn_kvpacked_func = None
|
|
flash_attn_func = None
|
|
|
|
try:
|
|
from flash_attn import flash_attn_varlen_func
|
|
from flash_attn.bert_padding import pad_input, unpad_input, index_first_axis
|
|
except ImportError as e:
|
|
print(e)
|
|
print('flash_attn varlen/bert_padding not available, disabling varlen attention')
|
|
flash_attn_varlen_func = None
|
|
pad_input = None
|
|
unpad_input = None
|
|
index_first_axis = None
|
|
|
|
|
|
def precompute_varlen_metadata(padding_mask: torch.Tensor):
|
|
"""
|
|
Precompute varlen attention metadata once to avoid recomputation in every attention layer.
|
|
|
|
Args:
|
|
padding_mask: Boolean tensor of shape (batch, seq_len) where True = valid
|
|
|
|
Returns:
|
|
Dict with cu_seqlens, max_seqlen, indices, batch_size, seq_len for use in attention
|
|
"""
|
|
if padding_mask is None or unpad_input is None:
|
|
return None
|
|
|
|
batch_size, seq_len = padding_mask.shape
|
|
|
|
# Compute cumulative sequence lengths (same for all of q, k, v)
|
|
seqlens = padding_mask.sum(dim=-1, dtype=torch.int32)
|
|
cu_seqlens = F.pad(torch.cumsum(seqlens, dim=0, dtype=torch.int32), (1, 0))
|
|
max_seqlen = seqlens.max().item()
|
|
|
|
# Compute indices for gathering valid tokens
|
|
# indices maps from packed position -> original (batch, seq) position
|
|
indices = torch.nonzero(padding_mask.flatten(), as_tuple=False).flatten()
|
|
|
|
return {
|
|
"cu_seqlens": cu_seqlens,
|
|
"max_seqlen": max_seqlen,
|
|
"indices": indices,
|
|
"batch_size": batch_size,
|
|
"seq_len": seq_len,
|
|
}
|
|
|
|
from .utils import compile
|
|
|
|
|
|
def _left_pad_to_match(emb, target_len):
|
|
"""Left-pad or right-trim emb along seq dim to match target_len.
|
|
|
|
Used for local conditioning embeddings that need to align with x
|
|
without affecting prepended tokens (memory tokens, global cond, etc.).
|
|
"""
|
|
emb_len = emb.shape[-2]
|
|
if emb_len < target_len:
|
|
return F.pad(emb, (0, 0, target_len - emb_len, 0), value=0.)
|
|
elif emb_len > target_len:
|
|
return emb[:, -target_len:, :]
|
|
return emb
|
|
|
|
if flex_attention_available:
|
|
try:
|
|
torch._dynamo.config.cache_size_limit = 5000
|
|
flex_attention_compiled = torch.compile(flex_attention, dynamic=False, mode="max-autotune-no-cudagraphs")
|
|
except Exception as e:
|
|
logging.debug(f"Could not compile flex_attention, using uncompiled version: {e}")
|
|
flex_attention_compiled = flex_attention
|
|
else:
|
|
flex_attention_compiled = None
|
|
|
|
|
|
# Cache band block_masks for sliding-window attention fallback (flex_attention path).
|
|
# Keyed by (seq_q, seq_k, w_left, w_right, device). create_block_mask is expensive
|
|
# but the result is reused across all transformer layers and forward passes.
|
|
_SLIDING_WINDOW_BLOCK_MASK_CACHE = {}
|
|
|
|
def _get_sliding_window_block_mask(seq_q, seq_k, w_left, w_right, device):
|
|
key = (seq_q, seq_k, int(w_left), int(w_right), str(device))
|
|
bm = _SLIDING_WINDOW_BLOCK_MASK_CACHE.get(key)
|
|
if bm is None:
|
|
wl, wr = int(w_left), int(w_right)
|
|
def _band_mod(b, h, q_idx, kv_idx):
|
|
delta = kv_idx - q_idx
|
|
return (delta >= -wl) & (delta <= wr)
|
|
bm = create_block_mask(_band_mod, B=None, H=None, Q_LEN=seq_q, KV_LEN=seq_k, device=device)
|
|
_SLIDING_WINDOW_BLOCK_MASK_CACHE[key] = bm
|
|
return bm
|
|
|
|
def _sliding_window_additive_mask(seq_q, seq_k, w_left, w_right, device, dtype):
|
|
"""Build a (seq_q, seq_k) additive mask for masked SDPA fallback.
|
|
0 inside the band [i - w_left, i + w_right], -inf outside.
|
|
"""
|
|
ii = torch.arange(seq_q, device=device)
|
|
jj = torch.arange(seq_k, device=device)
|
|
delta = jj[None, :] - ii[:, None]
|
|
in_band = (delta >= -int(w_left)) & (delta <= int(w_right))
|
|
mask = torch.zeros((seq_q, seq_k), dtype=dtype, device=device)
|
|
return mask.masked_fill(~in_band, float('-inf'))
|
|
|
|
|
|
# Chunked-halo SDPA fallback. Math-equivalent to masked SDPA with a band
|
|
# mask, but processes queries in non-overlapping chunks with a (w_left,
|
|
# w_right) halo of keys/values on each side — every query stays inside its
|
|
# chunk's softmax. Avoids materializing the O(N^2) mask.
|
|
#
|
|
# At realistic SAME-L decoder shapes (N=69632, W=17, packed sequence is
|
|
# latent_length * (stride+1)): ~34x faster than full masked SDPA, and
|
|
# ~140x less peak mask memory (~1 MB per chunk vs 9.7 GB for one N x N mask).
|
|
# Chunk size is a tunable; 1024 is a good default at typical pretransform
|
|
# decoder shapes. Larger chunks waste more compute on out-of-band tiles;
|
|
# smaller chunks suffer from launch overhead.
|
|
_SLIDING_WINDOW_CHUNK_SIZE = 1024
|
|
|
|
def _sliding_window_chunked_halo_sdpa(q, k, v, w_left, w_right, chunk_size=_SLIDING_WINDOW_CHUNK_SIZE):
|
|
B, H, N, D = q.shape
|
|
outs = []
|
|
for q_start in range(0, N, chunk_size):
|
|
q_end = min(q_start + chunk_size, N)
|
|
k_start = max(0, q_start - int(w_left))
|
|
k_end = min(N, q_end + int(w_right))
|
|
q_c = q[..., q_start:q_end, :]
|
|
k_c = k[..., k_start:k_end, :]
|
|
v_c = v[..., k_start:k_end, :]
|
|
q_idx = torch.arange(q_start, q_end, device=q.device)
|
|
k_idx = torch.arange(k_start, k_end, device=q.device)
|
|
delta = k_idx[None, :] - q_idx[:, None]
|
|
in_band = (delta >= -int(w_left)) & (delta <= int(w_right))
|
|
mask = torch.zeros(delta.shape, dtype=q.dtype, device=q.device).masked_fill(~in_band, float('-inf'))
|
|
outs.append(F.scaled_dot_product_attention(q_c, k_c, v_c, attn_mask=mask, is_causal=False))
|
|
return torch.cat(outs, dim=-2)
|
|
|
|
|
|
def checkpoint(function, *args, **kwargs):
|
|
kwargs.setdefault("use_reentrant", False)
|
|
# Preserve autocast context during recomputation to avoid dtype mismatches
|
|
if "context_fn" not in kwargs:
|
|
from torch.amp import autocast
|
|
import functools
|
|
# Get current autocast state
|
|
if torch.is_autocast_enabled():
|
|
dtype = torch.get_autocast_dtype('cuda')
|
|
def get_contexts():
|
|
return (
|
|
autocast('cuda', dtype=dtype),
|
|
autocast('cuda', dtype=dtype),
|
|
)
|
|
kwargs["context_fn"] = get_contexts
|
|
return torch.utils.checkpoint.checkpoint(function, *args, **kwargs)
|
|
|
|
|
|
# Copied and modified from https://github.com/lucidrains/x-transformers/blob/main/x_transformers/attend.py under MIT License
|
|
# License can be found in LICENSES/LICENSE_XTRANSFORMERS.txt
|
|
|
|
def create_causal_mask(i, j, device):
|
|
return torch.ones((i, j), device = device, dtype = torch.bool).triu(j - i + 1)
|
|
|
|
def or_reduce(masks):
|
|
head, *body = masks
|
|
for rest in body:
|
|
head = head | rest
|
|
return head
|
|
|
|
# positional embeddings
|
|
|
|
class AbsolutePositionalEmbedding(nn.Module):
|
|
def __init__(self, dim, max_seq_len):
|
|
super().__init__()
|
|
self.scale = dim ** -0.5
|
|
self.max_seq_len = max_seq_len
|
|
self.emb = nn.Embedding(max_seq_len, dim)
|
|
|
|
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 absolute 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 = self.emb(pos)
|
|
pos_emb = pos_emb * self.scale
|
|
return pos_emb
|
|
|
|
class ScaledSinusoidalEmbedding(nn.Module):
|
|
def __init__(self, dim, theta = 10000):
|
|
super().__init__()
|
|
assert (dim % 2) == 0, 'dimension must be divisible by 2'
|
|
self.scale = nn.Parameter(torch.ones(1) * dim ** -0.5)
|
|
|
|
half_dim = dim // 2
|
|
freq_seq = torch.arange(half_dim).float() / half_dim
|
|
inv_freq = theta ** -freq_seq
|
|
self.register_buffer('inv_freq', inv_freq, persistent = False)
|
|
|
|
def forward(self, x, pos = None, seq_start_pos = None):
|
|
seq_len, device = x.shape[1], x.device
|
|
|
|
if pos is None:
|
|
pos = torch.arange(seq_len, device = device)
|
|
|
|
if seq_start_pos is not None:
|
|
pos = pos - seq_start_pos[..., None]
|
|
|
|
emb = einsum('i, j -> i j', pos, self.inv_freq)
|
|
emb = torch.cat((emb.sin(), emb.cos()), dim = -1)
|
|
return emb * self.scale
|
|
|
|
class RotaryEmbedding(nn.Module):
|
|
def __init__(
|
|
self,
|
|
dim,
|
|
use_xpos = False,
|
|
scale_base = 512,
|
|
interpolation_factor = 1.,
|
|
base = 10000,
|
|
base_rescale_factor = 1.
|
|
):
|
|
super().__init__()
|
|
# proposed by reddit user bloc97, to rescale rotary embeddings to longer sequence length without fine-tuning
|
|
# has some connection to NTK literature
|
|
# https://www.reddit.com/r/LocalLLaMA/comments/14lz7j5/ntkaware_scaled_rope_allows_llama_models_to_have/
|
|
base *= base_rescale_factor ** (dim / (dim - 2))
|
|
|
|
inv_freq = 1. / (base ** (torch.arange(0, dim, 2).float() / dim))
|
|
self.register_buffer('inv_freq', inv_freq)
|
|
|
|
assert interpolation_factor >= 1.
|
|
self.interpolation_factor = interpolation_factor
|
|
|
|
if not use_xpos:
|
|
self.register_buffer('scale', None)
|
|
return
|
|
|
|
scale = (torch.arange(0, dim, 2) + 0.4 * dim) / (1.4 * dim)
|
|
|
|
self.scale_base = scale_base
|
|
self.register_buffer('scale', scale)
|
|
|
|
def forward_from_seq_len(self, seq_len):
|
|
device = self.inv_freq.device
|
|
|
|
t = torch.arange(seq_len, device = device)
|
|
return self.forward(t)
|
|
|
|
@autocast("cuda", enabled = False)
|
|
def forward(self, t):
|
|
device = self.inv_freq.device
|
|
|
|
t = t.to(torch.float32)
|
|
|
|
t = t / self.interpolation_factor
|
|
|
|
freqs = torch.einsum('i , j -> i j', t, self.inv_freq)
|
|
freqs = torch.cat((freqs, freqs), dim = -1)
|
|
|
|
if self.scale is None:
|
|
return freqs, 1.
|
|
|
|
power = (torch.arange(seq_len, device = device) - (seq_len // 2)) / self.scale_base
|
|
scale = self.scale ** rearrange(power, 'n -> n 1')
|
|
scale = torch.cat((scale, scale), dim = -1)
|
|
|
|
return freqs, scale
|
|
|
|
def rotate_half(x):
|
|
x = rearrange(x, '... (j d) -> ... j d', j = 2)
|
|
x1, x2 = x.unbind(dim = -2)
|
|
return torch.cat((-x2, x1), dim = -1)
|
|
|
|
|
|
@autocast("cuda", enabled = False)
|
|
def apply_rotary_pos_emb(t, freqs, scale = 1):
|
|
out_dtype = t.dtype
|
|
|
|
# cast to float32 if necessary for numerical stability
|
|
dtype = reduce(torch.promote_types, (t.dtype, freqs.dtype, torch.float32))
|
|
rot_dim, seq_len = freqs.shape[-1], t.shape[-2]
|
|
freqs, t = freqs.to(dtype), t.to(dtype)
|
|
freqs = freqs[-seq_len:, :]
|
|
|
|
if t.ndim == 4 and freqs.ndim == 3:
|
|
freqs = rearrange(freqs, 'b n d -> b 1 n d')
|
|
|
|
# partial rotary embeddings, Wang et al. GPT-J
|
|
t, t_unrotated = t[..., :rot_dim], t[..., rot_dim:]
|
|
|
|
t = (t * freqs.cos() * scale ) + (rotate_half(t) * freqs.sin() * scale)
|
|
|
|
t, t_unrotated = t.to(out_dtype), t_unrotated.to(out_dtype)
|
|
|
|
return torch.cat((t, t_unrotated), dim = -1)
|
|
|
|
# norms
|
|
class DynamicTanh(nn.Module):
|
|
def __init__(self, dim, init_alpha=4.0, **kwargs):
|
|
super().__init__()
|
|
self.alpha = nn.Parameter(torch.ones(1) * init_alpha)
|
|
self.gamma = nn.Parameter(torch.ones(dim))
|
|
self.beta = nn.Parameter(torch.zeros(dim))
|
|
|
|
def forward(self, x):
|
|
x = F.tanh(self.alpha * x)
|
|
return self.gamma * x + self.beta
|
|
|
|
class RunningInstanceNorm(nn.Module):
|
|
def __init__(self, dim, momentum = 0.99, eps = 1e-4, saturate = True, trainable_gain = True):
|
|
super().__init__()
|
|
self.register_buffer("running_mean", torch.zeros(1,1,dim))
|
|
self.register_buffer("running_std", torch.ones(1,1,dim))
|
|
self.saturate = saturate
|
|
self.eps = eps
|
|
self.momentum = momentum
|
|
self.dim = dim
|
|
self.trainable_gain = trainable_gain
|
|
if self.trainable_gain:
|
|
self.gain = nn.Parameter(torch.ones(1))
|
|
|
|
def _update_stats(self, x):
|
|
self.running_mean = self.running_mean * self.momentum + x.detach().mean(dim = [0,1]).view(1, 1, self.dim) * (1 - self.momentum)
|
|
self.running_std = (self.running_std * self.momentum + x.detach().std(dim = [0,1]).view(1, 1, self.dim) * (1 - self.momentum)).clip(min = self.eps)
|
|
|
|
def forward(self, x):
|
|
if self.training:
|
|
self._update_stats(x)
|
|
x = (x - self.running_mean) / self.running_std
|
|
if self.saturate:
|
|
x = torch.asinh(x)
|
|
if self.trainable_gain:
|
|
x = x * self.gain
|
|
return x
|
|
|
|
class LayerNorm(nn.Module):
|
|
def __init__(self, dim, bias=False, fix_scale=False, force_fp32=False, eps=1e-5):
|
|
"""
|
|
bias-less layernorm has been shown to be more stable. most newer models have moved towards rmsnorm, also bias-less
|
|
"""
|
|
super().__init__()
|
|
|
|
if fix_scale:
|
|
self.register_buffer("gamma", torch.ones(dim))
|
|
else:
|
|
self.gamma = nn.Parameter(torch.ones(dim))
|
|
|
|
if bias:
|
|
self.beta = nn.Parameter(torch.zeros(dim))
|
|
else:
|
|
self.register_buffer("beta", torch.zeros(dim))
|
|
|
|
self.eps = eps
|
|
|
|
self.force_fp32 = force_fp32
|
|
|
|
#@autocast("cuda", enabled = False)
|
|
def forward(self, x):
|
|
if not self.force_fp32:
|
|
return F.layer_norm(x, x.shape[-1:], weight=self.gamma, bias=self.beta, eps=self.eps)
|
|
else:
|
|
output = F.layer_norm(x.float(), x.shape[-1:], weight=self.gamma.float(), bias=self.beta.float(), eps=self.eps)
|
|
return output.to(x.dtype)
|
|
|
|
class RMSNorm(nn.Module):
|
|
def __init__(self, dim, fix_scale=False, force_fp32=False, eps=1e-5):
|
|
super().__init__()
|
|
|
|
if fix_scale:
|
|
self.register_buffer("gamma", torch.ones(dim))
|
|
else:
|
|
self.gamma = nn.Parameter(torch.ones(dim))
|
|
|
|
self.eps = eps
|
|
|
|
self.force_fp32 = force_fp32
|
|
|
|
def forward(self, x):
|
|
if not self.force_fp32:
|
|
return F.rms_norm(x, x.shape[-1:], weight=self.gamma, eps=self.eps)
|
|
else:
|
|
output = F.rms_norm(x.float(), x.shape[-1:], weight=self.gamma.float(), eps=self.eps)
|
|
return output.to(x.dtype)
|
|
|
|
class LayerScale(nn.Module):
|
|
def __init__(self, dim, init_val = 1e-5):
|
|
super().__init__()
|
|
self.scale = nn.Parameter(torch.full([dim], init_val))
|
|
def forward(self, x):
|
|
return x * self.scale
|
|
|
|
# feedforward
|
|
|
|
class GLU(nn.Module):
|
|
def __init__(
|
|
self,
|
|
dim_in,
|
|
dim_out,
|
|
activation: Callable,
|
|
use_conv = False,
|
|
conv_kernel_size = 3,
|
|
):
|
|
super().__init__()
|
|
self.act = activation
|
|
self.proj = nn.Linear(dim_in, dim_out * 2) if not use_conv else nn.Conv1d(dim_in, dim_out * 2, conv_kernel_size, padding = (conv_kernel_size // 2))
|
|
self.use_conv = use_conv
|
|
|
|
def forward(self, x):
|
|
if self.use_conv:
|
|
x = rearrange(x, 'b n d -> b d n')
|
|
x = self.proj(x)
|
|
x = rearrange(x, 'b d n -> b n d')
|
|
else:
|
|
x = self.proj(x)
|
|
|
|
x, gate = x.chunk(2, dim = -1)
|
|
return x * self.act(gate)
|
|
|
|
class Sin(nn.Module):
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def forward(self, x):
|
|
return torch.sin(3.14159265359 * x)
|
|
|
|
class FeedForward(nn.Module):
|
|
def __init__(
|
|
self,
|
|
dim,
|
|
dim_out = None,
|
|
mult = 4,
|
|
no_bias = False,
|
|
glu = True,
|
|
use_conv = False,
|
|
conv_kernel_size = 3,
|
|
zero_init_output = True,
|
|
sinusoidal = False
|
|
):
|
|
super().__init__()
|
|
inner_dim = int(dim * mult)
|
|
|
|
# Default to SwiGLU
|
|
|
|
activation = nn.SiLU() if not sinusoidal else Sin()
|
|
|
|
dim_out = dim if dim_out is None else dim_out
|
|
|
|
if glu:
|
|
linear_in = GLU(dim, inner_dim, activation)
|
|
else:
|
|
linear_in = nn.Sequential(
|
|
Rearrange('b n d -> b d n') if use_conv else nn.Identity(),
|
|
nn.Linear(dim, inner_dim, bias = not no_bias) if not use_conv else nn.Conv1d(dim, inner_dim, conv_kernel_size, padding = (conv_kernel_size // 2), bias = not no_bias),
|
|
Rearrange('b n d -> b d n') if use_conv else nn.Identity(),
|
|
activation
|
|
)
|
|
|
|
linear_out = nn.Linear(inner_dim, dim_out, bias = not no_bias) if not use_conv else nn.Conv1d(inner_dim, dim_out, conv_kernel_size, padding = (conv_kernel_size // 2), bias = not no_bias)
|
|
|
|
# init last linear layer to 0
|
|
if zero_init_output:
|
|
nn.init.zeros_(linear_out.weight)
|
|
if not no_bias:
|
|
nn.init.zeros_(linear_out.bias)
|
|
|
|
|
|
self.ff = nn.Sequential(
|
|
linear_in,
|
|
Rearrange('b d n -> b n d') if use_conv else nn.Identity(),
|
|
linear_out,
|
|
Rearrange('b n d -> b d n') if use_conv else nn.Identity(),
|
|
)
|
|
|
|
#@compile
|
|
def forward(self, x, varlen_metadata=None):
|
|
if varlen_metadata is not None and index_first_axis is not None and pad_input is not None:
|
|
# Pack valid tokens for efficient FFN computation (skip padding tokens)
|
|
# Padding positions become zeros after unpack, which is fine since FFN output
|
|
# is added to residual, preserving values at padding positions
|
|
batch_size = varlen_metadata["batch_size"]
|
|
seq_len = varlen_metadata["seq_len"]
|
|
indices = varlen_metadata["indices"]
|
|
dim = x.shape[-1]
|
|
|
|
# Pack to (N_valid, D)
|
|
x_packed = index_first_axis(x.reshape(-1, dim), indices)
|
|
|
|
# FFN on packed representation with pseudo-batch dim
|
|
x_packed = self.ff(x_packed.unsqueeze(0)).squeeze(0)
|
|
|
|
# Unpack back to (B, T, D)
|
|
return pad_input(x_packed, indices, batch_size, seq_len)
|
|
else:
|
|
return self.ff(x)
|
|
|
|
class Attention(nn.Module):
|
|
def __init__(
|
|
self,
|
|
dim,
|
|
dim_heads = 64,
|
|
dim_context = None,
|
|
causal = False,
|
|
zero_init_output=True,
|
|
qk_norm_eps = 1e-6,
|
|
qk_norm: Literal['l2', 'ln', 'rms', 'dyt', 'none'] = 'none',
|
|
differential = False,
|
|
feat_scale = False
|
|
):
|
|
super().__init__()
|
|
self.dim = dim
|
|
self.dim_heads = dim_heads
|
|
|
|
self.differential = differential
|
|
|
|
dim_kv = dim_context if dim_context is not None else dim
|
|
|
|
self.num_heads = dim // dim_heads
|
|
self.kv_heads = dim_kv // dim_heads
|
|
|
|
if dim_context is not None:
|
|
if differential:
|
|
self.to_q = nn.Linear(dim, dim * 2, bias=False)
|
|
self.to_kv = nn.Linear(dim_kv, dim_kv * 3, bias=False)
|
|
else:
|
|
self.to_q = nn.Linear(dim, dim, bias=False)
|
|
self.to_kv = nn.Linear(dim_kv, dim_kv * 2, bias=False)
|
|
else:
|
|
if differential:
|
|
self.to_qkv = nn.Linear(dim, dim * 5, bias=False)
|
|
else:
|
|
self.to_qkv = nn.Linear(dim, dim * 3, bias=False)
|
|
|
|
self.to_out = nn.Linear(dim, dim, bias=False)
|
|
|
|
if zero_init_output:
|
|
nn.init.zeros_(self.to_out.weight)
|
|
|
|
if qk_norm not in ['l2', 'ln', 'rms', 'dyt','none']:
|
|
raise ValueError(f'qk_norm must be one of ["l2", "ln", "rms" ,"dyt", "none"], got {qk_norm}')
|
|
|
|
self.qk_norm = qk_norm
|
|
self.qk_norm_eps = qk_norm_eps
|
|
|
|
if self.qk_norm == "ln":
|
|
self.q_norm = nn.LayerNorm(dim_heads, elementwise_affine=True, eps=qk_norm_eps)
|
|
self.k_norm = nn.LayerNorm(dim_heads, elementwise_affine=True, eps=qk_norm_eps)
|
|
elif self.qk_norm == "rms":
|
|
self.q_norm = RMSNorm(dim_heads, eps=qk_norm_eps)
|
|
self.k_norm = RMSNorm(dim_heads, eps=qk_norm_eps)
|
|
elif self.qk_norm == 'dyt':
|
|
self.q_norm = DynamicTanh(dim_heads)
|
|
self.k_norm = DynamicTanh(dim_heads)
|
|
|
|
self.feat_scale = feat_scale
|
|
|
|
if self.feat_scale:
|
|
self.lambda_dc = nn.Parameter(torch.zeros(dim))
|
|
self.lambda_hf = nn.Parameter(torch.zeros(dim))
|
|
|
|
self.causal = causal
|
|
|
|
@compile
|
|
def apply_qk_layernorm(self, q, k):
|
|
q_type = q.dtype
|
|
k_type = k.dtype
|
|
q = self.q_norm(q).to(q_type)
|
|
k = self.k_norm(k).to(k_type)
|
|
return q, k
|
|
|
|
|
|
def apply_attn(self, q, k, v, causal = None, flex_attention_block_mask = None, flex_attention_score_mod = None, flash_attn_sliding_window = None, padding_mask = None, varlen_metadata = None):
|
|
|
|
if self.num_heads != self.kv_heads:
|
|
# Repeat interleave kv_heads to match q_heads for grouped query attention
|
|
heads_per_kv_head = self.num_heads // self.kv_heads
|
|
k, v = map(lambda t: t.repeat_interleave(heads_per_kv_head, dim = 1), (k, v))
|
|
|
|
flash_attn_available = flash_attn_func is not None
|
|
flash_attn_varlen_available = flash_attn_varlen_func is not None and index_first_axis is not None
|
|
|
|
if causal and (flex_attention_block_mask is not None or flex_attention_score_mod is not None):
|
|
flex_attention_block_mask = None
|
|
flex_attention_score_mod = None
|
|
|
|
if flex_attention_block_mask is not None or flex_attention_score_mod is not None:
|
|
# Flex attention path - use V-zeroing for padding mask
|
|
if padding_mask is not None:
|
|
mask_expanded = padding_mask.unsqueeze(1).unsqueeze(-1).to(v.dtype)
|
|
v = v * mask_expanded
|
|
out = flex_attention_compiled(q,k,v,
|
|
block_mask = flex_attention_block_mask,
|
|
score_mod = flex_attention_score_mod)
|
|
elif flash_attn_available and varlen_metadata is not None and flash_attn_varlen_available:
|
|
# Flash attention with varlen using precomputed metadata (fast path)
|
|
batch_size = varlen_metadata["batch_size"]
|
|
seq_len = varlen_metadata["seq_len"]
|
|
cu_seqlens = varlen_metadata["cu_seqlens"]
|
|
max_seqlen = varlen_metadata["max_seqlen"]
|
|
indices = varlen_metadata["indices"]
|
|
|
|
fa_dtype_in = q.dtype
|
|
# Rearrange to (B, T, H, D) for flash_attn
|
|
q, k, v = map(lambda t: rearrange(t, 'b h n d -> b n h d'), (q, k, v))
|
|
|
|
if fa_dtype_in != torch.float16 and fa_dtype_in != torch.bfloat16:
|
|
q, k, v = map(lambda t: t.to(torch.float16), (q, k, v))
|
|
|
|
# Pack q, k, v using precomputed indices (much faster than calling unpad_input 3x)
|
|
num_heads, head_dim = q.shape[2], q.shape[3]
|
|
q_unpad = index_first_axis(q.reshape(-1, num_heads, head_dim), indices)
|
|
k_unpad = index_first_axis(k.reshape(-1, num_heads, head_dim), indices)
|
|
v_unpad = index_first_axis(v.reshape(-1, num_heads, head_dim), indices)
|
|
|
|
out_unpad = flash_attn_varlen_func(
|
|
q_unpad, k_unpad, v_unpad,
|
|
cu_seqlens, cu_seqlens,
|
|
max_seqlen, max_seqlen,
|
|
causal=causal if causal is not None else False,
|
|
window_size=flash_attn_sliding_window if flash_attn_sliding_window is not None else (-1, -1),
|
|
)
|
|
|
|
# Pad output back to original shape
|
|
out = pad_input(out_unpad, indices, batch_size, seq_len)
|
|
out = rearrange(out.to(fa_dtype_in), 'b n h d -> b h n d')
|
|
elif flash_attn_available:
|
|
# Standard flash attention (no padding mask, or varlen imports not available)
|
|
# Apply V-zeroing fallback if padding_mask provided but we couldn't use varlen
|
|
if padding_mask is not None:
|
|
mask_expanded = padding_mask.unsqueeze(1).unsqueeze(-1).to(v.dtype)
|
|
v = v * mask_expanded
|
|
fa_dtype_in = q.dtype
|
|
q, k, v = map(lambda t: rearrange(t, 'b h n d -> b n h d'), (q, k, v))
|
|
|
|
if fa_dtype_in != torch.float16 and fa_dtype_in != torch.bfloat16:
|
|
q, k, v = map(lambda t: t.to(torch.float16), (q, k, v))
|
|
|
|
out = flash_attn_func(q, k, v, causal = causal, window_size=flash_attn_sliding_window if (flash_attn_sliding_window is not None) else [-1,-1])
|
|
|
|
out = rearrange(out.to(fa_dtype_in), 'b n h d -> b h n d')
|
|
else:
|
|
# No flash-attn available. Sliding-window fallback cascade:
|
|
# Tier 2: flex_attention with band block_mask (best when torch.compile works)
|
|
# Tier 3: chunked-halo masked SDPA (math-equivalent, ~30x faster than tier 4)
|
|
# Tier 4: full masked SDPA (N x N mask) (last resort; high memory)
|
|
# For the no-sliding-window case, fall through to plain SDPA full attention.
|
|
# All apply V-zeroing for padding masks (cheap and equivalent to masking
|
|
# those positions out of attention output).
|
|
if padding_mask is not None:
|
|
mask_expanded = padding_mask.unsqueeze(1).unsqueeze(-1).to(v.dtype)
|
|
v = v * mask_expanded
|
|
if flash_attn_sliding_window is not None:
|
|
seq_q, seq_k = q.shape[2], k.shape[2]
|
|
wl, wr = flash_attn_sliding_window
|
|
handled = False
|
|
if flex_attention_available and flex_attention_compiled is not None:
|
|
try:
|
|
bm = _get_sliding_window_block_mask(seq_q, seq_k, wl, wr, q.device)
|
|
out = flex_attention_compiled(q, k, v, block_mask=bm)
|
|
handled = True
|
|
except Exception as _flex_err:
|
|
logging.debug(f"flex_attention failed, trying chunked-halo SDPA: {_flex_err}")
|
|
if not handled:
|
|
try:
|
|
out = _sliding_window_chunked_halo_sdpa(q, k, v, wl, wr)
|
|
handled = True
|
|
except Exception as _chunk_err:
|
|
logging.debug(f"chunked-halo SDPA failed, falling back to full masked SDPA: {_chunk_err}")
|
|
if not handled:
|
|
add_mask = _sliding_window_additive_mask(seq_q, seq_k, wl, wr, q.device, q.dtype)
|
|
out = F.scaled_dot_product_attention(q, k, v, attn_mask=add_mask, is_causal=False)
|
|
else:
|
|
out = F.scaled_dot_product_attention(q, k, v, is_causal=causal if causal is not None else False)
|
|
return out
|
|
|
|
|
|
#@compile
|
|
def forward(
|
|
self,
|
|
x,
|
|
context = None,
|
|
rotary_pos_emb = None,
|
|
rotary_pos_emb_k = None,
|
|
causal = None,
|
|
flex_attention_block_mask = None,
|
|
flex_attention_score_mod = None,
|
|
flash_attn_sliding_window = None,
|
|
padding_mask = None,
|
|
varlen_metadata = None,
|
|
):
|
|
h, kv_h, has_context = self.num_heads, self.kv_heads, context is not None
|
|
|
|
kv_input = context if has_context else x
|
|
|
|
if hasattr(self, 'to_q'):
|
|
# Use separate linear projections for q and k/v
|
|
if self.differential:
|
|
q, q_diff = self.to_q(x).chunk(2, dim=-1)
|
|
q, q_diff = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = h), (q, q_diff))
|
|
q = torch.stack([q, q_diff], dim = 1)
|
|
k, k_diff, v = self.to_kv(kv_input).chunk(3, dim=-1)
|
|
k, k_diff, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = kv_h), (k, k_diff, v))
|
|
k = torch.stack([k, k_diff], dim = 1)
|
|
else:
|
|
q = self.to_q(x)
|
|
q = rearrange(q, 'b n (h d) -> b h n d', h = h)
|
|
k, v = self.to_kv(kv_input).chunk(2, dim=-1)
|
|
k, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = kv_h), (k, v))
|
|
else:
|
|
# Use fused linear projection
|
|
if self.differential:
|
|
q, k, v, q_diff, k_diff = self.to_qkv(x).chunk(5, dim=-1)
|
|
q, k, v, q_diff, k_diff = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = h), (q, k, v, q_diff, k_diff))
|
|
q = torch.stack([q, q_diff], dim = 1)
|
|
k = torch.stack([k, k_diff], dim = 1)
|
|
else:
|
|
q, k, v = self.to_qkv(x).chunk(3, dim=-1)
|
|
q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = h), (q, k, v))
|
|
|
|
# Normalize q and k for cosine sim attention
|
|
if self.qk_norm == "l2":
|
|
q = F.normalize(q, dim=-1, eps=self.qk_norm_eps)
|
|
k = F.normalize(k, dim=-1, eps=self.qk_norm_eps)
|
|
elif self.qk_norm != "none":
|
|
q, k = self.apply_qk_layernorm(q, k)
|
|
# q = self.q_norm(q)
|
|
# k = self.k_norm(k)
|
|
|
|
if rotary_pos_emb is not None:
|
|
freqs, _ = rotary_pos_emb
|
|
q_dtype = q.dtype
|
|
k_dtype = k.dtype
|
|
q = q.to(torch.float32)
|
|
k = k.to(torch.float32)
|
|
freqs = freqs.to(torch.float32)
|
|
|
|
q_freqs = freqs
|
|
|
|
if rotary_pos_emb_k is not None:
|
|
k_freqs, _ = rotary_pos_emb_k
|
|
k_freqs = k_freqs.to(torch.float32)
|
|
else:
|
|
k_freqs = q_freqs
|
|
|
|
if q.shape[-2] >= k.shape[-2]:
|
|
ratio = q.shape[-2] / k.shape[-2]
|
|
q_freqs, k_freqs = freqs, ratio * freqs
|
|
else:
|
|
ratio = k.shape[-2] / q.shape[-2]
|
|
q_freqs, k_freqs = ratio * freqs, freqs
|
|
|
|
q = apply_rotary_pos_emb(q, q_freqs)
|
|
k = apply_rotary_pos_emb(k, k_freqs)
|
|
q = q.to(v.dtype)
|
|
k = k.to(v.dtype)
|
|
|
|
n, device = q.shape[-2], q.device
|
|
|
|
causal = self.causal if causal is None else causal
|
|
|
|
if n == 1 and causal:
|
|
causal = False
|
|
|
|
if self.differential:
|
|
q, q_diff = q.unbind(dim = 1)
|
|
k, k_diff = k.unbind(dim = 1)
|
|
out = self.apply_attn(q, k, v, causal = causal, flex_attention_block_mask = flex_attention_block_mask, flex_attention_score_mod = flex_attention_score_mod, flash_attn_sliding_window = flash_attn_sliding_window, padding_mask = padding_mask, varlen_metadata = varlen_metadata)
|
|
out_diff = self.apply_attn(q_diff, k_diff, v, causal = causal, flex_attention_block_mask = flex_attention_block_mask, flex_attention_score_mod = flex_attention_score_mod, flash_attn_sliding_window = flash_attn_sliding_window, padding_mask = padding_mask, varlen_metadata = varlen_metadata)
|
|
out = out - out_diff
|
|
else:
|
|
out = self.apply_attn(q, k, v, causal = causal, flex_attention_block_mask = flex_attention_block_mask, flex_attention_score_mod = flex_attention_score_mod, flash_attn_sliding_window = flash_attn_sliding_window, padding_mask = padding_mask, varlen_metadata = varlen_metadata)
|
|
# merge heads
|
|
out = rearrange(out, ' b h n d -> b n (h d)')
|
|
|
|
# Communicate between heads
|
|
|
|
# with autocast(enabled = False):
|
|
# out_dtype = out.dtype
|
|
# out = out.to(torch.float32)
|
|
# out = self.to_out(out).to(out_dtype)
|
|
out = self.to_out(out)
|
|
|
|
if self.feat_scale:
|
|
if padding_mask is not None:
|
|
mask = padding_mask.unsqueeze(-1).to(out.dtype) # (b, n, 1)
|
|
out_dc = (out * mask).sum(dim=-2, keepdim=True) / mask.sum(dim=-2, keepdim=True).clamp(min=1)
|
|
out_hf = out - out_dc
|
|
out = out + (self.lambda_dc * out_dc + self.lambda_hf * out_hf) * mask
|
|
else:
|
|
out_dc = out.mean(dim=-2, keepdim=True)
|
|
out_hf = out - out_dc
|
|
out = out + self.lambda_dc * out_dc + self.lambda_hf * out_hf
|
|
|
|
return out
|
|
|
|
class ConformerModule(nn.Module):
|
|
def __init__(
|
|
self,
|
|
dim,
|
|
norm_kwargs = {},
|
|
):
|
|
|
|
super().__init__()
|
|
|
|
self.dim = dim
|
|
|
|
self.in_norm = LayerNorm(dim, **norm_kwargs)
|
|
self.pointwise_conv = nn.Conv1d(dim, dim, kernel_size=1, bias=False)
|
|
self.glu = GLU(dim, dim, nn.SiLU())
|
|
self.depthwise_conv = nn.Conv1d(dim, dim, kernel_size=17, groups=dim, padding=8, bias=False)
|
|
self.mid_norm = LayerNorm(dim, **norm_kwargs) # This is a batch norm in the original but I don't like batch norm
|
|
self.swish = nn.SiLU()
|
|
self.pointwise_conv_2 = nn.Conv1d(dim, dim, kernel_size=1, bias=False)
|
|
|
|
#@compile
|
|
def forward(self, x):
|
|
x = self.in_norm(x)
|
|
x = rearrange(x, 'b n d -> b d n')
|
|
x = self.pointwise_conv(x)
|
|
x = rearrange(x, 'b d n -> b n d')
|
|
x = self.glu(x)
|
|
x = rearrange(x, 'b n d -> b d n')
|
|
x = self.depthwise_conv(x)
|
|
x = rearrange(x, 'b d n -> b n d')
|
|
x = self.mid_norm(x)
|
|
x = self.swish(x)
|
|
x = rearrange(x, 'b n d -> b d n')
|
|
x = self.pointwise_conv_2(x)
|
|
x = rearrange(x, 'b d n -> b n d')
|
|
|
|
return x
|
|
|
|
class TransformerBlock(nn.Module):
|
|
def __init__(
|
|
self,
|
|
dim,
|
|
dim_heads = 64,
|
|
cross_attend = False,
|
|
dim_context = None,
|
|
global_cond_dim = None,
|
|
local_add_cond_dim = None,
|
|
modular_local_cond_configs = None,
|
|
causal = False,
|
|
zero_init_branch_outputs = True,
|
|
conformer = False,
|
|
layer_ix = -1,
|
|
add_rope = False,
|
|
layer_scale = False,
|
|
norm_type = 'layer_norm',
|
|
attn_kwargs = {},
|
|
ff_kwargs = {},
|
|
norm_kwargs = {}
|
|
):
|
|
|
|
super().__init__()
|
|
self.dim = dim
|
|
self.dim_heads = min(dim_heads,dim)
|
|
self.cross_attend = cross_attend
|
|
self.dim_context = dim_context
|
|
self.causal = causal
|
|
|
|
if layer_scale and zero_init_branch_outputs:
|
|
print('zero_init_branch_outputs is redundant with layer_scale, setting zero_init_branch_outputs to False')
|
|
zero_init_branch_outputs = False
|
|
|
|
if norm_type not in ['layer_norm', 'rms_norm', 'dyt']:
|
|
raise ValueError(f'norm_type must be one of ["layer_norm", "rms_norm", "dyt"], got {norm_type}')
|
|
|
|
norm_layer_map = {
|
|
'layer_norm': LayerNorm,
|
|
'rms_norm': RMSNorm,
|
|
'dyt': DynamicTanh
|
|
}
|
|
norm_layer = norm_layer_map[norm_type]
|
|
|
|
self.pre_norm = norm_layer(dim,**norm_kwargs)
|
|
self.add_rope = add_rope
|
|
|
|
self.self_attn = Attention(
|
|
dim,
|
|
dim_heads = self.dim_heads,
|
|
causal = causal,
|
|
zero_init_output=zero_init_branch_outputs,
|
|
**attn_kwargs
|
|
)
|
|
|
|
self.self_attn_scale = LayerScale(dim) if layer_scale else nn.Identity()
|
|
|
|
self.cross_attend = cross_attend
|
|
if cross_attend:
|
|
self.cross_attend_norm = norm_layer(dim, **norm_kwargs)
|
|
self.cross_attn = Attention(
|
|
dim,
|
|
dim_heads = self.dim_heads,
|
|
dim_context=dim_context,
|
|
causal = causal,
|
|
zero_init_output=zero_init_branch_outputs,
|
|
**attn_kwargs
|
|
)
|
|
self.cross_attn_scale = LayerScale(dim) if layer_scale else nn.Identity()
|
|
|
|
self.ff_norm = norm_layer(dim, **norm_kwargs)
|
|
self.ff = FeedForward(dim, zero_init_output=zero_init_branch_outputs, **ff_kwargs)
|
|
self.ff_scale = LayerScale(dim) if layer_scale else nn.Identity()
|
|
|
|
self.layer_ix = layer_ix
|
|
|
|
self.conformer = None
|
|
if conformer:
|
|
self.conformer = ConformerModule(dim, norm_kwargs=norm_kwargs)
|
|
self.conformer_scale = LayerScale(dim) if layer_scale else nn.Identity()
|
|
|
|
self.global_cond_dim = global_cond_dim
|
|
|
|
if global_cond_dim is not None:
|
|
self.to_scale_shift_gate = nn.Parameter(torch.randn(6*dim)/dim**0.5)
|
|
|
|
self.local_add_cond_dim = local_add_cond_dim
|
|
|
|
if local_add_cond_dim is not None:
|
|
self.to_local_embed = nn.Sequential(
|
|
nn.Linear(local_add_cond_dim, dim),
|
|
nn.SiLU(),
|
|
nn.Linear(dim, dim)
|
|
)
|
|
|
|
nn.init.zeros_(self.to_local_embed[-1].weight)
|
|
nn.init.zeros_(self.to_local_embed[-1].bias)
|
|
|
|
else:
|
|
self.to_local_embed = None
|
|
|
|
# Modular local conditioning - independent projections per conditioning ID
|
|
self.modular_local_cond_configs = modular_local_cond_configs or []
|
|
self.modular_local_embeds = nn.ModuleDict()
|
|
|
|
for config in self.modular_local_cond_configs:
|
|
cond_id = config["id"]
|
|
cond_dim = config["dim"]
|
|
proj = nn.Sequential(
|
|
nn.Linear(cond_dim, dim),
|
|
nn.SiLU(),
|
|
nn.Linear(dim, dim)
|
|
)
|
|
# Zero-init output layer so new conditioning doesn't affect model initially
|
|
nn.init.zeros_(proj[-1].weight)
|
|
nn.init.zeros_(proj[-1].bias)
|
|
self.modular_local_embeds[cond_id] = proj
|
|
|
|
self.rope = RotaryEmbedding(self.dim_heads // 2) if add_rope else None
|
|
|
|
def _apply_local_conditioning(self, x, local_add_cond, modular_local_cond):
|
|
"""Apply local additive and modular local conditioning to x."""
|
|
if local_add_cond is not None and self.to_local_embed is not None:
|
|
local_emb = self.to_local_embed(local_add_cond)
|
|
x = x + _left_pad_to_match(local_emb, x.shape[-2])
|
|
|
|
if modular_local_cond is not None and len(self.modular_local_embeds) > 0:
|
|
modular_sum = None
|
|
for cond_id, proj in self.modular_local_embeds.items():
|
|
if cond_id in modular_local_cond:
|
|
local_emb = proj(modular_local_cond[cond_id])
|
|
local_emb = _left_pad_to_match(local_emb, x.shape[-2])
|
|
modular_sum = local_emb if modular_sum is None else modular_sum + local_emb
|
|
if modular_sum is not None:
|
|
x = x + modular_sum
|
|
|
|
return x
|
|
|
|
@compile
|
|
def forward(
|
|
self,
|
|
x,
|
|
context = None,
|
|
global_cond=None,
|
|
local_add_cond=None,
|
|
modular_local_cond=None,
|
|
rotary_pos_emb = None,
|
|
cross_attn_rotary_pos_emb = None,
|
|
self_attention_block_mask = None,
|
|
self_attention_score_mod = None,
|
|
cross_attention_block_mask = None,
|
|
cross_attention_score_mod = None,
|
|
self_attention_flash_sliding_window = None,
|
|
cross_attention_flash_sliding_window = None,
|
|
padding_mask = None,
|
|
varlen_metadata = None,
|
|
):
|
|
if rotary_pos_emb is None and self.add_rope:
|
|
rotary_pos_emb = self.rope.forward_from_seq_len(x.shape[-2])
|
|
|
|
if self.global_cond_dim is not None and self.global_cond_dim > 0 and global_cond is not None:
|
|
|
|
scale_self, shift_self, gate_self, scale_ff, shift_ff, gate_ff = (self.to_scale_shift_gate + global_cond).unsqueeze(1).chunk(6, dim=-1)
|
|
|
|
# self-attention with adaLN
|
|
residual = x
|
|
x = self.pre_norm(x)
|
|
x = x * (1 + scale_self) + shift_self
|
|
x = self.self_attn(x, rotary_pos_emb = rotary_pos_emb, flex_attention_block_mask = self_attention_block_mask, flex_attention_score_mod = self_attention_score_mod, flash_attn_sliding_window = self_attention_flash_sliding_window, padding_mask = padding_mask, varlen_metadata = varlen_metadata)
|
|
x = x * torch.sigmoid(1 - gate_self)
|
|
x = self.self_attn_scale(x)
|
|
x = x + residual
|
|
|
|
if context is not None and self.cross_attend:
|
|
if cross_attn_rotary_pos_emb is not None:
|
|
x = x + self.cross_attn_scale(self.cross_attn(self.cross_attend_norm(x), rotary_pos_emb = rotary_pos_emb, rotary_pos_emb_k = cross_attn_rotary_pos_emb, context = context, flex_attention_block_mask = cross_attention_block_mask, flex_attention_score_mod = cross_attention_score_mod, flash_attn_sliding_window = cross_attention_flash_sliding_window))
|
|
else:
|
|
x = x + self.cross_attn_scale(self.cross_attn(self.cross_attend_norm(x), context = context, flex_attention_block_mask = cross_attention_block_mask, flex_attention_score_mod = cross_attention_score_mod, flash_attn_sliding_window = cross_attention_flash_sliding_window))
|
|
|
|
if self.conformer is not None:
|
|
x = x + self.conformer_scale(self.conformer(x))
|
|
|
|
x = self._apply_local_conditioning(x, local_add_cond, modular_local_cond)
|
|
|
|
# feedforward with adaLN
|
|
residual = x
|
|
x = self.ff_norm(x)
|
|
x = x * (1 + scale_ff) + shift_ff
|
|
x = self.ff(x, varlen_metadata=varlen_metadata)
|
|
x = x * torch.sigmoid(1 - gate_ff)
|
|
x = self.ff_scale(x)
|
|
x = x + residual
|
|
|
|
else:
|
|
x = x + self.self_attn_scale(self.self_attn(self.pre_norm(x), rotary_pos_emb = rotary_pos_emb, flex_attention_block_mask = self_attention_block_mask, flex_attention_score_mod = self_attention_score_mod, flash_attn_sliding_window = self_attention_flash_sliding_window, padding_mask = padding_mask, varlen_metadata = varlen_metadata))
|
|
|
|
if context is not None and self.cross_attend:
|
|
if cross_attn_rotary_pos_emb is not None:
|
|
x = x + self.cross_attn_scale(self.cross_attn(self.cross_attend_norm(x), rotary_pos_emb = rotary_pos_emb, rotary_pos_emb_k = cross_attn_rotary_pos_emb, context = context, flex_attention_block_mask = cross_attention_block_mask, flex_attention_score_mod = cross_attention_score_mod, flash_attn_sliding_window = cross_attention_flash_sliding_window))
|
|
else:
|
|
x = x + self.cross_attn_scale(self.cross_attn(self.cross_attend_norm(x), context = context, flex_attention_block_mask = cross_attention_block_mask, flex_attention_score_mod = cross_attention_score_mod, flash_attn_sliding_window = cross_attention_flash_sliding_window))
|
|
|
|
if self.conformer is not None:
|
|
x = x + self.conformer_scale(self.conformer(x))
|
|
|
|
x = self._apply_local_conditioning(x, local_add_cond, modular_local_cond)
|
|
|
|
x = x + self.ff_scale(self.ff(self.ff_norm(x), varlen_metadata=varlen_metadata))
|
|
|
|
|
|
return x
|
|
|
|
class ContinuousTransformer(nn.Module):
|
|
def __init__(
|
|
self,
|
|
dim,
|
|
depth,
|
|
*,
|
|
dim_in = None,
|
|
dim_out = None,
|
|
dim_heads = 64,
|
|
cross_attend=False,
|
|
cond_token_dim=None,
|
|
final_cross_attn_ix=-1,
|
|
global_cond_dim=None,
|
|
local_add_cond_dim=None,
|
|
modular_local_cond_configs=None,
|
|
causal=False,
|
|
rotary_pos_emb=True,
|
|
cross_attn_rotary_pos_emb=False,
|
|
zero_init_branch_outputs=True,
|
|
conformer=False,
|
|
use_sinusoidal_emb=False,
|
|
use_abs_pos_emb=False,
|
|
abs_pos_emb_max_length=10000,
|
|
num_memory_tokens=0,
|
|
sliding_window=None,
|
|
**kwargs
|
|
):
|
|
|
|
super().__init__()
|
|
|
|
self.dim = dim
|
|
self.depth = depth
|
|
self.causal = causal
|
|
self.layers = nn.ModuleList([])
|
|
|
|
self.project_in = nn.Linear(dim_in, dim, bias=False) if dim_in is not None else nn.Identity()
|
|
self.project_out = nn.Linear(dim, dim_out, bias=False) if dim_out is not None else nn.Identity()
|
|
|
|
if rotary_pos_emb:
|
|
self.rotary_pos_emb = RotaryEmbedding(max(dim_heads // 2, 32))
|
|
else:
|
|
self.rotary_pos_emb = None
|
|
|
|
if cross_attn_rotary_pos_emb:
|
|
self.cross_attn_rotary_pos_emb = RotaryEmbedding(max(dim_heads // 2, 32))
|
|
else:
|
|
self.cross_attn_rotary_pos_emb = None
|
|
|
|
self.num_memory_tokens = num_memory_tokens
|
|
if num_memory_tokens > 0:
|
|
self.memory_tokens = nn.Parameter(torch.randn(num_memory_tokens, dim))
|
|
|
|
self.use_sinusoidal_emb = use_sinusoidal_emb
|
|
if use_sinusoidal_emb:
|
|
self.pos_emb = ScaledSinusoidalEmbedding(dim)
|
|
|
|
self.use_abs_pos_emb = use_abs_pos_emb
|
|
if use_abs_pos_emb:
|
|
self.pos_emb = AbsolutePositionalEmbedding(dim, abs_pos_emb_max_length + self.num_memory_tokens)
|
|
|
|
self.global_cond_embedder = None
|
|
if global_cond_dim is not None:
|
|
self.global_cond_embedder = nn.Sequential(
|
|
nn.Linear(global_cond_dim, dim),
|
|
nn.SiLU(),
|
|
nn.Linear(dim, dim * 6)
|
|
)
|
|
|
|
self.final_cross_attn_ix = final_cross_attn_ix
|
|
|
|
self.sliding_window = sliding_window
|
|
|
|
for i in range(depth):
|
|
should_cross_attend = cross_attend and (self.final_cross_attn_ix == -1 or i <= (self.final_cross_attn_ix))
|
|
self.layers.append(
|
|
TransformerBlock(
|
|
dim,
|
|
dim_heads = dim_heads,
|
|
cross_attend = should_cross_attend,
|
|
dim_context = cond_token_dim,
|
|
global_cond_dim = global_cond_dim,
|
|
local_add_cond_dim = local_add_cond_dim,
|
|
modular_local_cond_configs = modular_local_cond_configs,
|
|
causal = causal,
|
|
zero_init_branch_outputs = zero_init_branch_outputs,
|
|
conformer=conformer,
|
|
layer_ix=i,
|
|
**kwargs
|
|
)
|
|
)
|
|
|
|
def forward(
|
|
self,
|
|
x,
|
|
context = None,
|
|
prepend_embeds = None,
|
|
global_cond = None,
|
|
local_add_cond = None,
|
|
modular_local_cond = None,
|
|
return_info = False,
|
|
use_checkpointing = True,
|
|
exit_layer_ix = None,
|
|
padding_mask: Optional[torch.Tensor] = None,
|
|
**kwargs
|
|
):
|
|
batch, seq, device = *x.shape[:2], x.device
|
|
|
|
model_dtype = next(self.parameters()).dtype
|
|
x = x.to(model_dtype)
|
|
|
|
info = {
|
|
"hidden_states": [],
|
|
}
|
|
|
|
x = self.project_in(x)
|
|
|
|
if prepend_embeds is not None:
|
|
prepend_length, prepend_dim = prepend_embeds.shape[1:]
|
|
|
|
assert prepend_dim == x.shape[-1], 'prepend dimension must match sequence dimension'
|
|
|
|
x = torch.cat((prepend_embeds, x), dim = -2)
|
|
|
|
if self.num_memory_tokens > 0:
|
|
memory_tokens = self.memory_tokens.expand(batch, -1, -1)
|
|
x = torch.cat((memory_tokens, x), dim=1)
|
|
|
|
if self.rotary_pos_emb is not None:
|
|
rotary_pos_emb = self.rotary_pos_emb.forward_from_seq_len(x.shape[1])
|
|
else:
|
|
rotary_pos_emb = None
|
|
|
|
if self.cross_attn_rotary_pos_emb is not None:
|
|
cross_attn_rotary_pos_emb = self.cross_attn_rotary_pos_emb.forward_from_seq_len(context.shape[-1])
|
|
else:
|
|
cross_attn_rotary_pos_emb = None
|
|
|
|
if self.use_sinusoidal_emb or self.use_abs_pos_emb:
|
|
x = x + self.pos_emb(x)
|
|
|
|
if global_cond is not None and self.global_cond_embedder is not None:
|
|
global_cond = self.global_cond_embedder(global_cond)
|
|
|
|
# Extend padding mask for prepended tokens if provided
|
|
extended_padding_mask = None
|
|
varlen_metadata = None
|
|
if padding_mask is not None:
|
|
# Compute total prepend length (memory tokens + prepend_embeds)
|
|
prepend_length = self.num_memory_tokens
|
|
if prepend_embeds is not None:
|
|
prepend_length += prepend_embeds.shape[1]
|
|
|
|
# Prepend tokens are always valid for attention
|
|
if prepend_length > 0:
|
|
prepend_valid = torch.ones(batch, prepend_length, device=device, dtype=torch.bool)
|
|
extended_padding_mask = torch.cat([prepend_valid, padding_mask], dim=-1)
|
|
else:
|
|
extended_padding_mask = padding_mask
|
|
|
|
# Precompute varlen metadata once for all layers (major performance optimization)
|
|
# Only compute if varlen attention is actually available
|
|
if flash_attn_varlen_func is not None and index_first_axis is not None:
|
|
varlen_metadata = precompute_varlen_metadata(extended_padding_mask)
|
|
|
|
# Iterate over the transformer layers
|
|
for layer_ix, layer in enumerate(self.layers):
|
|
|
|
layer_kwargs = {
|
|
"context": context,
|
|
"rotary_pos_emb": rotary_pos_emb,
|
|
"cross_attn_rotary_pos_emb": cross_attn_rotary_pos_emb,
|
|
"global_cond": global_cond,
|
|
"local_add_cond": local_add_cond,
|
|
"modular_local_cond": modular_local_cond,
|
|
"self_attention_flash_sliding_window": self.sliding_window,
|
|
"padding_mask": extended_padding_mask,
|
|
"varlen_metadata": varlen_metadata
|
|
}
|
|
|
|
if use_checkpointing:
|
|
x = checkpoint(layer, x, **layer_kwargs, **kwargs)
|
|
else:
|
|
x = layer(x, **layer_kwargs, **kwargs)
|
|
|
|
if return_info:
|
|
info["hidden_states"].append(x)
|
|
|
|
if exit_layer_ix is not None and layer_ix == exit_layer_ix:
|
|
x = x[:, self.num_memory_tokens:, :]
|
|
|
|
if return_info:
|
|
return x, info
|
|
|
|
return x
|
|
|
|
x = x[:, self.num_memory_tokens:, :]
|
|
|
|
x = self.project_out(x)
|
|
|
|
if return_info:
|
|
return x, info
|
|
|
|
return x
|