GoldenGekko's picture
Add modeling_layers for Hub
82b5a8b verified
Raw
History Blame Contribute Delete
3.36 kB
"""Слои трансформера для Hub-экспорта (относительные импорты для trust_remote_code)."""
import torch
import torch.nn as nn
class FeedForward(nn.Module):
def __init__(self, emb_dim: int, dropout: float = 0.1):
super().__init__()
self.network = nn.Sequential(
nn.Linear(emb_dim, 4 * emb_dim),
nn.GELU(),
nn.Linear(4 * emb_dim, emb_dim),
nn.Dropout(dropout),
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.network(x)
class MultiHeadAttention(nn.Module):
def __init__(
self,
emb_dim: int,
n_heads: int,
context_length: int,
dropout: float = 0.1,
qvk_bias: bool = False,
):
super().__init__()
if emb_dim % n_heads != 0:
raise ValueError('emb_dim должно быть кратно n_heads')
self.model_dim = emb_dim
self.n_heads = n_heads
self.head_dim = self.model_dim // n_heads
self.qkv_proj = nn.Linear(
self.model_dim, 3 * self.model_dim, bias=qvk_bias,
)
self.out_proj = nn.Linear(
self.model_dim, self.model_dim, bias=qvk_bias,
)
self.dropout = nn.Dropout(dropout)
self.register_buffer(
'mask',
torch.tril(torch.ones(1, 1, context_length, context_length)),
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
batch_size, n_tokens, emb_dim = x.size()
qkv = self.qkv_proj(x)
q, k, v = qkv.split(self.model_dim, dim=-1)
queries = q.view(
batch_size, n_tokens, self.n_heads, self.head_dim,
).transpose(1, 2)
keys = k.view(
batch_size, n_tokens, self.n_heads, self.head_dim,
).transpose(1, 2)
values = v.view(
batch_size, n_tokens, self.n_heads, self.head_dim,
).transpose(1, 2)
attn_weights = (
queries @ keys.transpose(-2, -1)
) / (self.head_dim ** 0.5)
attn_weights = attn_weights.masked_fill(
self.mask[:, :, :n_tokens, :n_tokens] == 0, float('-inf'),
)
attn_weights = self.dropout(torch.softmax(attn_weights, dim=-1))
out_per_head = attn_weights @ values
out = (
out_per_head.transpose(1, 2)
.contiguous()
.view(batch_size, n_tokens, emb_dim)
)
return self.out_proj(out)
class TransformerBlock(nn.Module):
def __init__(
self,
emb_dim: int,
n_heads: int,
context_length: int,
dropout: float = 0.1,
qvk_bias: bool = False,
):
super().__init__()
self.attn = MultiHeadAttention(
emb_dim=emb_dim,
n_heads=n_heads,
context_length=context_length,
dropout=dropout,
qvk_bias=qvk_bias,
)
self.ffn = FeedForward(emb_dim=emb_dim, dropout=dropout)
self.ln_1 = nn.LayerNorm(emb_dim)
self.ln_2 = nn.LayerNorm(emb_dim)
def forward(self, x: torch.Tensor) -> torch.Tensor:
x = x + self.attn(self.ln_1(x))
x = x + self.ffn(self.ln_2(x))
return x