SabaPivot's picture
download
raw
6.73 kB
"""Figures for the reproduction poster / logbook."""
import json
import os
import sys
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt # noqa: E402
import numpy as np # noqa: E402
HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(HERE, "..", "outputs")
FIG = os.path.join(HERE, "..", "figs")
os.makedirs(FIG, exist_ok=True)
ACC = "#B5453C"
ACC2 = "#1F4E79"
GREY = "#6B7280"
plt.rcParams.update(
{
"font.size": 11,
"axes.grid": True,
"grid.alpha": 0.25,
"axes.spines.top": False,
"axes.spines.right": False,
"figure.dpi": 190,
"savefig.bbox": "tight",
}
)
def load(n):
with open(os.path.join(OUT, n)) as f:
return json.load(f)
# ---------------------------------------------------------------- fig 1
def fig_mechanism():
fig, ax = plt.subplots(figsize=(7.4, 3.5))
ax.axis("off")
ax.set_xlim(0, 10)
ax.set_ylim(0, 6)
ax.text(
5,
5.6,
"one +C / -C unit pair, two accumulation orders",
ha="center",
fontsize=13,
fontweight="bold",
color="#111827",
)
def chain(y, items, colour, label):
ax.text(0.15, y + 0.62, label, fontsize=11, fontweight="bold", color=colour)
x = 0.4
for i, (txt, res) in enumerate(items):
ax.add_patch(
plt.Rectangle(
(x, y - 0.32), 1.75, 0.72, fc="white", ec=colour, lw=1.6, zorder=2
)
)
ax.text(x + 0.875, y + 0.19, txt, ha="center", fontsize=10.5, zorder=3)
ax.text(
x + 0.875,
y - 0.16,
res,
ha="center",
fontsize=10.5,
color=colour,
fontweight="bold",
zorder=3,
)
if i < len(items) - 1:
ax.annotate(
"",
xy=(x + 2.05, y + 0.04),
xytext=(x + 1.78, y + 0.04),
arrowprops=dict(arrowstyle="->", color=GREY, lw=1.4),
)
x += 2.3
chain(
3.4,
[
("start", "t"),
("(+) C", "C (t lost)"),
("(-) C", "0"),
("(+) u", "u"),
],
ACC,
"AD accumulation of grad(x)",
)
chain(
1.1,
[("start", "0"), ("(+) C", "C"), ("(-) C", "0"), ("(+) v", "v")],
ACC2,
"forward accumulation",
)
ax.text(
5,
0.05,
"identical units, opposite downstream weights: the pair is invisible to f "
"and lethal to D",
ha="center",
fontsize=10.5,
color="#374151",
style="italic",
)
fig.savefig(os.path.join(FIG, "fig1_mechanism.png"))
plt.close(fig)
# ---------------------------------------------------------------- fig 2
def fig_exactness():
rows = load("claim12_theorem31.json")
acts = ["relu", "elu", "gelu", "swish", "sigmoid", "tanh"]
dts = ["float32", "float64"]
M = np.zeros((2, 6))
for r in rows:
M[dts.index(r["dtype"]), acts.index(r["activation"])] += (
r["value_mismatches"] + r["grad_mismatches"]
)
fig, ax = plt.subplots(figsize=(7.4, 2.5))
ax.imshow(M, cmap="Greens_r", vmin=0, vmax=1, aspect="auto")
for i in range(2):
for j in range(6):
ax.text(
j,
i,
"0",
ha="center",
va="center",
fontsize=15,
fontweight="bold",
color="#14532d",
)
ax.set_xticks(range(6))
ax.set_xticklabels(["ReLU", "ELU", "GELU", "Swish", "Sigmoid", "tanh"])
ax.set_yticks(range(2))
ax.set_yticklabels(["binary32", "binary64"])
ax.set_title(
"Theorem 3.1, L = 9: mismatches out of 33 domain points x 3 seeds\n"
"(value AND gradient, bit-exact)",
fontsize=11.5,
)
ax.grid(False)
fig.savefig(os.path.join(FIG, "fig2_exactness.png"))
plt.close(fig)
# ---------------------------------------------------------------- fig 3
def fig_lemma34_boundary():
rows = [r for r in load("claim4_lemma34.json") if r["dtype"] == "float32"]
acts = [r["activation"] for r in rows]
ok = [np.log2(r["largest_abs_y_still_suppressed"]) for r in rows]
leak = [np.log2(r["smallest_abs_y_that_leaks"]) for r in rows]
x = np.arange(len(acts))
fig, ax = plt.subplots(figsize=(7.4, 3.1))
ax.bar(x - 0.19, ok, 0.38, color=ACC2, label="largest |y| still fully suppressed")
ax.bar(x + 0.19, leak, 0.38, color=ACC, label="smallest |y| that leaks")
ax.axhline(127, ls="--", color=GREY, lw=1.2)
ax.text(
len(acts) - 0.5, 122, "$\\Omega = 2^{128}$", ha="right", fontsize=10, color=GREY
)
ax.set_xticks(x)
ax.set_xticklabels(
[a.upper() if a in ("relu", "elu") else a.capitalize() for a in acts]
)
ax.set_ylabel("$\\log_2 |y|$")
ax.set_title(
"Lemma 3.4 (binary32): input-gradient range over which the AD\n"
"gradient is exactly 0 while f = f* stays bit-exact",
fontsize=11.5,
)
ax.legend(fontsize=9.5, loc="upper left")
fig.savefig(os.path.join(FIG, "fig3_lemma34_range.png"))
plt.close(fig)
# ---------------------------------------------------------------- fig 4
def fig_thm32():
try:
d = load("claim3_theorem32.json")["y_dependent_gradient"]
except Exception:
return
ch = [c for c in d["checks"] if c["y"] > 0]
ys = np.array([c["y"] for c in ch])
gs = np.array([abs(c["got"]) for c in ch])
order = np.argsort(ys)
ys, gs = ys[order], gs[order]
fig, ax = plt.subplots(figsize=(7.4, 3.3))
ax.loglog(
ys,
gs,
"o-",
color=ACC,
lw=1.8,
ms=5,
label="IEEE-754 AD gradient $|D_{f,x}(y)|$",
)
ref = gs[0] * ys / ys[0]
ax.loglog(
ys,
ref,
"--",
color=ACC2,
lw=1.8,
label="exact real arithmetic (chain rule): $\\propto y$",
)
ax.set_xlabel("input gradient $y = \\varphi'_x(f(x))$")
ax.set_ylabel("$|D_{f,x}(y)|$")
ax.set_title(
"Theorem 3.2: one network, gradient prescribed on 24 bands\n"
"f(x) = 0 everywhere; $|D/y|$ spans "
f"{d['ratio_spread_orders']:.1f} orders of magnitude",
fontsize=11.5,
)
ax.legend(fontsize=9.5)
fig.savefig(os.path.join(FIG, "fig4_thm32.png"))
plt.close(fig)
if __name__ == "__main__":
fig_mechanism()
fig_exactness()
fig_lemma34_boundary()
fig_thm32()
print("figures:", sorted(os.listdir(FIG)))

Xet Storage Details

Size:
6.73 kB
·
Xet hash:
b20d87875fd692c644e6398550edc180664b7cc07360cf3d9bb5a93963042c9c

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.