Skip to content

Commit 39474cc

Browse files
committed
perf: this one is better
1 parent 401a586 commit 39474cc

3 files changed

Lines changed: 968 additions & 47 deletions

File tree

dev/notebooks/psuedo_pade_utils.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import warnings
2+
3+
import jax
4+
import jax.scipy.optimize as jspop
5+
import numpy as np
6+
import optax
7+
import scipy.optimize as spop
8+
import tqdm
9+
10+
11+
def min_optax(
12+
fun,
13+
x0,
14+
args=None,
15+
maxiter=100_000,
16+
learning_rate=1e-1,
17+
method="adan",
18+
optimizer=None,
19+
opt_state=None,
20+
update_prog_iter=100,
21+
):
22+
args = args or tuple()
23+
_vag_fun = jax.jit(jax.value_and_grad(fun))
24+
25+
if optimizer is None:
26+
optimizer = getattr(optax, method)(learning_rate)
27+
opt_state = optimizer.init(x0)
28+
29+
@jax.jit
30+
def _update_func(coeffs, opt_state):
31+
loss, grads = _vag_fun(coeffs, *args)
32+
updates, opt_state = optimizer.update(grads, opt_state, params=coeffs)
33+
coeffs = optax.apply_updates(coeffs, updates)
34+
return coeffs, opt_state, loss
35+
36+
loss, _ = _vag_fun(x0, *args)
37+
38+
prev_loss = loss
39+
coeffs = x0
40+
41+
loss = fun(coeffs, *args)
42+
initial_desc = f"{method}: {loss:12.8e} ({np.nan:+9.2e} delta)"
43+
44+
with tqdm.trange(maxiter, desc=initial_desc) as pbar:
45+
for i in pbar:
46+
coeffs, opt_state, loss = _update_func(coeffs, opt_state)
47+
48+
if i % update_prog_iter == 0 or i == 0:
49+
if prev_loss is not None:
50+
dloss = loss - prev_loss
51+
else:
52+
dloss = np.nan
53+
54+
pbar.set_description(f"{method}: {loss:12.8e} ({dloss:+9.2e} delta)")
55+
56+
prev_loss = loss
57+
58+
return coeffs, (optimizer, opt_state)
59+
60+
61+
def min_bfgs(
62+
fun,
63+
x0,
64+
args=None,
65+
maxiter=100,
66+
use_scipy=False,
67+
maxiter_per_bfgs_call=None,
68+
tol=None,
69+
method="BFGS",
70+
):
71+
args = args or tuple()
72+
jac = jax.jit(jax.grad(fun))
73+
hess = jax.jit(jax.hessian(fun))
74+
75+
coeffs = x0
76+
prev_loss = None
77+
if tol is None:
78+
tol = 1e-32 if use_scipy else 1e-16
79+
if maxiter_per_bfgs_call is None:
80+
maxiter_per_bfgs_call = 100_000 if use_scipy else 1000
81+
82+
loss = fun(coeffs, *args)
83+
initial_desc = f"{method}: {loss:12.8e} ({np.nan:+9.2e} delta, status {-1}, nit {0:6d})"
84+
85+
with tqdm.trange(maxiter, desc=initial_desc) as pbar:
86+
for _ in pbar:
87+
if use_scipy:
88+
with warnings.catch_warnings():
89+
warnings.filterwarnings("ignore", message=".*Unknown solver options.*")
90+
warnings.filterwarnings("ignore", message=".*does not use Hessian information.*")
91+
warnings.filterwarnings("ignore", message=".*does not use gradient information.*")
92+
res = spop.minimize(
93+
fun,
94+
coeffs,
95+
method=method,
96+
args=args,
97+
jac=jac,
98+
hess=hess,
99+
tol=tol,
100+
options={
101+
"maxiter": maxiter_per_bfgs_call,
102+
"gtol": tol,
103+
"xatol": tol,
104+
"fatol": tol,
105+
"adaptive": True,
106+
},
107+
)
108+
else:
109+
res = jspop.minimize(
110+
fun,
111+
coeffs,
112+
method="BFGS",
113+
args=args,
114+
tol=tol,
115+
options={"maxiter": maxiter_per_bfgs_call, "gtol": tol, "line_search_maxiter": 40},
116+
)
117+
118+
if np.all(coeffs == res.x):
119+
coeffs = coeffs * (1.0 + (np.random.uniform(size=coeffs.shape[0]) - 0.5) * 1e-10)
120+
else:
121+
coeffs = res.x
122+
123+
if prev_loss is not None:
124+
dloss = res.fun - prev_loss
125+
else:
126+
dloss = np.nan
127+
128+
prev_loss = res.fun
129+
130+
pbar.set_description(
131+
f"{method}: {res.fun:12.8e} ({dloss:+9.2e} delta, status {res.status}, nit {res.nit:6d})"
132+
)
133+
134+
return res.x

0 commit comments

Comments
 (0)