Introduzione: La Loss Function Guida Tutto
La funzione di perdita (loss function) e il criterio che il modello ottimizza durante il training. E la "bussola" dell'apprendimento: definisce cosa significa "sbagliare" e quanto. Scegliere la loss sbagliata può rendere impossibile l'apprendimento anche con l'architettura perfetta.
Cosa Imparerai
- Loss per regressione: MSE, MAE, Huber Loss
- Loss per classificazione: Cross-Entropy binaria e multiclasse
- Focal Loss per dataset sbilanciati
- Hinge Loss per SVM e margini
- Contrastive e Triplet Loss per embedding
- Come creare custom loss functions
Loss per Regressione
Mean Squared Error (MSE)
La loss più usata per la regressione. Penalizza gli errori grandi in modo quadratico:
La derivata rispetto alla predizione \\hat{y}_i:
Pro: differenziabile ovunque, gradiente proporzionale all'errore. Contro: sensibile agli outlier (un singolo punto anomalo può dominare la loss).
Mean Absolute Error (MAE)
Pro: robusta agli outlier (penalita lineare). Contro: gradiente costante (non accelera vicino al minimo), non differenziabile in zero.
Huber Loss: Il Compromesso
La Huber Loss combina il meglio di MSE e MAE: si comporta come MSE per errori piccoli e come MAE per errori grandi:
import numpy as np
def mse(y_true, y_pred):
return np.mean((y_true - y_pred)**2)
def mae(y_true, y_pred):
return np.mean(np.abs(y_true - y_pred))
def huber_loss(y_true, y_pred, delta=1.0):
error = np.abs(y_true - y_pred)
quadratic = np.minimum(error, delta)
linear = error - quadratic
return np.mean(0.5 * quadratic**2 + delta * linear)
# Dati normali
y_true = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
y_pred = np.array([1.1, 2.2, 2.8, 4.1, 4.9])
print("Senza outlier:")
print(f" MSE: {mse(y_true, y_pred):.4f}")
print(f" MAE: {mae(y_true, y_pred):.4f}")
print(f" Huber: {huber_loss(y_true, y_pred):.4f}")
# Aggiungi outlier
y_true_out = np.append(y_true, 6.0)
y_pred_out = np.append(y_pred, 20.0) # Outlier!
print("\nCon outlier:")
print(f" MSE: {mse(y_true_out, y_pred_out):.4f}")
print(f" MAE: {mae(y_true_out, y_pred_out):.4f}")
print(f" Huber: {huber_loss(y_true_out, y_pred_out):.4f}")
Loss per Classificazione
Binary Cross-Entropy (BCE)
Per classificazione binaria con output sigmoid \\hat{y} = \\sigma(z) \\in (0, 1):
La derivata (elegantemente semplice):
Categorical Cross-Entropy
Per classificazione multiclasse con output softmax:
Con label one-hot (solo un y_c = 1), diventa: L = -\\log(\\hat{y}_c), dove c e la classe corretta.
Focal Loss: Per Dataset Sbilanciati
La Focal Loss riduce il peso degli esempi facili per concentrarsi su quelli difficili:
dove p_t e la probabilità della classe corretta, \\gamma \\geq 0 e il focusing parameter (tipicamente 2), e \\alpha_t e il fattore di bilanciamento. Quando il modello e gia sicuro (p_t alto), il termine (1 - p_t)^\\gamma riduce il contributo alla loss.
import numpy as np
def softmax(z):
exp_z = np.exp(z - np.max(z, axis=-1, keepdims=True))
return exp_z / np.sum(exp_z, axis=-1, keepdims=True)
def cross_entropy_loss(y_true, logits):
"""Categorical cross-entropy con softmax."""
probs = softmax(logits)
n = y_true.shape[0]
log_probs = -np.log(probs[np.arange(n), y_true] + 1e-15)
return np.mean(log_probs)
def focal_loss(y_true, logits, gamma=2.0, alpha=1.0):
"""Focal loss per dataset sbilanciati."""
probs = softmax(logits)
n = y_true.shape[0]
pt = probs[np.arange(n), y_true]
focal_weight = alpha * (1 - pt) ** gamma
log_probs = -np.log(pt + 1e-15)
return np.mean(focal_weight * log_probs)
# Esempio: 3 classi
y_true = np.array([0, 1, 2, 1, 0])
logits = np.array([
[2.0, 0.5, -1.0], # Classe 0 facile
[0.1, 3.0, -0.5], # Classe 1 facile
[-1.0, 0.2, 1.5], # Classe 2 media
[0.5, 0.3, 0.2], # Classe 1 difficile
[0.1, 0.1, 0.1], # Classe 0 difficilissima
])
print(f"Cross-Entropy: {cross_entropy_loss(y_true, logits):.4f}")
print(f"Focal Loss (gamma=2): {focal_loss(y_true, logits, gamma=2):.4f}")
print(f"Focal Loss (gamma=0): {focal_loss(y_true, logits, gamma=0):.4f}") # = CE
Loss per Similarity Learning
Hinge Loss
Usata nelle SVM (Support Vector Machines), richiede un margine minimo tra classi:
dove y \\in \\{-1, +1\\}. Se il modello classifica correttamente con margine sufficiente, la loss e zero.
Contrastive Loss
Per coppie di embedding, avvicina i simili e allontana i diversi:
dove d = \\|f(x_1) - f(x_2)\\|, y=0 per coppie simili, y=1 per coppie diverse, e m e il margine.
Triplet Loss
Usa triplette (anchor, positive, negative) per apprendere embedding:
L'anchor deve essere più vicino al positive che al negative, con un margine m.
Temperature Scaling e Calibrazione
Il temperature scaling e una tecnica di post-calibrazione che aggiunge un parametro T > 0 alla softmax:
T > 1: distribuzioni più "morbide" (meno confidenti). T < 1: distribuzioni più "dure" (più confidenti). T = 1: softmax standard.
Guida alla Scelta della Loss
Regole pratiche:
- Regressione: MSE (standard), Huber (con outlier), MAE (mediana vs media)
- Classificazione binaria: Binary Cross-Entropy + sigmoid
- Classificazione multiclasse: Cross-Entropy + softmax
- Dataset sbilanciato: Focal Loss o Cross-Entropy con class weights
- Similarity/Embedding: Triplet Loss o Contrastive Loss
- Ranking: Hinge Loss o Margin Ranking Loss
Riepilogo
Punti Chiave da Ricordare
- MSE: \\frac{1}{n}\\sum(y - \\hat{y})^2 - standard per regressione, sensibile a outlier
- Cross-Entropy: -\\sum y_k \\log \\hat{y}_k - standard per classificazione
- Focal Loss: aggiunge (1-p_t)^\\gamma per bilanciare classi
- Huber Loss: robusto compromesso MSE/MAE con soglia \\delta
- Triplet Loss: per apprendere embedding con margine
- Temperature: T scala la confidenza della softmax
Nel Prossimo Articolo: esploreremo la statistica inferenziale per data scientists. Intervalli di confidenza, t-test, p-value, A/B testing e come evitare le trappole statistiche più comuni.







