mae-cross-objective / scripts /lora_calibrate.py
quinnlue's picture
MAE cross-objective mixture-ranking campaign
ffdcfe7 verified
Raw
History Blame Contribute Delete
4.06 kB
"""Recalibrate the LoRA readout at 15M before it is used as a campaign response.
lora-finetune-readout.md establishes rank 16 / 3 epochs / lr 3e-3 and sigma_ft
0.00233 at scale_base only, and says so explicitly: "Anything about scales other
than scale_base" is not established. ranking-transfer.md then names that
mistuning as the leading explanation for why its readout-matched correlation
(+0.537) sits below the mismatched one (+0.630) -- the LoRA readout reaches 94%
of the full fine-tune at base but only 82% at 15M. Carrying the base recipe to
15M unchanged would repeat that, on the arm this campaign actually reports.
Three passes, all on existing 15M MAE checkpoints, one GPU so the 64-arm
campaign keeps three:
1. epoch knee -- where val mAP stops rising while train mAP keeps climbing
2. lr boundary -- the base recipe's 3e-3 sits close to a divergence cliff
3. sigma_ft -- 3 checkpoints x 3 seeds, the noise the response carries
"""
import itertools
import json
import subprocess
import sys
from pathlib import Path
REPO = "/workspace/code/eat-map-regmix"
GPU = sys.argv[1] if len(sys.argv) > 1 else "0"
CKPT = {
"natural": "/workspace/runs/mae-validate/natural-lr0.0005/exports/step_00039833",
"d7": "/workspace/runs/mae-validate/d7-lr0.0007/exports/step_00039833",
"d185": "/workspace/runs/mae-validate/d185-lr0.0007/exports/step_00039833",
}
def lora(export: str, tag: str, **kw) -> dict | None:
cmd = ["python", "-m", "eatmap.cli.lora_finetune", "--export", export, "--tag", tag]
for k, v in kw.items():
cmd += [f"--{k.replace('_', '-')}", str(v)]
proc = subprocess.run(
cmd, cwd=REPO, capture_output=True,
env={**__import__("os").environ, "CUDA_VISIBLE_DEVICES": GPU, "PYTHONPATH": REPO},
)
out = Path(export) / f"lora.{tag}.json"
if proc.returncode or not out.exists():
print(f" FAIL {tag}: {proc.stderr.decode()[-300:]}")
return None
return json.loads(out.read_text())
def val(d: dict) -> float:
for k in ("lora/val_map", "val_map", "lora/map", "map"):
if k in d:
return d[k]
return next(v for k, v in d.items() if "map" in k.lower() and isinstance(v, float))
print("[1] epoch knee (natural, lr 3e-3)")
knee = {}
for ep in (1, 2, 3, 4, 6):
r = lora(CKPT["natural"], f"ep{ep}", epochs=ep, lr=3e-3, seed=0)
if r:
knee[ep] = val(r)
train = r.get("lora/train_map", r.get("train_map", float("nan")))
print(f" epochs {ep}: val {knee[ep]:.5f} train {train:.5f}")
print("\n[2] lr boundary (natural, 3 epochs)")
best_ep = max(knee, key=knee.get) if knee else 3
for lr in (1e-3, 3e-3, 1e-2):
r = lora(CKPT["natural"], f"lr{lr:g}", epochs=best_ep, lr=lr, seed=0)
if r:
print(f" lr {lr:g}: val {val(r):.5f}")
print(f"\n[3] sigma_ft grid (3 checkpoints x 3 seeds, {best_ep} epochs, lr 3e-3)")
import statistics as st
grid = {}
for name, seed in itertools.product(CKPT, (0, 1, 2)):
r = lora(CKPT[name], f"var-s{seed}", epochs=best_ep, lr=3e-3, seed=seed)
if r:
grid.setdefault(name, []).append(val(r))
for name, vals in grid.items():
print(f" {name:<9} {' '.join(f'{v:.5f}' for v in vals)} "
f"mean {st.mean(vals):.5f} sd {st.stdev(vals):.5f}")
if len(grid) >= 2:
pooled = (sum(st.variance(v) for v in grid.values() if len(v) > 1)
/ sum(1 for v in grid.values() if len(v) > 1)) ** 0.5
between = st.stdev([st.mean(v) for v in grid.values()])
print(f"\n sigma_ft (pooled within-checkpoint) = {pooled:.5f}")
print(f" between-checkpoint sd = {between:.5f}")
if between > pooled:
print(f" single-run reliability = "
f"{(between**2 - pooled**2)/between**2:.3f}")
print(f" (scale_base reference: sigma_ft 0.00233, reliability 0.31)")
Path("/workspace/analysis/lora_calibration_15m.json").write_text(
json.dumps({"epoch_knee": knee, "sigma_ft_grid": grid}, indent=1))
print("\nwrote /workspace/analysis/lora_calibration_15m.json")