# style_flow_matching_1d.py # Stabilny i uproszczony model dla Flow Matching przewidujący 3 style # (pitch, energy, duration), każdy wektorem 1x64, czyli wejście/wyjście (B, 3, 64). # # - Architektura: dekoderowy Transformer nad 3 tokenami stylu z Cross-Attn do # tokenów kondycjonujących (embedding). Stabilne pre-normy (RMSNorm), SiLU, # opcjonalny RoPE, DropPath (stochastic depth), dropout tokenów pamięci. # - Czas: sinusoidalny embedding czasu + MLP dodawany do tokenów stylu i pamięci. # - CFG: wbudowane przez FixedEmbedding (maskowanie embeddingu + skala). # - Strata: MSE lub SmoothL1 (Huber). # - Zależności: torch, einops. # # Oczekiwane kształty: # x: (B, 3, 64) -> style: pitch, energy, duration # embedding: (B, L, D) -> tokeny kondycjonujące # time t: (B,) w [0, 1] # Wyjście sieci: (B, 3, 64) # # Dla małego zbioru (~50k) polecane: # d_model=128, num_layers=4, num_heads=4, head_features=32, multiplier=3 # dropout=0.1, attn_dropout=0.1, ff_dropout=0.1 # mem_token_keep_prob=0.8, drop_path_prob=0.1 # FlowMatching1D(loss_type="smooth_l1", huber_delta=0.02) from __future__ import annotations from math import pi from typing import Optional, Tuple import torch import torch.nn as nn import torch.nn.functional as F from einops import rearrange from torch import Tensor, einsum # ------------------------- # Utils # ------------------------- def exists(x) -> bool: return x is not None def rand_bool(shape, proba: float, device=None) -> Tensor: if proba <= 0.0: return torch.zeros(shape, dtype=torch.bool, device=device) if proba >= 1.0: return torch.ones(shape, dtype=torch.bool, device=device) return torch.rand(shape, device=device) < proba def rearrange_many(tensors, pattern: str, **kwargs): return tuple(rearrange(t, pattern, **kwargs) for t in tensors) @torch.no_grad() def _time_warp(u: Tensor, kind: str = "cos") -> Tensor: # u w [0, 1] if kind == "linear": return u if kind == "cos": # 0.5 * (1 - cos(pi * u)) return 0.5 * (1.0 - torch.cos(pi * u)) raise ValueError(f"Unknown time_scheduler: {kind}") class DropPath(nn.Module): """ Stochastic depth (per-sample). Zera cały residual branch z prawdopodobieństwem drop_prob w trakcie treningu. W ewaluacji: identity. """ def __init__(self, drop_prob: float = 0.0): super().__init__() self.drop_prob = float(drop_prob) def forward(self, x: Tensor) -> Tensor: if self.drop_prob == 0.0 or not self.training: return x keep = 1.0 - self.drop_prob shape = (x.shape[0],) + (1,) * (x.ndim - 1) mask = x.new_empty(shape).bernoulli_(keep) return x * mask / keep # ------------------------- # Norms # ------------------------- class RMSNorm(nn.Module): def __init__(self, dim: int, eps: float = 1e-8, elementwise_affine: bool = True): super().__init__() self.eps = eps 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() return x / rms * self.weight def _make_norm(norm_type: str, dim: int) -> nn.Module: 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}") # ------------------------- # Time embeddings # ------------------------- class SinusoidalTimeEmbedding(nn.Module): def __init__(self, dim: int): super().__init__() assert dim % 2 == 0, "time embedding dim must be even" self.dim = dim def forward(self, t: Tensor) -> Tensor: # t: (B,) half = self.dim // 2 device = t.device exponents = torch.arange(half, device=device, dtype=t.dtype) freqs = torch.exp( -torch.log(torch.tensor(10000.0, device=device)) * exponents / half ) args = t[:, None] * freqs[None, :] return torch.cat([torch.sin(args), torch.cos(args)], dim=-1) def TimePositionalEmbedding(out_features: int, time_embed_dim: int = 128) -> nn.Module: return nn.Sequential( SinusoidalTimeEmbedding(time_embed_dim), nn.Linear(time_embed_dim, out_features), nn.SiLU(), nn.Linear(out_features, out_features), ) # ------------------------- # Fixed embedding for CFG # ------------------------- class FixedEmbedding(nn.Module): """ Learned positional embedding o długości 'max_length' i wymiarze 'features'. Używany jako embedding bezwarunkowy (CFG). """ def __init__(self, max_length: int, features: int): super().__init__() self.max_length = max_length self.features = features if features > 0: self.embedding = nn.Embedding(max_length, features) else: self.register_buffer("dummy", torch.zeros(1)) def forward(self, x_like: Tensor) -> Tensor: # x_like: (B, L, D) - wykorzystywane B i L batch_size, length = x_like.shape[0], x_like.shape[1] assert length <= self.max_length, "L must be <= max_length" device = x_like.device if self.features == 0: return x_like.new_zeros(batch_size, length, 0) pos = torch.arange(length, device=device) fixed = self.embedding(pos) # (L, D) fixed = fixed.unsqueeze(0).expand(batch_size, -1, -1) # (B, L, D) return fixed # ------------------------- # Rotary embeddings (optional) # ------------------------- class RotaryEmbedding(nn.Module): def __init__(self, dim: int, max_seq_len: int = 2048, base: int = 10000): super().__init__() assert dim % 2 == 0, "RoPE head dim must be even" self.dim = dim 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, n: int, device: torch.device, dtype: torch.dtype): positions = torch.arange(n, device=device, dtype=dtype).unsqueeze(1) angles = positions * self.inv_freq.to(device=device, dtype=dtype)[None, :] sin = torch.sin(angles) cos = torch.cos(angles) sin = torch.stack([sin, sin], dim=-1).reshape(n, self.dim) cos = torch.stack([cos, cos], dim=-1).reshape(n, self.dim) return sin, cos @staticmethod def rotate_half(x: Tensor) -> Tensor: x1, x2 = x[..., ::2], x[..., 1::2] return torch.stack((-x2, x1), dim=-1).reshape_as(x) # Self-attn: Nq == Nk def apply_rotary_same(self, q: Tensor, k: Tensor) -> Tuple[Tensor, Tensor]: n = q.shape[-2] device, dtype = q.device, q.dtype sin, cos = self._build_sin_cos(n, device, dtype) sin = sin.unsqueeze(0).unsqueeze(0) cos = cos.unsqueeze(0).unsqueeze(0) q = (q * cos) + (self.rotate_half(q) * sin) k = (k * cos) + (self.rotate_half(k) * sin) return q, k # Cross-attn: Nq może różnić się od Nk def apply_rotary_qk(self, q: Tensor, k: Tensor) -> Tuple[Tensor, Tensor]: n_q, n_k = q.shape[-2], k.shape[-2] # q sin_q, cos_q = self._build_sin_cos(n_q, q.device, q.dtype) sin_q = sin_q.unsqueeze(0).unsqueeze(0) cos_q = cos_q.unsqueeze(0).unsqueeze(0) q = (q * cos_q) + (self.rotate_half(q) * sin_q) # k sin_k, cos_k = self._build_sin_cos(n_k, k.device, k.dtype) sin_k = sin_k.unsqueeze(0).unsqueeze(0) cos_k = cos_k.unsqueeze(0).unsqueeze(0) k = (k * cos_k) + (self.rotate_half(k) * sin_k) return q, k # ------------------------- # Attention primitives # ------------------------- class FeedForward(nn.Module): def __init__(self, features: int, multiplier: int): super().__init__() mid = features * multiplier self.net = nn.Sequential( nn.Linear(features, mid), nn.SiLU(), nn.Linear(mid, features), ) def forward(self, x: Tensor) -> Tensor: return self.net(x) class SelfAttention(nn.Module): def __init__( self, features: int, *, head_features: int, num_heads: int, use_rope: bool = False, rope_max_seq_len: int = 512, attn_dropout: float = 0.0, out_dropout: float = 0.0, norm_type: str = "rms", ): super().__init__() self.num_heads = num_heads self.scale = head_features**-0.5 mid = head_features * num_heads self.norm = _make_norm(norm_type, features) self.to_qkv = nn.Linear(features, mid * 3, bias=False) self.to_out = nn.Linear(mid, 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() ) self.rotary = ( RotaryEmbedding(head_features, max_seq_len=rope_max_seq_len) if use_rope else None ) def forward(self, x: Tensor) -> Tensor: # x: (B, N, F) x_n = self.norm(x) if not isinstance(self.norm, nn.Identity) else x q, k, v = self.to_qkv(x_n).chunk(3, dim=-1) 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_same(q, k) sim = einsum("b h n d, b h m d -> b h n m", q, k) * self.scale attn = self.attn_dropout(sim.softmax(dim=-1)) out = einsum("b h n m, b h m d -> b h n d", attn, v) out = rearrange(out, "b h n d -> b n (h d)") out = self.out_dropout(self.to_out(out)) return out class CrossAttention(nn.Module): def __init__( self, features_q: int, features_kv: int, *, head_features: int, num_heads: int, use_rope: bool = False, rope_max_seq_len: int = 512, attn_dropout: float = 0.0, out_dropout: float = 0.0, norm_type: str = "rms", ): super().__init__() self.num_heads = num_heads self.scale = head_features**-0.5 mid = head_features * num_heads self.norm_q = _make_norm(norm_type, features_q) self.norm_kv = _make_norm(norm_type, features_kv) self.to_q = nn.Linear(features_q, mid, bias=False) self.to_kv = nn.Linear(features_kv, mid * 2, bias=False) self.to_out = nn.Linear(mid, features_q) 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() ) self.rotary = ( RotaryEmbedding(head_features, max_seq_len=rope_max_seq_len) if use_rope else None ) def forward(self, x: Tensor, mem: Tensor) -> Tensor: # x: (B, Nq, Fq), mem: (B, Nk, Fkv) x_n = self.norm_q(x) if not isinstance(self.norm_q, nn.Identity) else x m_n = self.norm_kv(mem) if not isinstance(self.norm_kv, nn.Identity) else mem q = self.to_q(x_n) k, v = self.to_kv(m_n).chunk(2, dim=-1) 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: # Nq i Nk mogą się różnić -> osobne sin/cos q, k = self.rotary.apply_rotary_qk(q, k) sim = einsum("b h n d, b h m d -> b h n m", q, k) * self.scale attn = self.attn_dropout(sim.softmax(dim=-1)) out = einsum("b h n m, b h m d -> b h n d", attn, v) out = rearrange(out, "b h n d -> b n (h d)") out = self.out_dropout(self.to_out(out)) return out # ------------------------- # Transformer style blocks # ------------------------- class StyleBlock(nn.Module): """ Jeden blok: x = x + DropPath(SelfAttn(x)) x = x + DropPath(CrossAttn(x, mem)) x = x + DropPath(FF(x)) """ def __init__( self, d_model: int, d_mem: int, *, num_heads: int, head_features: int, multiplier: int, use_rope_sa: bool = True, use_rope_ca: bool = True, rope_max_seq_len: int = 512, dropout: float = 0.0, attn_dropout: float = 0.0, ff_dropout: float = 0.0, norm_type: str = "rms", drop_path: Optional[nn.Module] = None, ): super().__init__() self.self_attn = SelfAttention( features=d_model, head_features=head_features, num_heads=num_heads, use_rope=use_rope_sa, rope_max_seq_len=rope_max_seq_len, attn_dropout=attn_dropout, out_dropout=dropout, norm_type=norm_type, ) self.cross_attn = ( CrossAttention( features_q=d_model, features_kv=d_mem, head_features=head_features, num_heads=num_heads, use_rope=use_rope_ca, rope_max_seq_len=rope_max_seq_len, attn_dropout=attn_dropout, out_dropout=dropout, norm_type=norm_type, ) if d_mem > 0 else None ) self.ff_norm = _make_norm(norm_type, d_model) self.ff = FeedForward(d_model, multiplier) self.ff_dropout = nn.Dropout(ff_dropout) if ff_dropout > 0.0 else nn.Identity() self.drop_path = drop_path if drop_path is not None else nn.Identity() def forward(self, x: Tensor, mem: Optional[Tensor]) -> Tensor: x = x + self.drop_path(self.self_attn(x)) if self.cross_attn is not None and exists(mem) and mem.size(-1) > 0: x = x + self.drop_path(self.cross_attn(x, mem)) ff_in = self.ff_norm(x) if not isinstance(self.ff_norm, nn.Identity) else x x = x + self.drop_path(self.ff_dropout(self.ff(ff_in))) return x # ------------------------- # StyleTransformer1d (velocity net) # ------------------------- class StyleTransformer1d(nn.Module): """ Model do przewidywania 3 wektorów stylu (B, 3, 64) w Flow Matching. 3 tokeny stylu są dekodowane z pomocą self-attn i cross-attn do tokenów kondycjonujących (embedding). """ def __init__( self, *, style_count: int = 3, # 3: pitch, energy, duration channels: int = 64, # rozmiar wektora stylu context_embedding_features: int = 256, # D dla tokenów kondycjonujących d_model: int = 256, num_layers: int = 6, num_heads: int = 8, head_features: int = 32, multiplier: int = 4, use_rope_sa: bool = True, use_rope_ca: bool = True, rope_max_seq_len: int = 512, time_embed_dim: int = 128, dropout: float = 0.0, attn_dropout: float = 0.0, ff_dropout: float = 0.0, norm_type: str = "rms", embedding_max_length: int = 512, mem_token_keep_prob: float = 1.0, drop_path_prob: float = 0.0, ): super().__init__() assert head_features % 2 == 0, "head_features must be even for RoPE" self.style_count = style_count self.channels = channels self.context_embedding_features = context_embedding_features self.d_model = d_model self.mem_token_keep_prob = float(mem_token_keep_prob) assert 0.0 < self.mem_token_keep_prob <= 1.0, "keep_prob in (0,1]" self.drop_path_prob = float(drop_path_prob) # Projekcje wejść self.x_in = nn.Linear(channels, d_model) self.mem_in = ( nn.Linear(context_embedding_features, d_model) if context_embedding_features > 0 else None ) # Embedding czasu dla x i pamięci self.time_mlp_x = TimePositionalEmbedding(d_model, time_embed_dim) self.time_mlp_mem = ( TimePositionalEmbedding(d_model, time_embed_dim) if context_embedding_features > 0 else None ) # Embedding ID stylu (0..T-1) self.style_id_emb = nn.Embedding(style_count, d_model) # Token-type embedding (0: style, 1: memory) self.type_emb = nn.Embedding(2, d_model) # Dropout wejściowy self.input_dropout = nn.Dropout(dropout) if dropout > 0.0 else nn.Identity() # DropPath schedule per-blok dps = [] if num_layers > 0 and self.drop_path_prob > 0.0: steps = [i / max(1, num_layers - 1) for i in range(num_layers)] dps = [DropPath(self.drop_path_prob * s) for s in steps] else: dps = [nn.Identity() for _ in range(num_layers)] # Bloki transformera self.blocks = nn.ModuleList() for li in range(num_layers): self.blocks.append( StyleBlock( d_model=d_model, d_mem=d_model if context_embedding_features > 0 else 0, num_heads=num_heads, head_features=head_features, multiplier=multiplier, use_rope_sa=use_rope_sa, use_rope_ca=use_rope_ca, rope_max_seq_len=rope_max_seq_len, dropout=dropout, attn_dropout=attn_dropout, ff_dropout=ff_dropout, norm_type=norm_type, drop_path=dps[li], ) ) # Wyjście per token stylu self.to_out = nn.Linear(d_model, channels) # Fixed (unconditional) embedding dla CFG self.fixed_embedding = FixedEmbedding( max_length=embedding_max_length, features=context_embedding_features ) def _encode_style_tokens(self, x: Tensor, t: Tensor) -> Tensor: # x: (B, T, C), t: (B,) assert ( x.size(1) == self.style_count and x.size(2) == self.channels ), "x must be (B, 3, 64)" b, t_len, _ = x.shape x_tok = self.x_in(x) # (B, T, d_model) # Style-id emb style_ids = torch.arange(t_len, device=x.device).unsqueeze(0).expand(b, -1) x_tok = x_tok + self.style_id_emb(style_ids) # Token type (0) x_tok = x_tok + self.type_emb.weight[0] # Time bias time_bias = self.time_mlp_x(t) # (B, d_model) x_tok = x_tok + time_bias.unsqueeze(1) return x_tok def _encode_memory_tokens(self, mem: Tensor, t: Tensor) -> Optional[Tensor]: # mem: (B, L, D) if self.context_embedding_features == 0 or mem.size(-1) == 0: return None mem_tok = self.mem_in(mem) # (B, L, d_model) mem_tok = mem_tok + self.type_emb.weight[1] # token-type 1 mem_tok = mem_tok + self.time_mlp_mem(t).unsqueeze(1) return mem_tok def run(self, x: Tensor, time: Tensor, embedding: Tensor) -> Tensor: """ x: (B, 3, 64) time: (B,) embedding: (B, L, D) return: (B, 3, 64) """ # Encode x_tok = self._encode_style_tokens(x, time) mem_tok = self._encode_memory_tokens(embedding, time) # Dropout wejścia x_tok = self.input_dropout(x_tok) if exists(mem_tok): mem_tok = self.input_dropout(mem_tok) # Dropout tokenów pamięci (per-token scaling) if self.training and self.mem_token_keep_prob < 1.0: keep = self.mem_token_keep_prob b, l, _ = mem_tok.shape mask = mem_tok.new_empty(b, l, 1).bernoulli_(keep) mem_tok = mem_tok * mask / keep # Bloki for blk in self.blocks: x_tok = blk(x_tok, mem_tok) # Wyjście (B, T, C) out = self.to_out(x_tok) return out def forward( self, x: Tensor, # (B, 3, 64) time: Tensor, # (B,) embedding_mask_proba: float = 0.1, embedding: Optional[Tensor] = None, # (B, L, D) embedding_scale: float = 1.0, ) -> Tensor: b, device = x.shape[0], x.device # Gdy D=0 i embedding niepodany, tworzymy placeholder (nieużywany) if not exists(embedding): if self.context_embedding_features == 0: embedding = x.new_zeros(b, 1, 0) else: raise AssertionError("embedding must be provided when D > 0") fixed_embedding = self.fixed_embedding(embedding) if embedding_mask_proba > 0.0: mask = rand_bool((b, 1, 1), proba=embedding_mask_proba, device=device) embedding = torch.where(mask, fixed_embedding, embedding) if embedding_scale != 1.0: out = self.run(x, time=time, embedding=embedding) out_u = self.run(x, time=time, embedding=fixed_embedding) return out_u + (out - out_u) * embedding_scale else: return self.run(x, time=time, embedding=embedding) # ------------------------- # Flow Matching (rectified-like) # ------------------------- class FlowMatching1DFR(nn.Module): """ Flow Matching z StyleTransformer1d jako siecią prędkości. Ścieżka: x_t = ((1 - (1 - sigma) * t) * z + t * x), z ~ N(0, I), t w (0, 1] Cel: v*(x_t, t) = x - (1 - sigma) * z Sieć przewiduje v_theta(x_t, t, cond). Strata: MSE lub SmoothL1. """ def __init__( self, net: nn.Module, # StyleTransformer1d *, sigma: float = 1e-5, time_scheduler: str = "cos", # "linear" | "cos" embedding_mask_proba: float = 0.1, loss_type: str = "smooth_l1", # "mse" | "smooth_l1" huber_delta: float = 0.02, ): super().__init__() self.net = net self.sigma = float(sigma) self.time_scheduler = time_scheduler self.embedding_mask_proba = float(embedding_mask_proba) assert loss_type in ("mse", "smooth_l1") self.loss_type = loss_type self.huber_delta = float(huber_delta) @torch.no_grad() def forward_diffusion( self, x: Tensor, t: Tensor, noise: Optional[Tensor] = None ) -> Tuple[Tensor, Tensor, Tensor]: if noise is None: noise = torch.randn_like(x) t_view = t.view(-1, 1, 1) x_t = ((1.0 - (1.0 - self.sigma) * t_view) * noise) + (t_view * x) return x_t, noise, t def _velocity_target(self, x: Tensor, z: Tensor) -> Tensor: return x - (1.0 - self.sigma) * z def velocity( self, x_t: Tensor, t: Tensor, *, embedding: Tensor, cfg: float = 1.0, rescale_cfg: float = 0.0, ) -> Tensor: # Szybka ścieżka (CFG wewnątrz modelu) if cfg == 1.0 and rescale_cfg == 0.0: return self.net( x_t, time=t, embedding=embedding, embedding_mask_proba=0.0, embedding_scale=1.0, ) # Jawny CFG + rescale v = self.net.run(x_t, time=t, embedding=embedding) fixed_emb = self.net.fixed_embedding(embedding) v_u = self.net.run(x_t, time=t, embedding=fixed_emb) v_cfg = v + cfg * (v - v_u) if rescale_cfg > 0.0: s_pos = v.std(dim=(-1, -2), keepdim=True).clamp_min(1e-8) s_cfg = v_cfg.std(dim=(-1, -2), keepdim=True).clamp_min(1e-8) v_rescaled = v_cfg * (s_pos / s_cfg) v_cfg = rescale_cfg * v_rescaled + (1.0 - rescale_cfg) * v_cfg return v_cfg def denoise_fn(self, x_t: Tensor, *, t: Tensor, embedding: Tensor) -> Tensor: v = self.net( x_t, time=t, embedding=embedding, embedding_mask_proba=0.0, embedding_scale=1.0, ) t_view = t.view(-1, 1, 1) x_hat = x_t + (1.0 - t_view) * v return x_hat def forward( self, x: Tensor, # (B, 3, 64) *, embedding: Tensor, # (B, L, D) x_mask: Optional[Tensor] = None, # opcjonalnie (B, 3) noise: Optional[Tensor] = None, ) -> Tuple[Tensor, Tensor]: B = x.size(0) device = x.device # Losowanie czasu u = torch.rand(B, device=device).clamp_(1e-5, 1.0) t = _time_warp(u, kind=self.time_scheduler) # Dyfuzja x_t, z, t = self.forward_diffusion(x, t, noise=noise) v_target = self._velocity_target(x, z) # Przewidywanie prędkości v_pred = self.net( x_t, time=t, embedding=embedding, embedding_mask_proba=self.embedding_mask_proba, embedding_scale=1.0, ) # Maskowana MSE / SmoothL1 if x_mask is not None: m = x_mask[..., None].float() else: m = torch.ones_like(v_pred) if self.loss_type == "mse": loss = F.mse_loss(v_pred, v_target, reduction="none") else: loss = F.smooth_l1_loss( v_pred, v_target, reduction="none", beta=self.huber_delta ) loss = (loss * m).mean() with torch.no_grad(): x_hat = self.denoise_fn(x_t, t=t, embedding=embedding) return loss, x_hat # ------------------------- # Przykład użycia # ------------------------- if __name__ == "__main__": # Konfiguracja „small-data” pod ~50k próbek net = StyleTransformer1d( style_count=3, channels=64, context_embedding_features=256, # D twojego conditioningu d_model=128, num_layers=4, num_heads=4, head_features=32, multiplier=3, use_rope_sa=True, use_rope_ca=True, rope_max_seq_len=512, time_embed_dim=128, dropout=0.1, attn_dropout=0.1, ff_dropout=0.1, norm_type="rms", embedding_max_length=512, mem_token_keep_prob=0.8, # dropout tokenów pamięci drop_path_prob=0.1, # stochastic depth ) fm = FlowMatching1D( net=net, sigma=1e-5, time_scheduler="cos", embedding_mask_proba=0.2, # CFG uczone maskowaniem loss_type="smooth_l1", huber_delta=0.02, ) B, L, D = 6, 14, 256 x = torch.randn(B, 3, 64) cond = torch.randn(B, L, D) loss, x_hat = fm(x, embedding=cond) print("loss:", float(loss.item()), "x_hat:", tuple(x_hat.shape))