harmonic-gpt-128m-byte-agent-multiparty / modeling_harmonic_byte_transformer.py
LisaMegaWatts's picture
Publish Transformer Agent multiparty SFT step 500
368884e verified
Raw
History Blame Contribute Delete
5.41 kB
"""Standalone architecture for the Harmonic GPT 128M byte transformer."""
from __future__ import annotations
import math
import torch
import torch.nn as nn
import torch.nn.functional as F
def _apply_rope(x: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) -> torch.Tensor:
cos = cos[: x.shape[-2]].to(device=x.device, dtype=x.dtype)[None, None, :, :]
sin = sin[: x.shape[-2]].to(device=x.device, dtype=x.dtype)[None, None, :, :]
even = x[..., 0::2]
odd = x[..., 1::2]
return torch.stack((even * cos - odd * sin, even * sin + odd * cos), dim=-1).flatten(-2)
class ModernSelfAttention(nn.Module):
def __init__(self, d_model: int, n_heads: int, max_seq_len: int, rope_base: float) -> None:
super().__init__()
if d_model % n_heads:
raise ValueError(f"d_model={d_model} must be divisible by n_heads={n_heads}")
self.n_heads = n_heads
self.head_dim = d_model // n_heads
if self.head_dim % 2:
raise ValueError(f"RoPE requires an even head dimension, got {self.head_dim}")
self.qkv_proj = nn.Linear(d_model, 3 * d_model, bias=False)
self.out_proj = nn.Linear(d_model, d_model, bias=False)
inv_freq = 1.0 / (
rope_base ** (torch.arange(0, self.head_dim, 2, dtype=torch.float32) / self.head_dim)
)
positions = torch.arange(max_seq_len, dtype=torch.float32)
angles = torch.outer(positions, inv_freq)
self.register_buffer("rope_cos", angles.cos(), persistent=False)
self.register_buffer("rope_sin", angles.sin(), persistent=False)
def forward(self, x: torch.Tensor) -> torch.Tensor:
batch, seq_len, d_model = x.shape
qkv = self.qkv_proj(x).view(batch, seq_len, 3, self.n_heads, self.head_dim)
q, k, v = qkv.unbind(dim=2)
q = _apply_rope(q.transpose(1, 2), self.rope_cos, self.rope_sin)
k = _apply_rope(k.transpose(1, 2), self.rope_cos, self.rope_sin)
v = v.transpose(1, 2)
attended = F.scaled_dot_product_attention(q, k, v, dropout_p=0.0, is_causal=True)
return self.out_proj(attended.transpose(1, 2).contiguous().view(batch, seq_len, d_model))
class SwiGLU(nn.Module):
def __init__(self, d_model: int, hidden_dim: int) -> None:
super().__init__()
self.gate_proj = nn.Linear(d_model, hidden_dim, bias=False)
self.up_proj = nn.Linear(d_model, hidden_dim, bias=False)
self.down_proj = nn.Linear(hidden_dim, d_model, bias=False)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
class ModernTransformerBlock(nn.Module):
def __init__(
self,
d_model: int,
n_heads: int,
hidden_dim: int,
max_seq_len: int,
rope_base: float,
rms_norm_eps: float,
) -> None:
super().__init__()
self.attn_norm = nn.RMSNorm(d_model, eps=rms_norm_eps)
self.attn = ModernSelfAttention(d_model, n_heads, max_seq_len, rope_base)
self.ffn_norm = nn.RMSNorm(d_model, eps=rms_norm_eps)
self.ffn = SwiGLU(d_model, hidden_dim)
def forward(self, x: torch.Tensor) -> torch.Tensor:
x = x + self.attn(self.attn_norm(x))
return x + self.ffn(self.ffn_norm(x))
class ModernByteTransformer(nn.Module):
"""LLaMA/OLMo-style causal decoder over the 256 raw byte values."""
def __init__(
self,
vocab_size: int = 256,
d_model: int = 768,
n_layers: int = 18,
n_heads: int = 12,
hidden_dim: int = 2048,
max_seq_len: int = 2048,
rope_base: float = 10_000.0,
rms_norm_eps: float = 1e-5,
) -> None:
super().__init__()
self.max_seq_len = max_seq_len
self.tok_emb = nn.Embedding(vocab_size, d_model)
self.blocks = nn.ModuleList(
[
ModernTransformerBlock(
d_model,
n_heads,
hidden_dim,
max_seq_len,
rope_base,
rms_norm_eps,
)
for _ in range(n_layers)
]
)
self.norm = nn.RMSNorm(d_model, eps=rms_norm_eps)
self.lm_head = nn.Linear(d_model, vocab_size, bias=False)
self.lm_head.weight = self.tok_emb.weight
self.apply(self._init_weights)
residual_std = 0.02 / math.sqrt(2 * n_layers)
for block in self.blocks:
nn.init.normal_(block.attn.out_proj.weight, mean=0.0, std=residual_std)
nn.init.normal_(block.ffn.down_proj.weight, mean=0.0, std=residual_std)
@staticmethod
def _init_weights(module: nn.Module) -> None:
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)
elif isinstance(module, nn.RMSNorm) and module.weight is not None:
nn.init.ones_(module.weight)
def forward(self, idx: torch.Tensor) -> torch.Tensor:
_, seq_len = idx.shape
if seq_len > self.max_seq_len:
raise ValueError(f"seq_len={seq_len} exceeds max_seq_len={self.max_seq_len}")
x = self.tok_emb(idx)
for block in self.blocks:
x = block(x)
return self.lm_head(self.norm(x))