Neural networks
Tensors, Axes, Shapes, and Batches
Learn to read tensor shapes semantically, track axes through operations, and distinguish batch, feature, spatial, temporal, and channel dimensions.
By the end you can
- Describe a tensor by both shape and axis meaning
- Trace common batch, sequence, channel, and spatial dimensions
- Recognize reshaping, transposing, broadcasting, and reduction mistakes
- Explain why shape correctness is necessary but not sufficient for semantic correctness
Key idea
The matrix that was the right shape and one row off
A gene-expression matrix at Duke was the right shape and indexed one row off. Baggerly and Coombes found it while trying to reconstruct the university's chemosensitivity signatures. Writing in The Annals of Applied Statistics in December 2009, they report that the cisplatin heatmap could only be reproduced by taking row 98 of the Györffy et al. table instead of row 97. Apply that one offset and 41 of the 45 reported probesets matched. For pemetrexed the sensitive/resistant labels were reversed as well. Those two groups were not merely shifted. They were swapped.
Nothing about the shape objected. The matrix had the dimensions everyone expected. Every operation ran. Patients were assigned to trial arms on the signatures it produced. “One theme that emerges is that the most common errors are simple (e.g., row or column offsets); conversely, it is our experience that the most simple errors are common,” the two authors wrote in their abstract.
The Institute of Medicine's 2012 report on translational omics records what followed. On 22 October 2010 Duke notified the NCI that multiple validation datasets were corrupted. The trials were closed and retraction was initiated. An off-by-one index is not a syntactic event. It is a semantic one, and the shape is no witness against it.
A tensor can have a valid shape and still represent the wrong thing.
Visual
Rank, shape, axis, and coordinate
These terms describe different aspects of a tensor, and only some of them are written down anywhere.
An array, as the NumPy paper in Nature put it in 2020, is a pointer to memory plus metadata: data type, shape and strides. One sentence there fixes the first two rows of this hierarchy: “The shape of an array determines the number of elements along each axis, and the number of axes is the dimensionality of the array.”
A versioned standard draws the same line independently. The Python array API standard 2025.12 specifies array.ndim as “Number of array dimensions (axes).” alongside array.shape, and NumPy's own reference page for numpy.ndarray.shape reads “Tuple of array dimensions.” Rank is recorded. Shape is recorded. The third row of the hierarchy is recorded by neither: no attribute in the standard or in the implementation states which dimension holds the batch. Axis semantics live only in the head of whoever wrote the code, or in the ledger they keep.
Rank
The number of axes, such as rank 2 for a matrix.
Shape
The ordered lengths of those axes, such as [32, 128].
Axis semantics
What each dimension means, such as batch then features.
Coordinate
One position selected along every axis.
Example
Common tensor layouts across domains
Conventions differ by domain, and for the same four numbers they differ between shipped APIs. tf.nn.conv2d takes data_format 'NHWC' as its default. torch.nn.Conv2d specifies its input as (N, C_in, H_in, W_in). The ONNX operator specification fixes Conv's input X as “Input data tensor from previous layer; has size (N x C x H x W), where N is the batch size, C is the number of channels, and H and W are the height and width.”
Three specifications, one convolution, and no agreement on the order. ONNX alone adds an optional dimension denotation of [DATA_BATCH, DATA_CHANNEL, DATA_FEATURE, DATA_FEATURE …]. It is the only one of the three that names an axis rather than fixing its position. That is why the labels have to travel with the numbers. A four-element shape moved between two of these APIs is still a legal four-element shape.
- Tabular batch: [examples, features], such as [64, 120].
- Token batch: [examples, tokens] before embedding, then [examples, tokens, hidden].
- Images in channels-first layout: [examples, channels, height, width] — the order torch.nn.Conv2d specifies as (N, C_in, H_in, W_in) and ONNX fixes as (N x C x H x W).
- Images in channels-last layout: [examples, height, width, channels] — the NHWC that tf.nn.conv2d takes as its data_format default.
- Audio spectrograms: often [examples, frequency, time] plus an optional channel axis.
- Graph mini-batches: node and edge tensors may use indices rather than one rectangular grid.
Comparison
Four operations that alter how data is read
Similar-looking tensor operations can have very different semantic effects. One of the four comes with a published algorithm that says precisely how it will go wrong.
Broadcasting aligns from the right. The Python array API standard 2025.12 states the rule: “If two arrays are of unequal rank, the array having a lower rank is promoted to a higher rank by (virtually) prepending singleton dimensions until the number of dimensions matches that of the array having a higher rank.” Both major implementations write down the same rule. NumPy's manual says it “starts with the trailing (i.e. rightmost) dimension and works its way left”, treating two dimensions as compatible when they are equal or one of them is 1. PyTorch's broadcasting semantics iterate “starting at the trailing dimension”.
Nothing in that algorithm consults what an axis means. A bias vector intended for the feature axis is accepted against whatever axis its trailing length happens to match, silently. What comes back is a well-formed tensor of exactly the expected shape. Reshape, transpose and reduce fail the same way for the same reason. Each is defined over lengths, and lengths are all the framework stores.
Reshape
Changes the grouping of stored elements without choosing a new order.
- Element count must match
- Can merge or split axes
- May hide lost semantics
- Example: flatten height and width
Transpose
Reorders axes while preserving their lengths.
- Changes memory view or layout
- Often needed between conventions
- Easy to swap batch and time
- Example: BCHW to BHWC
Broadcast
Expands compatible singleton dimensions conceptually.
- Avoids materialized copies
- Useful for bias and masks
- Can apply along a wrong axis
- Example: add one feature bias
Reduce
Aggregates values along named axes.
- Produces sums, means, maxima, or norms
- May remove or keep dimensions
- Changes statistical meaning
- Example: average token states
Padding introduces values that must not become evidence
Variable-length sequences are padded to a common length. The mask that accompanies them is a real tensor with a shape of its own, not a matter of good practice. Hugging Face's Transformers glossary works the example: two BERT-tokenized sentences of length 8 and 19, padded with zeros to a common 19, with the attention_mask written out as eight 1s followed by eleven 0s. “The attention mask is a binary tensor indicating the position of the padded indices so that the model does not attend to them,” says the glossary entry for attention mask.
The object is specified in the frameworks too. PyTorch's nn.MultiheadAttention takes key_padding_mask of shape (N, S), “indicating which elements within key to ignore for the purpose of attention (i.e. treat as "padding")”. The mechanism goes back to Attention Is All You Need in 2017, which records the implementation in a single line: “We implement this inside of scaled dot-product attention by masking out (setting to −∞) all values in the input of the softmax which correspond to illegal connections.”
Drop the mask and the eleven padded positions of that worked example are ordinary evidence. They receive finite attention weight instead of none. They enter pooling, losses and normalization alongside the eight real tokens. The shape is still correct throughout.
Padding is storage convenience; masking preserves the original data meaning.
Analogy
A labeled warehouse of multidimensional shelves
In one warehouse, every aisle, shelf, bin, and item position has a distinct label. Reordering labels without moving goods changes how workers interpret each address.
A warehouse address cannot capture tensor algebra across axes. Neural operations may intentionally mix coordinates to create entirely new representations.
The framework authors agree that position is a weak contract. Addressing a dimension by where it sits fails in three ways, and Alexander Rush's note Tensor Considered Harmful sets out all three. The first is private dimensions: a function has to account for them even when they are irrelevant to it. The second is broadcasting that aligns by absolute position — the trailing-dimension algorithm of the previous section. The third he calls access by comments. There the code “will run fine for whatever value dim is given”, because the comment naming the axes is checked by nothing. PyTorch shipped named tensors in version 1.3 on 10 October 2019 in response, and the release announcement cites that argument. The old convention was a comment reading Tensor[N, C, H, W] above the call. The new one names the axis inside the call itself.
Axis labels are part of the data contract, even when code stores only lengths.
Steps
A shape ledger for every model block
Maintain a small ledger during design and debugging. It exists because of what the previous sections established. The framework already records rank and shape for you, in array.ndim and array.shape, and records nothing at all about what any axis means. The ledger is where the missing third row of the vocabulary is kept. It is what a mask check or a row-index check is checked against.
1. Write shape
Record the ordered dimension sizes.
2. Name axes
Attach semantic labels and units to each dimension.
3. Predict operation
State which axes are mixed, preserved, added, or removed.
4. Check masks
Verify padding and missing positions cannot contribute accidentally.
5. Inspect samples
Map several tensor coordinates back to raw records.
Shape assertions that save hours
Assert expected rank, axis lengths, finite values, and allowed ranges at module boundaries. During early development, also inspect one example before and after every major transformation. Tests should include batch size one, empty optional fields, maximum sequence length, and non-contiguous tensor layouts when the framework permits them.
The category has been counted rather than merely complained about. A 2018 empirical study of TensorFlow program bugs classified 175 of them — 87 from Stack Overflow and 88 from GitHub — into seven root-cause categories. Twenty-four of the 175 were “Unaligned Tensor”: 15 from Stack Overflow, 9 from GitHub, 13.7% of the whole corpus. The definition is narrow and mechanical: “A bug spotted in computation graph construction phase when the shape of the input tensor does not match what it is expected is called an unaligned tensor bug.” Verma and Su re-used that same benchmark in 2020 for a tool called ShapeFlow. They call shape incompatibility “one of the most common bugs in deep learning code”, and on 52 such programs they report no false positives, a single false negative, and average speed-ups of 499x and 24x over running TensorFlow itself. Checking shapes is cheaper than running the graph, by roughly those factors.
Axis order is not only a readability question. It is measured in throughput. NVIDIA's Convolutional Layers User's Guide is explicit about the layout. It states that “convolutions implemented for Tensor Cores require NHWC layout and are fastest when input tensors are laid out in NHWC”, and adds that “NCHW layouts can still be operated on by Tensor Cores, but include some overhead due to automatic transpose operations”. PyTorch's own channels-last tutorial reports the other side of the same trade: over 22% faster training under automatic mixed precision, and gains of 8%–35% on Volta devices. That comes from re-ordering the same numbers in memory and changing nothing else.
Key takeaways
- Rank counts axes and shape lists their ordered lengths — the NumPy paper in Nature defined both in 2020, and neither array.shape nor array.ndim records what an axis means.
- Axis meaning is a contract the APIs themselves disagree on: tf.nn.conv2d defaults to NHWC, torch.nn.Conv2d takes (N, C_in, H_in, W_in), and only ONNX's dimension denotation names the axes at all.
- Reshape, transpose, broadcast and reduce differ fundamentally; broadcasting in particular aligns from the trailing dimension by a published algorithm that never consults semantics.
- Padding masks are shaped objects, not habits: eight 1s and eleven 0s for sentences of length 8 and 19, key_padding_mask of shape (N, S), and −∞ before the softmax in the 2017 transformer paper.
- A program can be shape-correct and still wrong — Baggerly and Coombes could reproduce the Duke cisplatin heatmap only from row 98 instead of row 97, and the trials were closed on 22 October 2010.
- Shape bugs are a measured category — 24 of 175 TensorFlow bugs, 13.7%, in the 2018 empirical study — which is why a shape ledger and boundary assertions repay their cost.