We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Shapes and Strides step 6 of 9
Fold the heads into the batch
Multi-head attention holds activations as:
(batch, heads, length, dim)
and then wants to hand them to something that takes a single batch axis. The
standard move is to fold heads into batch:
(batch, heads, length, dim) -> (batch * heads, length, dim)
Every head becomes its own item in a bigger batch. Nothing about the numbers changes; only the label on the first axis does.
Why it is free
Adjacent axes can always be merged as a view, because their elements are already adjacent in memory in exactly the right order. Look at the strides:
(2, 3, 4, 5) strides (60, 20, 5, 1)
(6, 4, 5) strides (20, 5, 1)
Axis 0 stepped 60 and axis 1 stepped 20 with three of them; the merged axis steps 20 with six. Same buffer, same order, one fewer number in the shape.
Where it stops being free
Merge two axes that are not adjacent in memory and there is nothing to merge:
x.permute(0, 2, 1, 3).reshape(batch * length, heads, dim) # copies
After the permute, the elements of the two leading axes are interleaved with
everything else. No stride describes the result, so reshape allocates. This
is why the standard implementation permutes after merging where it can, and
why contiguous() shows up next to view in every attention implementation
you will read.
Your task
def fold_heads(x: torch.Tensor) -> torch.Tensor
x is (batch, heads, length, dim). Return (batch * heads, length, dim)
without copying the buffer.
The starter uses torch.cat over a list comprehension, which is what this
looks like before you know about strides. It produces the right tensor and
allocates the whole thing.
Stuck?
PyTorch reference solution
Sign in to attempt this problem and reveal the reference solution.