cgc / scripts /compute_density_map.py
Lostboy231's picture
first commit
69202a6
Raw
History Blame Contribute Delete
4.56 kB
"""
scripts/compute_density_map.py
------------------------------
Phase 1 + 2: Collect per-head activations and compute capability density map.
Steps:
1. Load GPT-2 Medium
2. Load calibration data (WikiText-103-raw-v1, 128 seq Γ— 512 tok)
3. Run calibration data through model, collect per-head attention outputs
4. For each of 384 heads: train a TopK SAE, compute β, H, ψ, δ
5. Save density map to .npz
Runtime: ~15–20 min on T4 GPU (384 SAEs Γ— 5 epochs each)
Usage:
python scripts/compute_density_map.py --output results/density_map.npz
"""
import argparse
import random
import os
import sys
import numpy as np
import torch
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# ── Reproducibility ───────────────────────────────────────────────────────────
# Note: original experiments were run without fixed seeds.
# This seed ensures approximate reproducibility across runs.
SEED = 42
random.seed(SEED)
np.random.seed(SEED)
torch.manual_seed(SEED)
torch.cuda.manual_seed_all(SEED)
from transformers import GPT2Model, GPT2Tokenizer
from datasets import load_dataset
from cgc.density import collect_head_activations, compute_density_map
def parse_args():
p = argparse.ArgumentParser(description="Compute CGC capability density map")
p.add_argument("--output", type=str, default="results/density_map.npz",
help="Output path for density map")
p.add_argument("--n_sequences", type=int, default=128,
help="Number of calibration sequences (default: 128)")
p.add_argument("--seq_len", type=int, default=512,
help="Tokens per sequence (default: 512)")
p.add_argument("--batch_size", type=int, default=8,
help="Sequences per forward pass (default: 8)")
return p.parse_args()
def load_calibration_data(tokenizer, n_sequences, seq_len, device):
"""
Load WikiText-103-raw-v1 training split as non-overlapping token chunks.
Same dataset and split used for calibration in the CGC v1 paper.
"""
print("Loading calibration data (WikiText-103-raw-v1, train split)...")
dataset = load_dataset("Salesforce/wikitext",
"wikitext-103-raw-v1", split="train")
full_text = " ".join([
item["text"].strip()
for item in dataset
if len(item["text"].strip()) > 50
])
all_tokens = tokenizer.encode(full_text)
chunks = []
for i in range(n_sequences):
start = i * seq_len
end = start + seq_len
if end > len(all_tokens):
print(f"Warning: only {len(chunks)} sequences available.")
break
chunks.append(torch.tensor(all_tokens[start:end], dtype=torch.long))
data = torch.stack(chunks).to(device)
print(f"Calibration data: {data.shape} "
f"({data.shape[0] * data.shape[1]:,} tokens total)")
return data
def main():
args = parse_args()
os.makedirs(os.path.dirname(args.output) or ".", exist_ok=True)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Device: {device}")
if device.type == "cuda":
print(f"GPU: {torch.cuda.get_device_name(0)}")
vram = torch.cuda.get_device_properties(0).total_memory / 1e9
print(f"VRAM: {vram:.1f} GB")
# Load GPT-2 Medium
print("\nLoading GPT-2 Medium...")
tokenizer = GPT2Tokenizer.from_pretrained("gpt2-medium")
tokenizer.pad_token = tokenizer.eos_token
model = GPT2Model.from_pretrained("gpt2-medium")
model = model.to(device)
model.eval()
n_params = sum(p.numel() for p in model.parameters())
print(f"Loaded. Layers={model.config.n_layer} "
f"Heads={model.config.n_head} "
f"Params={n_params:,}")
# Calibration data
cal_data = load_calibration_data(
tokenizer, args.n_sequences, args.seq_len, device
)
# Phase 1: collect per-head activations
head_acts = collect_head_activations(
model, cal_data, device, args.batch_size
)
# Phase 2: train SAEs and compute density
density_map, _ = compute_density_map(
head_acts, device, seq_len=args.seq_len
)
# Save
density_map.save(args.output)
print(f"\nDensity map saved to: {args.output}")
print("Next: python scripts/run_compression.py "
f"--density_map {args.output}")
if __name__ == "__main__":
main()