train/eval modes and no_grad

PyTorch · Practical · 9 min

Mixing these up gives wrong validation numbers, random predictions or out-of-memory errors at inference.

Two independent switches control inference, and you usually want both.

`model.train()` / `model.eval()` set a flag on every sub-module. Only some layers react: Dropout stops dropping, and BatchNorm uses its running statistics instead of the batch's. Forgetting eval() makes predictions random (dropout) or batch-dependent (batch norm).

`torch.no_grad()` is a context manager (also a decorator) that stops autograd from recording operations. Outputs have requires_grad=False, no graph is kept and memory use drops. `torch.inference_mode()` is a stricter, slightly faster version: tensors created inside cannot be used in autograd later. Use it for pure inference and serving.

`t.detach()` returns a tensor sharing data with t but cut off from the graph. Use it when you want a value without its history: logging, storing outputs across steps, or feeding a target network.

A typical evaluation helper:

@torch.no_grad()
def evaluate(model, loader):
    model.eval()
    ...

Remember to switch back with model.train() before the next training epoch, since eval() persists until changed.

Example

import torch
from torch import nn

model = nn.Sequential(nn.Linear(100, 100), nn.Dropout(p=0.5))
x = torch.ones(1, 100)

model.train()
print(torch.equal(model(x), model(x)))   # False: different dropout masks
model.eval()
print(torch.equal(model(x), model(x)))   # True: dropout disabled

with torch.no_grad():
    y = model(x)
print(y.requires_grad)                   # False

with torch.inference_mode():
    z = model(x)
print(z.is_inference())                  # True

w = model[0].weight * 2
print(w.requires_grad, w.detach().requires_grad)   # True False

Remember

  • eval() changes layer behaviour; no_grad() stops graph recording
  • Use both for validation and inference
  • detach() keeps the values but drops the history

Watch out for

  • Accumulating total_loss += loss across steps, which keeps every graph alive; use loss.item() or loss.detach().

Check yourself

  1. Inside torch.no_grad(), a model with Dropout is still in train mode. What happens?

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#locally-disabling-gradient-computation