Skip to content
Back to skills

Transfer Learning Patterns

ASecurity

Use when applying transfer learning and domain adaptation.

  • 2 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 10, 2026
ai-agentspythongoperformance

Security analysis

A100/100

Scanned September 10, 2026

npx -y skills add LoopyLuci/Skills --skill transfer-learning-patterns --agent claude-code

Installs 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 with every re-scan.

Security grade badge for Transfer Learning Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/loopyluci-transfer-learning-patterns/badge)](https://www.skillsdirectory.com/skills/loopyluci-transfer-learning-patterns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…