SabaPivot/repro-logsumexp-artifacts / scripts /claim4_float32_probe.py
SabaPivot's picture
download
raw
3.57 kB
"""Claim 4 add-on: run the BASELINE dual kernel-SGD in single precision (float32) to
exhibit the actual floating-point overflow of Remark 3.1 (eps = 0.01 -> exp overflows
for z >= 0.887 in float32, z >= 7.098 in float64), and record the first non-finite
iteration. The proposed semi-dual is run under identical conditions for contrast.
"""
import json
import math
import os
import sys
from multiprocessing import Pool
import numpy as np
from scipy.special import expit
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from claim4_eot import EPS, sample_mu, sample_nu
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
OUT = os.path.join(ROOT, "outputs")
def run(args):
mode, sigma_sq, C, seed, rho, n_iter, dtype = args
dt = np.float32 if dtype == "float32" else np.float64
rng = np.random.default_rng(seed)
X = sample_mu(rng, n_iter).astype(dt)
Y = sample_nu(rng, n_iter).astype(dt)
c = ((X - Y) ** 2).astype(dt)
coeffs = np.zeros(n_iter, dtype=dt)
alpha = dt(-c[0] / EPS)
log_rho = math.log(rho) if rho else None
first_inf, first_nonfinite = None, None
max_z = -np.inf
for k in range(n_iter):
if k > 0:
ky = np.exp(-((Y[k] - Y[:k]) ** 2) / dt(sigma_sq))
v = dt(ky @ coeffs[:k])
else:
v = dt(0.0)
if mode == "dual":
if k > 0:
kx = np.exp(-((X[k] - X[:k]) ** 2) / dt(sigma_sq))
u = dt(kx @ coeffs[:k])
else:
u = dt(0.0)
z = dt(u + v - c[k]) # the quantity of Remark 3.1
max_z = max(max_z, float(z))
with np.errstate(over="ignore", invalid="ignore"):
e = np.exp(dt(z / EPS))
if not np.isfinite(e) and first_inf is None:
first_inf = k
g = dt(1.0) - e
else:
z = dt((v - c[k]) / EPS) - alpha
max_z = max(max_z, float(z * EPS))
g = dt(1.0 - expit(float(z) + log_rho) / rho)
alpha = dt(alpha + C * (-EPS * g) / math.sqrt(k + 1))
coeffs[k] = dt(C * g / math.sqrt(k + 1))
if not np.isfinite(coeffs[k]) and first_nonfinite is None:
first_nonfinite = k
break
return {
"mode": mode,
"dtype": dtype,
"sigma_sq": sigma_sq,
"C": C,
"seed": seed,
"rho": rho,
"n_iter": n_iter,
"first_exp_inf_iter": first_inf,
"first_nonfinite_coeff_iter": first_nonfinite,
"max_z": max_z,
"float32_overflow_z": 0.8872283554077147,
"float64_overflow_z": 7.09782712893384,
}
if __name__ == "__main__":
n = 20000
tasks = []
for C in [1e-3, 1e-2, 1e-1, 1.0]:
for s in range(3):
tasks.append(("dual", 1.0, C, s, None, n, "float32"))
for C in [1.0, 10.0]:
for s in range(3):
tasks.append(("semidual", 10.0, C, s, 0.1, n, "float32"))
with Pool(18) as pool:
recs = pool.map(run, tasks)
with open(os.path.join(OUT, "claim4_float32_probe.json"), "w") as fh:
json.dump(recs, fh, indent=2)
agg = {}
for r in recs:
key = f"{r['mode']}_C{r['C']}_{r['dtype']}"
agg.setdefault(key, {"overflow_runs": 0, "n": 0, "first_inf": [], "max_z": []})
agg[key]["n"] += 1
agg[key]["overflow_runs"] += int(r["first_exp_inf_iter"] is not None)
agg[key]["first_inf"].append(r["first_exp_inf_iter"])
agg[key]["max_z"].append(round(r["max_z"], 3))
print(json.dumps(agg, indent=1))

Xet Storage Details

Size:
3.57 kB
·
Xet hash:
9c221643844231bc2410027b551297b0920ffc576883199c7f758402d749e151

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