Skip to content

← Autograd Mechanics step 1 of 8

Medium Primitives

The graph you never needed

Two ways to evaluate something without wanting gradients. They produce the same tensor and they are not the same operation.

with torch.no_grad():
    metric = expensive(x).sum()      # no graph is built

metric = expensive(x).sum().detach() # a graph is built, then dropped

Both give a tensor with requires_grad=False and no grad_fn. Checking either of those cannot tell them apart, which is why the difference is so easy to miss.

What actually differs

Building a graph means saving tensors for the backward pass. Every operation that will need its input or output later keeps a reference to it, and those references keep the memory alive.

under no_grad                 0 tensors saved for backward
detached afterwards           tensors saved, then released

During the forward pass, the second version is holding every intermediate. Under no_grad those intermediates are freed as soon as the next operation finishes with them.

For one small expression this is nothing. For a validation pass over a whole dataset it is the difference between fitting in memory and not, which is exactly where people meet it: the training loop is fine and evaluation reliably runs out of memory.

The rule

Decide before the computation, not after. no_grad around the block is the answer for evaluation, metrics, and anything you are only going to look at. detach is for taking a value out of a graph you did want, which is a different question and is the previous track’s problem.

inference_mode goes further

with torch.inference_mode():
    ...

Everything no_grad does, plus it skips version counting and lets the allocator be more aggressive. Tensors made inside it are marked, and using one later in a graph raises rather than silently misbehaving. Prefer it for pure inference, and use no_grad when the results have to flow back into training code.

Your task

def evaluate(x: torch.Tensor) -> torch.Tensor

Return (x * 2).exp().sum() without building any graph at all.

The starter detaches at the end, which produces exactly the right tensor.