Differentiable Planning › Backpropagation Through Dynamics
World Models HandbookAll chapters Differentiable Planning › Backpropagation Through DynamicsOne section · Sections in this chapter2 / 10 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
The previous chapter used , , , , , and . Here we keep , , and , but write the state as to emphasize that it may be latent, and write the stage and terminal costs as and . Thus corresponds to the previous chapter's , while and correspond to and .
We work with a deterministic, differentiable dynamics model
where is the model state: it may be a fully observed physical configuration, a latent or belief state, or an observation when that observation is sufficient for the modeled transition. The action is continuous. The initial state is given and fixed. Over a horizon of transitions we accumulate the cost
where is the stage cost at time and is an optional terminal cost. The actions are the inputs to a recurrence, and is a scalar function of those inputs. This is exactly the structure of a recurrent neural network unrolled over time, except that we are differentiating with respect to the inputs rather than the weights.
In Recurrent State-Space Models we differentiated the loss with respect to model parameters to train the model. Here the model is frozen and we differentiate with respect to the action sequence to use the model. Both calculations apply the same reverse-mode chain rule to an unrolled graph. Parameter gradients accumulate across repeated uses of shared weights, while each action has its own time-indexed gradient. Technically, this is BPTT through the unrolled model with the model parameters held fixed and the time-indexed actions treated as differentiation variables.
To make the chain rule concrete, trace the computational paths from one action . It has a direct path to the stage cost and a path through the next state to later states and costs. The corresponding derivatives can still be zero: the cost may be locally flat, the action Jacobian may vanish, or later dynamics may erase the perturbation. The structural point is that a current action can contribute directly to the present cost and indirectly to future costs through the intervening transitions.
Define the state Jacobian and action Jacobian at time as
The sensitivity of a future state to a past action is then a product of state Jacobians:
Read this product from right to left: the action perturbs through , and each subsequent Jacobian transforms that perturbation. A subsequent Jacobian may mix or rotate directions and may shear a neighborhood of perturbations. Whether it amplifies or attenuates a particular perturbation depends on that direction and the chosen norm. If all relevant have operator norm at most a common , the sensitivity decays at least geometrically with separation. Growth requires corresponding expansion along the propagated directions; an operator norm above one alone does not guarantee it.
The adjoint recursion
Computing every action gradient by expanding its Jacobian products separately would repeat shared factors. For example, the state sensitivities and share the same suffix. A naive scalar implementation that forms each horizon-length product independently performs transition multiplications; one backward sweep performs . The adjoint (co-state) recursion is reverse-mode autodiff organized to reuse those suffixes.
Define the adjoint vector
interpreted as a column vector. The adjoint is a sensitivity of the objective to the state: it says how much the total cost would change if we could nudge directly. Because feeds into every later state and cost through the dynamics, this sensitivity already accumulates everything that happens downstream of time . At the end of the horizon the adjoint is just the terminal cost gradient:
Now walk backwards. The state influences the objective in exactly two ways: through the stage cost , and through the next state , whose adjoint we already have. The chain rule gives
The transpose appears because depends on through , and is a column vector. Under the local linearization, . Pulling a gradient back through the transition therefore multiplies by , converting next-state sensitivity into current-state sensitivity. For this discrete recurrence, the recursion is exactly the BPTT backward pass. It is the discrete-time analogue of the continuous ODE adjoint, which instead satisfies a backward differential equation; differentiating a chosen ODE discretization produces a discrete adjoint whose details depend on that discretization.
The action gradient then follows immediately. The action enters the objective only through and through :
where:
- : the direct sensitivity of the stage cost at time to the action taken at time
- : the action Jacobian, mapping an action perturbation into a next-state perturbation
- : the adjoint of the next state, which aggregates the sensitivity of every future cost
One backward sweep computes and every action gradient. Its arithmetic cost is a small constant multiple of the forward evaluation. A standard uncheckpointed implementation uses activation memory when per-step size is fixed; it retains the local information needed for the pullbacks, not necessarily explicit Jacobian matrices. Autodiff computes vector-Jacobian products such as and directly. Checkpointing or recomputation can reduce retained activations at additional compute cost.
The next two cells compute and plot analytic scalar multiplication counts for two organizations of the same action-sensitivity calculation. They do not benchmark Python exponentiation. Independently forming by repeated multiplication uses multiplications by . With the terminal seed available, the adjoint sweep needs multiplications to produce ; together, are the adjoints required by all action gradients.
import numpy as np
import torch
np.random.seed(0)
torch.manual_seed(0)
## Scalar linear system z_{t+1} = rho * z_t + a_t with a quadratic terminal cost,
## chosen so the exact adjoint recursion reduces to scalar multiplications with
## constant Jacobian F_t = rho and a simple terminal seed.
adjoint_rho = 0.93
adjoint_horizon = 200
## Forward rollout capturing intermediate states. The constant scalar Jacobian
## F_t = rho is stored separately in adjoint_rho and used by the backward sweep.
adjoint_a = torch.zeros(adjoint_horizon, requires_grad=True)
adjoint_states = [torch.tensor(0.0)]
for t in range(adjoint_horizon):
adjoint_states.append(adjoint_rho * adjoint_states[-1] + adjoint_a[t])
## Terminal cost gradient d c_H / d z_H with c_H(z) = (z - 1)^2.
adjoint_terminal_grad = 2.0 * (adjoint_states[-1] - 1.0).item()
## Matched adjoint sweep: lambda_H fixed, then form lambda_{H-1}, ..., lambda_1.
adjoint_lambda = adjoint_terminal_grad
adjoint_lambdas = [adjoint_lambda]
for t in range(adjoint_horizon - 1, 0, -1):
adjoint_lambda = adjoint_rho * adjoint_lambda
adjoint_lambdas.append(adjoint_lambda)
adjoint_lambdas = adjoint_lambdas[::-1] # lambda_1 ... lambda_H
## Direct per-action Jacobian products without reuse: sensitivities rho^{H-1-t}.
direct_products = np.array(
[adjoint_rho ** (adjoint_horizon - 1 - t) for t in range(adjoint_horizon)]
)
## These magnitudes are unused by the count plot. At sufficiently long horizons,
## direct_products may underflow.
## Count the scalar multiplications required by each strategy for the same horizon.
adjoint_sweep_ops = adjoint_horizon - 1
direct_product_ops = adjoint_horizon * (adjoint_horizon - 1) // 2
## Analytic count of multiplications by rho for the two organizations.
print(f"Adjoint sweep multiply count : {adjoint_sweep_ops}")
print(f"Direct product multiply count: {direct_product_ops}")
print(
f"Shared suffix factors reused : {direct_product_ops - adjoint_sweep_ops}"
)
This is the cheap gradient principle: reverse mode computes a full action gradient at a small constant multiple of one scalar objective evaluation, whereas coordinate-wise finite differences require one or more extra evaluations per action coordinate. This evaluation-cost asymmetry is one important reason differentiable planning is attractive in high dimensions. Directional and simultaneous-perturbation estimators have different tradeoffs, so the comparison here is specifically with coordinate-wise finite differences.
Unrolling the recursion
Substituting the adjoint recursion into itself gives the explicit form
and therefore
Every indirect future-cost contribution contains an action Jacobian and a possibly empty product of state-Jacobian transposes applied to a cost gradient. This formula motivates the stability analysis below, and it explains a subtlety that is easy to miss: the gradient with respect to an early action is a sum of many terms, one for each future cost, each weighted by a generally different, time-indexed Jacobian product. Terms can reinforce or cancel. A vanishing product for one future step does not necessarily mean the total gradient vanishes. Conversely, a single large product term can dominate the sum even when the surrounding terms are small, which is one reason the gradient profile across actions can look erratic in practice.
What breaks differentiability
Ordinary reverse mode needs a valid local pullback for every operation on the executed path. At a switch, an autodiff implementation may select a branch or subgradient convention; a planner may instead install a surrogate or custom pullback; and some operations provide no useful derivative. Backpropagation-based planners therefore need a usable sensitivity route for the optimized path: ordinary pullbacks, event-aware or implicit sensitivities, a relaxation or surrogate, or an estimator. Otherwise they must bypass or search the hard component separately.
- Contact and collision. Rigid-contact dynamics are often smooth within a fixed mode but hybrid across impacts. Classical derivatives can jump or fail to exist when contact timing or the active mode changes, while event-aware sensitivities can be valid away from grazing and other degenerate events. Compliant differentiable contact laws or relaxed complementarity conditions can smooth selected transitions, but they change the physical model and do not automatically smooth friction or contact activation. Another local approximation differentiates the active branch while holding the contact set fixed. This is locally exact only while perturbations preserve the full contact and friction mode; across a mode change it omits event sensitivity, although an optimizer may still use it heuristically.
- Discrete actions and argmax operations. With a one-hot encoding, hard has zero Jacobian away from ties and is nondifferentiable at ties, so it supplies no informative ordinary pathwise gradient for changing the selected category. A temperature-softmax relaxes a deterministic argmax; for categorical sampling, Gumbel-softmax relaxes the one-hot Gumbel-max sample. A straight-through estimator keeps the hard forward value but substitutes a surrogate backward derivative. These introduce approximation choices. For background on discrete and latent action representations, see Actions, Inverse Dynamics, and Latent Actions.
- Stochastic dynamics. A sample does not automatically provide a pathwise derivative with respect to the action. For a reparameterizable continuous distribution, write the sample as a deterministic function of the action and independent noise, for example with . Holding the sampled noise fixed then gives a pathwise gradient for a Monte Carlo objective. When reparameterization is unavailable, differentiating yields the ordinary term plus the likelihood-ratio term , provided differentiation can be interchanged with integration and the required terms are integrable. The likelihood-ratio term also requires action-independent support or vanishing boundary contributions; nonzero boundary terms from action-dependent support need a separate valid estimator. If the score itself is estimated, its conditional expectation given must equal the true score, or the weighted term must otherwise be jointly unbiased. Score-function estimators often have high variance. See Stochasticity and Uncertainty for the probabilistic background.
- Rendering and perception. At fixed inputs and parameters, a differentiable deterministic image encoder defines a repeatable mathematical gradient, although it may be expensive or badly scaled. Implementation-level repeatability additionally requires deterministic forward and backward kernels in a fixed software and hardware environment. Stochastic rendering, noisy observations, and sampled layers can add gradient variance. Surrogate derivatives can add bias or mismatch; randomized surrogates can also add variance. Hard thresholding, such as a binarized mask or hard attention selection, needs a relaxation, estimator, or custom pullback.
Simulation systems such as DiffTaichi and the published Brax physics engine provide automatic differentiation for substantial parts of a physics computation. So do MJX-JAX and supported NVIDIA Warp kernels. Coverage is backend- and feature-dependent: current MJX-Warp is not differentiable, and contact smoothness depends on the chosen formulation and settings. Planning by backpropagation may instead use analytical dynamics, a learned model, event-aware sensitivities, or an implicitly differentiated solver.