Fine-tuning: lagen vrijgeven en lage learning rates
Cursisten geven eerdere lagen vrij na de eerste training van de classificatiekop, passen een lagere learning rate toe om voorgetrainde features niet te vernietigen en observeren verbeteringen in nauwkeurigheid.
Fine-tuning: lagen vrijgeven en lage learning rates is een gratis Machine Learning Academy-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Machine Learning Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Machine Learning Academy bevat in totaal 4 lessen.
Waarom fijn afstellen na kenmerkextractie?
Kenmerkextractie past alleen de classificatiekop aan en laat het basisnetwerk vastgezet. Fijn afstellen gaat verder door ook enkele of alle lagen van het basisnetwerk bij te werken, zodat het model zijn representaties kan aanpassen aan jouw specifieke gegevensverdeling.
Fijn afstellen is vooral nuttig wanneer je domein afwijkt van ImageNet — bijvoorbeeld bij satellietbeelden, medische scans of foto's van industriële defecten. De kenmerken van ImageNet worden gedeeltelijk overgedragen, maar door ze aan te passen kan de nauwkeurigheid meetbaar verbeteren. Het risico is catastrofaal vergeten: als je met een hoge leersnelheid fijn afstelt, overschrijven de nieuwe gegevens de zorgvuldig vooraf geleerde kenmerken, waardoor de prestaties instorten.
De tweefasenstrategie voor fijn afstellen
De standaardaanpak voor fijn afstellen bestaat uit twee fasen. Fase 1: Zet het basisnetwerk volledig vast en train alleen de nieuwe classificatiekop gedurende enkele epoches, totdat deze convergeert. Zo begint de kop vanuit een redelijke toestand voordat gradiënten van het basisnetwerk worden toegevoegd.
Fase 2: Geef alle of enkele lagen van het basisnetwerk vrij en ga door met trainen met een zeer lage leersnelheid (doorgaans 10–100× lager dan in fase 1). Zo stuur je de vooraf geleerde kenmerken voorzichtig in de richting van je domein zonder ze te vernietigen. Fase 1 overslaan en vanaf het begin fijn afstellen met een hoge LR is de meest voorkomende fout die tot slechte resultaten leidt.
import torchvision.models as models
import torch.nn as nn
import torch.optim as optim
model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
# --- Phase 1: Freeze backbone, train head ---
for param in model.parameters():
param.requires_grad = False
model.fc = nn.Linear(model.fc.in_features, num_classes)
optimizer = optim.Adam(model.fc.parameters(), lr=1e-3)
# Train for 5-10 epochs...
# --- Phase 2: Unfreeze and fine-tune with low LR ---
for param in model.parameters():
param.requires_grad = True
optimizer = optim.Adam(model.parameters(), lr=1e-5) # 100x lowerSelectief vrijgeven: laag voor laag
In plaats van het volledige basisnetwerk in één keer vrij te geven, kun je dit laag voor laag doen, vanaf de bovenkant (het dichtst bij de uitvoer). Latere lagen bevatten namelijk de meest taakspecifieke kenmerken, terwijl vroege lagen universele kenmerken leren (randen en texturen) die zelden moeten worden bijgewerkt.
Voor ResNet-50 is de gebruikelijke volgorde voor selectief vrijgeven: (1) fc (al trainbaar), (2) layer4, (3) layer3 en ten slotte (4) layer1 en layer2 als dat nodig is. Na elke stap moet je evalueren of het extra vrijgeven de validatienauwkeurigheid verbetert, omdat meer trainbare parameters het risico op overfitting bij kleine datasets vergroten.
import torchvision.models as models
import torch.nn as nn
model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
# Freeze everything first
for param in model.parameters():
param.requires_grad = False
model.fc = nn.Linear(model.fc.in_features, num_classes)
# After phase 1 training, selectively unfreeze layer4
for param in model.layer4.parameters():
param.requires_grad = True
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f'Trainable (fc + layer4): {trainable:,}')
# Much fewer parameters to fine-tune than the full 25MDifferent####iële leersnelheden
Different####iële leersnelheden wijzen verschillende leersnelheden toe aan verschillende delen van het netwerk. De nieuwe kop wordt getraind met de hoogste snelheid (1e-3), recent vrijgegeven lagen van het basisnetwerk met een gematigde snelheid (1e-4) en vroege lagen van het basisnetwerk met de laagste snelheid (1e-5 of helemaal vastgezet).
De optimiser van PyTorch accepteert een lijst met parametergroepen, elk met een eigen lr. Dit is de standaardtechniek in de literatuur over transfer learning en wordt gebruikt in de differentiële leersnelheden van fast.ai. Het idee is dat delen van het netwerk met algemenere kenmerken minder aanpassingen nodig hebben dan taakspecifieke lagen.
import torch.optim as optim
import torchvision.models as models
model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V1)
model.fc = nn.Linear(model.fc.in_features, num_classes)
# Unfreeze everything
for p in model.parameters():
p.requires_grad = True
# Differential learning rates per layer group
optimizer = optim.Adam([
{'params': model.fc.parameters(), 'lr': 1e-3}, # Head: highest LR
{'params': model.layer4.parameters(), 'lr': 1e-4}, # Top block
{'params': model.layer3.parameters(), 'lr': 5e-5}, # Middle
{'params': list(model.layer1.parameters()) +
list(model.layer2.parameters()), 'lr': 1e-5} # Early layers
])Controleren op catastrofaal vergeten
Catastrofaal vergeten treedt op wanneer fijn afstellen met een grote leersnelheid de vooraf geleerde kenmerken overschrijft, waardoor de validatienauwkeurigheid zelfs onder de basiswaarde van kenmerkextractie daalt. Je ziet dit als een scherpe piek in het trainingsverlies vroeg in fase 2, gevolgd door langzaam herstel.
Doe het volgende om dit te voorkomen: (1) begin fase 2 altijd met een zeer lage leersnelheid, (2) controleer de validatienauwkeurigheid na elke epoche en stop onmiddellijk als deze onder het beste resultaat van fase 1 daalt, (3) gebruik een planner voor de leersnelheid die de leersnelheid van het basisnetwerk geleidelijk opwarmt en (4) sla tijdens fase 1 het beste modelcontrolepunt op, zodat je dit kunt herstellen als fase 2 mislukt.
import torch
best_val_acc = 0.0
best_state = None
for epoch in range(20):
train_one_epoch(model, train_loader, optimizer, criterion, device)
val_acc = evaluate(model, val_loader, device)
if val_acc > best_val_acc:
best_val_acc = val_acc
best_state = {k: v.clone() for k, v in model.state_dict().items()}
# Stop if validation drops more than 2% below best
if val_acc < best_val_acc - 0.02:
print('Early stop: possible catastrophic forgetting')
model.load_state_dict(best_state) # Restore best
breakPlanners voor de leersnelheid bij fijn afstellen
Een vaste leersnelheid is tijdens het volledige proces van fijn afstellen zelden optimaal. Planners voor de leersnelheid passen de LR tijdens het trainen aan om de convergentie te verbeteren. Voor fijn afstellen werken twee planners bijzonder goed: CosineAnnealingLR verlaagt de LR volgens een cosinuscurve geleidelijk van de beginwaarde naar bijna nul, en ReduceLROnPlateau verlaagt de LR telkens wanneer de validatiemetriek niet meer verbetert.
ReduceLROnPlateau met patience=2 is een veilige standaardinstelling: als het validatieverlies gedurende 2 opeenvolgende epoches niet verbetert, wordt de LR vermenigvuldigd met factor=0.1. Dit herstelt vaak de voortgang wanneer het trainen stagneert.
import torch.optim as optim
from torch.optim.lr_scheduler import ReduceLROnPlateau, CosineAnnealingLR
optimizer = optim.Adam(model.parameters(), lr=1e-4)
# Option 1: Reduce on plateau
scheduler = ReduceLROnPlateau(optimizer, mode='max', factor=0.1,
patience=2, verbose=True)
# Call after each validation: scheduler.step(val_acc)
# Option 2: Cosine annealing over T_max epochs
scheduler = CosineAnnealingLR(optimizer, T_max=20, eta_min=1e-7)
# Call after each epoch: scheduler.step()
print('Initial LR:', optimizer.param_groups[0]['lr'])Batchgrootte en regularisatie tijdens fijn afstellen
Fijn afstellen met een grotere batchgrootte vermindert ruis in de gradiënten. Dat is gunstig wanneer je kleine aanpassingen maakt aan vooraf geleerde kenmerken. Zeer grote batches kunnen echter de generalisatie verslechteren bij fijn afstellen (het probleem van de 'scherpe minima'). Een batchgrootte van 32–64 is een goed startpunt.
Voeg gewichtverval (L2-regularisatie) toe aan de optimiser: optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-4). Gewichtverval voorkomt dat één gewicht te groot wordt. Dit is vooral belangrijk bij fijn afstellen, omdat de vooraf getrainde gewichten al verstandige grootten hebben die we niet te sterk willen verstoren.
import torch.optim as optim
# Fine-tuning optimiser with weight decay
optimizer = optim.AdamW(
model.parameters(),
lr=1e-4,
weight_decay=1e-4 # L2 regularisation
)
# AdamW separates weight decay from gradient adaptation
# (standard Adam incorrectly applies decay to adaptive gradient scaling)
# AdamW is preferred for fine-tuning transformer models especially
print('Optimizer:', optimizer)Gegevensaugmentatie tijdens fijn afstellen
Gegevensaugmentatie past bij elke epoche willekeurige transformaties toe op trainingsafbeeldingen, waardoor de dataset effectief groter wordt. Dit is vooral belangrijk tijdens fijn afstellen wanneer je weinig afbeeldingen per klasse hebt. Veelgebruikte augmentaties voor natuurlijke afbeeldingen zijn: willekeurig horizontaal spiegelen, willekeurig roteren (±15°), willekeurig bijsnijden en kleurvariatie (helderheid, contrast en verzadiging).
Pas augmentatie alleen tijdens het trainen toe, niet tijdens validatie of inferentie. Gebruik voor de validatieset een aparte transformatie die alleen deterministische voorbewerking toepast (verkleinen, uitsnede vanuit het midden en normaliseren). Met transforms.Compose van PyTorch kun je dit eenvoudig beheren.
from torchvision import transforms
train_transform = transforms.Compose([
transforms.RandomResizedCrop(224, scale=(0.7, 1.0)),
transforms.RandomHorizontalFlip(p=0.5),
transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),
transforms.RandomRotation(degrees=15),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
val_transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])Praktische resultaten van fijn afstellen
Hoeveel verbetering levert fine-tuning op ten opzichte van feature-extractie? Op een typische aangepaste dataset met ongeveer 1000 afbeeldingen per klasse kan feature-extractie een nauwkeurigheid van 88% opleveren, terwijl fine-tuning 92–95% bereikt. De verbetering hangt sterk af van hoe verschillend je gegevens zijn van ImageNet.
Houd deze vier getallen bij om te begrijpen wat er gebeurt: validatienauwkeurigheid in fase 1 (de basiswaarde voor feature-extractie), aanvankelijke validatienauwkeurigheid in fase 2 (mag bij een juiste LR niet lager zijn dan die van fase 1), beste validatienauwkeurigheid in fase 2 (het voordeel van fine-tuning) en toetsnauwkeurigheid (het eindresultaat, slechts één keer aan het einde gerapporteerd om lekken van de toetsset te voorkomen).
# Example fine-tuning progression
results = {
'Phase 1 (frozen backbone, 10 epochs)': '88.2%',
'Phase 2 initial (unfroze layer4, epoch 1)': '88.5%',
'Phase 2 best (epoch 15)': '92.7%',
'Phase 2 (unfroze layer3 too, epoch 20)': '93.1%',
'Final test accuracy': '92.8%', # Reported only at the end
}
for stage, acc in results.items():
print(f'{stage}: {acc}')
# Key takeaway: fine-tuning added ~4.5% over feature extractionFine-tuning van ViT- versus CNN-backbones
Voor fine-tuning van ViT-modellen (Vision Transformer) is iets meer zorgvuldigheid nodig dan bij CNN's. ViT-modellen bevatten Layer Normalisation in plaats van Batch Normalisation. De modi model.eval() en model.train() beïnvloeden daardoor voornamelijk dropout en niet de normalisatiestatistieken. Dit maakt fine-tuning iets eenvoudiger.
ViT-modellen profiteren tijdens fine-tuning ook van een lagere maximale learning rate (1e-5 tot 5e-5 tegenover 1e-4 voor CNN's), omdat de attentiongewichten gevoelig zijn voor grote updates. De optimizer AdamW heeft sterk de voorkeur voor fine-tuning van ViT-modellen. Met zorgvuldige fine-tuning kan ViT-B/16 de CNN-basiswaarden bij veel taken overtreffen.
import torchvision.models as models
import torch.nn as nn
import torch.optim as optim
# Fine-tuning ViT-B/16
vit = models.vit_b_16(weights=models.ViT_B_16_Weights.IMAGENET1K_V1)
vit.heads = nn.Linear(768, num_classes)
# Very low LR for ViT fine-tuning
optimizer = optim.AdamW(
vit.parameters(),
lr=2e-5,
weight_decay=0.01
)
# Warm-up scheduler (common for transformers)
from torch.optim.lr_scheduler import LinearLR, CosineAnnealingLR, SequentialLR
warmup = LinearLR(optimizer, start_factor=0.01, total_iters=5)
cosine = CosineAnnealingLR(optimizer, T_max=25)
scheduler = SequentialLR(optimizer, schedulers=[warmup, cosine], milestones=[5])Korte controle
Test je begrip van de fine-tuningstrategieën uit deze les.
Samenvatting van de les
In deze les heb je geleerd dat fine-tuning in twee fasen eerst de head traint (met een bevroren backbone) en daarna de backbone ontdooit met een zeer lage learning rate om catastrofaal vergeten te voorkomen, dat differentieel learning-rategebruik hogere learning rates toewijst aan de head en lagere learning rates aan diepere lagen van de backbone, en dat selectief ontdooien vanaf de bovenste lagen naar beneden de beste balans tussen nauwkeurigheid en efficiëntie oplevert. Hierna passen we deze technieken toe op een echte uitdaging in medische beeldvorming met weinig gelabelde gegevens.
Leer Python met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 30
- Lessen
- 120
Veelgestelde vragen
Is de les “Fine-tuning: lagen vrijgeven en lage learning rates” gratis?
Ja — de volledige tekst van “Fine-tuning: lagen vrijgeven en lage learning rates” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Machine Learning Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Machine Learning Academy bevat in totaal 4 lessen.
Wat leer ik in “Fine-tuning: lagen vrijgeven en lage learning rates”?
Cursisten geven eerdere lagen vrij na de eerste training van de classificatiekop, passen een lagere learning rate toe om voorgetrainde features niet te vernietigen en observeren verbeteringen in nauw… Je oefent met Machine Learning Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Machine Learning Academy te beginnen?
Ervaring vooraf is niet nodig. Machine Learning Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.
Hoe lang duurt de les “Fine-tuning: lagen vrijgeven en lage learning rates”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Machine Learning Academy?
Ja. Elke les over Machine Learning Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Voorgetrainde modellen in torchvision: ResNet, EfficientNet en ViT
- Feature-extractie: de backbone bevriezen
- Fine-tuning: lagen vrijgeven en lage learning rates
- Domeinadaptatie: medische beeldvorming met schaarse labels