STAGE / models /modules /decoder.py
Vansh Chugh
initial deploy
2e1dc7f
Raw
History Blame Contribute Delete
4.95 kB
from abc import ABC, abstractmethod
from torch import nn, Tensor
import torch
import x_transformers as xt
from typing import Optional
import config as cfg
class ResidualTokenEmbedding(nn.Module):
def __init__(self,
dim: int,
num_tokens: int,
n_layers: int,
padding_token: Optional[int] = None):
super().__init__()
self.padding_token: Optional[int] = padding_token
self.emb = nn.ModuleList([
nn.Embedding(num_tokens, dim, padding_idx=self.padding_token)
for _ in range(n_layers)
])
for layer in self.emb:
nn.init.kaiming_normal_(layer.weight)
def forward(self, x):
n_res_layers = x.shape[1]
assert n_res_layers == len(self.emb)
token_emb: Tensor = sum( # type: ignore
[self.emb[i](x[:, i]) for i in range(n_res_layers)])
return token_emb
def create_sin_embedding(
positions: torch.Tensor,
dim: int,
max_period: float = 10000,
dtype: torch.dtype = torch.float32,
) -> torch.Tensor:
"""Create sinusoidal positional embedding, with shape `[B, T, C]`.
Args:
positions (torch.Tensor): LongTensor of positions.
dim (int): Dimension of the embedding.
max_period (float): Maximum period of the cosine/sine functions.
dtype (torch.dtype or str): dtype to use to generate the embedding.
Returns:
torch.Tensor: Sinusoidal positional embedding.
"""
# We aim for BTC format
assert dim % 2 == 0
half_dim = dim // 2
positions = positions.to(dtype)
adim = torch.arange(half_dim, device=positions.device,
dtype=dtype).view(1, 1, -1)
max_period_tensor = torch.full([],
max_period,
device=positions.device,
dtype=dtype) # avoid sync point
phase = positions / (max_period_tensor**(adim / (half_dim - 1)))
return torch.cat([torch.cos(phase), torch.sin(phase)], dim=-1)
class ResidualSinusoidalEmbedding(nn.Module):
def __init__(self, dim, theta=10000):
super().__init__()
assert dim % 2 == 0
self.scale = 1
self.theta = theta
self.dim = dim
def forward(self, x, pos=None, seq_start_pos=None):
B, K, T = x.shape
positions = (pos if pos is not None else torch.arange(
T, device=x.device).view(1, -1, 1))
pos_emb = create_sin_embedding(positions,
self.dim,
max_period=self.theta,
dtype=x.dtype)
return pos_emb * self.scale
class ResidualOutputProj(nn.Module):
def __init__(self, input_dim: int, output_dim: int, n_layers: int,
use_bias: bool):
super().__init__()
self.linears = nn.ModuleList([
nn.Linear(input_dim, output_dim, use_bias) for _ in range(n_layers)
])
def forward(self, x):
return torch.stack([layer(x) for layer in self.linears], dim=1)
class TransformerDecoder(ABC, nn.Module):
@abstractmethod
def forward(x, mask, context, context_mask, prepend_data, prepend_mask,
sum_data) -> Tensor:
...
class XTransformerDecoder(TransformerDecoder):
def __init__(
self,
num_tokens: int,
max_seq_len: int,
use_abs_pos_emb: bool,
scaled_sinu_pos_emb: bool,
dim: int,
depth: int,
heads: int,
attn_dim_head: int,
attn_flash: bool,
ff_no_bias: bool,
cross_attend: bool,
):
self.decoder: xt.TransformerWrapper = xt.TransformerWrapper(
num_tokens=self.input_card,
max_seq_len=500,
use_abs_pos_emb=True,
scaled_sinu_pos_emb=True,
attn_layers=xt.Decoder(
dim=self.dim,
depth=self.n_layers,
heads=self.n_heads,
attn_dim_head=64,
attn_flash=True,
ff_no_bias=True,
cross_attend=self.cross_attend,
),
)
self.decoder.token_emb = ResidualTokenEmbedding( # type: ignore
self.dim,
self.input_card,
self.n_q,
self.padding_token,
)
self.decoder.pos_emb = ResidualSinusoidalEmbedding( # type: ignore
dim=self.dim)
self.decoder.to_logits = ResidualOutputProj(self.dim, self.card,
self.n_q, False)
# TODO: this is horrendous, gotta find a fix
if not self.cross_attend:
self.nullwav_embeds = torch.load(cfg.weights_dir() /
"nullwav_embeds.pt")[0]
else:
self.nullwav_embeds = None