MachineSex/figures/plot_llm_epistasis.py
Giorgio Gilestro 287d2326cc epistasis_predicts: functional conflict, not weight geometry, predicts merge failure pre-merge
The decisive experiment from the external review. 39 LoRA parent pairs
(0.5B, 3 seeds) on three axes decorrelated by construction: conflict
(contradictory conventions on shared prompts, private budgets fixed),
compat (same prompts, SAME convention — overlap without conflict), and
duration (weight divergence, zero conflict). Six pre-merge predictors;
primary outcome = merge penalty (parent potential − merged achieved).

League table (Spearman vs penalty, n=39): functional measures predict
(dis_raw +0.460, epi_conf +0.446, p<0.005); geometry collapses
(delta_cos +0.03, delta_l2 +0.17 n.s.); gradient alignment weak (−0.35);
performance ~0. The first grid's apparent geometry win (+0.60) was an
overlap/volume artifact — the compat control axis (added for exactly
this) exposed and killed it: same overlap and data volume, zero penalty.
Honest riders in the README: confidence weighting does not beat raw
disagreement as a rank predictor (pre-registered internal prediction not
confirmed; it does double the conflict/compat level contrast), and
|rho|~0.45 is bounded by 0.5B merge-outcome noise (7B is the firm-up).

Also: micro-batched gradient accumulation (OOM fix on the shared 16GB
GPU), exact r-space LoRA-delta geometry (brute-force-verified test,
151 green), systemd-run runbook lesson (tmux dies with the SSH session
scope on this box).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BkRLcc18rwT2Lysu6PbG7v
2026-09-06 17:19:46 +01:00

87 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""The decisive-experiment figure — does pre-merge epistasis predict merge failure?
(A) The theory's predictor: operational epistasis (confidence-weighted bilateral disagreement,
measured before merging) against the merge penalty (parent potential merged achieved, the
hybrid-load analogue). Conflict-axis pairs in red, duration-axis pairs in blue.
(B) The geometry predictor on the same outcome: weight divergence (LoRA-delta L2) — the
matched-divergence contrast: the duration axis spans large weight divergence at ~zero penalty, while
the conflict axis generates penalty at modest divergence. Distance is not what breaks merging.
(C) The league table: |Spearman rho| against the merge penalty for every pre-merge predictor,
including the internal ablation (raw disagreement, which the theory predicts must mislead because it
counts harmless complementation as conflict).
Usage: python figures/plot_llm_epistasis.py
"""
from __future__ import annotations
import sys
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import spearmanr
sys.path.insert(0, str(Path(__file__).parent))
from _figlib import load_bundle, savefig # noqa: E402
PREDICTORS = [("epi_conf", "operational\nepistasis"),
("dis_raw", "raw\ndisagreement"),
("grad_cos", "gradient\nalignment"),
("delta_cos", "delta\ncosine"),
("delta_l2", "delta\nL2"),
("cross_perf", "cross-family\naccuracy")]
OUTCOME = "merge_penalty"
def _scatter(ax, df, xcol, xlabel, title):
for mode, color, marker in (("conflict", "#d62728", "o"), ("duration", "#2c7fb8", "s"),
("compat", "#41ab5d", "^")):
sub = df[df["mode"] == mode]
ax.scatter(sub[xcol], sub[OUTCOME], c=color, marker=marker, s=42, alpha=0.75,
label=f"{mode} axis")
rho, p = spearmanr(df[xcol], df[OUTCOME])
ax.set(xlabel=xlabel, ylabel="merge penalty (parent potential merged)",
title=f"{title}\nSpearman ρ = {rho:.2f} (p = {p:.1g}, n = {len(df)})")
ax.axhline(0, color="#999", lw=0.6)
ax.legend(frameon=False, fontsize=8)
def main() -> None:
import pandas as pd
df, _ = load_bundle("results/llm_epistasis")
try: # the overlap-without-conflict control axis
compat, _ = load_bundle("results/llm_epistasis_compat")
df = pd.concat([df, compat], ignore_index=True)
except Exception:
pass
fig, axes = plt.subplots(1, 3, figsize=(16.5, 4.9))
_scatter(axes[0], df, "epi_conf", "operational epistasis (pre-merge)",
"(A) the theory's predictor")
_scatter(axes[1], df, "delta_cos", "LoRA-delta cosine similarity (pre-merge)",
"(B) the geometry predictor — does it detect\nincompatibility, or just task overlap?")
ax = axes[2]
rhos, labels = [], []
for col, label in PREDICTORS:
rho, _ = spearmanr(df[col], df[OUTCOME])
rhos.append(abs(rho)); labels.append(label)
colors = ["#d62728" if c == "epi_conf" else ("#fc9272" if c == "dis_raw" else "#9ecae1")
for c, _ in PREDICTORS]
x = np.arange(len(rhos))
ax.bar(x, rhos, 0.62, color=colors)
ax.set_xticks(x); ax.set_xticklabels(labels, fontsize=7)
ax.set(ylabel="|Spearman ρ| vs merge penalty", ylim=(0, 1),
title="(C) predictor league table (pre-merge only)")
fig.suptitle("Predicting merge failure BEFORE merging: functional conflict, not weight divergence "
"(conflict, overlap-without-conflict, and divergence decorrelated by construction; 3 seeds)", y=1.03, fontsize=12)
fig.tight_layout()
savefig(fig, "results/llm_epistasis", "llm_epistasis")
if __name__ == "__main__":
main()