β˜€οΈSiang
Deep Learning

Transfer Learning: Pre-trained Models & Fine-Tuning

TOKEN

Panduan lengkap Transfer Learning β€” konsep pre-trained models, feature extraction vs fine-tuning, arsitektur populer (VGG, ResNet, EfficientNet), dan implementasi praktis dengan PyTorch dan TensorFlow

Artikel: Dl Transfer Learning Artikel: Dl Transfer Learning


1. Pengenalan Transfer Learning

Transfer Learning adalah teknik deep learning di mana kita menggunakan model yang sudah dilatih pada satu tugas (source task) sebagai titik awal untuk tugas baru (target task). Alih-alih melatih dari nol (from scratch), kita "mentransfer" pengetahuan yang sudah dipelajari oleh model pre-trained.

Analogi Transfer Learning

Diagram: Transfer Learning β€” Analogi
Transfer Learning β€” Analogi

TRANSFER LEARNING IN ML

Pre-trained on\nImageNet (1M images)

Fine-tune on\nmedical images (1K)

LEARNING TO DRIVE A CAR

Learn steering\nbraking, traffic rules

Apply to\nmotorcycle

Bagaimana Transfer Learning Bekerja?

Diagram: Feature Learning Hierarchy
Feature Learning Hierarchy

Layer 1-2: Low-level features\n(edges, colors, textures)

Layer 3-5: Mid-level features\n(shapes, patterns, parts)

Layer 6-8: High-level features\n(objects, faces, scenes)

Final Layer: Task-specific\n(classification head)



2. Mengapa Transfer Learning Penting?

Keuntungan Penjelasan Dampak
Lebih Sedikit DataModel sudah "tahu" fitur umum, tidak perlu jutaan dataBisa pakai ratusan atau ribuan gambar saja
Training Lebih CepatTidak perlu training dari nol, hanya menyesuaikan layer akhirDari minggu ke jam
Performa Lebih BaikPre-trained features biasanya lebih baik dari random initAkurasi lebih tinggi, especially data kecil
Hemat Sumber DayaTidak perlu GPU cluster untuk trainingBisa dilatih di laptop/GPU tunggal
Domain AdaptationPengetahuan dari domain besar bisa diadaptasi ke domain spesifikMedical imaging, satelit, dll

Kapan Menggunakan Transfer Learning?

Diagram: Decision Tree Transfer Learning
Decision Tree Transfer Learning

Large

Small

Yes

No

Yes

No

Dataset size?

Similar domain?

Similar domain?

Fine-tune\n(high LR)

Fine-tune\n(low LR)

Feature\nExtraction

Train from\nScratch



3. Feature Extraction: Membekukan Layer Pre-trained

Feature Extraction adalah strategi di mana kita menggunakan pre-trained model sebagai fixed feature extractor. Semua layer convolutional dibekukan (frozen) β€” weight-nya tidak diperbarui selama training. Kita hanya melatih layer classifier baru di akhir (disebut "head" atau "top").

Diagram: Feature Extraction
Feature Extraction

🧠 Pre-trained\nModel\n(Frozen)

πŸ“Š Extracted\nFeatures

🎯 New\nClassifier\n(Trainable)

πŸ“€ Task\nOutput



4. Fine-Tuning: Menyesuaikan Model ke Dataset Baru

Fine-Tuning melangkah lebih jauh dari feature extraction β€” kita melatih ulang sebagian atau seluruh layer pre-trained model, tapi dengan learning rate yang sangat kecil agar perubahan weight tidak merusak pengetahuan yang sudah dipelajari.

Diagram: Fine-Tuning Strategies
Fine-Tuning Strategies

STRATEGY 3: Full Fine-tune

All Layers\n(Trainable)

New Head

STRATEGY 2: Partial Fine-tune

Early Layers\n(Frozen)

Later Layers\n(Trainable)

New Head

STRATEGY 1: Freeze All

Pre-trained Layers\n(FROZEN 🧊)

New Head\n(Trainable)

Differential Learning Rates

πŸ“ Differential Learning Rates

Saat fine-tuning, gunakan learning rate berbeda untuk setiap kelompok layer:

  • Layer awal (general features): LR sangat kecil (1e-5 atau kurang)
  • Layer tengah (mid-level features): LR kecil (1e-4)
  • Layer akhir (task-specific) dan head baru: LR lebih besar (1e-3)

Alasan: Layer awal sudah sangat umum dan tidak perlu banyak perubahan. Layer akhir perlu lebih banyak adaptasi ke tugas baru.



5. Arsitektur Populer: VGG, ResNet, EfficientNet

Evolusi Arsitektur CNN

Model Tahun Keunggulan Parameters ImageNet Top-5
AlexNet2012Membuktikan deep learning works60M84.7%
VGG-16/192014Arsitektur sederhana, stack 3Γ—3 conv138M92.7%
GoogLeNet/Inception2014Inception module (multi-scale)6.8M93.3%
ResNet-50/101/1522015Skip connections (residual)25.6M96.4%
DenseNet2017Dense connections semua layer8M-20M94.5%
EfficientNet2019Compound scaling (widthΓ—depthΓ—resolution)5.3M-66M97.1%
Vision Transformer (ViT)2020Transformer untuk vision86M+97.7%

ResNet: Skip Connections

Diagram: ResNet Skip Connection
ResNet Skip Connection

Skip Connection\n(identity)

Input (x)

Conv1

Conv2

βž• Add

ReLU

Output



6. Implementasi: Transfer Learning dengan PyTorch

Python β€” Transfer Learning dengan PyTorch (ResNet50)
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import models, transforms, datasets
from torch.utils.data import DataLoader
import time
import copy

# === 1. PERSIAPAN DATA ===
# Transformasi untuk training (dengan augmentasi)
train_transform = transforms.Compose([
    transforms.RandomResizedCrop(224),
    transforms.RandomHorizontalFlip(),
    transforms.RandomRotation(15),
    transforms.ColorJitter(brightness=0.2, contrast=0.2),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406],  # ImageNet mean
                         [0.229, 0.224, 0.225])   # ImageNet std
])

# Transformasi untuk validasi (tanpa augmentasi)
val_transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize([0.485, 0.456, 0.406],
                         [0.229, 0.224, 0.225])
])

# Load dataset (ganti dengan path dataset Anda)
# train_dataset = datasets.ImageFolder('data/train', train_transform)
# val_dataset = datasets.ImageFolder('data/val', val_transform)
# train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
# val_loader = DataLoader(val_dataset, batch_size=32)

# === 2. LOAD PRE-TRAINED MODEL ===
model = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V2)

print("=== Arsitektur ResNet50 ===")
print(model)

# === 3. FEATURE EXTRACTION (Strategy 1: Freeze semua, train head) ===

# Bekukan semua parameter
for param in model.parameters():
    param.requires_grad = False

# Ganti classifier head untuk 10 kelas
num_classes = 10
model.fc = nn.Sequential(
    nn.Linear(model.fc.in_features, 512),
    nn.ReLU(),
    nn.Dropout(0.3),
    nn.Linear(512, num_classes)
)

# Hitung parameter yang trainable
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
total_params = sum(p.numel() for p in model.parameters())
print(f"\n=== Feature Extraction Mode ===")
print(f"Total parameters: {total_params:,}")
print(f"Trainable parameters: {trainable_params:,}")
print(f"Frozen parameters: {total_params - trainable_params:,}")
print(f"Trainable %: {trainable_params/total_params*100:.1f}%")

# === 4. FINE-TUNING (Strategy 2: Unfreeze beberapa layer) ===

def unfreeze_layers(model, num_layers_to_unfreeze):
    """Unfreeze layer terakhir dari ResNet"""
    # Freeze semua dulu
    for param in model.parameters():
        param.requires_grad = False
    
    # Unfreeze layer4 dan fc
    children = list(model.children())
    layers_to_unfreeze = children[-num_layers_to_unfreeze:]
    
    for layer in layers_to_unfreeze:
        for param in layer.parameters():
            param.requires_grad = True
    
    trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
    total = sum(p.numel() for p in model.parameters())
    print(f"\nUnfroze {num_layers_to_unfreeze} layers")
    print(f"Trainable: {trainable:,} / {total:,} ({trainable/total*100:.1f}%)")

# Unfreeze 2 layer terakhir (layer4 + fc)
unfreeze_layers(model, 2)

# === 5. DIFFERENTIAL LEARNING RATES ===
# Layer awal β†’ lr kecil, layer akhir β†’ lr lebih besar
optimizer = optim.Adam([
    {'params': model.layer4.parameters(), 'lr': 1e-4},
    {'params': model.fc.parameters(), 'lr': 1e-3},
], weight_decay=1e-4)

# Scheduler: kurangi lr saat training plateau
scheduler = optim.lr_scheduler.ReduceLROnPlateau(
    optimizer, mode='min', factor=0.5, patience=3, verbose=True
)

criterion = nn.CrossEntropyLoss()

# === 6. TRAINING LOOP ===
def train_model(model, criterion, optimizer, scheduler, num_epochs=25):
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model = model.to(device)
    
    best_model_wts = copy.deepcopy(model.state_dict())
    best_acc = 0.0
    
    for epoch in range(num_epochs):
        print(f'\nEpoch {epoch+1}/{num_epochs}')
        print('-' * 40)
        
        for phase in ['train', 'val']:
            if phase == 'train':
                model.train()
                dataloader = train_loader
            else:
                model.eval()
                dataloader = val_loader
            
            running_loss = 0.0
            running_corrects = 0
            
            for inputs, labels in dataloader:
                inputs = inputs.to(device)
                labels = labels.to(device)
                
                optimizer.zero_grad()
                
                with torch.set_grad_enabled(phase == 'train'):
                    outputs = model(inputs)
                    _, preds = torch.max(outputs, 1)
                    loss = criterion(outputs, labels)
                    
                    if phase == 'train':
                        loss.backward()
                        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
                        optimizer.step()
                
                running_loss += loss.item() * inputs.size(0)
                running_corrects += torch.sum(preds == labels.data)
            
            epoch_loss = running_loss / len(dataloader.dataset)
            epoch_acc = running_corrects.double() / len(dataloader.dataset)
            
            print(f'{phase} Loss: {epoch_loss:.4f} Acc: {epoch_acc:.4f}')
            
            if phase == 'val':
                scheduler.step(epoch_loss)
                if epoch_acc > best_acc:
                    best_acc = epoch_acc
                    best_model_wts = copy.deepcopy(model.state_dict())
    
    print(f'\nBest val Acc: {best_acc:.4f}')
    model.load_state_dict(best_model_wts)
    return model

# Jalankan training (uncomment jika data tersedia)
# model = train_model(model, criterion, optimizer, scheduler, num_epochs=20)

# === 7. PREDIKSI ===
def predict_image(model, image_path, transform):
    from PIL import Image
    
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    model.eval()
    
    image = Image.open(image_path).convert('RGB')
    image = transform(image).unsqueeze(0).to(device)
    
    with torch.no_grad():
        output = model(image)
        probabilities = torch.nn.functional.softmax(output[0], dim=0)
        predicted_class = torch.argmax(probabilities).item()
        confidence = probabilities[predicted_class].item()
    
    return predicted_class, confidence, probabilities

print("\nβœ“ Transfer Learning Pipeline Siap!")
print("  Uncomment fungsi train_model() dan siapkan dataset untuk mulai training.")


7. Implementasi: Transfer Learning dengan TensorFlow/Keras

Python β€” Transfer Learning dengan TensorFlow/Keras
import tensorflow as tf
from tensorflow.keras import layers, models
from tensorflow.keras.applications import EfficientNetB0
from tensorflow.keras.preprocessing import image_dataset_from_directory

# === 1. LOAD DATA ===
IMG_SIZE = 224
BATCH_SIZE = 32

# Load dataset (ganti dengan path dataset Anda)
# train_ds = image_dataset_from_directory(
#     'data/train', image_size=(IMG_SIZE, IMG_SIZE),
#     batch_size=BATCH_SIZE, validation_split=0.2,
#     subset='training', seed=42
# )
# val_ds = image_dataset_from_directory(
#     'data/train', image_size=(IMG_SIZE, IMG_SIZE),
#     batch_size=BATCH_SIZE, validation_split=0.2,
#     subset='validation', seed=42
# )

NUM_CLASSES = 10

# === 2. DATA AUGMENTATION ===
data_augmentation = tf.keras.Sequential([
    layers.RandomFlip("horizontal"),
    layers.RandomRotation(0.1),
    layers.RandomZoom(0.1),
    layers.RandomContrast(0.1),
])

# === 3. LOAD PRE-TRAINED EfficientNetB0 ===
base_model = EfficientNetB0(
    include_top=False,           # Tanpa classifier head
    weights='imagenet',          # Pre-trained di ImageNet
    input_shape=(IMG_SIZE, IMG_SIZE, 3)
)

# === 4. FEATURE EXTRACTION (freeze base model) ===
base_model.trainable = False

# Buat model baru
inputs = layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3))
x = data_augmentation(inputs)               # Augmentasi
x = base_model(x, training=False)           # Feature extraction
x = layers.GlobalAveragePooling2D()(x)      # Pooling
x = layers.Dropout(0.3)(x)                  # Regularisasi
x = layers.Dense(256, activation='relu')(x) # Hidden layer
x = layers.Dropout(0.2)(x)
outputs = layers.Dense(NUM_CLASSES, activation='softmax')(x)

model = models.Model(inputs, outputs)

print("=== Model Summary (Feature Extraction) ===")
model.summary()

# === 5. TRAIN FEATURE EXTRACTION ===
model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

# history1 = model.fit(train_ds, validation_data=val_ds, epochs=10)

# === 6. FINE-TUNING (unfreeze beberapa layer) ===
base_model.trainable = True

# Freeze semua kecuali 30 layer terakhir
for layer in base_model.layers[:-30]:
    layer.trainable = False

print(f"\nTrainable layers: {sum(1 for l in model.layers if l.trainable)}")

# Compile ulang dengan learning rate LEBIH KECIL
model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-5),  # LR kecil!
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

# history2 = model.fit(train_ds, validation_data=val_ds, epochs=20)

# === 7. LEARNING RATE SCHEDULER ===
lr_scheduler = tf.keras.callbacks.ReduceLROnPlateau(
    monitor='val_loss', factor=0.5, patience=3, min_lr=1e-7
)

early_stopping = tf.keras.callbacks.EarlyStopping(
    monitor='val_loss', patience=7, restore_best_weights=True
)

# history2 = model.fit(
#     train_ds, validation_data=val_ds, epochs=50,
#     callbacks=[lr_scheduler, early_stopping]
# )

print("\nβœ“ TensorFlow Transfer Learning Pipeline Siap!")


8. Strategi & Best Practice Transfer Learning

Tips Memilih Pre-trained Model

Faktor Pertimbangan Rekomendasi
Ukuran DatasetDataset kecil (<1000) vs besar (>10K)Kecil β†’ model kecil (MobileNet), Besar β†’ model besar (ResNet152)
ResourceEdge device vs serverEdge β†’ MobileNet/EfficientNet-Lite, Server β†’ ResNet/ViT
KecepatanReal-time vs batchReal-time β†’ MobileNet, Batch β†’ ResNet/EfficientNet
Kemiripan DomainDataset source vs targetMirip β†’ feature extraction, Beda β†’ fine-tune lebih banyak

Kesalahan Umum Transfer Learning

⚠️ Hindari Kesalahan Ini!
  • Learning rate terlalu besar saat fine-tuning β€” Merusak pengetahuan pre-trained (catastrophic forgetting)
  • Tidak menggunakan data augmentation β€” Terutama saat dataset kecil, augmentasi sangat penting
  • Melupakan normalisasi yang benar β€” Gunakan mean/std yang SAMA dengan pre-trained model (ImageNet: mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225])
  • Langsung unfreeze semua layer β€” Mulai dengan freeze semua, lalu unfreeze bertahap
  • Tidak menggunakan early stopping β€” Fine-tuning mudah overfit pada dataset kecil
  • Menggunakan model terlalu besar untuk dataset kecil β€” Model besar + data sedikit = overfitting


9. Quiz Pemahaman

🧠 Quiz: Transfer Learning

1. Apa itu Transfer Learning?

2. Dalam Feature Extraction, apa yang terjadi pada layer pre-trained?

3. Mengapa learning rate harus sangat kecil saat fine-tuning?

4. Strategi mana yang TEPAT untuk dataset kecil dengan tugas mirip ImageNet?

5. Apa fungsi skip connection di ResNet?

🎯 Ringkasan Artikel
  • Transfer Learning menggunakan pengetahuan model pre-trained untuk tugas baru
  • Feature Extraction = freeze base model, hanya train classifier head
  • Fine-Tuning = unfreeze sebagian/seluruh layer dengan learning rate kecil
  • Differential Learning Rates = layer awal lr kecil, layer akhir lr lebih besar
  • ResNet mengatasi vanishing gradient dengan skip connections
  • EfficientNet mengoptimalkan width, depth, dan resolution secara bersamaan
  • Untuk dataset kecil: feature extraction dulu, baru fine-tune bertahap
πŸ” Zoom
100%
🎨 Tema