Come ottimizzare i parametri degli algoritmi di Machine Learning

In questo articolo vedremo come ottimizzare l’addestramento degli algoritmi di classificazione di Machine Learning, scegliendo adeguatamente il valore dei parametri configurabili all’interno di ogni algoritmo. Questa attività è nota come tuning degli iperparametri (o hyperparameter optimization). Il termine iperparametro è utilizzato per distinguere questa tipologia di parametri da quelli restituiti in output dall’algoritmo, come ad esempio i pesi di un algoritmo di regressione logistica. In questa lezione useremo il metodo GridSearchCV della libreria di Python scikit-learn, che implementa al suo interno anche la cross-validation vista nella lezione precedente.

Configurare una griglia di parametri in una pipeline

Procediamo come al solito a importare il dataset Iris, dividere i dati in training e test e creare una pipeline che contenga le operazioni basilari di pre-processing e l’algoritmo di regressione logistica.

from sklearn.pipeline import Pipeline
log_regression_pipeline =Pipeline([("vn", SimpleImputer(strategy="mean")),
          ("sc", StandardScaler()),
          ("lr", LogisticRegression(random_state=0 ))])

Questa volta però non procediamo subito con l’addestreremo del modello, ma applichiamo alla pipeline appena creata il metodo get_params().

log_regression_pipeline.get_params()

Otteniamo così l’elenco dei parametri configurabili per tutti gli step della pipeline, con il relativo valore attuale.

output metodo get_params

Vediamo ad esempio che il metodo SimpleImputer è configurato attualmente per utilizzare la media come strategia di sostituzione dei valori null. Potrei decidere di confrontare i risultati ottenuti utilizzando un valore differente, come la mediana.

Analogamente l’algoritmo di regressione logistica è configurato con il parametro C uguale a 1.0 (a differenza della media, non abbiamo specificato nel codice di creazione della pipeline il valore di C e quindi il valore indicato 1.0 è quello di default). Questo parametro è legato alla regolarizzazione del modello: modificare il suo valore può portare a importanti cambiamenti. Vogliamo dunque testare l’algoritmo con più valori distinti del parametro C, ad esempio 0.8, 0.85, 0.9, 0.95 e 1.

Creeremo allora una griglia con le varie combinazioni di parametri che vogliamo testare:

param_grid = [{"lr__C": [0.8, 0.85, 0.9, 0.95, 1],
                         "vn__strategy": ["median","mean"]}]

Facciamo attenzione a valorizzare le chiavi del dizionario così come indicato nell’output del metodo get_params().

GridSearchCV per il tuning degli iperparametri

A questo punto possiamo importare il metodo GridSearchCV e passargli in input:

  • la pipeline che vogliamo ottimizzare
  • la griglia dei parametri che vogliamo testare
  • il numero di fold da utilizzare per eseguire la convalida incrociata e selezionare i valori migliori dei parametri

Ecco il codice:

from sklearn.model_selection import GridSearchCV
my_grid = GridSearchCV(estimator = my_first_pipeline,
                       param_grid = param_grid,
                       cv = 10 )

A questo punto lanciando il metodo fit eseguiremo ben 120 addestramenti! Più in particolare, per ognuna delle 10 combinazioni legate alla convalida incrociata, lanceremo l’algoritmo 12 volte relative a tutte le possibili combinazioni tra i due parametri lr__C e vn__strategy (6 per il primo e 2 per il secondo).

Facciamo attenzione quindi a valutare l’impatto computazionale dell’utilizzo della nostra griglia. In questo articolo stiamo analizzando il dataset Iris che contiene soltanto centocinquanta righe circa, quindi possiamo procedere tranquillamente e lanciare il metodo fit

my_grid.fit(x1,y1)

Jupyter-lab ci restituirà questa immagine di output

Creiamo il modello con gli iperparametri ottimizzati

Dopo aver eseguito l’addestramento, possiamo visualizzare la miglior combinazione trovata interrogando l’attributo best_params_

my_grid.best_params_

Tramite l’attributo best_score_ possiamo recuperare la media delle accuratezze ottenute con questo modello nelle 10 diverse suddivisioni eseguite dalla convalida incrociata. In questo caso il codice

my_grid.best_score_

restituirà 0.94. Possiamo dunque creare un nuovo modello utilizzando i migliori valori degli iperparametri appena ottenuti. Per far ciò possiamo sia creare manualmente la pipeline con quei parametri

best_lr_pipeline =Pipeline([("vn", SimpleImputer(strategy="median")),
          ("sc", StandardScaler()),
          ("lr", LogisticRegression(random_state=0, C=0.8))])

oppure recuperarla direttamente dall’attributo best_params_

best_lr_pipeline = my_grid.best_params_

La seconda opzione è sicuramente più veloce!

Valutiamo i risultati con il metodo score

Una volta ottenuto il modello migliore, posso valutarne l’accuratezza sul dataset di test, come spiegato nella lezione precedente.

best_lr_pipeline.fit(x1,y1)
best_lr_pipeline.score(x2,y2)

ottenendo in questo caso il 95%. Anche in questo caso sarei potuto arrivare allo stesso risultato un po’ più velocemente, utilizzando direttamente l’attributo score(). Infatti questa sequenza di operazioni:

  1. creare il modello con la scelta dei parametri migliori
  2. allenarlo sull’intero dataset di training
  3. valutarne l’accuratezza sui dati di test

è equivalente ad eseguire direttamente il codice

my_grid.score(x2,y2)

Continua a imparare

Torna in alto
Torna su