Ajuste de hiperparâmetros (visualização)
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 aprendizado de máquina durante o treinamento, mas sim definidos pelo usuário antes do início do processo de treinamento. Esses parâmetros são comumente referidos como hiperparâmetros, e exemplos incluem a taxa de aprendizagem, 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 aprendizado de máquina 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 FLAML
o , uma biblioteca Python leve para automação eficiente de operações de aprendizado de máquina e IA, para seus requisitos de ajuste de hiperparâmetros. Nos notebooks Fabric, os usuários podem solicitar flaml.tune
um ajuste econômico de hiperparâmetros.
Importante
Este recurso está em pré-visualização.
Ajustando o fluxo de trabalho
Há três etapas essenciais a serem usadas flaml.tune
para concluir uma tarefa básica de ajuste:
- Especifique o objetivo de ajuste em relação aos hiperparâmetros.
- Especifique um espaço de pesquisa dos hiperparâmetros.
- Especifique restrições de ajuste, incluindo restrições no orçamento de recursos para fazer o ajuste, restrições nas configurações e/ou restrições em uma (ou várias) métrica(s) específica(s).
Objetivo de afinação
O primeiro passo é especificar seu objetivo de ajuste. Para fazer isso, você deve primeiro especificar seu procedimento de avaliação com relação aos hiperparâmetros em uma função evaluation_function
definida pelo usuário. A função requer uma configuração de hiperparâmetro como entrada. Ele pode simplesmente retornar um valor de métrica em um escalar ou retornar um dicionário de nome de métrica e pares de valores métricos.
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"]}
Pesquisar espaço
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 o 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 parâmetros de amostragem. FLAML suporta os seguintes tipos de hiperparâmetros: 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 você pode personalizar domínios em seu espaço de pesquisa, visite a documentação do FLAML sobre como personalizar espaços de pesquisa.
Restrições de ajuste
A última etapa é especificar as restrições da tarefa de ajuste. Uma propriedade notável é que ele é capaz de concluir o processo de ajuste dentro de uma restrição de flaml.tune
recursos necessária. Para fazer isso, um usuário pode fornecer restrições de recursos em termos de tempo de relógio de parede (em segundos) usando o time_budget_s
argumento ou em termos do número de tentativas usando o num_samples
argumento.
# 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 de adição, você pode visitar a documentação do FLAML para obter opções avançadas de ajuste.
Juntando tudo
Depois de definirmos nossos critérios de ajuste, podemos executar o teste de ajuste. Para acompanhar os resultados de nossa avaliação, podemos aproveitar o registro automático MLFlow para capturar as métricas e os parâmetros de cada uma dessas execuções. Este código irá capturar todo o teste de ajuste de hiperparâmetros, destacando cada uma das combinações de hiperparâmetros que foram exploradas pelo 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, métricas, parâmetros e modelos devem ser registrados automaticamente à medida que o MLFlow é executado. No entanto, isso varia de acordo com o quadro. Métricas e parâmetros para modelos específicos podem não ser registrados. Por exemplo, nenhuma métrica será registrada para modelos XGBoost, LightGBM, Spark e SynapseML. Você pode saber mais sobre quais métricas e parâmetros são capturados de cada estrutura usando a documentação de registro automático MLFlow.
Sintonização paralela com o Apache Spark
A flaml.tune
funcionalidade suporta o ajuste do Apache Spark e de alunos de nó único. Além disso, ao ajustar alunos de nó único (por exemplo, alunos do Scikit-Learn), você também pode paralelizar o ajuste para acelerar seu processo de ajuste definindo use_spark = True
. Para clusters Spark, por padrão, o FLAML iniciará uma avaliação por executor. Você também pode personalizar o número de avaliações simultâneas usando o n_concurrent_trials
argumento.
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, você pode visitar a documentação do FLAML para trabalhos paralelos do Spark.
Visualizar resultados
O flaml.visualization
módulo fornece funções de utilidade para plotar o processo de otimização usando Plotly. Ao aproveitar o Plotly, os usuários podem explorar interativamente os resultados de seus experimentos AutoML. Para usar essas funções de plotagem, basta fornecer seu objeto otimizado flaml.AutoML
ou flaml.tune.tune.ExperimentAnalysis
como entrada.
Pode utilizar as seguintes funções no seu bloco de notas:
plot_optimization_history
: Histórico de otimização de gráficos de todos os ensaios no experimento.plot_feature_importance
: Plotar a importância de cada recurso no conjunto de dados.plot_parallel_coordinate
: Plotar as relações de parâmetros de alta dimensão no experimento.plot_contour
: Plotar a relação de parâmetros como gráfico de contorno no experimento.plot_edf
: Representar graficamente o valor objetivo EDF (função de distribuição empírica) da experiência.plot_timeline
: Traçar a linha do tempo do experimento.plot_slice
: Plotar a relação de parâmetros como gráfico de fatia em um estudo.plot_param_importance
: Plotar a importância do hiperparâmetro do experimento.