Spaces:
Running
Running
| """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) | |