HyperPEER / testbed /common.py
MikeyBeez's picture
Add HyperPEER pipeline, testbed code, results, docs, Gradio landing
e41a3a4 verified
Raw
History Blame Contribute Delete
4.57 kB
"""Shared pieces for the decoupled (capture -> offline-train) MLP compression
pipeline.
`Bank`, `collect`, and `build_buffer` are vendored VERBATIM (modulo this
docstring) from the in-context recipe scripts so this directory is a
self-contained, committable, re-runnable pipeline:
* Bank <- /tmp/train_compress2.py (subset-of-neurons compressed MLP)
* collect <- /tmp/train_compare.py (per-source streaming w/ retry)
* build_buffer <- /tmp/train_compare.py (reproducible corpus buffer)
Keeping build_buffer byte-identical to train_compare.py guarantees the held-out
eval set used by train_offline.py is the SAME fixed eval set as the in-context
baseline (52.4 ppl @ 5M tokens), so the two regimes are directly comparable.
"""
import itertools, time, random
import torch, torch.nn as nn, torch.nn.functional as F
from datasets import load_dataset
MODEL = "bigcode/starcoder2-3b"
class Bank(nn.Module):
"""A compressed MLP that keeps only E of the original intermediate neurons.
Initialized from the source MLP's own weights (a subset of rows/cols)."""
def __init__(self, src_mlp, E, init):
super().__init__()
if init == "topnorm":
idx = src_mlp.c_proj.weight.data.float().norm(dim=0).topk(E).indices
else:
idx = torch.randperm(src_mlp.c_fc.weight.shape[0])[:E]
self.down = nn.Parameter(src_mlp.c_fc.weight.data[idx].clone().float())
self.up = nn.Parameter(src_mlp.c_proj.weight.data[:, idx].t().clone().float())
self.b = nn.Parameter(src_mlp.c_fc.bias.data[idx].clone().float()
if src_mlp.c_fc.bias is not None else torch.zeros(E))
self.obias = nn.Parameter(src_mlp.c_proj.bias.data.clone().float()
if src_mlp.c_proj.bias is not None
else torch.zeros(src_mlp.c_proj.weight.shape[0]))
self.last_in = None; self.last_out = None
def forward(self, x):
self.last_in = x
act = F.gelu(x.float() @ self.down.t() + self.b, approximate="tanh")
out = (act @ self.up + self.obias).to(x.dtype)
self.last_out = out
return out
def collect(name, cfg, field, n_docs, attempts=5):
"""Stream up to n_docs texts; retry the whole source on transient errors
(e.g. HF CDN 408) until we have a healthy fraction."""
texts = []
for attempt in range(attempts):
texts = []
try:
ds = (load_dataset(name, cfg, split="train", streaming=True) if cfg
else load_dataset(name, split="train", streaming=True))
for ex in itertools.islice(ds, n_docs):
t = ex.get(field) or ""
if len(t) > 60: texts.append(t)
if len(texts) >= n_docs * 0.5:
print(f" {name}: {len(texts)} docs (attempt {attempt+1})", flush=True)
return texts
print(f" {name}: short ({len(texts)}), retrying", flush=True)
except Exception as e:
print(f" {name}: attempt {attempt+1} failed: {str(e)[:90]}", flush=True)
time.sleep(5)
print(f" {name}: giving up with {len(texts)} docs", flush=True)
return texts
def build_buffer(tok, target_tokens, seed=0):
"""Build a reproducible token buffer. The first K tokens are deterministic
given (collected corpus, seed), so a prefix slice is a fixed eval set."""
texts = collect("codeparrot/codeparrot-clean", None, "content", 9000)
texts += collect("HuggingFaceFW/fineweb-edu", "sample-10BT", "text", 9000)
random.seed(seed); random.shuffle(texts)
eos = tok.eos_token_id or 0
buf = []
for t in texts:
buf.extend(tok(t).input_ids + [eos])
if len(buf) >= target_tokens: break
return torch.tensor(buf[:target_tokens], dtype=torch.long)
# ------------------------------------------------------------------ tiny model
def tiny_starcoder2(seed=0):
"""A minuscule, randomly-initialized StarCoder2 with the SAME module
structure (Starcoder2MLP: c_fc / act / c_proj) as the 3B. Used to validate
the capture/train/eval code paths on CPU with no download and no GPU."""
from transformers import Starcoder2Config, AutoModelForCausalLM
torch.manual_seed(seed)
cfg = Starcoder2Config(
vocab_size=256, hidden_size=64, intermediate_size=128,
num_hidden_layers=2, num_attention_heads=4, num_key_value_heads=2,
max_position_embeddings=256, use_bias=True, tie_word_embeddings=True,
)
return AutoModelForCausalLM.from_config(cfg)