← Uber Interview Insights

Uber·Machine Learning Engineer·Technical Phone Screen·Senior

Senior
Apr 2026

Summary

Uber ML engineer interview, technical phone screen that was basically one meaty coding question about implementing multi-head self-attention from scratch in PyTorch, plus a bunch of follow-up theory questions. No shortcuts allowed, they explicitly said no nn.MultiheadAttention. Felt like a grad school exam.

Questions Asked (5)

Q1

Implement a MultiHeadSelfAttention module in PyTorch from scratch, without using any built-in attention layers. The class should accept embed_dim and num_heads, and the forward pass should take a tensor of shape (batch, seq_len, embed_dim) plus an optional mask.

Algorithms & Data StructuresTechnical Trade-offsSystem Design
Author's notes

This is the kind of question where you think you know it until you're actually writing the code.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements and constraints, then outline the mathematical operations of multi-head self-attention. Implement the module step-by-step, ensuring proper handling of the mask and efficient tensor operations, and finally discuss trade-offs and potential optimizations.

Pro tip: Mention that you would use a single linear projection for Q, K, V to improve efficiency, and emphasize the importance of scaling by sqrt(head_dim) to stabilize gradients.

1. Clarify requirements and constraints

Ask about input shapes, mask semantics (e.g., padding vs. causal), and whether to include bias or dropout. Confirm that no built-in attention layers are allowed.

2. Outline the mathematical formulation

Explain the steps: linear projections to Q, K, V; splitting into heads; scaled dot-product attention; concatenation; and final output projection.

3. Implement the module in PyTorch

Write the __init__ to define linear layers and parameters, and the forward method to compute attention, applying the mask appropriately (e.g., setting masked positions to -inf before softmax).

4. Test and validate

Suggest testing with a small example, checking output shapes, and verifying that masking works as expected (e.g., masked positions have zero attention weights).

5. Discuss trade-offs and optimizations

Talk about computational complexity, memory usage, and potential optimizations like using einsum or fused kernels, and how to handle large sequences.

Key Points to Mention

  • Scaling factor 1/sqrt(head_dim) to prevent softmax saturation
  • Proper reshaping and transposition for multi-head splitting (e.g., view and permute)
  • Mask application: additive mask with -inf before softmax, handling both padding and causal masks
  • Efficiency: combining Q, K, V projections into one linear layer for speed
  • Numerical stability: using torch.softmax with dim=-1 and avoiding NaNs from -inf
  • Output projection after concatenating heads to mix information across heads

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

Why do we scale the dot products by the square root of the head dimension before applying softmax?

Technical Trade-offs
Author's notes

Nailed this one.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Explain the mathematical reason: without scaling, the dot products grow with the head dimension, pushing softmax into saturated regions with tiny gradients. Then connect this to training stability and model performance, showing you understand both theory and practice.

Pro tip: Mention that the scaling factor is not arbitrary—it's derived from the variance of the dot product under the assumption of independent, zero-mean components, and that it ensures the softmax outputs remain in a reasonable range.

1. Define the dot product and softmax

Briefly state that attention computes dot products between queries and keys, then applies softmax to get attention weights.

2. Explain the variance growth

Show that if query and key components are independent with zero mean and unit variance, the dot product has variance equal to the head dimension, so its magnitude grows with sqrt(d_k).

3. Describe the softmax saturation problem

Large dot products cause softmax to produce near-one-hot distributions, leading to vanishing gradients and slow or unstable training.

4. Introduce the scaling factor

Dividing by sqrt(d_k) normalizes the variance back to 1, keeping softmax inputs in a range where gradients are well-behaved.

5. Conclude with practical impact

Summarize that this scaling is crucial for stable and efficient training of Transformers, and mention it's a standard part of the attention mechanism.

Key Points to Mention

  • Dot product variance grows linearly with head dimension d_k.
  • Softmax saturates when inputs are large, causing vanishing gradients.
  • Scaling by 1/sqrt(d_k) normalizes variance to approximately 1.
  • This improves gradient flow and training stability.
  • It is a key component of the scaled dot-product attention in Transformers.
  • The scaling factor is derived from statistical properties, not heuristic.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

What's the difference between causal attention and bidirectional attention, and how would you implement a causal mask?

Technical Trade-offsAlgorithms & Data Structures
Author's notes

I explained it fine conceptually but when they asked me to actually write the mask I blanked for a second.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining causal and bidirectional attention in terms of the attention mask, then contrast their use cases (e.g., autoregressive generation vs. representation learning). Finally, explain how to implement a causal mask with a lower-triangular matrix and apply it before softmax.

Pro tip: Mention that causal masks are essential for preventing information leakage in autoregressive models, and that efficient implementations use additive masks with -inf or boolean masks to avoid unnecessary computations.

1. Define Attention Mechanism

Briefly explain that attention computes weighted sums of values based on query-key similarities, and that masking controls which positions can attend to which.

2. Contrast Causal vs. Bidirectional

Explain that causal attention restricts each position to attend only to previous positions (and itself), while bidirectional attention allows all positions to attend to all others.

3. Discuss Use Cases

Mention that causal attention is used in decoder-only models (e.g., GPT) for autoregressive generation, while bidirectional attention is used in encoder-only models (e.g., BERT) for tasks like classification.

4. Implement Causal Mask

Describe creating a lower-triangular matrix of ones (size seq_len x seq_len), then converting it to an additive mask with 0s and -inf, and adding it to attention scores before softmax.

5. Highlight Efficiency and Variants

Note that masks can be boolean or additive, and that efficient implementations may use fused kernels or avoid materializing the full matrix.

Key Points to Mention

  • Causal attention prevents information leakage from future tokens, crucial for autoregressive generation.
  • Bidirectional attention allows full context, beneficial for tasks like masked language modeling.
  • Causal mask is typically a lower-triangular matrix (including diagonal) of ones.
  • Implementation: add mask to attention scores before softmax, setting masked positions to -inf.
  • Efficiency considerations: use boolean masks or optimized kernels to reduce memory and compute.
  • Examples: GPT uses causal attention; BERT uses bidirectional attention.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

Walk through the shape of the tensor at each step of the multi-head attention computation.

Algorithms & Data Structures
Author's notes

Probably the most useful follow-up they asked.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by defining the input tensor shape and the projection dimensions, then walk through each operation (linear projections, splitting into heads, scaled dot-product attention, concatenation, and output projection) while clearly stating the tensor shape at each step. Use a concrete example (e.g., batch size B, sequence length T, model dimension D, number of heads H) to make the shapes tangible and avoid ambiguity.

Pro tip: Mention that the per-head dimension is typically D/H, and that the computation is parallelized across heads; also note that the output projection returns the tensor to the original model dimension, which is crucial for residual connections.

1. Define input and projection shapes

State the input tensor shape (B, T, D) and the weight matrices for Q, K, V projections, each of shape (D, D). After linear projection, Q, K, V each have shape (B, T, D).

2. Split into multiple heads

Reshape Q, K, V from (B, T, D) to (B, T, H, D/H) and then transpose to (B, H, T, D/H) so that each head processes a slice of the feature dimension independently.

3. Compute scaled dot-product attention per head

For each head, compute attention scores as Q @ K^T / sqrt(D/H), resulting in shape (B, H, T, T). Apply softmax over the last dimension, then multiply by V to get (B, H, T, D/H).

4. Concatenate heads and project output

Transpose back to (B, T, H, D/H) and reshape to (B, T, D) by concatenating heads. Apply the output projection weight (D, D) to get the final output shape (B, T, D).

Key Points to Mention

  • Input tensor shape: (batch_size, sequence_length, model_dimension)
  • Linear projections for Q, K, V: each weight matrix is (model_dimension, model_dimension)
  • Splitting into heads: reshape to (batch_size, sequence_length, num_heads, head_dim) and transpose to (batch_size, num_heads, sequence_length, head_dim)
  • Scaled dot-product attention: scores shape (batch_size, num_heads, sequence_length, sequence_length), softmax over last dim, then multiply by V
  • Concatenation of heads: transpose and reshape back to (batch_size, sequence_length, model_dimension)
  • Output projection: final linear layer returns shape (batch_size, sequence_length, model_dimension)

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

What is the time and memory complexity of self-attention with respect to sequence length?

Technical Trade-offsSystem Design
Author's notes

O(n^2 * d) for both time and memory because of the QK^T matrix.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clearly stating the time and memory complexity of self-attention with respect to sequence length n: O(n^2 * d) time and O(n^2) memory for a single head, where d is the model dimension. Then explain the derivation by breaking down the matrix operations, and discuss the implications for long sequences and common optimizations like sparse attention or linear approximations.

Pro tip: Mention that while the time complexity is O(n^2 * d), the memory bottleneck is often the O(n^2) attention matrix, which limits sequence length in practice. Also, note that multi-head attention multiplies the cost by the number of heads, but since each head typically has dimension d/h, the total remains O(n^2 * d).

1. State the complexities

Clearly state that self-attention has O(n^2 * d) time complexity and O(n^2) memory complexity with respect to sequence length n, where d is the model dimension.

2. Derive from matrix operations

Explain that computing attention involves matrix multiplications: QK^T (n x d times d x n) gives n x n matrix, softmax, and then multiplication with V (n x n times n x d). Each step contributes to the overall complexity.

3. Discuss multi-head and batching

Clarify that for multi-head attention with h heads, each head operates on dimension d/h, so total time remains O(n^2 * d) and memory O(n^2 * h) if storing all heads, but often memory is O(n^2) per head.

4. Highlight practical implications

Emphasize that quadratic scaling limits sequence length, and mention common approaches to mitigate: sparse attention, low-rank approximations, or linear attention mechanisms.

5. Connect to system design trade-offs

Relate to real-world systems: for long sequences, memory becomes the bottleneck, so techniques like gradient checkpointing, chunked attention, or memory-efficient attention (e.g., FlashAttention) are used.

Key Points to Mention

  • Time complexity O(n^2 * d) due to pairwise interactions between all positions.
  • Memory complexity O(n^2) for the attention matrix, which is often the limiting factor.
  • Multi-head attention does not change asymptotic complexity if total dimension d is fixed.
  • Quadratic scaling makes long sequences computationally expensive.
  • Common optimizations: sparse attention, linear attention, low-rank approximations.
  • Practical systems use memory-efficient attention implementations like FlashAttention.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.