Implement Multi-Head Self-Attention
UberMachine Learning Engineer · Technical ScreenLast updated
This question tests the ability to implement the multi-head self-attention mechanism from scratch using PyTorch, focusing on tensor manipulation, linear projections, and the scaled dot-product attention formula.
Multi-Head Self-Attention Implementation
Implement a MultiHeadAttention class using PyTorch. The class should map an input tensor x of shape (batch_size, seq_len, embed_dim) to an output of the same shape. You must perform the following steps:
- Linear Projections: Apply three separate linear layers to transform the input into Queries (Q), Keys (K), and Values (V).
- Head Splitting: Reshape the Q, K, and V tensors into
(batch_size, num_heads, seq_len, head_dim), wherehead_dim = embed_dim / num_heads. - Scaled Dot-Product Attention: Compute
Attention(Q, K, V) = softmax((Q @ K.transpose(-2, -1)) / sqrt(head_dim)) @ V. - Concatenation and Projection: Concatenate the heads back together and pass them through a final linear output layer.
Function Signature
import torch
import torch.nn as nn
class MultiHeadAttention(nn.Module):
def __init__(self, embed_dim, num_heads):
super().__init__()
# Initialize your linear layers and parameters here
pass
def forward(self, x):
# x shape: (batch_size, seq_len, embed_dim)
# returns: (batch_size, seq_len, embed_dim)
pass
Constraints
embed_dimmust be divisible bynum_heads.- Use
torch.softmaxfor the attention scores.
Example
mha = MultiHeadAttention(embed_dim=512, num_heads=8)
x = torch.randn(32, 10, 512) # batch=32, seq_len=10, dim=512
output = mha(x)
# output.shape should be (32, 10, 512)
Edge Cases
- Consider scenarios where
seq_lenis 1. - Ensure the implementation handles arbitrary
batch_size.
Hints
Hint 1
Use `torch.transpose` or `permute` to arrange dimensions so that matrix multiplication occurs across the sequence length dimension for each head independently.
Hint 2
The scaling factor `1 / sqrt(head_dim)` is crucial for preventing the softmax input from becoming too large and saturating gradients.
Hint 3
Remember to reshape/flatten the final attention output back to `(batch_size, seq_len, embed_dim)` before the final linear projection.
Follow-up questions
- How would you integrate a padding mask into the attention calculation to ignore specific tokens in the sequence?
- Why is multi-head attention generally preferred over single-head attention with a larger hidden dimension?
- How would the memory complexity scale if the sequence length doubles?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.