A tensor can have rows, columns, or more dimensions, but its values live in a one-dimensional storage: a contiguous block of numbers of one type. The tensor is a view that translates its multidimensional indices into positions in that storage. Several tensors can look at the same numbers in different ways without allocating the values again. section 3.8
A 2D tensor has 1D storage
For `points = torch.tensor([[4.0, 1.0], [5.0, 3.0], [2.0, 1.0]])`, `points.storage()` contains six values in order: `4, 1, 5, 3, 2, 1`. Storage takes one index, not a row-and-column pair. Setting `points.storage()[0] = 2.0` changes `points[0, 0]` to `2.0`. Direct storage access is useful for understanding the layout, although it may not remain available in future PyTorch releases. section 3.8.1 section 3.8
A tensor finds its values using three pieces of metadata: **size** gives the length of each dimension, **storage offset** identifies its first value, and **stride** says how far to move in storage when an index increases by one. For a 2D tensor, the position of element `[i, j]` is `storage_offset + stride[0] * i + stride[1] * j`. The points tensor has stride `(2, 1)`: moving to the next row skips two storage positions; moving to the next column skips one. section 3.9 section 3.9.1
A slice shares its values
`second_point = points[1]` has size `(2,)`, storage offset `2`, and stride `(1,)`. It reads the same storage as `points`, starting at the second row. Consequently, `second_point[0] = 10.0` also changes `points[1, 0]`. Use `points[1].clone()` when changes to the new tensor must leave `points` alone: the clone has its own storage. section 3.9.1
Sharing storage makes layout changes cheap. `points.t()` transposes the points by changing the stride from `(2, 1)` to `(1, 2)`, without copying their values. Likewise, `view` can reshape suitable data without changing its storage: 17,520 hourly rows with 17 columns become 730 days × 24 hours × 17 columns using `bikes.view(-1, 24, bikes.shape[1])`. The resulting stride is `(408, 17, 1)`. These views change how indices reach numbers, not the numbers themselves. section 3.9.2 section 4.4.2
Not every layout works with `view`. A transpose can be noncontiguous even though it shares storage with its original tensor. If an operation requires contiguous data, `contiguous()` can put the values into a new, row-by-row storage with a matching stride. For the transposed points, that changes the stride from `(1, 2)` to `(3, 1)`; calling it on an already contiguous tensor does nothing. section 3.9.4
