aura-optax
AURA (Angular Update Rate Adaptation) for Optax.
AURA scales the update direction of a base optimizer by a per-parameter multiplier γ, which increases when consecutive directions agree in the complex plane and decreases when they do not. It is designed for complex-valued neural networks and applies to real-valued parameters as well. The package provides three optax.GradientTransformations:
aura_optax.scale_by_aura: AURA's multiplier alone, to be chained after the direction of any Optax optimizer;aura_optax.adam_aura: the Adam direction, scaled by AURA's multiplier, with decoupled weight decay;aura_optax.muon_aura: the Muon direction on weight matrices and the Adam direction on all other parameters, scaled by AURA's multiplier, with decoupled weight decay.
Installation
pip install aura-optax
The package requires Python ≥ 3.10, JAX and Optax ≥ 0.2.7. For GPU support, install the JAX build for your platform first, following the JAX installation guide.
Usage
scale_by_aura is a gradient transformation that multiplies each update by γ. It is placed in an optax.chain after the transformation that produces the direction (optax.scale_by_adam, optax.contrib.scale_by_muon, ...) and before the learning rate:
import optax
import aura_optax
optimizer = optax.chain(
optax.scale_by_adam(), # the direction of any Optax optimizer
aura_optax.scale_by_aura(), # AURA's multiplier
optax.add_decayed_weights(1e-4), # optional decoupled weight decay
optax.scale_by_learning_rate(1e-2),
)
The complete training loop below fits a complex-valued linear model by least squares with this optimizer:
import jax
import jax.numpy as jnp
import optax
import aura_optax
key_x, key_w, key_b, key_init = jax.random.split(jax.random.key(0), 4)
x = jax.random.normal(key_x, (256, 8), dtype=jnp.complex64)
y = (
x @ jax.random.normal(key_w, (4, 8), dtype=jnp.complex64).T
+ jax.random.normal(key_b, (4,), dtype=jnp.complex64)
)
params = {
"w": 0.1 * jax.random.normal(key_init, (4, 8), dtype=jnp.complex64),
"b": jnp.zeros(4, dtype=jnp.complex64),
}
def loss_fn(params):
residual = x @ params["w"].T + params["b"] - y
return jnp.mean(jnp.real(residual * jnp.conj(residual)))
optimizer = optax.chain(
optax.scale_by_adam(),
aura_optax.scale_by_aura(),
optax.add_decayed_weights(1e-4),
optax.scale_by_learning_rate(1e-2),
)
opt_state = optimizer.init(params)
@jax.jit
def train_step(params, opt_state):
loss, grads = jax.value_and_grad(loss_fn)(params)
grads = jax.tree.map(jnp.conj, grads) # see the note below
updates, opt_state = optimizer.update(grads, opt_state, params)
return optax.apply_updates(params, updates), opt_state, loss
for step in range(1000):
params, opt_state, loss = train_step(params, opt_state)
print(f"final loss: {loss:.3e}")
Complex gradients. For a real-valued loss L of complex parameters w = x + iy, jax.grad returns ∂L/∂x − i ∂L/∂y, which is the complex conjugate of the gradient g = ∂L/∂x + i ∂L/∂y whose negative is the steepest-descent direction. The gradients must therefore be conjugated before optimizer.update, as in the example above. The same conjugation is required by every Optax optimizer applied to complex parameters, and it leaves real-valued parameters unchanged.
Ready-made optimizers. adam_aura is the chain above; muon_aura applies AURA to the Muon direction on the 2-D parameters and to the Adam direction on all others, with its own gate values. Both take the learning rate as a scalar or an Optax schedule:
optimizer = aura_optax.adam_aura(learning_rate=1e-2)
optimizer = aura_optax.muon_aura(learning_rate=1e-2)
Monitoring the multiplier. AURA's state is the entry of opt_state at the position of scale_by_aura in the chain: opt_state[1] in the chain above and in adam_aura, opt_state[2] in muon_aura:
gamma = opt_state[1].multiplier # same tree structure as params
Method
TODO
License
MIT; see LICENSE.
Metadata
Release files for aura-optax 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| aura_optax-0.1.0.tar.gz | 7.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aura_optax-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 14.8 kB
Release files / aura_optax-0.1.0.tar.gz
| Download URL | aura_optax-0.1.0.tar.gz |
|---|---|
| Size | 7.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8b48e87fd8ce114b6efa866918fd3303f56fde7b614d2df3ab2d4c63ef465a63
|
|
BLAKE2b-256 checksum How to use checksums |
d32d5c83dc9ab58f0e40fed0ca28718b326780780701d44b38a785c58f388ebf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / aura_optax-0.1.0-py3-none-any.whl
| Download URL | aura_optax-0.1.0-py3-none-any.whl |
|---|---|
| Size | 7.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1329419e772ef669c2e64187ab0aea7cd496331c6af9493856a008f673ebe654
|
|
BLAKE2b-256 checksum How to use checksums |
16b7f5a48b5fbcd9feaab315f5c725aaa509c40cb43fb20d39aa8e683bfb62c2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for aura-optax 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.