summaryrefslogtreecommitdiff
path: root/experiments/plot_contrastive_bias_b1.py
diff options
context:
space:
mode:
authorYurenHao0426 <Blackhao0426@gmail.com>2026-08-06 12:48:41 -0500
committerYurenHao0426 <Blackhao0426@gmail.com>2026-08-06 12:48:41 -0500
commit34aaa2a02baceb9ae2a9821d974eaf8ddde71c9d (patch)
tree726074ed53f45cffd057f7399eac2e724e46f24c /experiments/plot_contrastive_bias_b1.py
parent05591963386af3d5f8ccd348ada45c393a3996d4 (diff)
results: audit Dual Prop state-bias screen
Diffstat (limited to 'experiments/plot_contrastive_bias_b1.py')
-rw-r--r--experiments/plot_contrastive_bias_b1.py80
1 files changed, 80 insertions, 0 deletions
diff --git a/experiments/plot_contrastive_bias_b1.py b/experiments/plot_contrastive_bias_b1.py
new file mode 100644
index 0000000..5fc70d1
--- /dev/null
+++ b/experiments/plot_contrastive_bias_b1.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+"""Plot the audited B1 activity-bias result without rerunning analysis."""
+import argparse
+import json
+from pathlib import Path
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+
+ROOT = Path(__file__).resolve().parents[1]
+DEFAULT_GATE = ROOT / "results" / "contrastive_bias" / "b1_gate.json"
+DEFAULT_OUT = ROOT / "results" / "contrastive_bias" / "b1_summary"
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--gate", type=Path, default=DEFAULT_GATE)
+ parser.add_argument("--out", type=Path, default=DEFAULT_OUT)
+ args = parser.parse_args()
+ with open(args.gate, encoding="utf-8") as handle:
+ report = json.load(handle)
+ rows = report["activity_table"]
+ ratios = np.arange(len(rows))
+ labels = [f"{row['ratio']:g}×" for row in rows]
+ clean = report["clean_final_validation_accuracy"]
+
+ plt.rcParams.update({
+ "font.family": "DejaVu Sans", "font.size": 9,
+ "axes.spines.top": False, "axes.spines.right": False,
+ })
+ figure, axes = plt.subplots(1, 2, figsize=(7.2, 2.65))
+
+ ax = axes[0]
+ ax.axhline(clean, color="#6b747b", linestyle="--", linewidth=1.2,
+ label=f"clean DP: {clean:.2f}")
+ ax.plot(ratios, [row["raw"] for row in rows], "X-", color="#c23b3b",
+ linewidth=1.5, markersize=7, label="raw (nonfinite at epoch 1)")
+ ax.plot(ratios, [row["innovation"] for row in rows], "o-",
+ color="#0878a8", linewidth=1.8, markersize=5, label="innovation")
+ ax.plot(ratios, [row["oracle"] for row in rows], "s-",
+ color="#263640", linewidth=1.5, markersize=4.5, label="oracle")
+ ax.set_xticks(ratios, labels)
+ ax.set_ylim(0, 78)
+ ax.set_xlabel("activity-dependent bias / clean teaching RMS")
+ ax.set_ylabel("final validation accuracy (%)")
+ ax.set_title("a Task result", loc="left", fontweight="bold")
+ ax.legend(frameon=False, fontsize=7.5, loc="lower right")
+
+ ax = axes[1]
+ width = 0.23
+ ax.bar(ratios - width, [1, 1, 1], width, color="#c23b3b", label="raw")
+ ax.bar(ratios, [20, 20, 20], width, color="#0878a8", label="innovation")
+ ax.bar(ratios + width, [20, 20, 20], width, color="#263640", label="oracle")
+ ax.set_xticks(ratios, labels)
+ ax.set_ylim(0, 22)
+ ax.set_yticks((0, 5, 10, 15, 20))
+ ax.set_xlabel("activity-dependent bias / clean teaching RMS")
+ ax.set_ylabel("epochs completed before nonfinite loss")
+ ax.set_title("b Stability", loc="left", fontweight="bold")
+ ax.legend(frameon=False, fontsize=7.5, loc="lower right")
+ ax.text(
+ 0.02, 0.95,
+ "innovation residual bias ≤ 8.96×10⁻⁸\npredictor label observations = 0",
+ transform=ax.transAxes, va="top", fontsize=7.5,
+ )
+
+ figure.suptitle(
+ "Dual Prop under neuron-specific activity bias",
+ x=0.08, ha="left", fontsize=12, fontweight="bold",
+ )
+ figure.tight_layout(rect=(0, 0, 1, 0.94))
+ args.out.parent.mkdir(parents=True, exist_ok=True)
+ figure.savefig(args.out.with_suffix(".pdf"), bbox_inches="tight")
+ figure.savefig(args.out.with_suffix(".png"), dpi=220, bbox_inches="tight")
+ plt.close(figure)
+
+
+if __name__ == "__main__":
+ main()