Files
SoundGame/tools/stable-audio-3/stable_audio_3/models/transformer.py
T
xsl 24c526af68 feat(assets): SA3 音效补齐 radio 11+1 与 dungeon 13源+15pan(token 走 hf-mirror 实测可用)
- 模型 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 全绿
2026-09-02 19:35:38 +08:00

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