Automatic Differentiation: The Autograd Engine
Deep learning neural networks learn by computing the gradient of a scalar loss function with respect to millions of model parameters. PyTorch’s crown jewel is Autograd: a dynamic reverse-mode automatic differentiation engine that records every tensor operation on a Directed Acyclic Graph (DAG) in real time.
1. How Autograd Constructs Dynamic Graphs
When a tensor is created with requires_grad=True, PyTorch begins tracking every mathematical transformation applied to it. Each operation instantiates a backward Function object (like MulBackward0 orAddBackward0) that stores the derivative formula:
import torch
# 1. Define leaf parameters with gradient tracking enabled
w = torch.tensor([2.0], requires_grad=True)
b = torch.tensor([3.0], requires_grad=True)
x = torch.tensor([4.0]) # Input data (fixed constant; does not require gradients)
# 2. Forward pass: Evaluate linear equation y = w*x + b
y = w * x + b # y = 2.0 * 4.0 + 3.0 = 11.0
# 3. Inspect backward function nodes in the computational DAG:
print("y value:", y.item()) # 11.0
print("Grad fn of y:", y.grad_fn) # <AddBackward0 object>
print("Next functions:", y.grad_fn.next_functions) # Links to MulBackward0 and leaf b!
# 4. Backward pass: Compute partial derivatives dy/dw and dy/db via chain rule
y.backward()
# 5. Access computed gradients:
print("dy/dw (equals x = 4.0):", w.grad.item()) # 4.0
print("dy/db (equals 1.0): ", b.grad.item()) # 1.02. The Gradient Accumulation Gotcha
Gradients Accumulate by Default!
When loss.backward() executes, PyTorch adds (accumulates) new gradients intoparam.grad instead of overwriting them (param.grad += new_grad). If you forget to clear gradients at each training step using optimizer.zero_grad(), gradients from previous batches will pollute the current step, causing loss divergence!
# Demonstration: Unintended Accumulation
x = torch.tensor([3.0], requires_grad=True)
for epoch in range(3):
y = x ** 2
y.backward()
print(f"Epoch {epoch + 1} Grad (Expected 6.0): {x.grad.item()}")
# Output:
# Epoch 1: 6.0
# Epoch 2: 12.0 (Accumulated 6 + 6!)
# Epoch 3: 18.0 (Accumulated 12 + 6!)
# CORRECT FIX: Always zero gradients between steps:
x.grad.zero_()3. Disabling Autograd for Inference: no_grad vs inference_mode
During model evaluation, validation, or live web API serving, tracking computational graphs consumes massive VRAM and slows down execution. PyTorch provides two mechanisms to disable tracking:
| Context Manager | Memory Savings | Version Tracking | Best Use Case |
|---|---|---|---|
with torch.no_grad(): | High | Enabled | Validation loops where tensors might later be used in training steps. |
with torch.inference_mode(): | Maximum (Fastest) | Disabled completely | Production Inference & API Serving. Eliminates all tracking overhead. |
# 1. Detaching a tensor from the graph (returns a view sharing storage, but no grad_fn)
raw_prediction = y.detach().cpu().numpy()
# 2. Modern High-Throughput Production Inference:
with torch.inference_mode():
features = torch.randn(64, 512)
# Forward pass executes without any computational graph memory overhead!
predictions = features @ torch.randn(512, 10)4. Authoring Custom Autograd Functions
When implementing novel activation functions, specialized loss metrics, or interfacing with custom C++/CUDA kernels, subclass torch.autograd.Function and specify both forward() and backward() methods:
import torch
class CustomReLU(torch.autograd.Function):
@staticmethod
def forward(ctx, input_tensor):
# Save input tensor for gradient calculation in the backward pass
ctx.save_for_backward(input_tensor)
return input_tensor.clamp(min=0)
@staticmethod
def backward(ctx, grad_output):
# Retrieve saved input tensor
input_tensor, = ctx.saved_tensors
# Derivative of ReLU: 1 if x > 0 else 0
grad_input = grad_output.clone()
grad_input[input_tensor <= 0] = 0
return grad_input
# Apply custom operator:
relu_fn = CustomReLU.apply
z = torch.tensor([-2.0, 3.0, 5.0], requires_grad=True)
out = relu_fn(z).sum()
out.backward()
print("Input:", z)
print("Gradients:", z.grad) # tensor([0., 1., 1.])Neural Networks with torch.nn
Continue to the next hands-on deep learning guide in this PyTorch series.
Explore Related Tools
Hand-picked utilities and calculators related to this tool.
