patrick-kidger / patrick-kidger/optimistix
Zero implicit gradients when using `ImplicitAdjoint` with CG solver
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 623
- Forks
- 54
- PR merge metrics
- No merged PRs in 30d
Description
Hi @patrick-kidger and @packquickly,
I was trying to implement the following meta-learning example from jax-opt in optimistix: Few-shot Adaptation with Model Agnostic Meta-Learning . However, I ran into an issue with implicit differentiation through the inner loop. The below example runs well when using optx.RecursiveCheckpointAdjoint but when I try to recreate the iMAML setup by putting optx.ImplicitAdjoint with a CG solver with 20 steps, all the meta-gradients are zero, and the meta-optimiser doesn't change at all in the training. Could you please help me identify the issue with the code? It seems to be an implementation detail for implicit adjoints that differs between jax-opt and optimistic.
Here is an MWE:
import optimistix as optx
import equinox as eqx
import lineax as lx
import jax
import jax.random as jr
import jax.numpy as jnp
import optax
key = jr.PRNGKey(0)
model = eqx.nn.MLP(1, 1, 40, 2, key=key)
sine_target = lambda x: 1.0 * jnp.sin(x - 0.5) # Target function
x = jr.normal(key, (10, 1)) # Randomly drawn inputs for validation
y_true = sine_target(x)
opt = optx.OptaxMinimiser(optax.adam(1e-3, eps_root=1e-8), 1e-7, 1e-7)
params, static = eqx.partition(model, eqx.is_inexact_array)
def apply_model(params, x):
model = eqx.combine(params, static)
return jax.vmap(model)(x)
def loss_fn(params, args):
y_pred = apply_model(params, x)
loss = jnp.mean(jnp.square(y_pred - y_true))
return loss, loss
def adapt_fn(params):
sol = optx.minimise(loss_fn,
opt,
params,
None,
has_aux=True,
max_steps=2,
throw=False,
adjoint=optx.ImplicitAdjoint(lx.CG(1e-7, 1e-7, max_steps=10)),
tags=lx.positive_semidefinite_tag)
return sol.aux # Return the final loss only
loss, grad = jax.value_and_grad(adapt_fn)(params)
print(f"Final loss: {loss:.5f}")
print(f"Gradient: {grad.layers[0].weight}")
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the provided MWE and tracing adapt_fn through ImplicitAdjoint with lx.CG. Compare that path with RecursiveCheckpointAdjoint and the referenced jax-opt MAML example. Done means the implicit-adjoint run produces nonzero meta-gradients and the meta-optimiser can update parameters.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- machine-learning
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100