Skip to content

← Memory, Copies and In-Place step 1 of 6

Medium Primitives

Clone, detach, or both

Jump to the task

clone() and detach() solve different problems. Cloning makes an independent copy of the data. Detaching stops gradient tracking through the result, but keeps the same storage.

For a floating-point tensor with requires_grad=True, while gradient recording is enabled:

Expression Shares storage with x? Requires gradients?
x Yes Yes
x.detach() Yes No
x.clone() No Yes
x.detach().clone() No No

The clone has a grad_fn, so gradients can flow back to x. If x does not require gradients, cloning it does not create that connection.

Why detaching is not a snapshot

import torch

x = torch.tensor([1.0, 2.0], requires_grad=True)
saved = x.detach()
with torch.no_grad():
    x.add_(10.0)
print(saved.tolist())  # [11.0, 12.0]

saved sees the mutation because it shares storage with x. To preserve the earlier values independently of later writes, you need a copy too. This matters when saving tensors for later inspection or keeping an initial state. If you only need to read a value without tracking gradients, and no later mutation can affect that use, detaching may be enough.

Choosing the order

x.detach().clone() first removes the gradient connection, then copies the data. x.clone().detach() also produces an independent, detached result. When x requires gradients and recording is enabled, cloning first creates an autograd node that the detach makes unnecessary.

Your task

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

Return a tensor with the same values, shape, dtype and device as x. It must not share storage with x, and requires_grad must be False. The function must work whether or not x requires gradients. The tests also mutate x after the call to check that the snapshot keeps its values.