Compartir vía


Ajuste de hiperparámetros (versión preliminar)

El ajuste de hiperparámetros es el proceso de búsqueda de los valores óptimos para los parámetros que el modelo de aprendizaje automático no ha aprendido durante el entrenamiento, sino que lo establece el usuario antes de que comience el proceso de entrenamiento. Estos parámetros se conocen normalmente como hiperparámetros y ejemplos de ellos son la velocidad de aprendizaje, el número de capas ocultas en una red neuronal, la intensidad de regularización y el tamaño del lote.

El rendimiento de un modelo de aprendizaje automático puede ser altamente sensible a la elección de hiperparámetros y el conjunto óptimo de hiperparámetros puede variar considerablemente en función del problema y el conjunto de datos específicos. Por lo tanto, el ajuste de hiperparámetros es un paso crítico en la canalización de aprendizaje automático, ya que puede tener un impacto significativo en el rendimiento de la precisión y la generalización del modelo.

En Fabric, los científicos de datos pueden aprovechar FLAML, una biblioteca ligera de Python para una automatización eficaz de las operaciones de aprendizaje automático e inteligencia artificial, para sus requisitos de ajuste de hiperparámetros. Dentro de los cuadernos de Fabric, los usuarios pueden llamar a flaml.tune para un ajuste económico de hiperparámetros.

Importante

Esta característica se encuentra en versión preliminar.

Flujo de trabajo de ajuste

Hay tres pasos esenciales a fin de usar flaml.tune para finalizar una tarea de optimización básica:

  1. Especifique el objetivo de ajuste con respecto a los hiperparámetros.
  2. Especifique un espacio de búsqueda de hiperparámetros.
  3. Especifique restricciones de ajuste, incluidas las restricciones del presupuesto de recursos para realizar el ajuste, las restricciones de las configuraciones y/o las restricciones de una métrica determinada (o varias).

Objetivo de ajuste

El primer paso es especificar el objetivo de ajuste. Para ello, primero debe especificar el procedimiento de evaluación con respecto a los hiperparámetros de una función evaluation_functiondefinida por el usuario. La función requiere una configuración de hiperparámetros como entrada. Simplemente puede devolver un valor de métrica en una escala o devolver un diccionario de pares de nombre de métrica y valor de métrica.

En el ejemplo siguiente, podemos definir una función de evaluación con respecto a 2 hiperparámetros denominados x y y.

import time

def evaluate_config(config: dict):
    """evaluate a hyperparameter configuration"""
    score = (config["x"] - 85000) ** 2 - config["x"] / config["y"]


    faked_evaluation_cost = config["x"] / 100000
    time.sleep(faked_evaluation_cost)
    # we can return a single float as a score on the input config:
    # return score
    # or, we can return a dictionary that maps metric name to metric value:
    return {"score": score, "evaluation_cost": faked_evaluation_cost, "constraint_metric": config["x"] * config["y"]}

Espacio de búsqueda

A continuación, se especifica un espacio de búsqueda de hiperparámetros. En el espacio de búsqueda, debe especificar valores válidos para los hiperparámetros y cómo se muestrean estos valores (por ejemplo, desde una distribución uniforme o una distribución uniforme del registro). En el ejemplo siguiente, podemos proporcionar el espacio de búsqueda para los hiperparámetros x y y. Los valores válidos para ambos son enteros que van desde [1, 100 000]. Estos hiperparámetros se muestrean uniformemente en los intervalos especificados.

from flaml import tune

# construct a search space for the hyperparameters x and y.
config_search_space = {
    "x": tune.lograndint(lower=1, upper=100000),
    "y": tune.randint(lower=1, upper=100000)
}

# provide the search space to tune.run
tune.run(..., config=config_search_space, ...)

Con FLAML, los usuarios pueden personalizar el dominio para un hiperparámetro determinado. Esto permite a los usuarios especificar un tipo e intervalo válido desde los parámetros de ejemplo. FLAML admite los siguientes tipos de hiperparámetros: flotante, entero y categórico. Puede ver este ejemplo a continuación para dominios usados habitualmente:

config = {
    # Sample a float uniformly between -5.0 and -1.0
    "uniform": tune.uniform(-5, -1),

    # Sample a float uniformly between 3.2 and 5.4,
    # rounding to increments of 0.2
    "quniform": tune.quniform(3.2, 5.4, 0.2),

    # Sample a float uniformly between 0.0001 and 0.01, while
    # sampling in log space
    "loguniform": tune.loguniform(1e-4, 1e-2),

    # Sample a float uniformly between 0.0001 and 0.1, while
    # sampling in log space and rounding to increments of 0.00005
    "qloguniform": tune.qloguniform(1e-4, 1e-1, 5e-5),

    # Sample a random float from a normal distribution with
    # mean=10 and sd=2
    "randn": tune.randn(10, 2),

    # Sample a random float from a normal distribution with
    # mean=10 and sd=2, rounding to increments of 0.2
    "qrandn": tune.qrandn(10, 2, 0.2),

    # Sample a integer uniformly between -9 (inclusive) and 15 (exclusive)
    "randint": tune.randint(-9, 15),

    # Sample a random uniformly between -21 (inclusive) and 12 (inclusive (!))
    # rounding to increments of 3 (includes 12)
    "qrandint": tune.qrandint(-21, 12, 3),

    # Sample a integer uniformly between 1 (inclusive) and 10 (exclusive),
    # while sampling in log space
    "lograndint": tune.lograndint(1, 10),

    # Sample a integer uniformly between 2 (inclusive) and 10 (inclusive (!)),
    # while sampling in log space and rounding to increments of 2
    "qlograndint": tune.qlograndint(2, 10, 2),

    # Sample an option uniformly from the specified choices
    "choice": tune.choice(["a", "b", "c"]),
}

Para obtener más información sobre cómo puede personalizar dominios dentro del espacio de búsqueda, visite la documentación de FLAML sobre la personalización de espacios de búsqueda.

Restricciones de ajuste

El último paso es especificar restricciones de la tarea de ajuste. Una propiedad notable de flaml.tune es que es capaz de completar el proceso de ajuste dentro de una restricción de recursos necesaria. Para ello, un usuario puede proporcionar restricciones de recursos en términos de tiempo de reloj (en segundos) mediante el argumento time_budget_s o en términos del número de pruebas mediante el argumento num_samples.

# Set a resource constraint of 60 seconds wall-clock time for the tuning.
flaml.tune.run(..., time_budget_s=60, ...)

# Set a resource constraint of 100 trials for the tuning.
flaml.tune.run(..., num_samples=100, ...)

# Use at most 60 seconds and at most 100 trials for the tuning.
flaml.tune.run(..., time_budget_s=60, num_samples=100, ...)

Para obtener más información sobre las restricciones de configuración de adición, puede visitar la documentación de FLAML para obtener más información sobre las opciones de ajuste avanzadas.

Reunión de todo

Una vez que hayamos definido nuestros criterios de ajuste, podemos ejecutar la prueba de ajuste. Para realizar un seguimiento de los resultados de nuestra prueba, podemos aprovechar el registro automático de MLFlow para capturar las métricas y los parámetros de cada una de estas ejecuciones. Este código capturará toda la prueba de ajuste de hiperparámetros, resaltando cada una de las combinaciones de hiperparámetros exploradas por FLAML.

import mlflow
mlflow.set_experiment("flaml_tune_experiment")
mlflow.autolog(exclusive=False)

with mlflow.start_run(nested=True, run_name="Child Run: "):
    analysis = tune.run(
        evaluate_config,  # the function to evaluate a config
        config=config_search_space,  # the search space defined
        metric="score",
        mode="min",  # the optimization mode, "min" or "max"
        num_samples=-1,  # the maximal number of configs to try, -1 means infinite
        time_budget_s=10,  # the time budget in seconds
    )

Nota:

Cuando el registro automático de MLflow está habilitado, las métricas, los parámetros y los modelos se deben registrar automáticamente a medida que se ejecuta MLFlow. Sin embargo, esto varía según el marco. Es posible que no se registren métricas y parámetros para modelos específicos. Por ejemplo, no se registrará ninguna métrica para los modelos XGBoost, LightGBM, Spark y SynapseML. Puede obtener más información sobre qué métricas y parámetros se capturan de cada marco mediante la documentación de registro automático de MLFlow.

Ajuste paralelo con Apache Spark

La funcionalidad flaml.tune admite el ajuste de Apache Spark y los aprendices de un solo nodo. Además, al ajustar los aprendices de un solo nodo (por ejemplo, los de Scikit-Learn), también puede paralelizar el ajuste para acelerar el proceso estableciendo use_spark = True. En el caso de los clústeres de Spark, de forma predeterminada, FLAML iniciará una prueba por ejecutor. También puede personalizar el número de pruebas simultáneas mediante el argumento n_concurrent_trials.


analysis = tune.run(
    evaluate_config,  # the function to evaluate a config
    config=config_search_space,  # the search space defined
    metric="score",
    mode="min",  # the optimization mode, "min" or "max"
    num_samples=-1,  # the maximal number of configs to try, -1 means infinite
    time_budget_s=10,  # the time budget in seconds
    use_spark=True,
)
print(analysis.best_trial.last_result)  # the best trial's result
print(analysis.best_config)  # the best config

Para obtener más información sobre cómo paralelizar las pistas de ajuste, puede visitar la documentación de FLAML para trabajos paralelos de Spark.

Visualización de los resultados

El módulo flaml.visualization proporciona funciones de utilidad para trazar el proceso de optimización mediante Plotly. Al aprovechar Plotly, los usuarios pueden explorar interactivamente sus resultados del experimento de AutoML. Para usar estas funciones de trazado, simplemente proporcione su objeto optimizado flaml.AutoML o flaml.tune.tune.ExperimentAnalysis como entrada.

Puede usar las siguientes funciones en el cuaderno:

  • plot_optimization_history: traza el historial de optimización de todas las pruebas del experimento.
  • plot_feature_importance: traza la importancia de cada característica del conjunto de datos.
  • plot_parallel_coordinate: traza las relaciones de parámetros de alta dimensión en el experimento.
  • plot_contour: traza la relación de parámetros como trazado de contorno en el experimento.
  • plot_edf: traza el valor objetivo EDF (función de distribución empírica) del experimento.
  • plot_timeline: traza la escala de tiempo del experimento.
  • plot_slice: traza la relación de parámetros como trazado de segmentos en un estudio.
  • plot_param_importance: traza la importancia de hiperparámetros del experimento.