backward
→Nonebackward(tensors: Tensor | Sequence[Tensor], grad_tensors: Tensor | Sequence[Tensor | None] | None = None, retain_graph: bool | None = None, create_graph: bool = False, inputs: Tensor | Sequence[Tensor] | None = None)Compute gradients of tensors w.r.t. the leaf variables in their graph.
Top-level entry point that triggers reverse-mode automatic
differentiation across the computation graph rooted at
tensors. For every leaf tensor x reachable from
tensors whose requires_grad is True, this function
accumulates into
x.grad, where is the (possibly weighted)
sum of the root tensors.
The chain rule is applied edge-by-edge during a topological walk of the graph in reverse order, so each intermediate Jacobian-vector product fires exactly once.
Parameters
None —
for the whole argument or one entry — is an implicit 1,
allowed only for a real root of one element.retain_graphbool= NoneTrue the intermediate saved tensors are not freed after
the backward pass, so the same graph can be traversed again.
Defaults to create_graph.create_graphbool= FalseTrue the operations performed during backward are
themselves recorded in the graph, enabling higher-order
differentiation (e.g. Hessian-vector products, meta-learning).
Implies stronger memory usage. Defaults to False..grad
changes, every other leaf in the graph keeps what it had. An
input that is not a leaf has its .grad filled too (it is
marked Tensor.retain_grad, as the reference does). An
input the roots do not reach is left alone. None (default)
accumulates into every leaf.Returns
NoneGradients are accumulated in-place onto each leaf tensor's
.grad attribute. Existing .grad values are added to,
not overwritten — call Tensor.zero_grad (or the
optimizer's zero_grad) between successive backward passes
if accumulation is undesired.
Raises
RuntimeErrorinputs is empty, or one of inputs does not require grad.TypeErrorNone, or an entry of
inputs is not a tensor.(ShapeMismatch, DtypeMismatch, DeviceMismatch)Notes
Reverse-mode AD computes
propagating cotangents from the roots through each saved op contract until every reachable leaf has received its contribution.
Memory/compute trade-off:
retain_graph=False(default) is the cheapest mode — once the walk finishes, every saved tensor is freed.retain_graph=True, create_graph=Falsekeeps activations so the same graph can be traversed again.create_graph=Trueadditionally records the backward ops in a new graph, doubling memory in the worst case but enabling and beyond.
Examples
>>> import lucid
>>> from lucid.autograd import backward
>>> x = lucid.tensor([1.0, 2.0, 3.0], requires_grad=True)
>>> y = (x * x).sum()
>>> backward(y)
>>> x.grad
tensor([2., 4., 6.])
Only the tensors in inputs accumulate:
>>> a = lucid.ones(2, requires_grad=True)
>>> b = lucid.ones(2, requires_grad=True)
>>> backward((a * b * 3).sum(), inputs=[a])
>>> a.grad, b.grad
(tensor([3., 3.]), None)Used by 3
- lucid._tensor.tensor
- lucid.autograd
- lucid.autograd.checkpoint