Optimizer & LR
Global
Parameter Groups
Assign different optimizers or learning rates to different parameter groups via masks:
net.optimizer(optax.adamw).scale(lrs(1e-3)) # global fallback
net.mask(decoder_mask).optimizer(optax.adam)
net.mask(decoder_mask).scale(lrs(5e-4))
net.mask(encoder_mask).optimizer(optax.sgd)
net.mask(encoder_mask).scale(lrs(1e-4))
mask(...) is consumed by the next mutator call. A bare global optimizer(...) clears all previously configured groups.
LR-Only Updates
During solve(), jNO logs group coverage, overlap, and uncovered-parameter diagnostics.
jno.optimizers — custom second-order optimizers
jno.optimizers holds only custom optimizers that aren't in optax; for chain, learning-rate
schedules and gradient clipping use optax directly. Each is an optax GradientTransformation, so it
composes with optax.chain and drops straight into .optimizer(...).
import optax, jno
k.optimizer(jno.optimizers.ssbroyden()) # 2nd-order; far fewer steps than Adam on inverse/PINN losses
k.optimizer(jno.optimizers.soap(learning_rate=3e-3))
k.optimizer(optax.chain( # compose with optax directly
optax.clip_by_global_norm(1.0),
jno.optimizers.ssbfgs(),
))
| Optimizer | What it is | Reference |
|---|---|---|
ssbroyden() / ssbfgs() |
Self-Scaled Broyden / BFGS quasi-Newton with a zoom line search — strong on smooth PINN / inverse losses | Urbán, Stefanou & Pons, Unveiling the optimization process of PINNs, J. Comput. Phys. 523 (2025) 113656 |
soap() / scale_by_soap() |
SOAP — Shampoo with Adam in the preconditioner's eigenbasis | Vyas et al., SOAP: Improving and Stabilizing Shampoo using Adam (2024), arXiv:2409.11321 |
Add your own: drop an optax-compatible GradientTransformation into a new module under
jno/optimizers/ and re-export it from jno/optimizers/__init__.py — it then works everywhere an
optax optimizer does.