VegaLM1-42M-Base / src /model.py
CNWPlayer's picture
Upload 5 files
cf7e812 verified
Raw
History Blame Contribute Delete
7.65 kB
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
class RMSNorm(nn.Module):
def __init__(self, dim, eps=1e-6):
super().__init__()
self.weight = nn.Parameter(torch.ones(dim))
self.eps = eps
def forward(self, x):
variance = x.float().pow(2).mean(-1, keepdim=True)
x = x * torch.rsqrt(variance + self.eps)
return self.weight * x
def rotate_half(x):
x1 = x[..., : x.shape[-1] // 2]
x2 = x[..., x.shape[-1] // 2 :]
return torch.cat((-x2, x1), dim=-1)
def apply_rope(x, cos, sin):
return (x * cos) + (rotate_half(x) * sin)
class RotaryEmbedding(nn.Module):
def __init__(self, head_dim, max_seq_len, base=10000.0):
super().__init__()
inv_freq = 1.0 / (
base ** (
torch.arange(0, head_dim, 2).float() / head_dim
)
)
self.register_buffer("inv_freq", inv_freq, persistent=False)
positions = torch.arange(max_seq_len).float()
freqs = torch.outer(positions, inv_freq)
emb = torch.cat((freqs, freqs), dim=-1)
self.register_buffer(
"cos_cached",
emb.cos()[None, None, :, :],
persistent=False,
)
self.register_buffer(
"sin_cached",
emb.sin()[None, None, :, :],
persistent=False,
)
def forward(self, seq_len):
return (
self.cos_cached[:, :, :seq_len, :],
self.sin_cached[:, :, :seq_len, :],
)
class SwiGLU(nn.Module):
def __init__(self, hidden_size, intermediate_size):
super().__init__()
self.gate_proj = nn.Linear(
hidden_size,
intermediate_size,
bias=False,
)
self.up_proj = nn.Linear(
hidden_size,
intermediate_size,
bias=False,
)
self.down_proj = nn.Linear(
intermediate_size,
hidden_size,
bias=False,
)
def forward(self, x):
return self.down_proj(
F.silu(self.gate_proj(x)) * self.up_proj(x)
)
class GQAttention(nn.Module):
def __init__(
self,
hidden_size,
num_heads,
num_kv_heads,
max_seq_len,
):
super().__init__()
assert hidden_size % num_heads == 0
self.num_heads = num_heads
self.num_kv_heads = num_kv_heads
self.head_dim = hidden_size // num_heads
assert num_heads % num_kv_heads == 0
self.q_proj = nn.Linear(
hidden_size,
num_heads * self.head_dim,
bias=False,
)
self.k_proj = nn.Linear(
hidden_size,
num_kv_heads * self.head_dim,
bias=False,
)
self.v_proj = nn.Linear(
hidden_size,
num_kv_heads * self.head_dim,
bias=False,
)
self.o_proj = nn.Linear(
hidden_size,
hidden_size,
bias=False,
)
self.rope = RotaryEmbedding(
self.head_dim,
max_seq_len,
)
def forward(self, x):
batch, seq_len, hidden = x.shape
q = self.q_proj(x)
k = self.k_proj(x)
v = self.v_proj(x)
q = q.view(
batch,
seq_len,
self.num_heads,
self.head_dim,
).transpose(1, 2)
k = k.view(
batch,
seq_len,
self.num_kv_heads,
self.head_dim,
).transpose(1, 2)
v = v.view(
batch,
seq_len,
self.num_kv_heads,
self.head_dim,
).transpose(1, 2)
cos, sin = self.rope(seq_len)
q = apply_rope(q, cos, sin)
k = apply_rope(k, cos, sin)
# Repeat KV heads for grouped-query attention.
repeat_factor = self.num_heads // self.num_kv_heads
k = k.repeat_interleave(
repeat_factor,
dim=1,
)
v = v.repeat_interleave(
repeat_factor,
dim=1,
)
y = F.scaled_dot_product_attention(
q,
k,
v,
is_causal=True,
)
y = y.transpose(1, 2).contiguous()
y = y.view(
batch,
seq_len,
hidden,
)
return self.o_proj(y)
class TransformerBlock(nn.Module):
def __init__(
self,
hidden_size,
num_heads,
num_kv_heads,
intermediate_size,
max_seq_len,
):
super().__init__()
self.attn_norm = RMSNorm(hidden_size)
self.attn = GQAttention(
hidden_size,
num_heads,
num_kv_heads,
max_seq_len,
)
self.ffn_norm = RMSNorm(hidden_size)
self.ffn = SwiGLU(
hidden_size,
intermediate_size,
)
def forward(self, x):
x = x + self.attn(
self.attn_norm(x)
)
x = x + self.ffn(
self.ffn_norm(x)
)
return x
class VegaLM(nn.Module):
def __init__(
self,
vocab_size=32000,
hidden_size=512,
num_layers=12,
num_heads=8,
num_kv_heads=4,
intermediate_size=880,
max_seq_len=2048,
):
super().__init__()
self.vocab_size = vocab_size
self.hidden_size = hidden_size
self.token_embedding = nn.Embedding(
vocab_size,
hidden_size,
)
self.layers = nn.ModuleList(
[
TransformerBlock(
hidden_size=hidden_size,
num_heads=num_heads,
num_kv_heads=num_kv_heads,
intermediate_size=intermediate_size,
max_seq_len=max_seq_len,
)
for _ in range(num_layers)
]
)
self.final_norm = RMSNorm(hidden_size)
self.lm_head = nn.Linear(
hidden_size,
vocab_size,
bias=False,
)
# Tie input embeddings and output projection.
self.lm_head.weight = self.token_embedding.weight
self.apply(self._init_weights)
def _init_weights(self, module):
if isinstance(module, nn.Linear):
nn.init.normal_(
module.weight,
mean=0.0,
std=0.02,
)
elif isinstance(module, nn.Embedding):
nn.init.normal_(
module.weight,
mean=0.0,
std=0.02,
)
def forward(self, input_ids, targets=None):
x = self.token_embedding(input_ids)
for layer in self.layers:
x = layer(x)
x = self.final_norm(x)
logits = self.lm_head(x)
loss = None
if targets is not None:
loss = F.cross_entropy(
logits.view(-1, self.vocab_size),
targets.view(-1),
)
return logits, loss
def count_parameters(model):
return sum(
p.numel()
for p in model.parameters()
if p.requires_grad
)
if __name__ == "__main__":
model = VegaLM()
params = count_parameters(model)
print(f"Parameters: {params:,}")
print(f"Parameters: {params / 1e6:.2f}M")
x = torch.randint(
0,
32000,
(2, 128),
)
logits, _ = model(x)
print(f"Input: {x.shape}")
print(f"Output: {logits.shape}")