Few-Shot Learning Low-Data Adaptation One-Shot Learning

# Few-Shot Learning: Low-Data Adaptation & One-Shot Learning

## Introduction & Motivation

Few-shot learning: learn from minimal examples per class; 1-5 samples typical. Metric learning: learn comparison function. Matching networks: attention over support set. Relation networks: learnable similarity. Applications: rapid task adaptation, limited data scenarios, cold-start problems.

Motivation: Real-world often limited per-class data. Few-shot enables learning from scarce labels.

Applications: New disease diagnosis, rare object detection, new language translation.

---

## Core Concepts & Theory

### Support and Query Sets

Support: labeled few examples per class. Query: unlabeled; test classification.

### Metric Learning

Learn embedding space; classify via distance.

### Matching Networks

Compute attention weights over support; classify as weighted average.

---

## Mathematical Formulation

N-way K-shot task:
- N classes, K examples per class in support set S
- Query set Q: unlabeled samples
- Task: classify Q samples via S

Matching Networks:
$$P(y|x, S) = \sum_{i \in S} a(x, x_i) y_i$$

attention weight a(x, x_i) normalized.

Relation Network:
$$ ext{relation}_c(x) = ext{Net}( ext{concat}(x, c))$$

learnable relation score.

---

## Advanced Theory & Extensions

### Siamese Networks

Twin encoder branches; learn similarity via contrastive loss.

### Prototypical Networks

Meta-learning; learn metric space.

### Optimization-Based

MAML, learned optimizers; rapid gradient-based adaptation.

---

## Computational Considerations

Metric learning: O(K·N·forward) distance computation.

Matching networks: O(K·N) attention; reasonable.

Relation networks: O(K·N) relation computation.

---

## Practical Implementation Strategies

### Data Augmentation

Limited data; augment support set; common practice.

### Episodic Training

Simulate few-shot tasks during training; distribution match.

### Fine-Tuning

Adapt on support set; gradient or metric-based.

---

## Benchmark Datasets & Evaluation

miniImageNet: Standard; 5-way 1-shot, 5-way 5-shot.

omniglot: Character recognition; 60-way 1-shot.

CUB: Fine-grained birds; domain adaptation benchmark.

---

## Key Challenges & Limitations

### Domain Gap

Pretraining domain ≠ few-shot domain; hurts adaptation.

### Overfitting

Few examples; high variance; regularization critical.

### Scalability

Metric computation O(K·N) per query; expensive.

---

## Hyperparameter Tuning

Support size K: 1-5 typical; more = easier.

N-way: 5-20 typical; more = harder.

Learning rate: 0.001-0.1; few-shot typically high.

---

## Real-World Applications & Case Studies

Medical Imaging: Rare disease diagnosis; few labeled scans.

Object Detection: New object category; one-shot localization.

Machine Translation: New language; few parallel sentences.

---

## Integration with Other Methods

Few-Shot + Domain Adaptation → cross-domain low-shot.

Few-Shot + Contrastive Learning → better metric space.

---

## Summary & Key Takeaways

Few-shot learning via metric learning, matching networks, and meta-learning enables classification with minimal labeled examples through learned similarity and rapid adaptation.

Principles:
1. Support/Query split: learn from few, test on many.
2. Metric learning: learn comparison function.
3. Matching: attention over support set.
4. Episodic training: simulate few-shot tasks.
5. Data augmentation: critical with few examples.

---

---

## Appendix: Practical Labs

### Lab 1: Support and Query Sets

import numpy as np
from collections import defaultdict

def create_few_shot_task(X, y, n_way=5, n_shot=1, n_query=15):
 """Create N-way K-shot task"""
 classes = np.unique(y)
 selected_classes = np.random.choice(classes, n_way, replace=False)
 
 support_X, support_y = [], []
 query_X, query_y = [], []
 
 for c in selected_classes:
 class_indices = np.where(y == c)[0]
 selected_idx = np.random.choice(class_indices, n_shot + n_query, replace=False)
 
 support_X.append(X[selected_idx[:n_shot]])
 support_y.extend([c] * n_shot)
 
 query_X.append(X[selected_idx[n_shot:n_shot + n_query]])
 query_y.extend([c] * n_query)
 
 support_X = np.vstack(support_X)
 query_X = np.vstack(query_X)
 
 return support_X, support_y, query_X, query_y

# Test
np.random.seed(42)
X = np.random.randn(500, 64)
y = np.repeat(np.arange(10), 50)

support_X, support_y, query_X, query_y = create_few_shot_task(X, y, n_way=5, n_shot=1)

assert support_X.shape == (5, 64), "Support shape correct"
assert query_X.shape == (75, 64), "Query shape correct"
assert len(support_y) == 5, "Support labels correct"
print("✓ Few-shot task creation working")

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

### Lab 2: Matching Networks

import torch
import numpy as np

def matching_networks(query_feature, support_features, support_labels, n_way):
 """Matching networks: attention-based classification"""
 # Compute attention
 query_expanded = query_feature.unsqueeze(0) # [1, dim]
 dists = torch.cdist(query_expanded, support_features)[0] # [K]
 
 # Softmax attention
 attention = torch.softmax(-dists, dim=0) # Negative distance
 
 # Weighted average over support labels
 logits = torch.zeros(n_way)
 for c in range(n_way):
 mask = torch.tensor([label == c for label in support_labels])
 logits[c] = attention[mask].sum()
 
 return logits

# Test
np.random.seed(42)
query = torch.randn(64)
support_features = torch.randn(5, 64)
support_labels = [0, 1, 2, 3, 4]

logits = matching_networks(query, support_features, support_labels, n_way=5)

assert logits.shape == (5,), "Logits shape correct"
assert abs(logits.sum().item() - 1.0) < 1e-6, "Attention weights sum to 1"
print("✓ Matching networks working")

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

### Lab 3: Siamese Networks

import torch
import torch.nn as nn

class SiameseNetwork(nn.Module):
 def __init__(self, input_dim=784, hidden_dim=128):
 super().__init__()
 self.encoder = nn.Sequential(
 nn.Linear(input_dim, hidden_dim),
 nn.ReLU(),
 nn.Linear(hidden_dim, hidden_dim),
 nn.ReLU(),
 nn.Linear(hidden_dim, hidden_dim)
 )
 self.classifier = nn.Sequential(
 nn.Linear(hidden_dim * 2, hidden_dim),
 nn.ReLU(),
 nn.Linear(hidden_dim, 1),
 nn.Sigmoid()
 )

 def forward(self, x1, x2):
 feat1 = self.encoder(x1)
 feat2 = self.encoder(x2)
 
 combined = torch.cat([feat1, feat2], dim=1)
 similarity = self.classifier(combined)
 
 return similarity

# Test
model = SiameseNetwork()
x1 = torch.randn(8, 784)
x2 = torch.randn(8, 784)

similarity = model(x1, x2)

assert similarity.shape == (8, 1), "Similarity shape correct"
assert (similarity >= 0).all() and (similarity <= 1).all(), "Similarity in [0,1]"
print("✓ Siamese network working")

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

### Lab 4: Few-Shot Evaluation Metrics

import numpy as np

def compute_few_shot_accuracy(query_labels, predicted_labels):
 """Compute accuracy for few-shot task"""
 correct = np.sum(query_labels == predicted_labels)
 total = len(query_labels)
 accuracy = correct / total
 
 return accuracy

def compute_few_shot_confidence_interval(accuracies, confidence=0.95):
 """Compute CI over multiple tasks"""
 mean_acc = np.mean(accuracies)
 std_acc = np.std(accuracies)
 n_tasks = len(accuracies)
 
 # 95% CI
 margin = 1.96 * std_acc / np.sqrt(n_tasks)
 
 return mean_acc, margin

# Test
np.random.seed(42)
# Simulate 100 tasks
accuracies = np.random.uniform(0.7, 1.0, 100)

mean_acc, margin = compute_few_shot_confidence_interval(accuracies)

assert 0 <= mean_acc <= 1, "Mean accuracy in [0,1]"
assert margin > 0, "Margin positive"
assert np.isfinite(mean_acc) and np.isfinite(margin), "All finite"
print("✓ Few-shot metrics working")

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

Go deeper with CFSGPT

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

Create Free Account