transformer-weights / scripts /run_correlations.py
angerami's picture
Claude Opus 4.8
Add QK/OV equilibrium observables to correlations stage
1062742
Raw History Blame Contribute Delete
3.4 kB
#!/usr/bin/env python3
"""
Correlation analysis stage: compute head-head correlation matrices from model weights.
Outputs .npz files per circuit to --out-dir.
Examples:
python scripts/run_correlations.py --model gpt2 --out-dir correlations
python scripts/run_correlations.py --model pythia-70m-deduped --revision step8000 \
--circuits QK OV --out-dir correlations
"""
import argparse
import subprocess
import time
import hashlib
import json
import mlflow
from mlflow.entities import Dataset as DatasetEntity, DatasetInput
from transformer_analysis.pair_pipeline import run_multi_circuit_analysis
def parse_args():
p = argparse.ArgumentParser()
p.add_argument("--model", required=True)
p.add_argument("--revision", default="")
p.add_argument("--out-dir", default="correlations")
p.add_argument("--cache-dir", default="./model_data")
p.add_argument("--circuits", nargs="+", default=["QK"])
p.add_argument("--metrics", nargs="+", default=["frob_cosine", "pearson_corr", "hist_jensen_shannon"])
p.add_argument("--equilibrium", action="store_true", default=False,
help="Also compute QK/OV equilibrium observables per head")
p.add_argument("--device", default=None)
p.add_argument("--max-workers", type=int, default=4)
p.add_argument("--mlflow-uri", default="file:./mlruns")
p.add_argument("--mlflow-experiment", default="production")
return p.parse_args()
def _git_sha():
try:
return subprocess.check_output(["git", "rev-parse", "--short", "HEAD"], text=True).strip()
except Exception:
return "unknown"
def main():
args = parse_args()
revision = args.revision or None
mlflow.set_tracking_uri(args.mlflow_uri)
mlflow.set_experiment(args.mlflow_experiment)
rev_label = revision or "main"
run_name = f"{args.model}-{rev_label}-correlations"
with mlflow.start_run(run_name=run_name):
mlflow.set_tag("mlflow.note.content", "Compute head-head correlation matrices from model weights → .npz")
mlflow.set_tag("model", args.model)
mlflow.log_params({
"model": args.model,
"revision": rev_label,
"circuits": ",".join(args.circuits),
"metrics": ",".join(args.metrics),
"equilibrium": args.equilibrium,
"max_workers": args.max_workers,
"out_dir": args.out_dir,
"git_sha": _git_sha(),
})
t0 = time.time()
run_multi_circuit_analysis(
model_name=args.model,
revision=revision,
circuits=tuple(args.circuits),
metrics=tuple(args.metrics),
equilibrium=args.equilibrium,
cache_dir=args.cache_dir,
out_dir=args.out_dir,
device=args.device,
max_workers=args.max_workers,
)
mlflow.log_metric("wall_time_s", time.time() - t0)
digest = hashlib.md5(args.out_dir.encode()).hexdigest()[:8]
entity = DatasetEntity(
name=f"{args.model}-{rev_label}-correlations",
digest=digest,
source_type="local",
source=json.dumps({"uri": args.out_dir}),
)
mlflow.MlflowClient().log_inputs(
mlflow.active_run().info.run_id,
[DatasetInput(dataset=entity, tags=[])],
)
if __name__ == "__main__":
main()