|
import math |
|
|
|
import torch |
|
import torch.nn as nn |
|
|
|
from cube3d.model.transformers.norm import LayerNorm, RMSNorm |
|
|
|
|
|
def init_linear(module, embed_dim: int): |
|
""" |
|
Initializes the weights and biases of a given linear module. |
|
Args: |
|
module (nn.Module): The module to initialize. Expected to be an instance of nn.Linear. |
|
embed_dim (int): The embedding dimension used to calculate the standard deviation |
|
for weight initialization. |
|
Returns: |
|
None |
|
""" |
|
|
|
if isinstance(module, nn.Linear): |
|
nn.init.normal_(module.weight, std=math.sqrt(1.0 / embed_dim)) |
|
if module.bias is not None: |
|
torch.nn.init.zeros_(module.bias) |
|
|
|
|
|
def init_tfixup(module: nn.Module, num_layers: int): |
|
"""Special initialization from https://www.cs.toronto.edu/~mvolkovs/ICML2020_tfixup.pdf |
|
|
|
Args: |
|
module (nn.Module): decoder/encoder module |
|
num_layers (int): number of layers in the module |
|
""" |
|
with torch.no_grad(): |
|
for pn, p in module.named_parameters(): |
|
if ( |
|
pn.endswith("c_proj.weight") |
|
or pn.endswith("up_proj.weight") |
|
or pn.endswith("down_proj.weight") |
|
): |
|
p *= (4 * num_layers) ** (-0.25) |
|
elif pn.endswith("c_v.weight"): |
|
p *= (4 * num_layers) ** (-0.25) * math.sqrt(2) |
|
|
|
|
|
class MLP(nn.Module): |
|
def __init__(self, embed_dim, hidden_dim, bias=True, approximate="none"): |
|
""" |
|
MLP with GELU activation function." |
|
""" |
|
|
|
super().__init__() |
|
self.up_proj = nn.Linear(embed_dim, hidden_dim, bias=bias) |
|
self.down_proj = nn.Linear(hidden_dim, embed_dim, bias=bias) |
|
self.act_fn = nn.GELU(approximate=approximate) |
|
|
|
def forward(self, x): |
|
return self.down_proj(self.act_fn(self.up_proj(x))) |
|
|
|
|
|
class SelfAttention(nn.Module): |
|
def __init__( |
|
self, |
|
embed_dim: int, |
|
num_heads: int, |
|
bias: bool = True, |
|
eps: float = 1e-6, |
|
): |
|
""" |
|
Initializes the self attention mechanism. |
|
Args: |
|
embed_dim (int): The dimensionality of the embedding space. |
|
num_heads (int): The number of attention heads. |
|
bias (bool, optional): Whether to include bias terms in the linear layers. Defaults to True. |
|
eps (float, optional): A small value added for numerical stability. Defaults to 1e-6. |
|
Raises: |
|
AssertionError: If `embed_dim` is not divisible by `num_heads`. |
|
""" |
|
|
|
super().__init__() |
|
assert embed_dim % num_heads == 0 |
|
self.num_heads = num_heads |
|
self.c_qk = nn.Linear(embed_dim, 2 * embed_dim, bias=bias) |
|
self.c_v = nn.Linear(embed_dim, embed_dim, bias=bias) |
|
self.c_proj = nn.Linear(embed_dim, embed_dim, bias=bias) |
|
|
|
head_dim = embed_dim // num_heads |
|
self.q_norm = RMSNorm(head_dim) |
|
self.k_norm = RMSNorm(head_dim) |
|
|
|
def forward(self, x, attn_mask=None, is_causal: bool = False): |
|
""" |
|
Performs the forward pass of the attention mechanism. |
|
Args: |
|
x (torch.Tensor): Input tensor. |
|
attn_mask (Optional[torch.Tensor]): Attention mask to apply. Default is None. |
|
is_causal (bool): If True, applies a causal mask to prevent attending to future positions. |
|
Default is False. |
|
Returns: |
|
torch.Tensor: Output tensor after applying |
|
the attention mechanism and projection. |
|
""" |
|
|
|
b, l, d = x.shape |
|
|
|
q, k = self.c_qk(x).chunk(2, dim=-1) |
|
v = self.c_v(x) |
|
|
|
q = q.view(b, l, self.num_heads, -1).transpose(1, 2) |
|
k = k.view(b, l, self.num_heads, -1).transpose(1, 2) |
|
v = v.view(b, l, self.num_heads, -1).transpose(1, 2) |
|
|
|
q = self.q_norm(q) |
|
k = self.k_norm(k) |
|
|
|
is_causal = is_causal and attn_mask is None |
|
y = torch.nn.functional.scaled_dot_product_attention( |
|
q, |
|
k, |
|
v, |
|
attn_mask=attn_mask, |
|
dropout_p=0.0, |
|
is_causal=is_causal, |
|
) |
|
|
|
y = y.transpose(1, 2).contiguous().view(b, l, d) |
|
|
|
y = self.c_proj(y) |
|
return y |
|
|
|
|
|
class CrossAttention(nn.Module): |
|
def __init__( |
|
self, |
|
embed_dim: int, |
|
num_heads: int, |
|
q_dim=None, |
|
kv_dim=None, |
|
bias: bool = True, |
|
): |
|
""" |
|
Initializes the cross attention mechanism. |
|
Args: |
|
embed_dim (int): The dimensionality of the embedding space. |
|
num_heads (int): The number of attention heads. |
|
q_dim (int, optional): The dimensionality of the query input. Defaults to `embed_dim`. |
|
kv_dim (int, optional): The dimensionality of the key and value inputs. Defaults to `embed_dim`. |
|
bias (bool, optional): Whether to include a bias term in the linear projections. Defaults to True. |
|
Raises: |
|
AssertionError: If `embed_dim` is not divisible by `num_heads`. |
|
""" |
|
super().__init__() |
|
assert embed_dim % num_heads == 0 |
|
|
|
q_dim = q_dim or embed_dim |
|
kv_dim = kv_dim or embed_dim |
|
|
|
self.c_q = nn.Linear(q_dim, embed_dim, bias=bias) |
|
self.c_k = nn.Linear(kv_dim, embed_dim, bias=bias) |
|
self.c_v = nn.Linear(kv_dim, embed_dim, bias=bias) |
|
self.c_proj = nn.Linear(embed_dim, embed_dim, bias=bias) |
|
self.num_heads = num_heads |
|
|
|
def forward(self, x, c, attn_mask=None, is_causal: bool = False): |
|
""" |
|
Forward pass for the attention mechanism. |
|
Args: |
|
x (torch.Tensor): Input tensor of shape. |
|
c (torch.Tensor): Context tensor. |
|
attn_mask (torch.Tensor, optional): Attention mask. |
|
Defaults to None. |
|
is_causal (bool, optional): Whether to apply causal masking. Defaults to False. |
|
Returns: |
|
torch.Tensor: Output tensor. |
|
""" |
|
|
|
q, k = self.c_q(x), self.c_k(c) |
|
v = self.c_v(c) |
|
|
|
b, l, d = q.shape |
|
s = k.shape[1] |
|
|
|
q = q.view(b, l, self.num_heads, -1).transpose(1, 2) |
|
k = k.view(b, s, self.num_heads, -1).transpose(1, 2) |
|
v = v.view(b, s, self.num_heads, -1).transpose(1, 2) |
|
|
|
y = torch.nn.functional.scaled_dot_product_attention( |
|
q, |
|
k, |
|
v, |
|
attn_mask=attn_mask, |
|
dropout_p=0.0, |
|
is_causal=(attn_mask is not None) and is_causal, |
|
) |
|
|
|
y = y.transpose(1, 2).contiguous().view(b, l, d) |
|
|
|
y = self.c_proj(y) |
|
return y |
|
|
|
|
|
class EncoderLayer(nn.Module): |
|
def __init__( |
|
self, |
|
embed_dim: int, |
|
num_heads: int, |
|
bias: bool = True, |
|
eps: float = 1e-6, |
|
) -> None: |
|
""" |
|
Initializes the EncoderLayer module. |
|
Args: |
|
embed_dim (int): The dimensionality of the embedding space. |
|
num_heads (int): The number of attention heads. |
|
bias (bool, optional): Whether to include bias terms in the layers. Defaults to True. |
|
eps (float, optional): A small value added for numerical stability in normalization layers. Defaults to 1e-6. |
|
""" |
|
super().__init__() |
|
self.ln_1 = LayerNorm(embed_dim, elementwise_affine=False, eps=eps) |
|
self.attn = SelfAttention(embed_dim, num_heads, bias=bias, eps=eps) |
|
self.ln_2 = LayerNorm(embed_dim, elementwise_affine=False, eps=eps) |
|
self.mlp = MLP(embed_dim=embed_dim, hidden_dim=embed_dim * 4, bias=bias) |
|
|
|
def forward(self, x, attn_mask=None, is_causal: bool = False): |
|
""" |
|
Performs the forward pass of the transformer block. |
|
Args: |
|
x (torch.Tensor): The input tensor. |
|
attn_mask (torch.Tensor, optional): An optional attention mask tensor to apply during the |
|
attention computation. Default is None. |
|
is_causal (bool, optional): If True, applies a causal mask to prevent attention to future |
|
positions. Default is False. |
|
Returns: |
|
torch.Tensor: The output tensor of the same shape as the input. |
|
""" |
|
|
|
x = x + self.attn(self.ln_1(x), attn_mask=attn_mask, is_causal=is_causal) |
|
x = x + self.mlp(self.ln_2(x)) |
|
return x |
|
|
|
|
|
class EncoderCrossAttentionLayer(nn.Module): |
|
def __init__( |
|
self, |
|
embed_dim: int, |
|
num_heads: int, |
|
q_dim=None, |
|
kv_dim=None, |
|
bias: bool = True, |
|
eps: float = 1e-6, |
|
) -> None: |
|
""" |
|
Initializes the EncoderAttentionLayer module with cross-attention, |
|
and a feed-forward MLP. |
|
Args: |
|
embed_dim (int): The dimensionality of the embedding space. |
|
num_heads (int): The number of attention heads. |
|
q_dim (int, optional): Dimensionality of the query input. Defaults to `embed_dim`. |
|
kv_dim (int, optional): Dimensionality of the key and value inputs. Defaults to `embed_dim`. |
|
bias (bool, optional): Whether to include bias terms in the layers. Defaults to True. |
|
eps (float, optional): A small value added to the denominator for numerical stability |
|
in layer normalization. Defaults to 1e-6. |
|
""" |
|
super().__init__() |
|
|
|
q_dim = q_dim or embed_dim |
|
kv_dim = kv_dim or embed_dim |
|
|
|
self.attn = CrossAttention( |
|
embed_dim, |
|
num_heads, |
|
q_dim=q_dim, |
|
kv_dim=kv_dim, |
|
bias=bias, |
|
) |
|
|
|
self.ln_1 = LayerNorm(q_dim, elementwise_affine=False, eps=eps) |
|
self.ln_2 = LayerNorm(kv_dim, elementwise_affine=False, eps=eps) |
|
|
|
self.ln_f = LayerNorm(embed_dim, elementwise_affine=False, eps=eps) |
|
self.mlp = MLP(embed_dim=embed_dim, hidden_dim=embed_dim * 4, bias=bias) |
|
|
|
def forward(self, x, c, attn_mask=None, is_causal: bool = False): |
|
""" |
|
Forward pass for the attention mechanism. |
|
Args: |
|
x (torch.Tensor): The input tensor to the attention mechanism. |
|
c (torch.Tensor): The context tensor used for cross-attention. |
|
attn_mask (torch.Tensor, optional): An optional attention mask to control |
|
which positions can attend to others. Defaults to None. |
|
is_causal (bool, optional): If True, applies a causal mask to prevent |
|
attending to future positions. Defaults to False. |
|
Returns: |
|
torch.Tensor: The output tensor after applying attention and MLP layers. |
|
""" |
|
|
|
x = x + self.attn( |
|
self.ln_1(x), self.ln_2(c), attn_mask=attn_mask, is_causal=is_causal |
|
) |
|
x = x + self.mlp(self.ln_f(x)) |
|
return x |
|
|