import os, json, base64, re, time import numpy as np import gradio as gr import torch import torch.nn as nn import torch.nn.functional as F CONFIG = { "corpus_file": "Recognizement_Corpus.txt", "context_length": 12, "embed_dim": 16, "num_heads": 2, "num_layers": 1, "ffn_hidden": 48, "batch_size": 128, "max_vocab": 700, "learning_rate": 0.015, "focal_gamma": 0.5, "loss_norm": True, "max_epochs": 600, "target_loss": 0.10, } PAD, UNK, EOS = "", "", "" PAD_ID, UNK_ID, EOS_ID = 0, 1, 2 def tokenize(text): text = text.replace("", " __PAD__ ").replace("", " __UNK__ ").replace("", " __EOS__ ") text = text.lower() text = re.sub(r"([.,!?;:])", r" \1 ", text) return text.replace("__PAD__", "").replace("__UNK__", "").replace("__EOS__", "").split() def build_vocab(tokens, max_vocab=None): from collections import Counter freq = Counter(tokens) vocab = {PAD: 0, UNK: 1, EOS: 2} for tok, _ in freq.most_common(): if tok in vocab: continue if max_vocab and len(vocab) >= max_vocab: break vocab[tok] = len(vocab) return vocab def build_dataset(lines, vocab, ctx): X_all, Y_all, M_all = [], [], [] for line in lines: toks = tokenize(line) + [EOS] ids = [vocab.get(t, UNK_ID) for t in toks][:ctx+1] real_len = len(ids) padded = ids + [PAD_ID] * (ctx + 1 - len(ids)) X_all.append(padded[:-1]); Y_all.append(padded[1:]) M_all.append([1.0 if i < real_len - 1 else 0.0 for i in range(ctx)]) return (torch.tensor(X_all, dtype=torch.long), torch.tensor(Y_all, dtype=torch.long), torch.tensor(M_all, dtype=torch.float32)) class MHSA(nn.Module): def __init__(self, D, H, ctx): super().__init__() self.D, self.H, self.hd = D, H, D // H self.Wq = nn.Linear(D, D); self.Wk = nn.Linear(D, D) self.Wv = nn.Linear(D, D); self.Wo = nn.Linear(D, D) self.register_buffer("mask", torch.triu(torch.full((ctx, ctx), -1e9), diagonal=1)) def forward(self, x): B, T, D = x.shape Q = self.Wq(x).view(B, T, self.H, self.hd).transpose(1, 2) K = self.Wk(x).view(B, T, self.H, self.hd).transpose(1, 2) V = self.Wv(x).view(B, T, self.H, self.hd).transpose(1, 2) S = (Q @ K.transpose(-2, -1)) / (self.hd ** 0.5) + self.mask[:T, :T] A = F.softmax(S, dim=-1) O = (A @ V).transpose(1, 2).reshape(B, T, D) return self.Wo(O) class Block(nn.Module): def __init__(self, D, H, Ff, ctx): super().__init__() self.ln1 = nn.LayerNorm(D); self.attn = MHSA(D, H, ctx) self.ln2 = nn.LayerNorm(D) self.W1 = nn.Linear(D, Ff); self.W2 = nn.Linear(Ff, D) def forward(self, x): x = x + self.attn(self.ln1(x)) x = x + self.W2(F.relu(self.W1(self.ln2(x)))) return x class Transformer(nn.Module): def __init__(self, V, ctx, D, H, L, Ff): super().__init__() self.V, self.ctx, self.D = V, ctx, D self.H, self.L, self.Ff = H, L, Ff self.tok_emb = nn.Embedding(V, D) self.pos_emb = nn.Embedding(ctx, D) self.blocks = nn.ModuleList([Block(D, H, Ff, ctx) for _ in range(L)]) self.ln_f = nn.LayerNorm(D) self.Wout = nn.Linear(D, V, bias=True) def forward(self, X): B, T = X.shape pos = torch.arange(T, device=X.device).unsqueeze(0) x = self.tok_emb(X) + self.pos_emb(pos) for b in self.blocks: x = b(x) return self.Wout(self.ln_f(x)) def focal_loss(logits, Y, M, gamma, log_V): B, T, V = logits.shape lf = logits.reshape(B*T, V) Yf = Y.reshape(B*T); Mf = M.reshape(B*T) log_probs = F.log_softmax(lf, dim=-1) probs = log_probs.exp() idx = torch.arange(B*T, device=logits.device) p_t = probs[idx, Yf].clamp(1e-9, 1.0 - 1e-9) log_pt = -torch.log(p_t) focal_val = ((1.0 - p_t) ** gamma) * log_pt Msum = Mf.sum() + 1e-9 loss = (focal_val * Mf).sum() / Msum loss_norm = loss / log_V # grad: s * (probs - onehot) * mask / Msum s = ((1.0 - p_t) ** gamma) + gamma * p_t * ((1.0 - p_t) ** (gamma - 1.0)) * log_pt s = torch.nan_to_num(s, nan=0.0, posinf=0.0, neginf=0.0) grad_logits = probs.clone() grad_logits[idx, Yf] -= 1.0 grad_logits = grad_logits * Mf.unsqueeze(1) * s.unsqueeze(1) / Msum return loss_norm, grad_logits.reshape(B, T, V) def to_b64(t): return base64.b64encode(t.detach().cpu().numpy().astype("