Compartilhar via


Ajuste de hiperparâmetros (preview)

O ajuste de hiperparâmetros é 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, definidos 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 específico e do conjunto de dados. O ajuste de hiperparâmetros é, portanto, uma etapa crítica no pipeline de aprendizado de máquina, pois pode ter um impacto significativo na precisão e no desempenho de generalização do modelo.

No Fabric, os cientistas de dados podem aproveitar a FLAML, uma biblioteca Python leve para automação eficiente de operações de aprendizado de máquina e IA, nos requisitos de ajuste de hiperparâmetros. Nos notebooks do Fabric, os usuários podem solicitar flaml.tune para o ajuste econômico de hiperparâmetros.

Importante

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

Ajuste do fluxo de trabalho

Há três etapas essenciais para usar flaml.tune na conclusão de 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 do hiperparâmetro.
  3. Especifique restrições de ajuste, incluindo restrições na cota de recursos para fazer o ajuste, restrições nas configurações ou restrições em uma métrica específica ou várias delas.

Objetivo de ajuste

O primeiro passo é especificar o objetivo de ajuste. Para isso, você deve primeiro especificar o procedimento de avaliação em relação aos hiperparâmetros em uma função evaluation_function definida pelo usuário. A função requer uma configuração de hiperparâmetros como entrada. Ela pode simplesmente retornar um valor de métrica em um escalar ou retornar um dicionário de pares de nome de métrica e valor de métrica.

No exemplo abaixo, podemos definir uma função de avaliação em relação a 2 hiperparâmetros denominados 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 dos hiperparâmetros. No espaço de pesquisa, é necessário especificar valores válidos para os hiperparâmetros e como esses valores formam amostras (por exemplo, de uma distribuição uniforme ou de uma distribuição uniforme logarítmica). 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 números inteiros que variam de [1, 100.000]. Esses hiperparâmetros formam amostras uniformes 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 a 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 formar amostras de parâmetros. A FLAML é compatível com os seguintes tipos de hiperparâmetros: flutuante, 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 no espaço de pesquisa, visite a documentação da 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 é a capacidade de concluir o processo de ajuste em uma restrição de recursos necessária. Para isso, um usuário pode fornecer restrições de recursos em termos do tempo de relógio de parede (em segundos) usando o argumento time_budget_s ou em termos do número de avaliações 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 da FLAML para obter 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 da nossa avaliação, podemos aproveitar o registro em log automático do MLFlow para capturar as métricas e os parâmetros de cada uma dessas execuções. Esse código captura toda a avaliação do ajuste de hiperparâmetros, destacando cada uma das combinações de hiperparâmetros que foram exploradas pela 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
    )

Observação

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

Ajuste paralelo com o Apache Spark

A funcionalidade flaml.tune é compatível com o ajuste do Apache Spark e de aprendizes de nó único. Além disso, ao ajustar aprendizes de nó único (por exemplo, aprendizes de Scikit-Learn), você também pode paralelizar o ajuste para acelerar o processo de ajuste definindo use_spark = True. Em clusters do Spark, por padrão, a FLAML inicia 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 as trilhas de ajuste, visite a documentação da FLAML para trabalhos paralelos do Spark.

Visualizar os resultados

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

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

  • plot_optimization_history: plotar o histórico de otimização de todas as avaliações do experimento.
  • plot_feature_importance: plotar a importância de cada recurso no conjunto de dados.
  • plot_parallel_coordinate: plotar os relacionamentos de parâmetros de alta dimensão no experimento.
  • plot_contour: plotar o relacionamento de parâmetros como gráfico de curva de nível no experimento.
  • plot_edf: plotar a FDE (função de distribuição empírica) do valor objetivo do experimento.
  • plot_timeline: plotar a linha do tempo do experimento.
  • plot_slice: plotar o relacionamento de parâmetros como gráfico de pizza em um estudo.
  • plot_param_importance: plotar a importância de hiperparâmetros do experimento.