Differentiable simulation#
Genesis World can run the physics engine in differentiable mode, so you can backpropagate a loss defined on simulation outputs all the way back to the inputs that produced them. Use it to optimize control signals, fit physical parameters, or train policies through the dynamics rather than around them.
Minimal example#
Enable differentiable mode with requires_grad=True on gs.options.SimOptions, run the simulation forward, then call backward() on a loss:
import genesis as gs
import torch
gs.init(backend=gs.gpu)
scene = gs.Scene(
sim_options=gs.options.SimOptions(
dt=0.01, # seconds
requires_grad=True, # enable differentiable mode
),
)
robot = scene.add_entity(gs.morphs.URDF(file="robot.urdf"))
scene.build()
# A control signal we want gradients for
force = torch.zeros(robot.n_dofs, device=gs.device, requires_grad=True)
for _ in range(100):
robot.control_dofs_force(force)
scene.step()
target = torch.tensor([1.0, 0.0, 0.5], device=gs.device)
loss = torch.nn.functional.mse_loss(robot.get_pos(), target)
loss.backward() # propagates through every step back to `force`
print(force.grad)
How autodiff works#
Enable it once, on the scene: set
requires_grad=Trueings.options.SimOptions. Genesis World then records the intermediate substep state each step needs for the backward pass. The flag defaults toFalse, so a simulation is non-differentiable unless you opt in; see Limitations for what differentiable mode costs.State getters return differentiable tensors: methods such as
get_pos(),get_vel(), andget_qpos()return ags.Tensor(a subclass oftorch.Tensorthat also carries a reference to the scene it came from). See the Tensor reference.backward()flows through the physics: callingbackward()on any tensor derived from scene state runs the standard PyTorch backward pass, then continues the gradient backward through time across the recorded steps, down to the inputs you marked withrequires_grad=True.Inputs are ordinary leaf tensors: control forces, initial positions, and target values are plain PyTorch tensors created with
requires_grad=True. Any operation that mixes them with scene-derived tensors yields a scene-tracked tensor, which keeps the graph connected.
A single forward run supports one backward pass. Reset the scene with scene.reset() before the next forward pass, for example once per optimization step. State tensors follow the batched-optional shape convention (([n_envs,] ...)); see Conventions.
Detaching from the scene#
To stop gradients from flowing back into the simulation, drop the tensor’s scene association:
pos = robot.get_pos()
pos_detached = pos.detach() # detaches from autograd and from the scene
pos_sceneless = pos.sceneless() # keeps autograd, drops only the scene link
detach() removes the scene link by default (sceneless=True); pass sceneless=False to keep it. Use sceneless() when you want a tensor to stay in the PyTorch graph but not feed gradients back through the physics. Reading tensor.scene tells you which scene, if any, a tensor is bound to.
Note
Mixing two tensors that belong to different scenes raises an error, since gradients cannot flow into more than one scene. Call sceneless() on one of them first if you do not need the gradient to reach its scene.
Limitations#
Memory scales with horizon: differentiable mode stores intermediate substep state for every step, so long trajectories consume proportionally more GPU memory. Set
substeps_localings.options.SimOptionsto control how much substep state is retained; in differentiable mode it must be divisible bysubsteps.Some contact and collision paths have no gradients: gradients through them may be zero or undefined. The rigid solver uses the GJK collision path when gradients are required (see Collision detection), and the elliptic friction cone is unsupported (see Constraint model).
Coupler support: the default legacy coupler carries gradients; the SAP coupler does not. See Coupling.
Hibernation: unavailable when
requires_grad=True; see Collision detection.Numerical stability over long horizons: gradients backpropagated through many steps can vanish or explode, as with any long recurrent computation.
See also#
Differentiable simulation: the differentiable tensor and creation-op reference.
Checkpoints and simulation state: resetting the scene between optimization passes.
Coupling: which coupler to use for gradients.