Use when applying transfer learning and domain adaptation.
Scanned 9/10/2026
Install to Claude Code
npx -y skills add LoopyLuci/Skills --skill transfer-learning-patterns --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Transfer Learning Patterns?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/loopyluci-transfer-learning-patterns)More formats (shields.io, HTML) on the badges page.
---
name: transfer-learning-patterns
description: "Use when applying transfer learning and domain adaptation."
version: 1.0.0
author: Hermes Agent
license: MIT
metadata:
hermes:
tags: [transfer-learning, domain-adaptation, fine-tuning, pre-training]
related_skills: [self-supervised-learning, llm-fine-tuning-lora, meta-learning-few-shot, ml-pipeline-design]
---
# Transfer Learning and Domain Adaptation
Transferring knowledge from pre-trained models to new tasks and domains — fine-tuning strategies, feature extraction, domain adaptation, and multi-task learning patterns.
## When to Use
- You have a small dataset but access to a large pre-trained model
- Your target domain differs from the source domain (distribution shift)
- Training from scratch is too expensive (compute, data, or time)
- You need to adapt a general model to a specific use case
- Building multi-task systems that share representations
## Transfer Learning Strategies
| Strategy | Data Labeled | Compute | Performance | When to Use |
|----------|-------------|---------|-------------|-------------|
| Feature Extraction | Few | Low | Good | Source/target similar |
| Full Fine-Tuning | Moderate | High | Best | Source/target somewhat different |
| Adapters/LoRA | Few | Medium | Near-best | Resource-constrained |
| Progressive Unfreezing | Few | Medium | Good | Uncertain similarity |
| Distillation | Moderate | Medium | Good | Model compression + transfer |
## Feature Extraction
```python
import torch
import torch.nn as nn
import torchvision.models as models
class FeatureExtractor:
"""Use pre-trained model as fixed feature extractor."""
def __init__(self, model_name='resnet50', device='cuda'):
# Load pre-trained model without classification head
weights = 'IMAGENET1K_V2'
model = getattr(models, model_name)(weights=weights)
self.model = nn.Sequential(*list(model.children())[:-1])
self.model.eval()
self.model.to(device)
self.device = device
@torch.no_grad()
def extract(self, images):
"""Extract features (no gradients)."""
features = self.model(images)
return features.squeeze(-1).squeeze(-1) # Remove spatial dims
# Train a simple classifier on extracted features
def train_on_features(model, train_loader, num_classes, feature_dim=2048):
classifier = nn.Linear(feature_dim, num_classes)
optimizer = torch.optim.Adam(classifier.parameters(), lr=1e-3)
criterion = nn.CrossEntropyLoss()
# Pre-compute all features (fast epoch training)
all_features, all_labels = [], []
with torch.no_grad():
for images, labels in train_loader:
features = model.extract(images.to(model.device))
all_features.append(features.cpu())
all_labels.append(labels)
all_features = torch.cat(all_features)
all_labels = torch.cat(all_labels)
for epoch in range(100):
preds = classifier(all_features)
loss = criterion(preds, all_labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
return classifier
```
## Fine-Tuning
### Full Fine-Tuning
```python
def full_finetune(model, train_loader, val_loader, num_classes, epochs=10):
"""Fine-tune the entire model."""
# Replace classification head
in_features = model.classifier[0].in_features
model.classifier = nn.Linear(in_features, num_classes)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) # Lower LR
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, epochs)
criterion = nn.CrossEntropyLoss()
for epoch in range(epochs):
model.train()
for images, labels in train_loader:
preds = model(images)
loss = criterion(preds, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
scheduler.step()
# Validation
model.eval()
val_acc = compute_accuracy(model, val_loader)
print(f"Epoch {epoch}: val_acc={val_acc:.4f}")
return model
```
### Progressive Unfreezing
```python
class ProgressiveUnfreeze:
"""Gradually unfreeze layers from top to bottom.
Phase 1: Train new head only (epochs 1-2)
Phase 2: Unfreeze last block (epochs 3-4)
Phase 3: Unfreeze more blocks (epochs 5-10)
"""
def __init__(self, model, num_stages=4):
self.model = model
self.stages = num_stages
# Freeze all
for param in model.parameters():
param.requires_grad = False
def stage(self, stage_num, lr=1e-4):
"""Configure model for training stage."""
if stage_num == 0:
# Only train the new head
for param in self.model.head.parameters():
param.requires_grad = True
elif stage_num == 1:
# Unfreeze last block
for param in self.model.blocks[-1].parameters():
param.requires_grad = True
elif stage_num >= self.stages - 1:
# Unfreeze everything
for param in self.model.parameters():
param.requires_grad = True
def train(self, train_loader, val_loader, epochs_per_stage=3, base_lr=1e-4):
for stage in range(self.stages):
self.stage(stage, base_lr)
lr = base_lr * (10 ** (-stage)) # Lower LR for early layers
optimizer = torch.optim.Adam(
[p for p in self.model.parameters() if p.requires_grad], lr=lr
)
for epoch in range(epochs_per_stage):
self._train_epoch(optimizer, train_loader)
acc = self._evaluate(val_loader)
print(f"Stage {stage}, Epoch {epoch}: val_acc={acc:.4f}")
```
## Domain Adaptation
### Adversarial Domain Adaptation
```python
class DomainAdversarialNetwork(nn.Module):
"""Domain-adversarial training (Ganin et al., 2016).
Feature extractor trained to fool domain classifier,
so features become domain-invariant."""
def __init__(self, feature_extractor, num_classes):
super().__init__()
self.feature_extractor = feature_extractor
self.class_classifier = nn.Linear(512, num_classes)
self.domain_classifier = nn.Sequential(
nn.Linear(512, 256), nn.ReLU(), nn.Linear(256, 2) # Source vs target
)
def forward(self, x, alpha=0.1):
features = self.feature_extractor(x)
# Gradient reversal layer (implemented via gradient scaling)
# In forward pass: identity
# In backward pass: multiply gradients by -alpha
class_output = self.class_classifier(features)
domain_output = self.domain_classifier(
GradientReversal.apply(features, alpha)
)
return class_output, domain_output
```
## Common Pitfalls
1. **Catastrophic forgetting** — fine-tuning on new task destroys pre-trained knowledge; use low LR, shorter training
2. **Domain shift** — pre-trained on ImageNet, deployed on medical images; may need domain adaptation
3. **Head vs body LR** — new head needs higher LR than pre-trained body; use different LR groups
4. **Overly aggressive fine-tuning** — full fine-tuning on tiny dataset overfits; freeze more or use LoRA
5. **Batch norm adaptation** — batchnorm statistics need updating on new domain; use small batches or freeze BN
6. **Task mismatch** — pre-trained on classification, fine-tuned on detection; low-level features still transfer
## Verification Checklist
- [ ] Pre-trained model's input format matches target data (size, normalization, channels)
- [ ] Feature extractor approach evaluated before full fine-tuning
- [ ] Learning rate for fine-tuning lower than from-scratch (1/10th)
- [ ] Catastrophic forgetting checked (pre-training task accuracy preserved)
- [ ] Domain adaptation considered if source/target distributions differ significantly
- [ ] Progressive unfreezing beats one-shot fine-tuning
- [ ] No overfitting on small target dataset (check val vs train gap)
## See Also
- self-supervised-learning — pre-training without labels
- llm-fine-tuning-lora — efficient LLM fine-tuning
- meta-learning-few-shot — learning from very few examples
- ml-pipeline-design — integrating transfer in pipelines
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!