pc-sho-dlm-code / app_local.py
Zae
PC-SHO-DLM: full architecture with MSA integration
c2d8a57
Raw History Blame Contribute Delete
5.59 kB
"""PC-SHO-DLM: LOCAL PC Training on A100 — Single mode, fast."""
import json, os, sys, threading, time
import gradio as gr
import torch
import torch.nn.functional as F
from torch.utils.data import DataLoader, Dataset
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
from model import PCSHODLM, PCSHOConfig, LocalParameterUpdater, count_parameters
class CharDS(Dataset):
def __init__(self, text, seq_len):
self.seq_len = seq_len
self.data = torch.tensor([min(b+1,256) for b in text.encode("utf-8")], dtype=torch.long)
self.n = max(1, (len(self.data)-seq_len)//seq_len)
def __len__(self): return self.n
def __getitem__(self, i):
return {"input_ids": self.data[i*self.seq_len:(i+1)*self.seq_len]}
LOG = []
STATUS = "Idle"
def train():
global STATUS, LOG
LOG = ["Starting LOCAL PC training on A100..."]
device = "cuda" if torch.cuda.is_available() else "cpu"
LOG.append(f"Device: {device}")
if device == "cuda":
LOG.append(f"GPU: {torch.cuda.get_device_name()}")
LOG.append(f"VRAM: {torch.cuda.get_device_properties(0).total_memory/1e9:.1f} GB")
config = PCSHOConfig(
vocab_size=257, max_seq_len=512, d_model=512, n_heads=8,
n_layers=12, d_ff=2048, n_diffusion_steps=128, n_settling_steps=6,
mask_token_id=0, dropout=0.1, feedback_rank=128,
)
LOG.append(f"Model: {count_parameters(PCSHODLM(config)):,} params")
STATUS = "Loading data..."
from datasets import load_dataset
ds = load_dataset("wikitext","wikitext-103-raw-v1",split="train")
dv = load_dataset("wikitext","wikitext-103-raw-v1",split="validation")
tt = "\n".join([r["text"] for r in ds if r["text"].strip()])[:100_000_000]
vt = "\n".join([r["text"] for r in dv if r["text"].strip()])
train_ds, val_ds = CharDS(tt,config.max_seq_len), CharDS(vt,config.max_seq_len)
LOG.append(f"Data: {len(tt):,} train, {len(vt):,} val chars")
model = PCSHODLM(config).to(device)
model.train()
updater = LocalParameterUpdater(model, lr_forward=3e-4, lr_feedback=3e-4, lr_readout=3e-4, lr_precision=3e-5)
tl = DataLoader(train_ds, batch_size=64, shuffle=True, drop_last=True, num_workers=4, pin_memory=True)
vl = DataLoader(val_ds, batch_size=64, shuffle=False, num_workers=2, pin_memory=True)
STATUS = "Training LOCAL PC..."
LOG.append(f"\n{'='*60}\nMode: LOCAL PC | Params: {count_parameters(model):,}\n{'='*60}")
step, start, max_steps = 0, time.time(), 10000
log_data = {"steps":[],"losses":[],"energies":[]}
while step < max_steps:
for batch in tl:
if step >= max_steps: break
x_0 = batch["input_ids"].to(device)
result = updater.step({"input_ids": x_0})
step += 1
loss = result.get("loss",0); energies = result.get("energies",[])
if step % 100 == 0:
elapsed = time.time()-start
tps = step*64*config.max_seq_len/elapsed
e = f"{energies[-1]:.0f}" if energies else "N/A"
msg = f"[local] Step {step:6d} | Loss: {loss:.4f} | Energy: {e} | Tok/s: {tps:.0f} | {elapsed:.0f}s"
LOG.append(msg); log_data["steps"].append(step); log_data["losses"].append(loss); log_data["energies"].append(energies[-1] if energies else 0)
if step % 2000 == 0:
model.eval()
tl2,tt2=0.0,0
with torch.no_grad():
for vb in vl:
vx=vb["input_ids"].to(device); vo=model(vx); nm=vo["mask"].sum().item()
if nm>0: tl2+=vo["loss"].item()*nm; tt2+=nm
if tt2>100000: break
vl2=tl2/max(1,tt2); LOG.append(f" --> [local] Val loss: {vl2:.4f}"); log_data.setdefault("val",[]).append((step,vl2))
model.train()
model.eval()
tl2,tt2=0.0,0
with torch.no_grad():
for vb in vl:
vx=vb["input_ids"].to(device); vo=model(vx); nm=vo["mask"].sum().item()
if nm>0: tl2+=vo["loss"].item()*nm; tt2+=nm
if tt2>200000: break
fv=tl2/max(1,tt2); log_data["final_val"]=fv
LOG.append(f"DONE: {step} steps in {time.time()-start:.0f}s | Final val: {fv:.4f}")
STATUS = "Complete!"
os.makedirs("results",exist_ok=True)
torch.save({"model":model.state_dict(),"config":config,"log":log_data},"results/local_pc_10k.pt")
with open("results/local_pc_log.json","w") as f: json.dump(log_data,f)
try:
from huggingface_hub import HfApi
HfApi().upload_folder(folder_path="results",repo_id="zotowata/pc-sho-dlm-local",repo_type="space",path_in_repo="results")
LOG.append("Results uploaded!")
except: pass
_thread = None
def start():
global _thread
if _thread and _thread.is_alive(): return "Already running!"
_thread = threading.Thread(target=train, daemon=True); _thread.start()
return "LOCAL PC training started on A100!"
with gr.Blocks(title="PC-SHO-DLM Local PC") as demo:
gr.Markdown("# PC-SHO-DLM: LOCAL PC Training (A100)")
with gr.Row():
btn = gr.Button("Start Training", variant="primary")
st = gr.Textbox(label="Status", value="Idle")
log = gr.Textbox(label="Log", lines=25, max_lines=50)
btn.click(start, outputs=st)
refresh = gr.Button("Refresh"); refresh.click(lambda: "\n".join(LOG[-50:]), outputs=log); refresh.click(lambda: STATUS, outputs=st)
timer = gr.Timer(5); timer.tick(lambda: "\n".join(LOG[-50:]), outputs=log); timer.tick(lambda: STATUS, outputs=st)
demo.launch()