๐ŸŽ“ A1Learner
๐Ÿ”

PyTorch Gradients of Vectors

A vector is a row of values in one tensor. backward() works on a scalar, so a vector answer is summed into a scalar first.

A vector answer fails

This call fails on purpose. It raises a RuntimeError, and the stable last line says grad can be implicitly created only for scalar outputs.

import torch

x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x ** 2
y.backward()

Sum first, then backward()

The sum turns the row of answers into one scalar. backward() then fills one gradient per input value.

x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x ** 2
total = y.sum()
total.backward()
print(x.grad)

Each value gets its own gradient

The gradient of v ** 3 is 3 * v ** 2 for each value. The two inputs get 48 and 75.

v = torch.tensor([4.0, 5.0], requires_grad=True)
(v ** 3).sum().backward()
print(v.grad)

Example

import torch

a = torch.tensor(2.0, requires_grad=True)
b = torch.tensor(5.0, requires_grad=True)
c = torch.tensor(2.0, requires_grad=True)
total = a ** 2 + 3 * b + c ** 3
total.backward()
print("Total:", total.item())
print("Gradient for a:", a.grad.item())
print("Gradient for b:", b.grad.item())
print("Gradient for c:", c.grad.item())

Key points

  • Scalar: one single number
  • backward() on a vector answer raises a RuntimeError
  • Use .sum() to turn a vector answer into a scalar
  • Each input value gets its own gradient in .grad
  • The gradient row lines up with the input row, value by value
  • In short, sum first, then backward() fills one gradient per input

In this example, a, b, and c are three separate tracked inputs. total adds a ** 2, 3 * b, and c ** 3 into one scalar. backward() then fills one gradient per input. The prints read the values out with .item(). total is 27.0. a gets 4.0, from 2 * a at a = 2. b gets 3.0, and c gets 12.0, from 3 * c ** 2 at c = 2.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท Python Playground

Exercise

Why is .sum() called before backward() on a vector answer?