Attention Mechanisms Self-Attention Scaled Dot-Product

# Attention Mechanisms: Self-Attention & Scaled Dot-Product

## Introduction & Motivation

Attention: dynamically weight context by relevance. Scaled dot-product attention: query-key-value triple. Self-attention: attend within sequence; enables long-range dependencies. Applications: NLP, vision, multimodal models.

Motivation: RNNs struggle with long-range dependencies (vanishing gradients). Attention provides direct paths; parallelizable.

Applications: Machine translation, question answering, image captioning, visual reasoning.

---

## Core Concepts & Theory

### Query-Key-Value

Query: what to look for. Key: what each position offers. Value: information to aggregate.

### Scaled Dot-Product Attention

Similarity: dot product of query-key. Scale by √d_k; softmax; aggregate values.

### Multi-Head Attention

Multiple representation subspaces; captures diverse patterns.

---

## Mathematical Formulation

Scaled dot-product attention:
$$ ext{Attention}(Q, K, V) = ext{softmax}\left(\frac{QK^T}{\sqrt{d_k}} ight)V$$

Multi-head attention:
$$ ext{MultiHead}(Q, K, V) = ext{Concat}( ext{head}_1, \ldots, ext{head}_h) W^O$$

where head_i = Attention(QW_i^Q, KW_i^K, VW_i^V).

---

## Advanced Theory & Extensions

### Masked Attention

Prevent attending to future positions; autoregressive generation.

### Relative Position Bias

Bias attention by relative distances; improves locality.

### Linear Attention

Approximate softmax attention; O(n) complexity.

---

## Computational Considerations

Attention: O(n² d) where n=sequence length, d=dimension.

Multi-head: O(n² d); linear in d due to head aggregation.

Memory: O(n²) for attention weights.

---

## Practical Implementation Strategies

### Dropout on Attention Weights

Prevent overfitting; random attention zeroing.

### Layer Normalization

Normalize inputs/outputs; stable training.

### Attention Visualization

Inspect learned attention patterns; interpretability.

---

## Benchmark Datasets & Evaluation

BLEU (Machine Translation): Attention baseline strong.

SQuAD (QA): Attention-based models excel.

COCO (Captioning): Attention over image regions.

---

## Key Challenges & Limitations

### Quadratic Complexity

O(n²) limits very long sequences.

### Position Awareness

Attention permutation-invariant; needs position encoding.

### Information Bottleneck

Single attention head may be insufficient.

---

## Hyperparameter Tuning

Number of heads: 4-16; typically 8.

Attention dropout: 0.1-0.3.

Scaling factor: √d_k (fixed); alternatively learnable.

---

## Real-World Applications & Case Studies

Machine Translation: Seq2Seq with attention; standard.

Visual QA: Attend over image regions by question.

Code Understanding: Attention for cross-references.

---

## Integration with Other Methods

Attention + LSTM → hybrid seq2seq (Bahdanau).

Attention + Transformer → full attention-based architecture.

---

## Summary & Key Takeaways

Attention mechanisms via scaled dot-product enable dynamic context weighting, with multi-head variants capturing diverse representations across sequence positions.

Principles:
1. Query-key-value: decompose input into three roles.
2. Softmax attention weights: probability distribution over positions.
3. Scaled by √d_k: prevent vanishing gradients.
4. Multi-head: diverse subspace representations.
5. Parallel computation: efficient vs sequential RNNs.

---

---

## Appendix: Practical Labs

### Lab 1: Scaled Dot-Product Attention

import torch
import torch.nn.functional as F
import numpy as np

def scaled_dot_product_attention(Q, K, V, mask=None):
 """Compute scaled dot-product attention"""
 d_k = Q.size(-1)
 
 # Attention scores
 scores = torch.matmul(Q, K.transpose(-2, -1)) / np.sqrt(d_k)
 
 if mask is not None:
 scores = scores.masked_fill(mask == 0, float('-inf'))
 
 # Attention weights
 weights = F.softmax(scores, dim=-1)
 
 # Weighted sum of values
 output = torch.matmul(weights, V)
 
 return output, weights

# Test
Q = torch.randn(8, 10, 64) # [batch, seq_len, d_k]
K = torch.randn(8, 10, 64)
V = torch.randn(8, 10, 64)

output, weights = scaled_dot_product_attention(Q, K, V)

print(f"Attention output shape: {output.shape}, Weights shape: {weights.shape}")
assert output.shape == V.shape, "Should preserve value dimensions"
assert weights.shape == (8, 10, 10), "Should be attention matrix"
print("✓ Scaled attention working")

if __name__ == "__main__":
 print("Lab 1: Attention - PASSED")

### Lab 2: Multi-Head Attention

import torch
import torch.nn as nn

class MultiHeadAttention(nn.Module):
 def __init__(self, d_model=512, num_heads=8):
 super().__init__()
 self.num_heads = num_heads
 self.d_k = d_model // num_heads
 
 self.W_q = nn.Linear(d_model, d_model)
 self.W_k = nn.Linear(d_model, d_model)
 self.W_v = nn.Linear(d_model, d_model)
 self.W_o = nn.Linear(d_model, d_model)
 
 def forward(self, Q, K, V):
 batch_size = Q.size(0)
 
 # Linear projections
 Q = self.W_q(Q).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
 K = self.W_k(K).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
 V = self.W_v(V).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
 
 # Scaled dot-product attention
 scores = torch.matmul(Q, K.transpose(-2, -1)) / (self.d_k ** 0.5)
 weights = torch.softmax(scores, dim=-1)
 output = torch.matmul(weights, V)
 
 # Concatenate heads
 output = output.transpose(1, 2).contiguous().view(batch_size, -1, 512)
 output = self.W_o(output)
 
 return output

# Test
mha = MultiHeadAttention(d_model=512, num_heads=8)
Q = torch.randn(8, 10, 512)
K = torch.randn(8, 10, 512)
V = torch.randn(8, 10, 512)

output = mha(Q, K, V)

print(f"MHA output shape: {output.shape}")
assert output.shape == (8, 10, 512), "Should preserve dimensions"
print("✓ Multi-head attention working")

if __name__ == "__main__":
 print("Lab 2: MHA - PASSED")

### Lab 3: Masked Attention

import torch
import torch.nn.functional as F
import numpy as np

def masked_attention(Q, K, V, mask=None):
 """Attention with optional masking (causal, padding)"""
 d_k = Q.size(-1)
 
 scores = torch.matmul(Q, K.transpose(-2, -1)) / np.sqrt(d_k)
 
 # Apply mask (0 = mask out, 1 = keep)
 if mask is not None:
 scores = scores.masked_fill(mask == 0, float('-inf'))
 
 weights = F.softmax(scores, dim=-1)
 weights = weights.masked_fill(mask == 0, 0) # Zero out masked positions
 
 output = torch.matmul(weights, V)
 
 return output, weights

# Test: causal mask (autoregressive)
seq_len = 10
causal_mask = torch.tril(torch.ones(seq_len, seq_len)).unsqueeze(0) # [1, 10, 10]

Q = torch.randn(2, seq_len, 64)
K = torch.randn(2, seq_len, 64)
V = torch.randn(2, seq_len, 64)

output, weights = masked_attention(Q, K, V, mask=causal_mask)

print(f"Masked attention output shape: {output.shape}")
assert output.shape == V.shape, "Should preserve value shape"
print("✓ Masked attention working")

if __name__ == "__main__":
 print("Lab 3: Masked Attention - PASSED")

### Lab 4: Attention Visualization

import torch
import torch.nn.functional as F
import numpy as np

def analyze_attention_heads(attention_weights):
 """Analyze attention head patterns"""
 # attention_weights: [batch, num_heads, seq_len, seq_len]
 
 batch_size, num_heads, seq_len, _ = attention_weights.shape
 
 # Entropy per head (measure of focus)
 entropy = -(attention_weights * torch.log(attention_weights + 1e-8)).sum(dim=-1).mean()
 
 # Diagonal focus (attending to self)
 diag_focus = torch.diagonal(attention_weights, dim1=-2, dim2=-1).mean()
 
 return entropy.item(), diag_focus.item()

# Test
weights = torch.softmax(torch.randn(2, 8, 10, 10), dim=-1)

entropy, diag = analyze_attention_heads(weights)

print(f"Attention entropy: {entropy:.4f}, Diagonal focus: {diag:.4f}")
assert 0 <= entropy, "Entropy should be non-negative"
assert 0 <= diag <= 1, "Diagonal focus should be in [0,1]"
print("✓ Attention analysis working")

if __name__ == "__main__":
 print("Lab 4: Analysis - PASSED")

Go deeper with CFSGPT

Get AI-powered deep-dives, save terms, and run advanced simulations — free account.

Create Free Account