How gradients land — and when they accumulate
tensor.backward() is the call that triggers the backward pass. It expects to be called on a scalar; if your tensor isn't scalar, you have to provide an "incoming gradient" argument that tells backward how to weight each output element. In normal supervised learning your loss is always a scalar, so this argument almost never appears in your code.
The .grad accumulator
After backward, the gradient lands in leaf_tensor.grad. Critical fact: repeated backward calls add to the existing .grad, not overwrite it. That's why every training loop has optimizer.zero_grad() at the top — to reset the accumulator.
The accumulation behavior is occasionally useful: it's what makes gradient accumulation (simulating a larger batch by accumulating gradients across several mini-batches before stepping the optimizer) trivial.
Non-scalar outputs
If you must call .backward() on a non-scalar tensor, you have to pass a tensor of the same shape as a "virtual incoming gradient" — this is the vector-Jacobian product (vJp). In practice, you'll see this in research code (computing per-sample gradients, custom losses) more than in normal training.