| import math, torch, torch.nn as nn, torch.nn.functional as F | |
| import sentencepiece as spm | |
| sp = spm.SentencePieceProcessor() | |
| sp.load("tok.model") | |
| VOCAB = sp.get_piece_size() | |
| def encode(t):return sp.encode(t, out_type=int) | |
| def rope(T, d, device): | |
| inv = 1.0 / (10000 ** (torch.arange(0, d, 2, device=device).float() / d)) | |
| pos = torch.arange(T, device=device).float() | |
| freqs = torch.outer(pos, inv) | |
| cos = freqs.cos()[None, None, :, :] | |
| sin = freqs.sin()[None, None, :, :] | |
| return cos, sin | |
| def apply_rope(x, cos, sin): | |
| x1 = x[..., ::2] | |
| x2 = x[..., 1::2] | |
| out = torch.empty_like(x) | |
| out[..., ::2] = x1 * cos - x2 * sin | |
| out[..., 1::2] = x1 * sin + x2 * cos | |
| return out | |
| def causal_mask(T, device): | |
| return torch.triu(torch.ones(T, T, device=device, dtype=torch.bool), diagonal=1) | |
| class RMSNorm(nn.Module): | |
| def __init__(self, d, eps=1e-6): | |
| super().__init__() | |
| self.w = nn.Parameter(torch.ones(d)) | |
| self.eps = eps | |
| def forward(self, x): | |
| return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps) * self.w | |
| class SwiGLU(nn.Module): | |
| def __init__(self, d): | |
| super().__init__() | |
| self.fc = nn.Linear(d, d * 4 * 2) | |
| self.out = nn.Linear(d * 4, d) | |
| def forward(self, x): | |
| a, b = self.fc(x).chunk(2, dim=-1) | |
| return self.out(F.silu(a) * b) | |
| class Attention(nn.Module): | |
| def __init__(self, d, h): | |
| super().__init__() | |
| assert d % h == 0 | |
| self.h = h | |
| self.dh = d // h | |
| self.qkv = nn.Linear(d, d * 3) | |
| self.out = nn.Linear(d, d) | |
| def forward(self, x): | |
| B, T, C = x.shape | |
| q, k, v = self.qkv(x).chunk(3, dim=-1) | |
| q = q.view(B, T, self.h, self.dh).transpose(1, 2) | |
| k = k.view(B, T, self.h, self.dh).transpose(1, 2) | |
| v = v.view(B, T, self.h, self.dh).transpose(1, 2) | |
| cos, sin = rope(T, self.dh, x.device) | |
| q = apply_rope(q, cos, sin) | |
| k = apply_rope(k, cos, sin) | |
| att = (q @ k.transpose(-2, -1)) / math.sqrt(self.dh) | |
| mask = causal_mask(T, x.device) | |
| att = att.masked_fill(mask, float("-inf")) | |
| att = F.softmax(att, dim=-1) | |
| y = att @ v | |
| y = y.transpose(1, 2).contiguous().view(B, T, C) | |
| return self.out(y) | |
| class Block(nn.Module): | |
| def __init__(self, d, h): | |
| super().__init__() | |
| self.n1 = RMSNorm(d) | |
| self.attn = Attention(d, h) | |
| self.n2 = RMSNorm(d) | |
| self.mlp = SwiGLU(d) | |
| def forward(self, x): | |
| x = x + self.attn(self.n1(x)) | |
| x = x + self.mlp(self.n2(x)) | |
| return x | |
| class GPT(nn.Module): | |
| def __init__(self): | |
| super().__init__() | |
| d = 1024 | |
| L = 12 | |
| H = 16 | |
| self.emb = nn.Embedding(VOCAB, d) | |
| self.blocks = nn.ModuleList([Block(d, H) for _ in range(L)]) | |
| self.norm = RMSNorm(d) | |
| self.head = nn.Linear(d, VOCAB, bias=False) | |
| self.head.weight = self.emb.weight | |
| def forward(self, x): | |
| x = self.emb(x) | |
| for b in self.blocks: | |
| x = b(x) | |
| return self.head(self.norm(x)) | |
| Qdevice = "cuda" if torch.cuda.is_available() else "cpu" | |
| def load_qed(path, device="cpu",dw=False): | |
| package = torch.load(path,map_location=device) | |
| model = GPT() | |
| model.load_state_dict(package["state_dict"]) | |
| None if dw else print(f"Loading {package['model_name']} by {package['author']}") | |
| model.to(device) | |
| model.eval() | |
| return model |