Linear algebra for LLMsPart 4: Tensors, shapes and einsum
Reshape vs transpose
8 min
Memory is one flat list
A tensor’s numbers sit in one long line. Row-major order (PyTorch’s default) stores row 1, then row 2: the last axis changes fastest.
Write
Reshape re-cuts the same list
reshape (or view) keeps the flat order and cuts it into new rows: 1 2 | 3 4 | 5 6. The numbers don’t move in memory.
Transpose is a different thing
The transpose is also , but its rows are . Same shape as the reshape, different matrix. PyTorch transposes by swapping the strides (how far to jump in memory for each axis), so nothing is copied, and the result is no longer laid out in row-major order: it’s non-contiguous.
Write
Splitting heads, step 1: view
Two tokens, features, heads of . view(2, 2, 2) cuts each token’s 4 features into 2 heads: head 0 gets features 1–2, head 1 gets features 3–4. Shape . Correct so far.
Step 2: transpose heads to the front
transpose(0, 1) swaps the token and head axes: . Each head now holds one row per token, made of that token’s own slice of features. Attention can run on each head separately.
Write
view(T, h, d_h) then transpose(0, 1) → .The bug: view straight into
view(2, 2, 2) read as cuts the flat list a₁ a₂ a₃ a₄ b₁ b₂ b₃ b₄ in the wrong places. Head 0’s “two tokens” are really two halves of token a; token b vanished from it. The shape is right, so no error, but attention now mixes features as if they were tokens.
Write
view(h, T, d_h) directly scrambles tokens. Always view to first, then transpose.With a batch, and back again
q = x.view(B, T, h, d_h).transpose(1, 2) # (B, h, T, d_h)
# ... attention per head ...
out = out.transpose(1, 2).reshape(B, T, h * d_h) # (B, T, d), heads mergedAfter transpose, the tensor is non-contiguous, so .view would fail. .reshape copies when it has to (or write .contiguous().view(...)).
✏️ Your turn
Which shape?
With heads, write the shape of x.view(2, 6, 3, 4).transpose(1, 2), and what each axis means.
Work it out on paper, then go to the next card to check.
Answer
The view gives = (batch, token, head, feature); swapping axes 1 and 2 puts heads before tokens.
📌 Recap
Reshape vs transpose in one card
- Memory is flat and row-major: the last axis changes fastest.
reshape/viewre-cuts the flat order; transpose swaps axes (strides) and makes the tensor non-contiguous.- Split heads:
view(B, T, h, d_h).transpose(1, 2). Viewing straight to scrambles tokens without an error. - Merge back:
transpose(1, 2).reshape(B, T, d).
Write