Autograd: automatic gradients

PyTorch · Essentials · 12 min

Gradients are what training follows; autograd computes them for any Python code you write.

Autograd is PyTorch's automatic differentiation engine. When a tensor has requires_grad=True, every operation on it is recorded in a graph of functions. Calling .backward() on a scalar result walks that graph backwards and stores d(result)/d(tensor) in each leaf tensor's .grad.

Key facts:

  • Parameters of nn layers already have requires_grad=True; input data does not.
  • backward() needs a scalar (like a loss). For a non-scalar output, reduce it first with .sum() or .mean().
  • Gradients accumulate: a second backward() adds to .grad rather than replacing it. That is why training loops call optimizer.zero_grad() every step.
  • Each result tensor has a grad_fn naming the operation that created it, e.g. AddBackward0.
  • By default the graph is freed after backward(); calling it twice on the same graph raises an error unless you pass retain_graph=True.

The graph is built dynamically as your Python runs, so loops, if statements and function calls all work naturally. This define-by-run design is what makes PyTorch easy to debug: you can print tensors and step through with a debugger at any point.

Example

import torch

x = torch.tensor(3.0, requires_grad=True)
y = x ** 2 + 2 * x          # y = 15
y.backward()
print(x.grad)               # tensor(8.)   dy/dx = 2x + 2
print(y.grad_fn)            # <AddBackward0 object at ...>

w = torch.tensor([1.0, -2.0], requires_grad=True)
c = torch.tensor([3.0, 4.0])
(w * c).sum().backward()
print(w.grad)               # tensor([3., 4.])

(w * c).sum().backward()    # a new graph, gradients add up
print(w.grad)               # tensor([6., 8.])

w.grad = None               # reset, like optimizer.zero_grad()

Remember

  • Set requires_grad=True on leaves; call .backward() on a scalar
  • Gradients accumulate in .grad until you clear them
  • The graph is rebuilt on every forward pass (define-by-run)

Watch out for

  • Forgetting to zero gradients, so each step uses the sum of all previous gradients.

Check yourself

  1. You call loss.backward() twice (recomputing loss each time) without zeroing. What is in w.grad?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: pytorch.org/docs/stable/notes/autograd.html