Train mode and eval mode are different functions
Some PyTorch layers — Dropout, BatchNorm, LayerNorm with affine=True usually behaves the same — change behavior depending on whether the model is in training or evaluation mode. Dropout zeros random units in train, identity in eval. BatchNorm uses batch statistics in train and running statistics in eval. Forgetting to switch causes silent metric noise.
Switch with model.train() and model.eval(). They are recursive — calling on the top-level module switches every submodule.
model.train(), every validation loop starts with model.eval(). Even if you 'know' you set it correctly five lines ago.Pair eval mode with no_grad/inference_mode
For evaluation you don't need gradients, and computing them wastes memory and time. Use torch.inference_mode() (newer, faster) or torch.no_grad() (older, equivalent for most use cases).
Common eval bugs
Computing accuracy on the GPU then printing CPU values — every .item() forces a CUDA sync. Aggregate on the GPU, sync once at the end of the epoch.
Mismatched preprocessing — training applies augmentations (random crop, flip, color jitter), evaluation should apply only deterministic preprocessing (resize, center crop, normalize). Mixing the two is one of the most common silent bugs in vision training.