Parallelizzare l'ottimizzazione di iperparametri con Hyperopt

Nota

La versione open source di Hyperopt non è più gestita.

Hyperopt non è incluso in Databricks Runtime per Machine Learning dopo la versione 16.4 LTS ML. Azure Databricks consiglia di usare Optuna per l'ottimizzazione a nodo singolo oppure RayTune per un'esperienza simile alla funzionalità di ottimizzazione degli iperparametri di Hyperopt distribuita e deprecata. Altre informazioni sull'uso di RayTune in Azure Databricks.

Questo notebook di esempio illustra come scalare l'ottimizzazione degli iperparametri da un singolo computer a un cluster Azure Databricks utilizzando Hyperopt con SparkTrials. Ottimizzando un classificatore SVM scikit-learn sul set di dati Iris, si crea prima un flusso di lavoro su computer singolo fmin(), quindi lo si parallelizza sui lavoratori Spark, con MLflow che monitora automaticamente ogni esperimento.

Importare i pacchetti necessari e caricare il set di dati

from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
from sklearn.svm import SVC

from hyperopt import fmin, tpe, hp, SparkTrials, STATUS_OK, Trials

# If you are running Databricks Runtime for Machine Learning, `mlflow` is already installed and you can skip the following line.
import mlflow
# Load the iris dataset from scikit-learn
iris = iris = load_iris()
X = iris.data
y = iris.target

Parte 1. Flusso di lavoro Hyperopt a computer singolo

Ecco i passaggi in un flusso di lavoro Hyperopt:

  1. Definire una funzione da ridurre al minimo.
  2. Definire uno spazio di ricerca sugli iperparametri.
  3. Selezionare un algoritmo di ricerca.
  4. Eseguire l'algoritmo di ottimizzazione con Hyperopt fmin().

Per altre informazioni, vedere la documentazione di Hyperopt.

Definire una funzione per ridurre al minimo

In questo esempio viene usato un classificatore di macchine a vettori di supporto. L'obiettivo è trovare il valore migliore per il parametro Cdi regolarizzazione .

La maggior parte del codice per un flusso di lavoro Hyperopt si trova nella funzione obiettivo. Questo esempio usa il classificatore a vettori di supporto di scikit-learn.

Se il cluster utilizza Databricks Runtime 11.3 ML, modifica il classificatore del vettore di supporto per accettare un parametro posizionale, clf = SVC(C).

def objective(C):
    # Create a support vector classifier model
    clf = SVC(C=C)

    # Use the cross-validation accuracy to compare the models' performance
    accuracy = cross_val_score(clf, X, y).mean()

    # Hyperopt tries to minimize the objective function. A higher accuracy value means a better model, so you must return the negative accuracy.
    return {'loss': -accuracy, 'status': STATUS_OK}

Definire lo spazio di ricerca sugli iperparametri

Per informazioni dettagliate sulla definizione di uno spazio di ricerca e di espressioni di parametro, vedere la documentazione di Hyperopt .

search_space = hp.lognormal('C', 0, 1.0)

Selezionare un algoritmo di ricerca

Le due scelte principali sono:

  • hyperopt.tpe.suggest: albero degli estimatori parzen, approccio bayesiano che esegue l'iterativa e seleziona in modo adattivo le nuove impostazioni degli iperparametri da esplorare in base ai risultati precedenti
  • hyperopt.rand.suggest: ricerca casuale, approccio non adattivo che esegue campioni sullo spazio di ricerca
algo=tpe.suggest

Eseguire l'algoritmo di ottimizzazione con Hyperopt fmin()

Impostare max_evals sul numero massimo di punti nello spazio degli iperparametri da testare, ovvero il numero massimo di modelli da adattare e valutare.

argmin = fmin(
  fn=objective,
  space=search_space,
  algo=algo,
  max_evals=16)
# Print the best value found for C
print("Best value found: ", argmin)

Parte 2. Ottimizzazione distribuita con Apache Spark e MLflow

Per distribuire l'ottimizzazione, aggiungere un altro argomento a fmin(): una Trials classe denominata SparkTrials.

SparkTrials accetta 2 argomenti facoltativi:

  • parallelism: numero di modelli da adattare e valutare contemporaneamente. Il valore predefinito è il numero di slot di attività Spark disponibili.
  • timeout: Tempo massimo (in secondi) per cui fmin() può funzionare. Il valore predefinito non è un limite massimo di tempo.

In questo esempio viene usata la funzione obiettivo molto semplice definita in Cmd 7. In questo caso, la funzione viene eseguita rapidamente e l'overhead dell'avvio dei processi Spark domina il tempo di calcolo, quindi i calcoli per il caso distribuito richiedono più tempo. Per i problemi del mondo reale, la funzione obiettivo è più complessa e l'uso di SparkTrails per distribuire i calcoli è più veloce rispetto alla regolazione a computer singolo.

Il rilevamento automatizzato di MLflow è abilitato per impostazione predefinita. Per usarlo, chiamare mlflow.start_run() prima di chiamare fmin() come illustrato nell'esempio.

from hyperopt import SparkTrials

# To display the API documentation for the SparkTrials class, uncomment the following line.
# help(SparkTrials)
spark_trials = SparkTrials()

with mlflow.start_run():
  argmin = fmin(
    fn=objective,
    space=search_space,
    algo=algo,
    max_evals=16,
    trials=spark_trials)
# Print the best value found for C
print("Best value found: ", argmin)

Per visualizzare l'esperimento MLflow associato al notebook, fare clic sull'icona Esperimento nella barra di contesto del notebook in alto a destra. Qui è possibile visualizzare tutte le esecuzioni. Per visualizzare le esecuzioni nell'interfaccia utente di MLflow, fare clic sull'icona all'estrema destra accanto a Esecuzioni di esperimenti.

Per esaminare l'effetto della regolazione C:

  1. Selezionare le esecuzioni risultanti e fare clic su Confronta.
  2. Nel grafico a dispersione selezionare C per asse X e perdita per asse Y.

Dopo aver eseguito le azioni nell'ultima cella del notebook, dovrebbe venir visualizzata l'interfaccia utente di MLflow:

Demo di Hyperopt MLflow

Notebook di esempio

Parallelizzare l'ottimizzazione di iperparametri con Hyperopt

Ottenere il notebook