PyTorch torch.no_grad vs torch.inference_mode
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.
Introduction
Both torch.no_grad() and torch.inference_mode() disable gradient computation in PyTorch, but they are not interchangeable. inference_mode is stricter and faster, designed for production inference paths. no_grad is more permissive, designed for situations where you want to stop gradient tracking but still need normal tensor behavior. Choosing the right one depends on whether your code is purely read-only inference or a mixed workflow.
What torch.no_grad() Does
torch.no_grad() tells PyTorch to stop building the autograd computation graph for operations inside the context. This saves memory (no gradient tensors stored) and speeds things up (no graph construction overhead).
Tensors produced inside torch.no_grad() are regular tensors. You can mutate them, use them in subsequent autograd operations outside the block, and treat them like any other tensor. The only thing no_grad removes is the gradient recording.
As a decorator
Both context managers also work as decorators:
What torch.inference_mode() Does
torch.inference_mode() also disables autograd, but it goes further by creating inference tensors that carry additional restrictions. These tensors cannot be used in autograd computations later, cannot be mutated in certain ways, and allow PyTorch to skip internal bookkeeping that no_grad still performs.
The key difference: tensors created inside inference_mode are marked as inference tensors. If you try to use them in a gradient-tracked operation outside the block, PyTorch raises an error.
Side-by-Side Comparison
| Feature | torch.no_grad() | torch.inference_mode() |
| Disables gradient tracking | Yes | Yes |
| Saves memory | Yes | Yes, more aggressively |
| Tensors usable in autograd later | Yes | No (raises error) |
| Skips version counting | No | Yes |
| Skips view tracking | No | Yes |
| Performance benefit | Good | Better |
| Available since | PyTorch 0.4 | PyTorch 1.9 |
| Safe for mixed workflows | Yes | No |
| Recommended for production inference | Works but not optimal | Yes |
Performance Difference
The performance gap comes from the internal bookkeeping that inference_mode eliminates:
- Version counting: PyTorch tracks a version counter on every tensor to detect in-place modifications that could invalidate the autograd graph.
inference_modeskips this entirely. - View tracking: When you create a view of a tensor (e.g.,
tensor.view(...),tensor[0]), PyTorch normally tracks the relationship between the view and the base tensor for autograd correctness.inference_modeskips this.
These savings compound in models with many operations, especially transformer architectures with heavy view and reshape usage.
The exact speedup varies by model and hardware. For small models the difference is negligible. For large models with complex tensor operations, inference_mode can be measurably faster.
When to Use Each One
Use torch.inference_mode() when:
- Serving predictions in a production API
- Running evaluation on a test dataset with no training interaction
- Deploying a model where the output tensors never need gradients
- Benchmarking inference throughput
Use torch.no_grad() when:
- Running a validation loop inside a training script where tensors might interact with the training logic
- Computing loss for logging during training (where loss tensors may be used in metrics that touch autograd)
- Debugging model outputs and inspecting intermediate tensors
- Working with older codebases that were written before
inference_modeexisted - Using GAN training loops where generator outputs feed back into discriminator gradients
Critical: Neither Replaces model.eval()
This is the most common source of bugs. torch.no_grad() and torch.inference_mode() control autograd behavior. model.eval() controls module behavior. They solve different problems.
| Concern | Controlled by |
| Gradient computation | torch.no_grad() / torch.inference_mode() |
| Dropout behavior | model.eval() / model.train() |
| BatchNorm statistics | model.eval() / model.train() |
If your model has dropout or batch normalization layers and you only use a context manager without calling model.eval(), those layers still behave as if they are training. Dropout will randomly zero activations. BatchNorm will use batch statistics instead of running statistics. Your inference results will be wrong and non-deterministic.
Correct inference setup always combines both:
Using as Function Decorators
Both work as decorators, which is cleaner for standalone prediction functions:
The decorator form is equivalent to wrapping the entire function body in the context manager.
Common Pitfalls
- Using
inference_modein a training loop's validation step when loss tensors are later used in autograd. If any tensor from inside the block touches a gradient-tracked computation, you get aRuntimeError. Useno_gradfor validation loops that interact with training logic. - Forgetting
model.eval(). Neither context manager changes dropout or batch norm behavior. You must callmodel.eval()separately. - Using
no_gradeverywhere out of habit. If your inference path is genuinely read-only, you are leaving performance on the table. Switch toinference_modefor production serving. - Assuming the two are interchangeable. They have different guarantees.
inference_modeis intentionally stricter. Code that works underno_gradmay fail underinference_mode. - Nesting contexts unnecessarily.
inference_modeinsideno_grad(or vice versa) works but adds no benefit. The inner context is redundant. - Not calling
model.train()after validation. If you setmodel.eval()for validation but forget to callmodel.train()before the next training iteration, your model trains with frozen dropout and batch norm.
Summary
torch.no_grad()disables gradient tracking while keeping tensors flexible and compatible with subsequent autograd operations.torch.inference_mode()is a stricter, faster mode that creates inference tensors with additional restrictions, enabling PyTorch to skip version counting and view tracking.- Use
inference_modefor production inference, model serving, and pure evaluation where output tensors never re-enter autograd. - Use
no_gradfor validation loops inside training, debugging, and mixed workflows where tensors might interact with gradient-tracked code. - Always combine either context manager with
model.eval()to get correct behavior from dropout and batch normalization layers. - The performance difference is most noticeable in large models with heavy tensor operations. For small models, both are effectively equivalent.
Related reading
- PyTorch using LR-Scheduler with param groups of different LR's
- PyTorch What's the difference between state_dict and parameters?
- Quantize a Keras neural network model
- Question about Backpropagation Algorithm with Artificial Neural Networks -- Order of updating
- pytorch torchvision.datasets.ImageFolder FileNotFoundError Found no valid file for the classes .ipynb_checkpoints
- Pytorch ValueError optimizer got an empty parameter list
- Q-learning vs dynamic programming
- Q-learning vs temporal-difference vs model-based reinforcement learning

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.