Skip to content

← Batching and the Data Path step 1 of 5

Easy Primitives

Adding an axis, or extending one

Jump to the task

stack adds a new axis. cat joins values along an existing axis. For a list of equally sized vectors, that distinction determines whether you get a batch or one long vector:

import torch

examples = [torch.tensor([1., 2.]), torch.tensor([3., 4.])]
batch = torch.stack(examples)
joined = torch.cat(examples)
print(batch.tolist())  # [[1.0, 2.0], [3.0, 4.0]]
print(list(batch.shape))  # [2, 2]
print(joined.tolist())  # [1.0, 2.0, 3.0, 4.0]
print(list(joined.shape))  # [4]

stack requires all input shapes to match. Its new axis has one position per input tensor. For ordinary nonempty inputs, cat requires matching sizes on every axis except the one being joined.

Does the input already have a batch axis?

For three individual examples of shape (4,), stacking produces (3, 4). For three single-example batches of shape (1, 4), concatenating along axis zero produces (3, 4) instead:

Input shapes stack along axis 0 cat along axis 0
Three tensors of shape (4,) (3, 4) (12,)
Three tensors of shape (1, 4) (3, 1, 4) (3, 4)

Choose based on what each axis represents. Stacking is appropriate for individual examples without a batch axis. Concatenation is appropriate for joining existing batches or extending a feature axis.

Storage and copying

With the default calls used here, both operations construct a new result buffer and copy the input values into it. Stacking has the same value and shape semantics as inserting an axis into each input and concatenating; that is not a guarantee about its internal implementation.

The harness creates each example separately, so the batch needs combined storage. In other code, inputs might already be slices of a shared batch; retaining that original batch can avoid an unnecessary split-and-rejoin. Separate tensor objects do not necessarily mean separate storage.

Splitting a strided tensor with split or chunk returns views. split can use a piece size or explicit section sizes. chunk requests a number of pieces, but may return fewer than requested. Neither requires copying the values merely to describe the pieces.

Your task

def collate(examples: list) -> torch.Tensor

Given a nonempty list of equal-length 1-D tensors, return shape (len(examples), length). Each output row must contain the corresponding example. The starter concatenates into one long vector; replace it with an operation that creates the batch axis.