nur-dev's picture
PNS-Bind-25M: implementation, configs, eval, results, reproduction
f930dac verified
Raw History Blame Contribute Delete
1.91 kB
"""Transcript-window baseline: "the context window is the mind".
A causal decoder-only transformer over the last W transcript tokens (the same
per-event token stream PNSR sees, concatenated), parameter-matched to PNSR,
with the IDENTICAL factorized head system and cache record bank. TXE is the
same class with W = one event (current-event-only trained null).
"""
from __future__ import annotations
from dataclasses import dataclass
import torch
import torch.nn as nn
from .modules import Block, HeadSystem, RecordEncoder
@dataclass
class TXConfig:
vocab: int = 8192
d: int = 384
heads: int = 8
layers: int = 10 # param-matched to PNSR (see PNSRConfig.enc_layers note)
window: int = 768
class TX(nn.Module):
def __init__(self, cfg: TXConfig):
super().__init__()
self.cfg = cfg
d = cfg.d
self.tok_emb = nn.Embedding(cfg.vocab, d)
self.pos_emb = nn.Parameter(torch.zeros(cfg.window, d))
self.blocks = nn.ModuleList(Block(d, cfg.heads) for _ in range(cfg.layers))
self.ln = nn.LayerNorm(d)
self.recenc = RecordEncoder(d, self.tok_emb)
self.heads = HeadSystem(d)
mask = torch.triu(torch.ones(cfg.window, cfg.window, dtype=torch.bool), 1)
self.register_buffer("causal", mask, persistent=False)
def forward(self, tok, rec_bank, live_mask):
"""tok: [B,W] left-padded with 0; final position is the query point."""
B, W = tok.shape
pad = tok == 0
x = self.tok_emb(tok.long()) + self.pos_emb[:W]
am = self.causal[:W, :W]
for blk in self.blocks:
x = blk(x, attn_mask=am, self_padding_mask=pad)
h = self.ln(x[:, -1]) # final token = query position
return self.heads(None, h, None, rec_bank, live_mask)
def param_report(self):
return {"total": sum(p.numel() for p in self.parameters())}