liveBook · Manning

Tensor storage

As explained in Deep Learning with PyTorch, Second Edition

A one-dimensional memory buffer underlying tensor views.

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

How Deep Learning with PyTorch, Second Edition covers it

How deep it goes
Works through one-dimensional indexing, offset and stride calculations, shared mutation, and contiguity; does not detail memory allocation internals.
Examples
Uses a three-row points tensor, its indexed and transposed views, and hourly bicycle data reshaped into daily sequences.
What it assumes
Assumes basic tensor creation and indexing while defining storage and its layout metadata from the ground up.
What you can do after
Diagnose/debug with it by predicting shared mutations, reading strides and offsets, and recognizing when a layout needs a contiguous copy.
How it connects
Connects tensor storage to tensor views, shape, storage offset, stride, transpose, reshape, cloning, and contiguous tensors.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Deep Learning with PyTorch, Second Edition. The section links point to the parts of the book it draws on.