Riutilizzare la Conoscenza: L'Idea del Transfer Learning
Il transfer learning è una delle tecniche più rivoluzionarie del Machine Learning moderno. L'idea è semplice ma potente: invece di addestrare un modello da zero su ogni nuovo problema, si parte da un modello già addestrato su un grande dataset (il source domain) e lo si adatta al proprio problema specifico (il target domain). Questo funziona perché le feature apprese nei layer iniziali (bordi, texture, forme per le immagini; struttura del linguaggio per il testo) sono universali e trasferibili.
Il transfer learning ha democratizzato il deep learning: non serve più un cluster di GPU e milioni di immagini per addestrare un classificatore di immagini. Si può prendere un modello pre-addestrato come ResNet (addestrato su 1.2 milioni di immagini ImageNet) e adattarlo al proprio problema con poche centinaia di immagini e un training di pochi minuti.
Cosa Imparerai in Questo Articolo
- Quando e perché il transfer learning funziona
- Feature extraction vs fine-tuning
- Strategie di layer freezing
- Modelli pre-addestrati per immagini e testo
- Data augmentation per piccoli dataset
- Implementazione pratica con Python
Feature Extraction: Congelare il Backbone
La strategia più semplice di transfer learning è la feature extraction: si usa il modello pre-addestrato come estrattore di feature fisse, si rimuove l'ultimo layer (la testa di classificazione) e si aggiunge un nuovo classificatore addestrato sul target domain. I pesi del backbone restano congelati: non vengono aggiornati durante il training. Questo è ideale quando il target dataset è piccolo e il source domain è simile al target.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_digits
import numpy as np
# Simulazione di transfer learning con scikit-learn
# Il concetto: usare feature apprese da un modello pre-addestrato
# come input per un classificatore leggero
# Dataset: riconoscimento cifre (8x8 pixel)
digits = load_digits()
X, y = digits.data, digits.target
# Scenario 1: Training diretto (no transfer)
direct_pipeline = Pipeline([
('scaler', StandardScaler()),
('clf', LogisticRegression(max_iter=5000, random_state=42))
])
scores_direct = cross_val_score(direct_pipeline, X, y, cv=5, scoring='accuracy')
print(f"Diretto (tutte le feature): {scores_direct.mean():.3f}")
# Scenario 2: Simulazione feature extraction
# Pre-trained model ha gia' estratto feature ad alto livello
# Usiamo PCA come proxy per le "feature apprese"
from sklearn.decomposition import PCA
# Feature extractor pre-addestrato (congela i pesi)
feature_extractor = PCA(n_components=20, random_state=42)
X_features = feature_extractor.fit_transform(X)
# Nuovo classificatore sulle feature estratte
transfer_pipeline = Pipeline([
('scaler', StandardScaler()),
('clf', LogisticRegression(max_iter=5000, random_state=42))
])
scores_transfer = cross_val_score(transfer_pipeline, X_features, y, cv=5, scoring='accuracy')
print(f"Feature extraction (20 comp): {scores_transfer.mean():.3f}")
# Scenario 3: Con dataset ridotto (simula pochi dati nel target domain)
small_idx = np.random.choice(len(X), size=200, replace=False)
X_small, y_small = X[small_idx], y[small_idx]
X_small_features = feature_extractor.transform(X_small)
scores_small_direct = cross_val_score(direct_pipeline, X_small, y_small, cv=5)
scores_small_transfer = cross_val_score(transfer_pipeline, X_small_features, y_small, cv=5)
print(f"\nCon solo 200 campioni:")
print(f" Diretto: {scores_small_direct.mean():.3f}")
print(f" Feature extraction: {scores_small_transfer.mean():.3f}")
Fine-Tuning: Adattare il Modello
Il fine-tuning va oltre la feature extraction: dopo aver sostituito la testa di classificazione, si scongelano alcuni layer del backbone e si ri-addestrano con un learning rate molto basso. Questo permette al modello di adattare anche le feature intermedie al target domain. La regola generale è: più il target domain è diverso dal source, più layer conviene scongelare.
Le strategie di layer freezing includono: scongelare solo l'ultimo blocco di layer (conservative), scongelare progressivamente dalla fine verso l'inizio (gradual unfreezing), e usare learning rate diversi per layer diversi (discriminative learning rates, dove i layer profondi hanno un learning rate più basso).
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_digits
import numpy as np
digits = load_digits()
X, y = digits.data, digits.target
# Simulazione di fine-tuning:
# Step 1: Pre-training su un sottoinsieme (source domain)
# Step 2: Fine-tuning su un altro sottoinsieme (target domain)
# Source domain: cifre 0-4
source_mask = y <= 4
X_source, y_source = X[source_mask], y[source_mask]
# Target domain: cifre 5-9 (con pochi dati)
target_mask = y > 4
X_target, y_target = X[target_mask], y[target_mask] - 5
# Solo 50 campioni nel target domain
np.random.seed(42)
small_idx = np.random.choice(len(X_target), size=50, replace=False)
X_target_small = X_target[small_idx]
y_target_small = y_target[small_idx]
# Modello 1: Training from scratch sul target piccolo
from_scratch = GradientBoostingClassifier(
n_estimators=100, random_state=42
)
scores_scratch = cross_val_score(
from_scratch, X_target_small, y_target_small, cv=5
)
# Modello 2: Pre-trained sul source, fine-tuned sul target
pretrained = GradientBoostingClassifier(
n_estimators=100, random_state=42,
warm_start=True # permette di continuare il training
)
# Pre-training sul source
pretrained.fit(X_source, y_source)
# Fine-tuning: aggiungiamo altri estimators sul target
pretrained.n_estimators = 150 # aggiungi 50 estimators
pretrained.fit(X_target_small, y_target_small)
# Data Augmentation: aggiungi rumore per ampliare il dataset
noise_factor = 0.3
X_augmented = np.vstack([
X_target_small,
X_target_small + np.random.normal(0, noise_factor, X_target_small.shape),
X_target_small + np.random.normal(0, noise_factor, X_target_small.shape)
])
y_augmented = np.concatenate([y_target_small] * 3)
aug_model = GradientBoostingClassifier(n_estimators=100, random_state=42)
scores_aug = cross_val_score(aug_model, X_augmented, y_augmented, cv=5)
print("Risultati con 50 campioni target:")
print(f" From scratch: {scores_scratch.mean():.3f}")
print(f" Data augmentation: {scores_aug.mean():.3f}")
Modelli Pre-Addestrati nell'Ecosistema
Per le immagini, i modelli più usati sono addestrati su ImageNet (1.2M immagini, 1000 classi): ResNet (architettura residual), EfficientNet (ottimizzato per efficienza), VGG (semplice ma efficace). Per il testo, i modelli transformer pre-addestrati dominano: BERT (Google, bidirezionale), GPT (OpenAI, generativo), RoBERTa (ottimizzazione di BERT).
Hugging Face è la piattaforma di riferimento per modelli pre-addestrati: migliaia di
modelli per classificazione testo, traduzione, question answering, generazione di testo e molto altro,
tutti accessibili con poche righe di codice tramite la libreria transformers.
Quando Conviene il Transfer Learning
Il transfer learning è la scelta giusta quando: il dataset target è piccolo (meno di qualche migliaio di campioni), il source domain è simile al target (immagini naturali per classificare immagini mediche), o quando si vuole risparmiare tempo e risorse computazionali. Non conviene quando: il source e target domain sono molto diversi (testo vs immagini), il dataset target è già grande, o le feature del source non sono utili per il target.
Costo training: Pre-addestrare BERT da zero richiede 4 giorni su 16 TPU (costo stimato $10K-$50K). Fine-tuning BERT su un task specifico richiede pochi minuti su una singola GPU. Questa differenza di costo spiega perché il transfer learning è la scelta standard nel deep learning moderno.
Punti Chiave
- Il transfer learning riutilizza modelli pre-addestrati su grandi dataset per nuovi problemi
- Feature extraction: congela il backbone, addestra solo la nuova testa di classificazione
- Fine-tuning: scongela progressivamente i layer con learning rate basso
- Funziona meglio quando source e target domain sono simili e il target dataset è piccolo
- ResNet/EfficientNet per immagini, BERT/GPT per testo sono i modelli standard
- Data augmentation complementa il transfer learning quando i dati sono scarsi







