Buckets:

Rishik001's picture
download
raw
12.1 kB
"""
Extended classifier and MLP ablations over pre-computed SAE feature vectors.
Sections:
1. Classical sklearn classifiers
2. Feature count sweep (top-N from the 100, ordered by variance desc)
3. MLP activation functions
4. MLP dropout
5. MLP weight decay
6. MLP with batch normalisation
"""
import json
import warnings
from pathlib import Path
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import BernoulliNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
warnings.filterwarnings("ignore")
# ---------------------------------------------------------------------------
# Datasets
# ---------------------------------------------------------------------------
CHECKPOINTS = [
("decode",
"checkpoints_shuffled_512/gemma-3-1b-it_20260618_112951_train_features.parquet",
"checkpoints_shuffled_512/gemma-3-1b-it_20260618_112951_test_features.parquet"),
("prefill+decode",
"checkpoints_shuffled_512_prefill_decode/gemma-3-1b-it_20260618_122805_train_features.parquet",
"checkpoints_shuffled_512_prefill_decode/gemma-3-1b-it_20260618_122805_test_features.parquet"),
("prefill",
"checkpoints_shuffled_512_prefill/gemma-3-1b-it_20260618_123516_train_features.parquet",
"checkpoints_shuffled_512_prefill/gemma-3-1b-it_20260618_123516_test_features.parquet"),
]
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
N_SEEDS = 5
BASE_EPOCHS = 50
LR = 1e-3
BATCH = 512
# ---------------------------------------------------------------------------
# Data loading
# ---------------------------------------------------------------------------
def load_dataset(train_path, test_path, n_features=100):
tr = pd.read_parquet(train_path)
te = pd.read_parquet(test_path)
feat_cols = [c for c in tr.columns if c != "label"][:n_features]
X_tr = tr[feat_cols].values.astype(np.float32)
y_tr = tr["label"].values.astype(np.int64)
X_te = te[feat_cols].values.astype(np.float32)
y_te = te["label"].values.astype(np.int64)
n_classes = int(y_tr.max()) + 1
return X_tr, y_tr, X_te, y_te, n_classes
# ---------------------------------------------------------------------------
# Flexible MLP
# ---------------------------------------------------------------------------
class FlexMLP(nn.Module):
def __init__(self, n_in, n_classes, hidden_sizes,
activation="relu", dropout=0.0, batch_norm=False):
super().__init__()
act_map = {
"relu": nn.ReLU,
"gelu": nn.GELU,
"silu": nn.SiLU,
"elu": nn.ELU,
"tanh": nn.Tanh,
}
Act = act_map[activation]
layers = []
prev = n_in
for h in hidden_sizes:
layers.append(nn.Linear(prev, h))
if batch_norm:
layers.append(nn.BatchNorm1d(h))
layers.append(Act())
if dropout > 0:
layers.append(nn.Dropout(dropout))
prev = h
layers.append(nn.Linear(prev, n_classes))
self.net = nn.Sequential(*layers)
def forward(self, x):
return self.net(x)
def train_eval_mlp(X_tr, y_tr, X_te, y_te, n_classes, hidden_sizes,
activation="relu", dropout=0.0, batch_norm=False,
weight_decay=0.0, epochs=BASE_EPOCHS, seed=0):
torch.manual_seed(seed)
n_in = X_tr.shape[1]
model = FlexMLP(n_in, n_classes, hidden_sizes,
activation=activation, dropout=dropout,
batch_norm=batch_norm).to(DEVICE)
opt = torch.optim.AdamW(model.parameters(), lr=LR,
weight_decay=weight_decay,
fused=(DEVICE == "cuda"))
loss_fn = nn.CrossEntropyLoss()
Xtr = torch.tensor(X_tr).to(DEVICE)
ytr = torch.tensor(y_tr).to(DEVICE)
Xte = torch.tensor(X_te).to(DEVICE)
yte = torch.tensor(y_te).to(DEVICE)
n = Xtr.shape[0]
model.train()
for _ in range(epochs):
perm = torch.randperm(n, device=DEVICE)
for s in range(0, n, BATCH):
idx = perm[s: s + BATCH]
loss = loss_fn(model(Xtr[idx]), ytr[idx])
opt.zero_grad(); loss.backward(); opt.step()
model.eval()
with torch.no_grad():
preds = model(Xte).argmax(-1)
return (preds == yte).float().mean().item()
def run_mlp(X_tr, y_tr, X_te, y_te, n_classes, hidden_sizes, **kwargs):
accs = [train_eval_mlp(X_tr, y_tr, X_te, y_te, n_classes,
hidden_sizes, seed=s, **kwargs)
for s in range(N_SEEDS)]
return np.mean(accs), np.std(accs)
# ---------------------------------------------------------------------------
# Printing helpers
# ---------------------------------------------------------------------------
def header(title):
print(f"\n{'='*72}")
print(f" {title}")
print(f"{'='*72}")
def row(label, mean, std, extra=""):
print(f" {label:<35} {mean:>7.1%} ±{std:.3f} {extra}")
# ---------------------------------------------------------------------------
# Section 1: Classical sklearn classifiers
# ---------------------------------------------------------------------------
SKLEARN_CLASSIFIERS = [
("LogReg C=0.01", LogisticRegression(C=0.01, max_iter=1000, random_state=42)),
("LogReg C=0.1", LogisticRegression(C=0.1, max_iter=1000, random_state=42)),
("LogReg C=1", LogisticRegression(C=1.0, max_iter=1000, random_state=42)),
("LogReg C=10", LogisticRegression(C=10.0, max_iter=1000, random_state=42)),
("SVM linear C=0.1", SVC(kernel="linear", C=0.1, random_state=42)),
("SVM linear C=1", SVC(kernel="linear", C=1.0, random_state=42)),
("SVM linear C=10", SVC(kernel="linear", C=10.0, random_state=42)),
("SVM RBF C=1", SVC(kernel="rbf", C=1.0, random_state=42)),
("SVM RBF C=10", SVC(kernel="rbf", C=10.0, random_state=42)),
("SVM RBF C=100", SVC(kernel="rbf", C=100., random_state=42)),
("kNN k=1", KNeighborsClassifier(n_neighbors=1)),
("kNN k=3", KNeighborsClassifier(n_neighbors=3)),
("kNN k=5", KNeighborsClassifier(n_neighbors=5)),
("kNN k=11", KNeighborsClassifier(n_neighbors=11)),
("RandomForest 100", RandomForestClassifier(n_estimators=100, random_state=42)),
("RandomForest 500", RandomForestClassifier(n_estimators=500, random_state=42)),
("GradientBoosting", GradientBoostingClassifier(n_estimators=200, random_state=42)),
("BernoulliNB", BernoulliNB()),
]
all_results = []
for ds_label, train_path, test_path in CHECKPOINTS:
X_tr, y_tr, X_te, y_te, n_classes = load_dataset(train_path, test_path)
header(f"[1] Classical classifiers — {ds_label}")
print(f" {'Classifier':<35} {'Acc':>7}")
for name, clf in SKLEARN_CLASSIFIERS:
clf.fit(X_tr, y_tr)
acc = (clf.predict(X_te) == y_te).mean()
print(f" {name:<35} {acc:>7.1%}")
all_results.append({"section": "sklearn", "dataset": ds_label,
"label": name, "mean_acc": acc, "std_acc": 0})
# ---------------------------------------------------------------------------
# Section 2: Feature count sweep (top-N of the 100, ordered by variance)
# ---------------------------------------------------------------------------
FEATURE_COUNTS = [5, 10, 20, 30, 50, 75, 100]
# Use best MLP from previous ablations (512→256) and LogReg C=1 for comparison
BASE_ARCH = [512, 256]
for ds_label, train_path, test_path in CHECKPOINTS:
header(f"[2] Feature count sweep — {ds_label}")
print(f" {'N features':<20} {'MLP 512→256':>12} {'LogReg C=1':>12}")
for nf in FEATURE_COUNTS:
X_tr, y_tr, X_te, y_te, n_classes = load_dataset(train_path, test_path, n_features=nf)
mlp_mean, mlp_std = run_mlp(X_tr, y_tr, X_te, y_te, n_classes, BASE_ARCH)
lr = LogisticRegression(C=1.0, max_iter=1000, random_state=42)
lr.fit(X_tr, y_tr)
lr_acc = (lr.predict(X_te) == y_te).mean()
print(f" top-{nf:<15} {mlp_mean:>11.1%} {lr_acc:>11.1%}")
all_results.append({"section": "feature_count", "dataset": ds_label,
"label": f"top-{nf}", "mlp": mlp_mean, "lr": lr_acc})
# ---------------------------------------------------------------------------
# Section 3: MLP activation functions (arch: 256→128, decode only)
# ---------------------------------------------------------------------------
ACTIVATIONS = ["relu", "gelu", "silu", "elu", "tanh"]
ABLATION_ARCH = [256, 128]
for ds_label, train_path, test_path in CHECKPOINTS:
X_tr, y_tr, X_te, y_te, n_classes = load_dataset(train_path, test_path)
header(f"[3] Activation functions — {ds_label} (arch: 256→128)")
for act in ACTIVATIONS:
mean, std = run_mlp(X_tr, y_tr, X_te, y_te, n_classes, ABLATION_ARCH, activation=act)
row(act, mean, std)
all_results.append({"section": "activation", "dataset": ds_label,
"label": act, "mean_acc": mean, "std_acc": std})
# ---------------------------------------------------------------------------
# Section 4: Dropout (arch: 512→256)
# ---------------------------------------------------------------------------
DROPOUTS = [0.0, 0.1, 0.2, 0.3, 0.5]
for ds_label, train_path, test_path in CHECKPOINTS:
X_tr, y_tr, X_te, y_e, n_classes = load_dataset(train_path, test_path)
header(f"[4] Dropout — {ds_label} (arch: 512→256)")
for dr in DROPOUTS:
mean, std = run_mlp(X_tr, y_tr, X_te, y_e, n_classes, BASE_ARCH, dropout=dr)
row(f"dropout={dr}", mean, std)
all_results.append({"section": "dropout", "dataset": ds_label,
"label": f"dropout={dr}", "mean_acc": mean, "std_acc": std})
# ---------------------------------------------------------------------------
# Section 5: Weight decay (arch: 512→256)
# ---------------------------------------------------------------------------
WEIGHT_DECAYS = [0.0, 1e-4, 1e-3, 1e-2, 1e-1, 0.5]
for ds_label, train_path, test_path in CHECKPOINTS:
X_tr, y_tr, X_te, y_te, n_classes = load_dataset(train_path, test_path)
header(f"[5] Weight decay — {ds_label} (arch: 512→256)")
for wd in WEIGHT_DECAYS:
mean, std = run_mlp(X_tr, y_tr, X_te, y_te, n_classes, BASE_ARCH, weight_decay=wd)
row(f"wd={wd}", mean, std)
all_results.append({"section": "weight_decay", "dataset": ds_label,
"label": f"wd={wd}", "mean_acc": mean, "std_acc": std})
# ---------------------------------------------------------------------------
# Section 6: Batch normalisation (arch: 256→128, with/without, ±dropout)
# ---------------------------------------------------------------------------
BN_CONFIGS = [
("no BN, no drop", dict(batch_norm=False, dropout=0.0)),
("BN, no drop", dict(batch_norm=True, dropout=0.0)),
("no BN, drop=0.2", dict(batch_norm=False, dropout=0.2)),
("BN + drop=0.2", dict(batch_norm=True, dropout=0.2)),
]
for ds_label, train_path, test_path in CHECKPOINTS:
X_tr, y_tr, X_te, y_te, n_classes = load_dataset(train_path, test_path)
header(f"[6] Batch norm — {ds_label} (arch: 256→128)")
for name, kwargs in BN_CONFIGS:
mean, std = run_mlp(X_tr, y_tr, X_te, y_te, n_classes, ABLATION_ARCH, **kwargs)
row(name, mean, std)
all_results.append({"section": "batch_norm", "dataset": ds_label,
"label": name, "mean_acc": mean, "std_acc": std})
# ---------------------------------------------------------------------------
# Save
# ---------------------------------------------------------------------------
out = Path("ablations2_results.json")
with open(out, "w") as f:
json.dump(all_results, f, indent=2)
print(f"\n\nAll results saved to {out}")

Xet Storage Details

Size:
12.1 kB
·
Xet hash:
812873fa3840e7a51bff90c96d8b2661875dd348a582906a73d2911d56cd5a82

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.