diff options
| author | haoyuren <13851610112@163.com> | 2026-07-28 07:53:50 +0800 |
|---|---|---|
| committer | haoyuren <13851610112@163.com> | 2026-07-28 07:53:50 +0800 |
| commit | 99b95217a30f75e9e35b5044850ced4ab802bc87 (patch) | |
| tree | 9aca82fc9f9165b6e7585eefe1061956638462aa /scripts/plot_aaai_main_figures.py | |
| parent | e65dd2e2460b1da48c83a930304cf9b269fc4447 (diff) | |
Redesign main figure panels and track figure-source CSVs
Panel 1a: rename to Backward rules; DFA drawn as direct side-to-side
arrows from the error to each hidden layer. Panel 1b: replace the dual
y-axis with stacked guarantee/cost sub-axes. Figure 2: reader-facing
panel titles; legend renames (linear extrapolation, relinearization).
Track the regenerated figure-source CSVs (verified bit-exact against
the frozen paper numbers) so figures can be rebuilt without rerunning
experiments.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'scripts/plot_aaai_main_figures.py')
| -rw-r--r-- | scripts/plot_aaai_main_figures.py | 88 |
1 files changed, 56 insertions, 32 deletions
diff --git a/scripts/plot_aaai_main_figures.py b/scripts/plot_aaai_main_figures.py index cd12011..f0eb0c3 100644 --- a/scripts/plot_aaai_main_figures.py +++ b/scripts/plot_aaai_main_figures.py @@ -46,7 +46,7 @@ def draw_schematic(ax: plt.Axes) -> None: ax.set_xlim(0, 1) ax.set_ylim(0, 1) ax.axis("off") - rows = [(0.82, "BP", "#2f6f9f"), (0.50, "FA", "#c65f16"), (0.18, "DFA", "#2b8a3e")] + rows = [(0.84, "BP", "#2f6f9f"), (0.54, "FA", "#c65f16"), (0.16, "DFA", "#2b8a3e")] x_positions = [0.18, 0.42, 0.66, 0.90] labels = ["$h_1$", "$h_2$", "$h_3$", "error"] for y, name, color in rows: @@ -65,15 +65,21 @@ def draw_schematic(ax: plt.Axes) -> None: ) ax.text((left + right) / 2, y + 0.035, arrow_label, ha="center", fontsize=8) else: + rads = {x_positions[0]: 0.26, x_positions[1]: 0.32, x_positions[2]: 0.0} for left in x_positions[:-1]: ax.annotate( "", - xy=(left + 0.04, y), - xytext=(x_positions[-1] - 0.04, y), - arrowprops=dict(arrowstyle="->", color=color, lw=1.2, alpha=0.9), + xy=(left + 0.045, y), + xytext=(x_positions[-1] - 0.045, y), + arrowprops=dict( + arrowstyle="->", + color=color, + lw=1.4, + connectionstyle=f"arc3,rad={rads[left]}", + ), ) - ax.text(0.56, y + 0.055, "direct random maps", ha="center", fontsize=8) - ax.set_title("Fixed random feedback rules", fontsize=10) + ax.text(0.54, y - 0.145, "direct random maps", ha="center", fontsize=8) + ax.set_title("Backward rules", fontsize=10) def figure_one(args: argparse.Namespace) -> Path: @@ -83,45 +89,58 @@ def figure_one(args: argparse.Namespace) -> Path: theory_rows = read_csv(args.null_dir / "theory_gap_summary.csv") empirical_rows = read_csv(args.null_dir / "empirical_gap_summary.csv") - fig, axes = plt.subplots(1, 3, figsize=(14.2, 4.1), dpi=220) - draw_schematic(axes[0]) - panel_label(axes[0], "a") + fig = plt.figure(figsize=(14.2, 4.7), dpi=220) + gs = fig.add_gridspec(2, 3, height_ratios=[1.0, 1.5], hspace=0.14, wspace=0.28) + ax_schem = fig.add_subplot(gs[:, 0]) + ax_top = fig.add_subplot(gs[0, 1]) + ax_bottom = fig.add_subplot(gs[1, 1], sharex=ax_top) + ax_cal = fig.add_subplot(gs[:, 2]) + + draw_schematic(ax_schem) + panel_label(ax_schem, "a") - ax = axes[1] theory_by_width = {int(row["width"]): float(row["mean"]) for row in theory_rows} empirical_by_width = {int(row["width"]): float(row["mean"]) for row in empirical_rows} widths = sorted(set(theory_by_width) & set(empirical_by_width)) - ax.plot( + + ax_top.plot(widths, [1.0 / (width * width) for width in widths], "k--", lw=1.4, label="$1/D$") + ax_top.set_yscale("log") + ax_top.set_ylabel("guaranteed\nalignment", fontsize=8) + ax_top.grid(alpha=0.16, which="both") + ax_top.legend(fontsize=7, loc="upper right") + ax_top.tick_params(labelbottom=False) + ax_top.set_title("Matrix mismatch is not optimization cost", fontsize=10) + panel_label(ax_top, "b") + + ax_bottom.plot( widths, [theory_by_width[width] for width in widths], "o-", color="#8c6d31", label="random-direction deletion", ) - ax.plot( + ax_bottom.plot( widths, [empirical_by_width[width] for width in widths], "s-", color="#c65f16", label="measured FA cost", ) - ax.set_yscale("log") - ax.set_xlabel("width") - ax.set_ylabel("finite-time loss gap") - ax.grid(alpha=0.16, which="both") - ax2 = ax.twinx() - ax2.plot(widths, [1.0 / (width * width) for width in widths], "k--", lw=1.4, label="$1/D$") - ax2.set_yscale("log") - ax2.set_ylabel("best guaranteed squared alignment") - handles1, labels1 = ax.get_legend_handles_labels() - handles2, labels2 = ax2.get_legend_handles_labels() - ax.legend(handles1 + handles2, labels1 + labels2, fontsize=7, loc="upper right") + ax_bottom.set_yscale("log") + ax_bottom.set_xlabel("width") + ax_bottom.set_ylabel("finite-time loss gap", fontsize=8) + ax_bottom.grid(alpha=0.16, which="both") + ax_bottom.legend(fontsize=7, loc="upper right") worst_ratio = max(theory_by_width[width] / empirical_by_width[width] for width in widths) - ax.text(0.04, 0.05, f"null overestimate: up to {worst_ratio:.0f}×", transform=ax.transAxes, fontsize=8) - ax.set_title("Matrix mismatch is not optimization cost", fontsize=10) - panel_label(ax, "b") + ax_bottom.text( + 0.04, + 0.07, + f"null overestimate: up to {worst_ratio:.0f}×", + transform=ax_bottom.transAxes, + fontsize=8, + ) - ax = axes[2] + ax = ax_cal depths = sorted({int(row["depth"]) for row in init_rows}) cmap = plt.cm.viridis depth_color = {depth: cmap(index / max(len(depths) - 1, 1)) for index, depth in enumerate(depths)} @@ -254,22 +273,27 @@ def figure_two(args: argparse.Namespace) -> Path: ax.errorbar(depths, means, yerr=sems, marker=marker, capsize=2, label=f"width {width}") ax.set_xlabel("hidden-layer depth") ax.set_ylabel("FA loss - BP loss") - ax.set_title("Later cost changes with training dynamics", fontsize=10) + ax.set_title("Finite time cost under a shared training schedule", fontsize=10) ax.grid(alpha=0.16) ax.legend(fontsize=7) panel_label(ax, "a") - scatter_predictor(axes[1], rows, [("fixed_gap", "^", "frozen $K(0)$")], "Frozen initialization misses drift") + scatter_predictor( + axes[1], + rows, + [("fixed_gap", "^", "frozen $K(0)$")], + "Freezing the initialization operators\nmisses their evolution", + ) panel_label(axes[1], "b") scatter_predictor( axes[2], rows, [ - ("velocity_gap", "o", "linear velocity"), - ("retangent_gap", "s", "early retangent"), + ("velocity_gap", "o", "linear extrapolation"), + ("retangent_gap", "s", "relinearization"), ], - "Two snapshots recover the later cost", + "Two operator measurements\nrecover the later cost", ) panel_label(axes[2], "c") |
