| from math import floor, log, pi |
| from typing import Any, List, Optional, Sequence, Tuple, Union |
|
|
| from .utils import * |
|
|
| import torch |
| import torch.nn as nn |
| from einops import rearrange, reduce, repeat |
| from einops.layers.torch import Rearrange |
| from einops_exts import rearrange_many |
| from torch import Tensor, einsum |
|
|
|
|
| """ |
| Utils + Transformer with RoPE (Rotary Positional Embeddings) |
| Extended to support RMSNorm or LayerNorm via `norm_type` parameter. |
| """ |
|
|
|
|
| class RMSNorm(nn.Module): |
| """RMSNorm: normalizacja po RMS (nie odejmuje średniej).""" |
|
|
| def __init__(self, dim: int, eps: float = 1e-8, elementwise_affine: bool = True): |
| super().__init__() |
| self.dim = dim |
| self.eps = eps |
| self.elementwise_affine = elementwise_affine |
| if elementwise_affine: |
| self.weight = nn.Parameter(torch.ones(dim)) |
| else: |
| self.register_buffer("weight", torch.ones(dim)) |
|
|
| def forward(self, x: Tensor) -> Tensor: |
| |
| rms = x.pow(2).mean(dim=-1, keepdim=True).add(self.eps).sqrt() |
| x_normed = x / rms |
| return x_normed * self.weight |
|
|
|
|
| def _make_norm(norm_type: str, dim: int) -> nn.Module: |
| """Helper: create norm module by name.""" |
| if norm_type is None or norm_type == "none": |
| return nn.Identity() |
| if norm_type == "layer": |
| return nn.LayerNorm(dim) |
| if norm_type == "rms": |
| return RMSNorm(dim) |
| raise ValueError(f"Unknown norm_type: {norm_type}") |
|
|
|
|
| class Transformer1d(nn.Module): |
| def __init__( |
| self, |
| num_layers: int, |
| channels: int, |
| num_heads: int, |
| head_features: int, |
| multiplier: int, |
| use_context_time: bool = True, |
| use_rope: bool = False, |
| rope_max_seq_len: int = 512, |
| context_embedding_features: Optional[int] = None, |
| embedding_max_length: int = 512, |
| |
| dropout: float = 0.0, |
| attn_dropout: float = 0.0, |
| ff_dropout: float = 0.0, |
| |
| norm_type: str = "layer", |
| ): |
| """ |
| Transformer1d simplified for the case where cross-attention/context |
| features are never used. |
| |
| - context_features and context_features_multiplier removed. |
| - All attention is self-attention. |
| """ |
| super().__init__() |
|
|
| |
| context_embedding_features = context_embedding_features or 0 |
|
|
| self.context_embedding_features = context_embedding_features |
| total_features = channels + context_embedding_features |
|
|
| |
| self.input_dropout = nn.Dropout(dropout) if dropout > 0.0 else nn.Identity() |
| self._dropout = dropout |
| self._attn_dropout = attn_dropout |
| self._ff_dropout = ff_dropout |
|
|
| self.blocks = nn.ModuleList( |
| [ |
| TransformerBlock( |
| features=total_features, |
| head_features=head_features, |
| num_heads=num_heads, |
| multiplier=multiplier, |
| use_rope=use_rope, |
| rope_max_seq_len=rope_max_seq_len, |
| |
| dropout=dropout, |
| attn_dropout=attn_dropout, |
| ff_dropout=ff_dropout, |
| norm_type=norm_type, |
| ) |
| for _ in range(num_layers) |
| ] |
| ) |
|
|
| self.to_out = nn.Sequential( |
| Rearrange("b t c -> b c t"), |
| nn.Conv1d(in_channels=total_features, out_channels=channels, kernel_size=1), |
| ) |
|
|
| |
| |
| self.use_context_time = use_context_time |
|
|
| if use_context_time: |
| context_mapping_features = total_features |
| self.to_mapping = nn.Sequential( |
| nn.Linear(context_mapping_features, context_mapping_features), |
| nn.GELU(), |
| nn.Linear(context_mapping_features, context_mapping_features), |
| nn.GELU(), |
| ) |
|
|
| self.to_time = nn.Sequential( |
| TimePositionalEmbedding(dim=channels, out_features=context_mapping_features), |
| nn.GELU(), |
| ) |
| self.mapping_features = context_mapping_features |
| else: |
| self.to_mapping = None |
| self.to_time = None |
| self.mapping_features = None |
|
|
| self.fixed_embedding = FixedEmbedding( |
| max_length=embedding_max_length, features=context_embedding_features |
| ) |
|
|
| def get_mapping(self, time: Optional[Tensor] = None) -> Optional[Tensor]: |
| """Compute mapping solely from time. `features` is intentionally removed.""" |
| if not self.use_context_time: |
| return None |
| assert exists(time), "use_context_time=True but no time features provided" |
| mapping = self.to_time(time) |
| mapping = self.to_mapping(mapping) |
| return mapping |
|
|
| def run(self, x: Tensor, time: Tensor, embedding: Tensor) -> Tensor: |
| |
| |
| mapping = self.get_mapping(time) |
| |
| x = torch.cat([x.expand(-1, embedding.size(1), -1), embedding], dim=-1) |
|
|
| if mapping is not None: |
| mapping = mapping.unsqueeze(1).expand(-1, embedding.size(1), -1) |
|
|
| |
| x = self.input_dropout(x) |
|
|
| for block in self.blocks: |
| if mapping is not None: |
| x = x + mapping |
| x = block(x) |
|
|
| x = x.mean(dim=1).unsqueeze(1) |
| x = self.to_out(x) |
| x = x.transpose(-1, -2) |
|
|
| return x |
|
|
| def forward( |
| self, |
| x: Tensor, |
| time: Tensor, |
| embedding_mask_proba: float = 0.1, |
| embedding: Optional[Tensor] = None, |
| embedding_scale: float = 1.0, |
| ) -> Tensor: |
| """ |
| Note: `features` tensor argument has been removed intentionally because it will |
| never be provided. |
| """ |
| assert exists(embedding), "embedding must be provided" |
| b, device = embedding.shape[0], embedding.device |
| fixed_embedding = self.fixed_embedding(embedding) |
| if embedding_mask_proba > 0.0: |
| |
| batch_mask = rand_bool( |
| shape=(b, 1, 1), proba=embedding_mask_proba, device=device |
| ) |
| embedding = torch.where(batch_mask, fixed_embedding, embedding) |
|
|
| if embedding_scale != 1.0: |
| |
| out = self.run(x, time, embedding=embedding) |
| out_masked = self.run(x, time, embedding=fixed_embedding) |
| return out_masked + (out - out_masked) * embedding_scale |
| else: |
| return self.run(x, time, embedding=embedding) |
|
|
|
|
| """ |
| Rotary Positional Embedding implementation |
| """ |
|
|
|
|
| class RotaryEmbedding(nn.Module): |
| """ |
| RoPE implementation that caches sin/cos for up to max_seq_len. |
| Works on head dimension d (must be even). |
| """ |
|
|
| def __init__(self, dim: int, max_seq_len: int = 512, base: int = 10000): |
| super().__init__() |
| assert dim % 2 == 0, "Rotary embedding dim must be even" |
| self.dim = dim |
| self.max_seq_len = max_seq_len |
| self.base = base |
| |
| inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim)) |
| self.register_buffer("inv_freq", inv_freq, persistent=False) |
| |
|
|
| def _build_sin_cos(self, seq_len: int, device: torch.device, dtype: torch.dtype): |
| |
| positions = torch.arange(seq_len, device=device, dtype=dtype).unsqueeze(1) |
| angles = positions * rearrange(self.inv_freq.to(device=device, dtype=dtype), "d -> 1 d") |
| sin = torch.sin(angles) |
| cos = torch.cos(angles) |
| |
| sin = torch.stack([sin, sin], dim=-1).reshape(seq_len, self.dim) |
| cos = torch.stack([cos, cos], dim=-1).reshape(seq_len, self.dim) |
| return sin, cos |
|
|
| @staticmethod |
| def rotate_half(x: Tensor) -> Tensor: |
| |
| x1 = x[..., ::2] |
| x2 = x[..., 1::2] |
| |
| x_rotated = torch.stack((-x2, x1), dim=-1).reshape_as(x) |
| return x_rotated |
|
|
| def apply_rotary(self, q: Tensor, k: Tensor) -> Tuple[Tensor, Tensor]: |
| """ |
| Apply RoPE to q and k. |
| |
| q,k shapes: (b, h, n, d) with d == self.dim |
| """ |
| assert q.shape[-1] == self.dim and k.shape[-1] == self.dim |
|
|
| seq_len = q.shape[-2] |
| device = q.device |
| dtype = q.dtype |
|
|
| sin, cos = self._build_sin_cos(seq_len, device=device, dtype=dtype) |
| |
| sin = sin.unsqueeze(0).unsqueeze(0) |
| cos = cos.unsqueeze(0).unsqueeze(0) |
|
|
| q_out = (q * cos) + (self.rotate_half(q) * sin) |
| k_out = (k * cos) + (self.rotate_half(k) * sin) |
| return q_out, k_out |
|
|
|
|
| """ |
| Attention Components (self-attention only) with RoPE |
| """ |
|
|
|
|
| def FeedForward(features: int, multiplier: int) -> nn.Module: |
| mid_features = features * multiplier |
| return nn.Sequential( |
| nn.Linear(in_features=features, out_features=mid_features), |
| nn.GELU(), |
| nn.Linear(in_features=mid_features, out_features=features), |
| ) |
|
|
|
|
| class AttentionBase(nn.Module): |
| def __init__( |
| self, |
| features: int, |
| *, |
| head_features: int, |
| num_heads: int, |
| use_rope: bool, |
| rope_max_seq_len: int = 512, |
| out_features: Optional[int] = None, |
| |
| attn_dropout: float = 0.0, |
| out_dropout: float = 0.0, |
| ): |
| super().__init__() |
| self.scale = head_features ** -0.5 |
| self.num_heads = num_heads |
| self.use_rope = use_rope |
| mid_features = head_features * num_heads |
|
|
| if out_features is None: |
| out_features = features |
|
|
| self.to_out = nn.Linear(in_features=mid_features, out_features=out_features) |
|
|
| |
| self.attn_dropout = nn.Dropout(attn_dropout) if attn_dropout > 0.0 else nn.Identity() |
| self.out_dropout = nn.Dropout(out_dropout) if out_dropout > 0.0 else nn.Identity() |
|
|
| |
| if use_rope: |
| |
| self.rotary = RotaryEmbedding(dim=head_features, max_seq_len=rope_max_seq_len) |
| else: |
| self.rotary = None |
|
|
| def forward(self, q: Tensor, k: Tensor, v: Tensor) -> Tensor: |
| |
| |
| q, k, v = rearrange_many((q, k, v), "b n (h d) -> b h n d", h=self.num_heads) |
|
|
| |
| if self.rotary is not None: |
| q, k = self.rotary.apply_rotary(q, k) |
|
|
| |
| sim = einsum("... n d, ... m d -> ... n m", q, k) |
| sim = sim * self.scale |
| |
| attn = sim.softmax(dim=-1) |
| |
| attn = self.attn_dropout(attn) |
| |
| out = einsum("... n m, ... m d -> ... n d", attn, v) |
| out = rearrange(out, "b h n d -> b n (h d)") |
| out = self.to_out(out) |
| out = self.out_dropout(out) |
| return out |
|
|
|
|
| class Attention(nn.Module): |
| def __init__( |
| self, |
| features: int, |
| *, |
| head_features: int, |
| num_heads: int, |
| out_features: Optional[int] = None, |
| use_rope: bool, |
| rope_max_seq_len: int = 512, |
| |
| attn_dropout: float = 0.0, |
| out_dropout: float = 0.0, |
| |
| norm_type: str = "layer", |
| ): |
| """ |
| Self-attention only (context / cross-attention removed). |
| """ |
| super().__init__() |
|
|
| mid_features = head_features * num_heads |
|
|
| self.norm = _make_norm(norm_type, features) |
| |
| self.to_q = nn.Linear(in_features=features, out_features=mid_features, bias=False) |
| self.to_kv = nn.Linear(in_features=features, out_features=mid_features * 2, bias=False) |
|
|
| self.attention = AttentionBase( |
| features, |
| out_features=out_features, |
| num_heads=num_heads, |
| head_features=head_features, |
| use_rope=use_rope, |
| rope_max_seq_len=rope_max_seq_len, |
| attn_dropout=attn_dropout, |
| out_dropout=out_dropout, |
| ) |
|
|
| def forward(self, x: Tensor) -> Tensor: |
| |
| if not isinstance(self.norm, nn.Identity): |
| x_norm = self.norm(x) |
| else: |
| x_norm = x |
| q = self.to_q(x_norm) |
| k, v = torch.chunk(self.to_kv(x_norm), 2, dim=-1) |
| return self.attention(q, k, v) |
|
|
|
|
| """ |
| Transformer Blocks |
| """ |
|
|
|
|
| class TransformerBlock(nn.Module): |
| def __init__( |
| self, |
| features: int, |
| num_heads: int, |
| head_features: int, |
| multiplier: int, |
| use_rope: bool, |
| rope_max_seq_len: int = 512, |
| |
| dropout: float = 0.0, |
| attn_dropout: float = 0.0, |
| ff_dropout: float = 0.0, |
| |
| norm_type: str = "layer", |
| ): |
| super().__init__() |
|
|
| |
| self.attention = Attention( |
| features=features, |
| num_heads=num_heads, |
| head_features=head_features, |
| use_rope=use_rope, |
| rope_max_seq_len=rope_max_seq_len, |
| attn_dropout=attn_dropout, |
| out_dropout=dropout, |
| norm_type=norm_type, |
| ) |
|
|
| self.feed_forward = FeedForward(features=features, multiplier=multiplier) |
|
|
| |
| self.norm_ff = _make_norm(norm_type, features) |
| self.ff_dropout = nn.Dropout(ff_dropout) if ff_dropout > 0.0 else nn.Identity() |
|
|
| def forward(self, x: Tensor) -> Tensor: |
| x = self.attention(x) + x |
| |
| if not isinstance(self.norm_ff, nn.Identity): |
| ff_in = self.norm_ff(x) |
| else: |
| ff_in = x |
| ff_out = self.feed_forward(ff_in) |
| ff_out = self.ff_dropout(ff_out) |
| x = ff_out + x |
| return x |
|
|
|
|
| """ |
| Time Embeddings (unchanged) |
| """ |
|
|
|
|
| class SinusoidalEmbedding(nn.Module): |
| def __init__(self, dim: int): |
| super().__init__() |
| self.dim = dim |
|
|
| def forward(self, x: Tensor) -> Tensor: |
| device, half_dim = x.device, self.dim // 2 |
| emb = torch.tensor(log(10000) / (half_dim - 1), device=device) |
| emb = torch.exp(torch.arange(half_dim, device=device) * -emb) |
| emb = rearrange(x, "i -> i 1") * rearrange(emb, "j -> 1 j") |
| return torch.cat((emb.sin(), emb.cos()), dim=-1) |
|
|
|
|
| class LearnedPositionalEmbedding(nn.Module): |
| """Used for continuous time""" |
|
|
| def __init__(self, dim: int): |
| super().__init__() |
| assert (dim % 2) == 0 |
| half_dim = dim // 2 |
| self.weights = nn.Parameter(torch.randn(half_dim)) |
|
|
| def forward(self, x: Tensor) -> Tensor: |
| x = rearrange(x, "b -> b 1") |
| freqs = x * rearrange(self.weights, "d -> 1 d") * 2 * pi |
| fouriered = torch.cat((freqs.sin(), freqs.cos()), dim=-1) |
| fouriered = torch.cat((x, fouriered), dim=-1) |
| return fouriered |
|
|
|
|
| def TimePositionalEmbedding(dim: int, out_features: int) -> nn.Module: |
| return nn.Sequential( |
| LearnedPositionalEmbedding(dim), |
| nn.Linear(in_features=dim + 1, out_features=out_features), |
| ) |
|
|
|
|
| class FixedEmbedding(nn.Module): |
| def __init__(self, max_length: int, features: int): |
| super().__init__() |
| self.max_length = max_length |
| self.embedding = nn.Embedding(max_length, features) |
|
|
| def forward(self, x: Tensor) -> Tensor: |
| batch_size, length, device = *x.shape[0:2], x.device |
| assert_message = "Input sequence length must be <= max_length" |
| assert length <= self.max_length, assert_message |
| position = torch.arange(length, device=device) |
| fixed_embedding = self.embedding(position) |
| fixed_embedding = repeat(fixed_embedding, "n d -> b n d", b=batch_size) |
| return fixed_embedding |