Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Gradients

Gradients helps differentiate through GTSAM, for example to learn factor parameters from a loss evaluated on optimized estimates. The application provides loss derivatives on the estimates, and parameterized factors provide derivatives of their raw factor residuals. Gradients combines these to return a loss gradient for a requested parameter vector, including the noise weighting.

Two noisy observations provide a worked example of learning an observation parameter. The Python tutorial extends the workflow to odometry calibration and a training update. The mathematical derivation is in the final advanced section.

The PyTorch tutorial trains a small MLP through several factor graphs using raw factor VJPs.

Open In Colab

Identifying a parameter

A ParameterTag identifies one application-owned parameter vector. Create the tag once and use it in both the factors and the gradient query. The tag holds no parameter values, dimensions, or factor registrations; the values can be ordinary NumPy arrays or belong to an automatic-differentiation library.

Each new tag has a distinct identity, even if its display name matches another tag’s name. Copying a tag preserves its identity and keeps it alive. Python equality and dictionary lookup compare that shared identity.

A factor with a parameter

Two noisy observations constrain a scalar state xx: the learnable observation z0=1z_0=1 and the fixed observation z1=3z_1=3. Their standard deviations are σ0=1\sigma_0=1 and σ1=2\sigma_1=2. The raw factor residual for observation ii is ei=x−zie_i=x-z_i; GTSAM applies the noise model to obtain the whitened factor residual ri=ei/σir_i=e_i/\sigma_i.

A Python CustomFactor supplies the raw factor residual and its state Jacobian in its usual error callback. Its optional fourth constructor argument supplies a vector–Jacobian product (VJP) for a requested parameter: multiply the transpose of the raw factor residual’s parameter Jacobian by the supplied vector. That supplied vector is called a factor residual cotangent; it describes how the loss changes with a raw factor residual change.

Here ∂e0/∂z0=−1\partial e_0/\partial z_0=-1, so the VJP returns the negative of its input. Gradients has already accounted for noise weighting and the effect of re-solving the graph. Return None for any tag the factor does not recognize. The solved state and supplied cotangent stay fixed during this calculation.

Solved x: 1.400000

The parameter loss gradient

The loss L(x)=xL(x)=x has derivative dL/dx=1dL/dx=1 at the optimized value x⋆=1.4x^\star=1.4. Supply that derivative in a VectorValues, which associates each vector with its state key. These loss derivatives are called state cotangents in the API. Omitted state keys have zero loss derivative; a squared-error loss 12∥x−target∥2\tfrac12\|x-\mathrm{target}\|^2 would instead supply x−targetx-\mathrm{target}.

parameterGradient asks every active factor for its contribution to the requested tag and sums the returned vectors. Ordinary factors and custom factors without a parameter callback declare no parameter dependencies. They still influence the optimized state and its derivative.

Loss gradient for the observation: [0.8]

Increasing the first observation increases the estimate, and hence this loss, by approximately 0.8 times the observation change. An unrecognized tag returns None, whereas a recognized parameter with zero gradient returns an explicit zero vector. All participating factors must return finite, nonempty vectors of the same dimension for a given tag.

Several factors can recognize the same tag, and one factor can recognize several tags by branching in its callback. Query each parameter separately to choose which blocks to train. Each query reuses the factorization and performs one adjoint calculation; no factor list or parameter registration is needed.

Parameter updates and automatic differentiation

A training step adds any direct parameter dependence of the loss to parameterGradient’s result. For a parameter vector θ\theta and penalty weight α\alpha, a penalty 12α∥θ∥2\tfrac12\alpha\|\theta\|^2 contributes αθ\alpha\theta in addition to the derivative through the optimized states. The odometry tutorial computes both contributions and performs an update.

An automatic-differentiation library can implement parameterVjp by differentiating the dot product of the supplied cotangent and the raw factor residual with respect to the requested parameter. Treat the solved states and the cotangent as constants, or detach them from the library’s derivative graph. The callback returns a vector in that parameter’s coordinates. Noise models remain fixed; the callback does not differentiate or apply them.

Changing the parameters requires a new optimized solution and a new Gradients object. Reuse the parameter tags across these training steps. For repeated queries at one solution, keep the factors, their parameter values, active sets, and noise models unchanged.

Factor residual queries

pullback and pushforward expose lower-level operations on whitened factor residuals. They use Errors, GTSAM’s collection of factor-associated vectors, which appears as a list of NumPy arrays in Python. Each entry corresponds to an original graph slot; null or inactive slots have empty vectors. Use these operations when the application already works in factor residual coordinates.

pullback returns the loss gradient for additive changes in each whitened factor residual. The scalar example has one coordinate per observation and an empty block for the unused slot.

First factor: [-0.8]
Empty factor slot: []
Second factor: [-0.4]

A factor residual direction specifies how the whitened factor residuals change for a chosen parameter direction, holding the solved state fixed. Increasing z0z_0 at unit rate gives the first factor direction −1/σ0-1/\sigma_0 and leaves the second factor unchanged. pushforward returns the corresponding change in the optimized state. Pairing the factor residual direction with the pullback result gives the same loss derivative as parameterGradient.

State change per unit observation change: [0.8]

Whitening distinguishes the low-level queries from the parameter callback. For raw factor residuals ee and fixed whitening matrix WW, the whitened factor residuals are r=Wer=We. A pullback result rˉ\bar r becomes WTrˉW^T\bar r before it can be passed to a raw factor VJP. parameterGradient performs this conversion automatically, including for correlated Gaussian noise. Signs and coordinate order must match the factor’s raw error callback.

The query methods differ in the quantities they accept and return:

MethodSupplyReceive
parameterGradient(g, tag)Keyed state loss gradients and a parameter tagA parameter loss gradient vector, or None if no factor recognizes the tag
pullback(g)Keyed state loss gradientsLoss gradients on whitened factor residuals, grouped by factor
pushforward(q)Whitened factor residual directions, grouped by factorKeyed changes in optimized states
adjoint(g)Keyed state loss gradientsAn intermediate state vector; see the advanced section

State results contain every active key. Unknown keys, incorrect dimensions, nonfinite inputs, and incorrect factor block counts raise errors. A factor with no state variables retains its factor residual block but has zero state response.

Constructors and factorization reuse

The default constructor factors the linearized system using Cholesky elimination and an automatic key ordering called COLAMD. QR is an alternative factorization, selected with gtsam.Gradients.Factorization.QR. An explicit Ordering lists each active state key exactly once; extra entries in the solution Values are ignored.

The Gaussian constructors accept explicit factor residual rows or an existing Gaussian Bayes tree, which stores the factorization used for sparse solves. For the ordinary factor residuals here, graph.linearize(solution) produces the same factor residual rows as the nonlinear constructor.

The nonlinear constructors retain both the factor residual Jacobians and the context needed for parameter VJPs. They obtain raw factor residual Jacobians from each active NoiseModelFactor, apply Gaussian whitening, and retain those rows even if a factor has a reduced linearize() override. The sum of squared factor residuals must match the optimized objective.

The Gaussian constructors support the lower-level queries using explicit JacobianFactor rows. They lack nonlinear factor callbacks and therefore reject parameterGradient. If the supplied rows combine or project original factor residuals, the application supplies any mapping back to those errors. Hessian-only factors do not define factor residual coordinates and are unsupported.

Construction requires finite, positive-definite Gaussian noise and a nonsingular state system. Robust losses and hard constraints are unsupported. The caller optimizes the graph and checks stationarity before construction.

Gradients owns its numerical factor residual rows and normally computes its own Bayes tree. The existing-tree constructor copies tree topology and shares conditional and noise-model pointers, following native GaussianBayesTree ownership. Shared numerical data must remain unchanged. A reused tree must factor the same undamped system; matching keys and dimensions cannot establish numerical freshness, especially for a partially relinearized iSAM2 tree.

Nonlinear construction also retains the original factors by shared ownership and copies the solved Values for VJP calls. The source containers can go out of scope, but the factors, parameter values captured by callbacks, and noise models must remain unchanged during queries. Query workspaces are independent; concurrent parameter queries additionally require thread-safe callbacks.

All constructor choices give the same factor residual loss gradients.

Advanced: implicit differentiation and the Gauss-Newton approximation

The implicit-function theorem (IFT) relates changes in optimized variables to changes in factor parameters by differentiating the equation satisfied at a stationary solution. Stationarity means that the estimation objective’s gradient is zero.

State derivatives use the local coordinates in which GTSAM perturbs the supplied estimate, called its tangent coordinates. Hold that coordinate basis fixed throughout one derivative calculation. Let XX collect the state variables, θ\theta the factor parameters, X⋆X^\star the supplied solution, and r(X,θ)r(X,\theta) the whitened factor residual vector. The matrices J=∂XrJ=\partial_Xr and P=∂θrP=\partial_\theta r are the factor residual Jacobians with respect to states and parameters, respectively. The equations collect factor residual coordinates into mathematical vectors; the API keeps them grouped by factor in Errors.

The gradient of the estimation objective provides the equation to differentiate. Write ϕ(X,θ)=12∥r(X,θ)∥2\phi(X,\theta)=\tfrac12\|r(X,\theta)\|^2 for that objective and F=∂XϕF=\partial_X\phi for its state gradient. At the solution,

F(X⋆,θ)=JTr=0.F(X^\star,\theta)=J^T r=0.

Differentiating this zero-gradient equation relates a parameter change to the corresponding change in the optimized states. Let θ˙\dot\theta be a parameter change direction and X˙\dot X the corresponding state change. With A=∂XFA=\partial_XF and B=∂θFB=\partial_\theta F, the equation is AX˙+Bθ˙=0A\dot X+B\dot\theta=0. When AA is nonsingular, the IFT gives

X˙=−A−1Bθ˙.\dot X=-A^{-1}B\dot\theta.

The derivative terms used by Gradients

The exact state derivative AA and mixed state-parameter derivative BB each contain a term weighted by the factor residual values. Writing rir_i for factor residual coordinate ii, their expressions are

A=JTJ+∑iri ∂XX2ri,B=JTP+∑iri ∂Xθ2ri.A=J^TJ+\sum_i r_i\,\partial^2_{XX}r_i,\qquad B=J^TP+\sum_i r_i\,\partial^2_{X\theta}r_i.

Gradients uses H=JTJH=J^TJ in place of AA and JTPJ^TP in place of BB. These are the Gauss-Newton terms. The approximation therefore applies to both the state Hessian, the second state derivative of the estimation objective, and the mixed state-parameter derivative. An exact state Hessian alone does not make the parameter response exact if the mixed derivative still has a term weighted by factor residuals.

Forward mode applies the approximate state derivative to a parameter direction. Define the induced factor residual direction as q=Pθ˙q=P\dot\theta; then pushforward(q) computes

X˙=−H−1JTq.\dot X=-H^{-1}J^Tq.

Reverse mode propagates the supplied state loss gradient through the same linear system. Let gg be that gradient, and let the intermediate state vector λ\lambda, called the state adjoint, solve Hλ=gH\lambda=g. adjoint(g) returns λ\lambda, and pullback(g) returns the factor residual loss gradient rˉ\bar r:

Hλ=g,rˉ=−Jλ.H\lambda=g,\qquad \bar r=-J\lambda.

The total parameter loss gradient adds the direct loss derivative to the contribution through the states. With the direct term evaluated at fixed XX,

∇θL=∂θL∣X fixed+PTrˉ.\nabla_\theta L= \left.\partial_\theta L\right|_{X\ \mathrm{fixed}}+P^T\bar r.

Two triangular solves through the Bayes-tree factorization apply H−1H^{-1}. Queries reuse that factorization without assembling a global Jacobian, Hessian, or inverse. parameterGradient evaluates PTrˉP^T\bar r through the factors’ VJP methods; the application adds any direct parameter loss derivative. For a raw factor residual ee with fixed whitening r=Wer=We, it passes eˉ=WTrˉ\bar e=W^T\bar r to parameterVjp, which returns (∂θe)Teˉ(\partial_\theta e)^T\bar e. This also handles correlated Gaussian noise, where WW need not be symmetric.

Agreement with exact differentiation

Gauss-Newton and exact implicit differentiation agree when the omitted terms weighted by factor residuals vanish. This happens when all factor residuals are zero or when every factor residual is a linear function plus a constant in the combined state and parameter coordinates, called a jointly affine factor residual. The scalar prior example and odometry tutorial have this form.

For nonlinear problems with nonzero factor residuals, exact reoptimization can give a different derivative from the Gauss-Newton calculation. Convergence establishes stationarity; it does not remove the second derivatives weighted by factor residuals.

Independent columns of JJ, also called full column rank, ensure that H=JTJH=J^TJ is nonsingular. The operations also require consistent Gaussian whitening, fixed tangent coordinates, and a matching undamped factorization. They apply no damping or pseudoinverse fallback.

Intermediate state adjoint: [0.8]

Loss gradients for manifold-valued states

Pose loss gradients must be expressed in the local update coordinates used by the optimizer at the solved pose. For example, a Pose2 update has two translation coordinates and one rotation coordinate. A loss written in other coordinates needs a derivative that converts it to those local coordinates.

A comparison with a reference pose contributes its own Jacobian to that conversion. Let ei=Local⁡xiref(xi)e_i=\operatorname{Local}_{x_i^{\mathrm{ref}}}(x_i) be the comparison error, ViV_i a fixed symmetric loss-weight matrix, and JeiJ_{e_i} the Jacobian of that error with respect to local updates at the solved xix_i. For loss 12eiTViei\tfrac12e_i^TV_i e_i, supply JeiTVieiJ_{e_i}^TV_i e_i as the state cotangent. This comparison Jacobian is generally not identity. The scalar example’s ordinary coordinates need no such conversion.