Tensors and requires_grad in PyTorch
The grad function computes one gradient on request and returns it, while the backward method fills the grad attribute of every tracked tensor on the path to the loss.
One Loss, Two Ways to Ask for Gradients
A PyTorch program can build a loss from an input, a weight, a bias, a sigmoid, and a binary cross-entropy calculation. Once that loss exists, you can ask for a gradient in two different ways: torch.autograd.grad returns a requested gradient, while loss.backward() computes gradients for tracked tensors that contributed to the loss and stores them in their grad attributes. The distinction is not just what you ask PyTorch to calculate; it is also where you get the result.
Follow the same small computation throughout this article. Its input is x1 = 1.1, its weight is w1 = 2.2, its bias is b = 0.0, and its target is y = 1.0. The forward pass multiplies the input by the weight, adds the bias, applies sigmoid, and measures the error with binary cross-entropy. The key question is how the gradient request and the tracked tensors determine what you can read afterward.
Follow the Forward Computation
The loss is the end of a chain of operations, not an isolated number. The input and weight feed a multiplication; that result and the bias feed an addition; the result passes through sigmoid; and the sigmoid output is compared with the target by the binary cross-entropy loss. Autograd records the tensor operations in this forward pass so it can trace gradients back from the loss.
To investigate a surprising gradient, trace this chain rather than staring only at the final value. Start with the loss and identify the operations that produced it; then follow their inputs backward toward the weight, bias, and input. The first link where your expected value and the program's value disagree is the place to inspect.
Which Tensors Receive Gradients
The requires_grad setting determines which tensors are tracked for gradients. The source example tracks the bias b and reads gradients for both w1 and b after backward. More generally, only tensors created with requires_grad=True receive gradients. A tensor also needs to contribute to the loss through the recorded computation for that loss to provide a path back to it. If a parameter has requires_grad=False, do not expect a gradient for it from this tracked path.
Returned Gradients and Stored Gradients
torch.autograd.grad asks for a gradient with respect to a chosen tensor and returns that gradient as the function result. In the example, grad(loss, b, retain_graph=True) asks for the loss gradient with respect to b, and the returned value is assigned to grad_L_b. By contrast, loss.backward() does not name a parameter to request; the loss's recorded graph identifies the tracked tensors that contributed to it, and their gradients are stored in their grad attributes.
Read the result from the place that matches the call. The value returned by grad is the answer to its one requested gradient question; backward fills the grad attributes of tracked tensors on the path to the loss. In the example, grad_L_b comes from the first call, while w1.grad and b.grad are read after the second.
Reuse the Graph with retain_graph
Both gradient calls in the example rely on the same computation graph. The program calls grad first and then calls backward on the same loss. Passing retain_graph=True to grad preserves the graph for the later backward call, allowing backward to fill w1.grad and b.grad after grad has already returned grad_L_b.
Trace a Surprising Gradient
Finding where to inspect the computation
Suppose the gradient you read for a parameter seems unexpected. Use the source program's forward chain to decide which operations and tensors to check, without guessing the gradient's numeric value.
- 1Start with the value you read
Identify whether it came from grad_L_b, the value returned by grad, or from an attribute such as w1.grad or b.grad, which backward fills.
- 2Check tracking
Confirm that the tensor whose gradient you are inspecting has
requires_grad=True and is on the recorded path to the loss. - 3Trace the forward chain
Follow input and weight through multiplication, add the bias, pass the result through sigmoid, and check how binary cross-entropy compares the output with target y.
- 4Find the first disagreement
Compare the values at each link with what the code specifies. The first operation or tensor whose value differs from your expectation is where to investigate.
A useful gradient check begins with the value's source, then follows the recorded forward operations back toward the relevant parameter. Hand tracing helps locate a disagreement; autograd remains the mechanism that computes the gradient in the program.
The source setup also invites a sign prediction for the bias gradient: b starts at 0.0, the target is 1.0, and the sigmoid output is below 1. Commit to a sign before checking the program's result. That prediction is a hand check of the traced computation, not a substitute for letting autograd calculate the gradient.
What do you think happens?
For the stated setup, should the loss gradient with respect to b be positive or negative?
Reveal answer
Negative
The sigmoid output is below the target value of 1.0. Increasing the bias moves the pre-sigmoid value upward and the prediction toward the target, so the loss decreases as b increases; the gradient with respect to b is therefore negative at this point.
Mistakes to Avoid
Common mistake Expecting grad to fill a tensor's .grad attribute.
What it looks likeCalling grad(loss, b, retain_graph=True) and then looking only at b.grad for the result of that call.
Why it failsgrad returns the requested gradient as its result; the example assigns that returned value to grad_L_b.
Do this insteadRead the returned value, such as grad_L_b. Use backward when you want gradients stored in tracked tensors' grad attributes.
Common mistake Expecting backward to return only the gradient for one selected parameter.
What it looks likeCalling loss.backward() and expecting it to act like a request for b alone.
Why it failsThe loss graph records which tracked tensors contributed to the loss; backward fills their grad attributes.
Do this insteadUse grad when you want to request a gradient for a chosen tensor. Use backward to populate grad attributes for tracked tensors on the path.
Common mistake Reading a gradient without checking requires_grad.
Why it failsThe source states that only tensors created with
requires_grad=True receive gradients.Do this insteadCheck the tensor's tracking setting and its connection to the loss before expecting a gradient.
Common mistake Calling grad and then backward on the same loss without retaining the graph.
Why it failsThe later backward call needs the same computation graph that the earlier grad call used.
Do this insteadWhen both calls need the same graph in this sequence, pass retain_graph=True to grad.
Common mistake Debugging only from the final gradient number.
Why it failsThe value depends on the chain of forward operations and tensors that produced the loss.
Do this insteadTrace the values through multiplication, addition, sigmoid, and binary cross-entropy, and locate the first point that differs from your expectation.
Practice the Gradient Trace
A program calls grad(loss, b, retain_graph=True), then calls loss.backward(), and finally reads grad_L_b, w1.grad, and b.grad. For each value, identify which call supplies it. Then name the forward operations you would inspect first if b.grad seemed unexpected.
Hints
- Separate the value returned by grad from the attributes filled by backward.
- Trace the source computation from multiplication through the loss.
Key Takeaways
grad(loss, tensor)returns the requested gradient; it does not provide the example's result through that tensor's .grad attribute.loss.backward()fills grad attributes for tracked tensors that contributed to the loss.requires_graddetermines which tensors are tracked to receive gradients.retain_graph=True lets the later backward call reuse the graph after the earlier grad call.- To debug an unexpected gradient, identify where you read it and trace the forward tensors and operations back from the loss.