Tensors are layered: Storage + view metadata
A tensor is two things: a Storage (a contiguous 1-D blob of typed memory) and a view on that storage (shape, stride, offset). When you slice or transpose, the storage usually doesn't change — only the view does. That's why slicing is O(1) and why .transpose() is "free" but breaks contiguity.
What stride actually means
t.stride() returns a tuple of integers, one per dimension, telling PyTorch how many elements to step over in storage when you advance one index along that dimension. For a contiguous (3, 4) float tensor, stride is (4, 1): walking down a row jumps 4 elements; walking across a column jumps 1.
Transpose swaps the strides without touching storage: a (3, 4) tensor with stride (4, 1) becomes a (4, 3) tensor with stride (1, 4). That's why .is_contiguous() returns False after transpose — walking elements in memory order no longer matches walking the dim order.
Why this matters
- You can predict whether an operation will allocate or just rewrite metadata.
- You can reason about why some "trivial" transforms (e.g. NHWC → NCHW for an image batch) actually cost real time and memory.
- You can debug "why does my training take 30% more memory than I expect" — usually one accidental copy.