Esercizio - Ricerca del miglior C per una SVM lineare sul dataset digits (laboratorio 10)
Teoria: Apprendimento automatico nell'IA - supervisionato, SVM e valutazioneQuadro del machine learning nel corso di IA. Tre forme di apprendimento: supervisionato (coppie ingresso-uscita, classificazione se l'uscita è discreta e regressione se è un numero), non supervisionato (pattern senza feedback, per esempio clustering) e per rinforzo (ricompense). Un'ipotesi h approssima la funzione vera f e si valuta sul test set, non sul training set: un modello troppo semplice ha bias alto (underfitting), uno troppo complesso varianza alta (overfitting). Servono training, validation e test set; con pochi dati si usa la k-fold cross-validation. Alberi di decisione: si sceglie l'attributo con massimo guadagno d'informazione Gain = B(p/(p+n)) - somma (Nk/N) B(pk/Nk), si pota con il test del chi quadro (Delta > Delta*), si riduce la varianza con bagging e random forest. Perdita L1 e L2, regressione lineare e discesa del gradiente w <- w - alpha dL/dw. SVM: separatore a margine massimo, vettori di supporto, kernel trick con K(xj,xk). Pipeline scikit-learn del laboratorio 10: load_digits, train_test_split, SVC(C, kernel, gamma), fit, predict, classification_report, confusion_matrix, cross_val_score.Apprendimento automatico nell'IA - supervisionato, SVM e valutazione →, sezioni 3, 6 e 7. Sul parametro e sulla SVM a margine morbido: Support vector machines e metodi kernelUna SVM cerca l'iperpiano $w\cdot x+b=0$ che separa due classi con il margine più largo possibile: normalizzando $y_i(w\cdot x_i+b)\ge1$ il margine totale vale $2/|w|$, quindi si risolve $\min\frac12|w|^2$ (problema convesso, nessun minimo locale). Con classi sovrapposte si ammettono errori con le variabili di scarto $\xi_i$ e il parametro $C$ (soft margin, equivalente alla hinge loss più una penalità su $|w|^2$); $C$ piccolo = margine largo e più bias, $C$ grande = margine stretto e più varianza, si sceglie per cross-validation. La soluzione dipende solo dai vettori di supporto ($w=\sum\alpha_iy_ix_i$) e solo tramite prodotti scalari, per questo si può sostituire $x_i\cdot x_j$ con un kernel $K(x_i,x_j)=\langle\phi(x_i),\phi(x_j)\rangle$ (polinomiale, RBF) senza calcolare $\phi$: così si ottengono bordi non lineari. La SVR usa lo stesso schema con un tubo di tolleranza $\varepsilon$. Nell'esame le SVM sono solo nella parte teorica.Support vector machines e metodi kernel → e Esercizio - SVM a margine rigido e morbido a mano. Sulle metriche: Metriche di classificazioneIn classificazione binaria ogni previsione è vero positivo (TP), vero negativo (TN), falso positivo (FP, errore di tipo I) o falso negativo (FN, errore di tipo II). Da queste quattro quantità: accuracy $=\frac{TP+TN}{TP+TN+FP+FN}$, specificità $=\frac{TN}{TN+FP}$, precision $=\frac{TP}{TP+FP}$, recall $=\frac{TP}{TP+FN}$, e la loro media armonica $F_1=\frac{2PR}{P+R}$. Con dati sbilanciati l'accuracy inganna (un modello che predice sempre la classe maggioritaria ha 99%): si usano precision, recall, F1, ROC-AUC, la cross-validation stratificata e il riequilibrio con undersampling o oversampling (non SMOTE). Cambiando la soglia sulla probabilità si ottiene la curva ROC (TPR contro FPR) e l'area AUC. Approfondimento: non nel programma di Telecomunicazioni.Metriche di classificazione →.
Testo. Creare una SVM con kernel lineare usando scikit-learn. Verificare le prestazioni al variare dell'iperparametro usando la funzione numpy.logspace nell'intervallo (cioè start=-20, stop=0, num=20: venti valori da a , equispaziati in scala logaritmica) sul dataset digits.
(a) Trovare la miglior configurazione di con una cross-validation a 3 fold sul dataset digits. (b) Fare il grafico del punteggio ottenuto per ogni configurazione, con i valori di sull'asse e il punteggio di CV sull'asse (media e deviazione standard). Suggerimento: usare la scala logaritmica. (c) Addestrare e testare il modello sul dataset digits con la miglior configurazione trovata.
Soluzione
(a) Scelta di con la cross-validation
Per ogni valore di si fa una 3-fold cross-validation sull'intero dataset (1 797 immagini , 10 classi): cross_val_score addestra 3 volte su due terzi dei dati e valuta sul terzo rimasto (per un classificatore le fold sono stratificate, cioè mantengono le proporzioni delle classi), poi si tengono la media e la deviazione standard dei 3 punteggi. Si sceglie il con la media più alta.
import numpy as np
from sklearn import datasets, svm, metrics
from sklearn.model_selection import cross_val_score, train_test_split
X, y = datasets.load_digits(return_X_y=True) # X ha forma (1797, 64): le immagini sono gia' appiattite
svc = svm.SVC(kernel="linear")
C_s = np.logspace(-20, 0, 20) # 20 valori tra 1e-20 e 1, in scala logaritmica
scores, scores_std = [], []
for C in C_s:
svc.C = C
s = cross_val_score(svc, X, y, cv=3, n_jobs=1) # 3 punteggi (accuracy), uno per fold
scores.append(np.mean(s)); scores_std.append(np.std(s))
best = int(np.argmax(scores)); best_C = C_s[best]
print("Il C con il punteggio piu' alto e':", best_C, "punteggio:", round(scores[best], 4))I venti punteggi medi (dal più basso al più alto, come nell'output del corso): Il valore migliore è per ( con nell'ordine crescente). I valori rilevanti, con la deviazione standard sulle 3 fold:
| punteggio medio | dev. standard | |
|---|---|---|
| da a | ||
Il corso osserva che l'ultima parte della curva (gli ultimi quattro valori) dà prestazioni confrontabili: si sceglie il massimo dell'accuratezza, ma i quattro valori sono statisticamente indistinguibili (le differenze, , sono molto minori della deviazione standard). A parità di prestazioni conviene il più piccolo, cioè il modello più regolarizzato.
(b) Il grafico
import matplotlib.pyplot as plt
plt.figure()
plt.semilogx(C_s, scores)
plt.semilogx(C_s, np.array(scores) + np.array(scores_std), "b--") # media + deviazione standard
plt.semilogx(C_s, np.array(scores) - np.array(scores_std), "b--") # media - deviazione standard
plt.xlabel("Parametro C"); plt.ylabel("Punteggio di CV"); plt.ylim(0, 1.1)
plt.show()La curva ha tre zone:
- : punteggio costante . Con minuscolo la penalità sugli errori è quasi nulla, il modello è sotto-adattato (underfitting): tutti i coefficienti duali restano a e il classificatore degenera, predicendo la stessa cifra per tutti gli esempi (provato sull'intero dataset con : sempre la cifra 3, tutti i 1 797 punti sono vettori di supporto). Il punteggio è vicino alla probabilità di indovinare a caso ().
- : salita ripida ( a , a ).
- : plateau attorno a -: oltre non serve penalizzare di più gli errori (con il modello classifica perfettamente il training e ha 436 vettori di supporto su 1 797; con ne ha 648).
(c) Addestramento e test con il miglior
Per il test si ricarica il dataset come in aula, si appiattiscono le immagini e si divide senza rimescolare (shuffle=False): 75% training (1 347 immagini, le prime) e 25% test (450 immagini, le ultime).
digits = datasets.load_digits()
data = digits.images.reshape((len(digits.images), -1))
X_train, X_test, y_train, y_test = train_test_split(data, digits.target, test_size=0.25, shuffle=False)
svc = svm.SVC(kernel="linear", C=best_C)
svc.fit(X_train, y_train)
predicted = svc.predict(X_test)
print(metrics.classification_report(y_test, predicted))Output (identico a quello del corso):
precision recall f1-score support
0 0.98 0.98 0.98 43
1 0.96 0.96 0.96 46
2 1.00 1.00 1.00 43
3 0.95 0.77 0.85 47
4 0.96 0.94 0.95 48
5 0.92 0.98 0.95 45
6 0.98 0.98 0.98 47
7 0.90 0.96 0.92 45
8 0.78 0.88 0.83 41
9 0.89 0.87 0.88 45
accuracy 0.93 450L'accuratezza sul test è ( cifre su ), inferiore a quella della CV (). Il corso nota che le due cifre non sono confrontabili: la CV è fatta su tutto il dataset con fold stratificate, il test è fatto sul solo ultimo quarto, senza rimescolare, cioè su una parte diversa del dataset da quella usata per l'addestramento. Le classi più difficili sono la 3 (recall : giuste su , ; precision : ) e la 8 (precision , recall ): dalla matrice di confusione la 3 viene scambiata soprattutto con la 8 (6 volte), poi con la 7 (3 volte) e con la 5 (2 volte). Da qui .
Perché si usa la CV e non il test per scegliere . Se fosse scelto guardando il test, l'accuratezza riportata sarebbe ottimistica: il test "trapela" nel modello. Qui si sceglie con la CV (sul training), poi il test misura solo la generalizzazione finale.
Versione ripasso
Teoria: Apprendimento automatico nell'IA - supervisionato, SVM e valutazioneQuadro del machine learning nel corso di IA. Tre forme di apprendimento: supervisionato (coppie ingresso-uscita, classificazione se l'uscita è discreta e regressione se è un numero), non supervisionato (pattern senza feedback, per esempio clustering) e per rinforzo (ricompense). Un'ipotesi h approssima la funzione vera f e si valuta sul test set, non sul training set: un modello troppo semplice ha bias alto (underfitting), uno troppo complesso varianza alta (overfitting). Servono training, validation e test set; con pochi dati si usa la k-fold cross-validation. Alberi di decisione: si sceglie l'attributo con massimo guadagno d'informazione Gain = B(p/(p+n)) - somma (Nk/N) B(pk/Nk), si pota con il test del chi quadro (Delta > Delta*), si riduce la varianza con bagging e random forest. Perdita L1 e L2, regressione lineare e discesa del gradiente w <- w - alpha dL/dw. SVM: separatore a margine massimo, vettori di supporto, kernel trick con K(xj,xk). Pipeline scikit-learn del laboratorio 10: load_digits, train_test_split, SVC(C, kernel, gamma), fit, predict, classification_report, confusion_matrix, cross_val_score.Apprendimento automatico nell'IA - supervisionato, SVM e valutazione →, Support vector machines e metodi kernelUna SVM cerca l'iperpiano $w\cdot x+b=0$ che separa due classi con il margine più largo possibile: normalizzando $y_i(w\cdot x_i+b)\ge1$ il margine totale vale $2/|w|$, quindi si risolve $\min\frac12|w|^2$ (problema convesso, nessun minimo locale). Con classi sovrapposte si ammettono errori con le variabili di scarto $\xi_i$ e il parametro $C$ (soft margin, equivalente alla hinge loss più una penalità su $|w|^2$); $C$ piccolo = margine largo e più bias, $C$ grande = margine stretto e più varianza, si sceglie per cross-validation. La soluzione dipende solo dai vettori di supporto ($w=\sum\alpha_iy_ix_i$) e solo tramite prodotti scalari, per questo si può sostituire $x_i\cdot x_j$ con un kernel $K(x_i,x_j)=\langle\phi(x_i),\phi(x_j)\rangle$ (polinomiale, RBF) senza calcolare $\phi$: così si ottengono bordi non lineari. La SVR usa lo stesso schema con un tubo di tolleranza $\varepsilon$. Nell'esame le SVM sono solo nella parte teorica.Support vector machines e metodi kernel →.
Procedura.
C_s = np.logspace(-20, 0, 20); per ogni :svc.C = C,cross_val_score(svc, X, y, cv=3)(3 fold stratificate), si tengono media e deviazione standard. Si sceglie il con la media più alta; poi si addestra su training (75%,shuffle=False) e si testa.
Risultati. Punteggi medi: , poi (12 volte), , , , , , , per . Gli ultimi quattro sono indistinguibili (differenze contro deviazione standard ): a parità conviene il più piccolo.
Grafico (scala logaritmica): (1) : punteggio costante , modello degenerato (predice una sola cifra, underfitting); (2) salita ripida tra e ; (3) plateau per . Vettori di supporto: 648 con il migliore, 436 con .
Test (450 immagini): accuratezza ( giuste), meno della CV () perché i test sono diversi (ultimo quarto non rimescolato). Cifra 3: recall (, ), precision (), ; cifra 8: precision .
svc = svm.SVC(kernel="linear", C=best_C).fit(X_train, y_train)
print(metrics.classification_report(y_test, svc.predict(X_test)))Errori tipici: scegliere sul test set (leakage); dimenticare la scala logaritmica del grafico; confrontare l'accuratezza di CV con quella del test come se fossero la stessa misura; scegliere sempre il massimo.