tensorflow / tensorflow/probability

Possible inconsistency in adjoint state initialisation for time-dependent ODEs

Open
#1,318 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Jupyter Notebook
Stars
4.4k
Forks
1.1k
PR merge metrics
No merged PRs in 30d

Description

Hello,

I am currently trying to compute the gradient of the ODE:

The ODE is defined indeed only for . I forged the following minimal code to compute the gradient with respect to :

import tensorflow as tf
import tensorflow_probability as tfp


def f(t, y, p):
    """Right-hand-side of the ODE
    """
    return p*tf.sqrt(t)


# initial state and parameter
y0, t0, p = tf.constant(1, dtype=tf.float64), tf.constant(0, dtype=tf.float64), tf.Variable(0.5, dtype=tf.float64)

with tf.GradientTape() as tape:
    ode_solution = tfp.math.ode.DormandPrince().solve(f, t0, y0, solution_times=[8e-3], constants={'p': p})
    gradients = tape.gradient(ode_solution.states, [p])

print(ode_solution.states, gradients)

This example gets stuck in an infinite loop while computing the gradient, I think because the variable derivatives in math/ode/base.py:374 is not a number (in my case, square root of a negative value), and it does not work with DormandPrince(). Instead, the BDF solver seems to work correctly.

I was trying to debug it, and I noticed that it happens when grad_fn invokes adjoint_solver._initialize_solver_internal_state( ... ) on math/ode/base.py:452; under the hood, it is computing an initial state for the adjoint state integration between lines 459 and 464 of math/ode/base.py. In doing so, it assumes a time for the computation of the augmented ODE, and takes the opposite of the time (in math/ode/base.py:368). I guess that this may break time-dependent ODEs.

Is there a specific reason for this choice of the initial time? Or one can set it to something else anyway?

The BDF solver suffers the same issue, but does not get stuck for some reason. It is apparently able to digest such NaN initial value of the derivative.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the example with DormandPrince and BDF, then inspect math/ode/base.py around lines 368, 374, and 452-464, especially adjoint_solver._initialize_solver_internal_state. Compare the initial derivative and solver behavior for the time-dependent ODE. Done means the reported initialization inconsistency is understood and the affected solver behavior is addressed or clearly documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, tensorflow
Domain
backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.