Compartilhar via


Ajuste de hiperparâmetros (versão prévia)

O ajuste do hiperparâmetro é o processo de encontrar os valores ideais para os parâmetros que não são aprendidos pelo modelo de machine learning durante o treinamento, mas sim definido pelo usuário antes do início do processo de treinamento. Esses parâmetros são comumente chamados de hiperparâmetros, e exemplos incluem a taxa de aprendizado, o número de camadas ocultas em uma rede neural, a força de regularização e o tamanho do lote.

O desempenho de um modelo de machine learning pode ser altamente sensível à escolha de hiperparâmetros, e o conjunto ideal de hiperparâmetros pode variar muito dependendo do problema e do conjunto de dados específicos. O ajuste do hiperparâmetro é, portanto, uma etapa crítica no pipeline de aprendizado de máquina, pois pode ter um impacto significativo no desempenho de precisão e generalização do modelo.

No Fabric, os cientistas de dados podem aproveitar FLAML, uma biblioteca python leve para automação eficiente de operações de machine learning e IA, para seus requisitos de ajuste de hiperparâmetro. Nos notebooks do Fabric, os usuários podem utilizar flaml.tune para ajuste econômico de hiperparâmetro.

Importante

Esse recurso está na versão prévia.

Ajuste do fluxo de trabalho

Há três etapas essenciais para usar flaml.tune para concluir uma tarefa básica de ajuste:

  1. Especifique o objetivo de ajuste em relação aos hiperparâmetros.
  2. Especifique um espaço de pesquisa dos hiperparâmetros.
  3. Especifique restrições de ajuste, incluindo restrições no orçamento de recursos para fazer o ajuste, restrições nas configurações ou/e restrições em uma (ou várias) métricas específicas.

Objetivo de ajuste

A primeira etapa é especificar seu objetivo de ajuste. Para fazer isso, primeiro especifique o procedimento de avaliação em relação aos hiperparâmetros em uma função definida pelo usuário evaluation_function. A função requer uma configuração de hiperparâmetro como entrada. Ele pode simplesmente retornar um valor de métrica como escalar ou retornar um dicionário com pares de nome de métrica e valor de métrica.

No exemplo a seguir, podemos definir uma função de avaliação em relação a dois hiperparâmetros chamados x e 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"]}

Espaço de pesquisa

Em seguida, especificaremos o espaço de pesquisa de hiperparâmetros. No espaço de pesquisa, você precisa especificar valores válidos para seus hiperparâmetros e como esses valores são amostrados (por exemplo, de uma distribuição uniforme ou de uma distribuição log-uniforme). No exemplo abaixo, podemos fornecer o espaço de pesquisa para os hiperparâmetros x e y. Os valores válidos para ambos são inteiros que variam de [1, 100.000]. Esses hiperparâmetros são amostrados uniformemente nos 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, ...)

Com FLAML, os usuários podem personalizar o domínio para um hiperparâmetro específico. Isso permite que os usuários especifiquem um tipo e um intervalo válido para amostrar parâmetros. O FLAML dá suporte aos seguintes tipos de hiperparâmetro: float, inteiro e categórico. Você pode ver este exemplo abaixo para domínios comumente usados:

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 saber mais sobre como personalizar domínios em seu espaço de pesquisa, visite a documentação FLAML sobre como personalizar espaços de pesquisa.

Restrições de ajuste

A última etapa é especificar restrições da tarefa de ajuste. Uma propriedade notável de flaml.tune é que ele é capaz de concluir o processo de ajuste dentro de uma restrição de recurso necessária. Para fazer isso, um usuário pode fornecer restrições de recurso em termos de tempo real (em segundos) usando o argumento time_budget_s ou em termos do número de testes usando o 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 saber mais sobre restrições de configuração adicionais, visite a documentação do FLAML para acessar opções avançadas de ajuste.

Juntando as peças

Depois de definirmos nossos critérios de ajuste, podemos executar a avaliação de ajuste. Para acompanhar os resultados de nossa avaliação, podemos aproveitar o registro automático em log do MLFlow para capturar as métricas e os parâmetros para cada uma dessas execuções. Esse código capturará toda a avaliação de ajuste do hiperparâmetro, realçando cada uma das combinações de hiperparâmetro que foram 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

Quando o registro automático do MLflow está habilitado, as métricas, os parâmetros e os modelos devem ser registrados automaticamente à medida que o MLFlow é executado. No entanto, isso varia de acordo com a estrutura. Métricas e parâmetros para modelos específicos podem não ser registrados. Por exemplo, nenhuma métrica será registrada nos modelos XGBoost, LightGBM, Spark e SynapseML. Você pode saber mais sobre quais métricas e parâmetros são capturados de cada framework usando a documentação de registro automático do MLFlow.

Otimização paralela com o Apache Spark

A funcionalidade flaml.tune dá suporte ao ajuste tanto do Apache Spark quanto dos algoritmos de aprendizado em apenas um nó. Além disso, ao ajustar modelos de nó único (por exemplo, modelos Scikit-Learn), você também pode paralelizar o ajuste configurando use_spark = True para acelerar o processo de ajuste. Para clusters Spark, por padrão, FLAML iniciará uma avaliação por executor. Você também pode personalizar o número de avaliações simultâneas usando o 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 saber mais sobre como paralelizar suas trilhas de ajuste, visite a documentação do FLAML para trabalhos paralelos do Spark.

Visualizar resultados

O módulo flaml.visualization fornece funções de utilitário para plotar o processo de otimização usando Plotly. Aproveitando Plotly, os usuários podem explorar interativamente seus resultados do experimento AutoML. Para usar essas funções de plotagem, basta fornecer seu objeto flaml.AutoML ou flaml.tune.tune.ExperimentAnalysis otimizado como uma entrada.

Você pode usar as seguintes funções em seu notebook:

  • plot_optimization_history: Plotar o histórico de otimização de todas as tentativas no experimento.
  • plot_feature_importance: Importância do gráfico para cada característica no conjunto de dados.
  • plot_parallel_coordinate: Plote as relações de parâmetros de alta dimensão no experimento.
  • plot_contour: Plote a relação de parâmetros como gráfico de contorno no experimento.
  • plot_edf: Plote o valor objetivo da função de distribuição empírica (EDF) do experimento.
  • plot_timeline: Plote a linha do tempo do experimento.
  • plot_slice: Represente a relação entre parâmetros como gráfico de seção em um estudo.
  • plot_param_importance: Plote a importância do hiperparâmetro do experimento.