Implement Multi-Head Attention from Scratch in NumPy
AmazonApplied Scientist · OnsiteLast updated
This problem tests your understanding of Transformer components by requiring an implementation of Multi-Head Scaled Dot-Product Attention using only NumPy, emphasizing matrix manipulations and numerical stability.
Multi-Head Attention Implementation
Implement the MultiHeadAttention class using NumPy. Your implementation should perform the core attention mechanism used in Transformer architectures.
Requirements
- Linear Projections: Given input
Xof shape(batch_size, seq_len, d_model), project into Queries, Keys, and Values using weight matricesWq,Wk,Wvof shape(d_model, d_model). - Split Heads: Reshape the projected matrices to
(batch_size, num_heads, seq_len, d_k)whered_k = d_model / num_heads. - Scaled Dot-Product Attention: Compute
Attention(Q, K, V) = softmax((Q @ K.T) / sqrt(d_k)) @ V. - Causal Masking: Optionally apply a mask to prevent tokens from attending to future positions (i.e., setting values in the upper triangle of the attention matrix to negative infinity before softmax).
- Output: Concatenate the results from heads and apply a final linear projection
Wo.
Function Signature
import numpy as np
class MultiHeadAttention:
def __init__(self, d_model, num_heads):
# Initialize weight matrices here
pass
def forward(self, X, mask=None):
# Perform the multi-head attention operation
# Returns the output tensor of shape (batch_size, seq_len, d_model)
pass
Constraints
d_modelwill always be divisible bynum_heads.- Use a numerically stable softmax implementation:
exp(x - max(x)).
Example
Input: X (1, 3, 8), num_heads = 2.
Internal d_k = 4. The attention scores for each head will be (1, 2, 3, 3) shaped tensors before being concatenated back to (1, 3, 8).
Edge Cases
mask=None: Standard self-attention.mask=True: Apply a causal (look-ahead) mask.- Single-head vs. Multi-head scenarios.
Hints
Hint 1
To reshape the tensors for heads, use np.transpose() carefully to ensure the dimensions are (batch, heads, seq_len, d_k) before performing dot products.
Hint 2
For the causal mask, create a matrix of ones where the lower triangle is 1 and the rest 0; multiply positions with 0 by a very large negative number before applying softmax.
Hint 3
Remember that the softmax function must be applied across the last dimension (the key-sequence dimension).
Follow-up questions
- How would you modify this implementation to handle variable-length sequences using padding masks?
- Explain the memory complexity of the attention mechanism. At what sequence length does this approach become the primary bottleneck?
- If you were deploying this to a production inference service, what specific NumPy optimizations or BLAS libraries would you look into to improve performance?
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.