Ajuste de Hiperparâmetros
O que é Ajuste de Hiperparâmetros (Hyperparameter Tuning)?
Ajuste de hiperparâmetros é o processo de selecionar valores de configuração que governam como um modelo de aprendizado de máquina (machine learning) é treinado, com o objetivo de maximizar o desempenho em dados não vistos. Ao contrário dos parâmetros do modelo (model parameters) (pesos (weights) aprendidos a partir dos dados), os hiperparâmetros (hyperparameters) são definidos antes do treinamento e, em geral, controlam:
- Capacidade do modelo (por exemplo, profundidade de uma árvore, número de camadas em uma rede)
- Comportamento da otimização (por exemplo, taxa de aprendizado (learning rate), tamanho do lote (batch size))
- Força da regularização (regularization) (por exemplo, penalidade L2, taxa de dropout (dropout))
- Escolhas de processamento de dados/atributos (features) (por exemplo, n-gramas (n-grams), opções de normalização (normalization))
O ajuste de hiperparâmetros faz parte da seleção de modelos (model selection) e deve ser feito com práticas cuidadosas de avaliação (geralmente Validação Cruzada (Cross-Validation)) para evitar resultados excessivamente otimistas.
Por que o ajuste importa (e por que é difícil)
Hiperparâmetros influenciam fortemente o trade-off viés–variância (bias–variance tradeoff) (veja Trade-off Viés–Variância). Por exemplo:
- Uma árvore de decisão muito profunda pode se ajustar bem aos dados de treino, mas sofrer sobreajuste (overfit) (alta variância).
- Regularização demais pode causar subajuste (underfit) (alto viés).
- Uma taxa de aprendizado muito alta pode impedir a convergência; muito baixa pode tornar o treinamento proibitivamente lento.
O ajuste é difícil porque:
- O espaço de busca (search space) pode ser de alta dimensionalidade e misto (contínuo, inteiro, categórico).
- O treinamento costuma ser estocástico (stochastic) (inicialização aleatória, minilotes (minibatching)), tornando a avaliação ruidosa.
- Cada avaliação pode ser cara (treinar um modelo grande).
- Os “melhores” hiperparâmetros dependem do conjunto de dados, da métrica e do orçamento computacional (compute budget).
Do ponto de vista matemático, o ajuste costuma ser tratado como otimização de caixa-preta (black-box optimization):
[ \text{maximize } f(\lambda) \quad \text{where } \lambda \in \Lambda ]
- (\lambda): vetor de hiperparâmetros
- (\Lambda): espaço de busca
- (f(\lambda)): desempenho de validação (estimado via holdout (holdout) ou validação cruzada)
Como (f) é caro e não tem gradiente analítico, dependemos de estratégias de busca como busca em grade (grid search), busca aleatória (random search) e otimização bayesiana (Bayesian optimization).
Fluxo de trabalho de ajuste de hiperparâmetros (base prática)
Um fluxo de trabalho robusto de ajuste normalmente se parece com isto:
Defina o objetivo e a métrica (metric)
- Classificação: acurácia, F1, ROC-AUC, perda logarítmica (log loss)
- Regressão: RMSE, MAE, R²
- Ranqueamento/recomendações: NDCG, MAP Escolha uma métrica alinhada a objetivos de negócio ou científicos.
Divida os dados corretamente
- Use um conjunto de teste (test set) apenas uma vez no final.
- Use validação ou validação cruzada para o ajuste.
- Para séries temporais, use divisões sensíveis ao tempo (sem vazamento de dados (data leakage)).
Construa uma pipeline (pipeline) segura contra vazamento
- O pré-processamento deve ser ajustado dentro de cada dobra (fold) de treinamento.
- No scikit-learn, isso significa usar
Pipeline.
Escolha um espaço de busca
- Intervalos razoáveis, escalas corretas (frequentemente escala logarítmica para taxas).
- Inclua dependências condicionais (conditional dependencies) (por exemplo,
penaltydepende do solver).
Escolha uma estratégia de busca
- Comece barato e amplo; depois refine.
- Considere métodos de multifidelidade (multi-fidelity) se o treinamento for caro.
Considere o ruído
- Repita a avaliação ou use validação cruzada robusta.
- Controle a aleatoriedade (sementes (seeds)) quando apropriado.
Finalize
- Reajuste (refit) usando todos os dados de treinamento com os melhores hiperparâmetros.
- Avalie uma única vez no conjunto de teste separado.
Busca em Grade
Ideia
A busca em grade enumera um conjunto fixo de valores candidatos para cada hiperparâmetro e testa todas as combinações.
Se você tem:
- 5 valores para
max_depth - 4 valores para
min_samples_split - 3 valores para
min_samples_leaf
Isso dá (5 \times 4 \times 3 = 60) treinamentos de modelo (vezes o número de dobras de validação cruzada).
Quando funciona bem
- Espaços de busca de baixa dimensionalidade (1–3 hiperparâmetros)
- Quando você tem boas hipóteses prévias sobre intervalos adequados
- Quando treinar é barato e você quer cobertura sistemática
Limitações
- Explosão combinatória (combinatorial explosion): o custo cresce exponencialmente com o número de hiperparâmetros.
- Desperdiça tentativas em dimensões irrelevantes se apenas alguns hiperparâmetros forem os mais importantes.
- Muitas vezes é rígida demais: você não consegue se adaptar facilmente com base nos resultados.
Exemplo: busca em grade com scikit-learn
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
pipe = Pipeline([
("scaler", StandardScaler()),
("svc", SVC())
])
param_grid = {
"svc__C": [0.1, 1, 10, 100],
"svc__gamma": [1e-3, 1e-2, 1e-1],
"svc__kernel": ["rbf"]
}
search = GridSearchCV(
pipe,
param_grid=param_grid,
cv=5,
scoring="f1",
n_jobs=-1
)
search.fit(X_train, y_train)
print(search.best_params_, search.best_score_)
Busca Aleatória
Ideia
A busca aleatória amostra combinações de hiperparâmetros a partir de distribuições especificadas (uniforme (uniform), log-uniforme (log-uniform), categórica, etc.) por um orçamento fixo de tentativas.
Isso costuma ser surpreendentemente forte. Uma intuição-chave (popularizada por Bergstra & Bengio, 2012) é que, em muitos problemas, apenas um pequeno subconjunto de hiperparâmetros é realmente determinante. A busca aleatória explora mais valores distintos de cada hiperparâmetro do que a busca em grade para o mesmo número de tentativas, especialmente em dimensões mais altas.
Quando funciona bem
- Espaços moderados/altamente dimensionais
- Você ainda não conhece bons intervalos
- Você tem um orçamento fixo (por exemplo, “tentar 100 execuções”)
Escolhendo distribuições (importante)
Muitos hiperparâmetros operam em escalas multiplicativas; amostrá-los de forma uniforme é ineficiente.
Boas práticas comuns:
- Log-uniforme para:
- taxa de aprendizado (por exemplo, (10^{-5}) a (10^{-1}))
- força de regularização (L2, weight decay)
Cde SVM, parâmetros de kernel
- Uniforme para parâmetros limitados:
- taxa de dropout em ([0, 0.5])
- Intervalos inteiros para contagens:
- profundidade de árvore, número de estimadores, unidades ocultas
Exemplo: RandomizedSearchCV
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import RandomizedSearchCV
param_dist = {
"n_estimators": np.arange(200, 1200, 100),
"max_depth": [None] + list(np.arange(3, 25)),
"min_samples_split": np.arange(2, 50),
"max_features": ["sqrt", "log2", None],
}
rf = RandomForestClassifier(random_state=0)
search = RandomizedSearchCV(
rf,
param_distributions=param_dist,
n_iter=60, # budget
cv=5,
scoring="roc_auc",
n_jobs=-1,
random_state=0
)
search.fit(X_train, y_train)
print(search.best_params_, search.best_score_)
Otimização Bayesiana (Bayesian Optimization) — Busca Bayesiana (Bayesian Search)
Ideia
A otimização bayesiana (Bayesian optimization, BO) escolhe hiperparâmetros de forma sequencial ao:
- Ajustar um modelo substituto (surrogate model) que prevê desempenho dado um conjunto de hiperparâmetros.
- Usar uma função de aquisição (acquisition function) para decidir quais hiperparâmetros tentar a seguir, equilibrando:
- Aproveitamento (exploitation) (tentar o que parece melhor)
- Exploração (exploration) (tentar regiões incertas)
Isso torna a BO eficiente em amostras (sample-efficient): ela frequentemente encontra boas configurações em menos tentativas do que a busca aleatória, especialmente quando cada tentativa é cara.
A otimização bayesiana está intimamente relacionada (e frequentemente é implementada como) métodos de Otimização Bayesiana como:
- Substitutos baseados em processo gaussiano (Gaussian process, GP) (BO clássico)
- Estimador de Parzen Estruturado em Árvore (Tree-structured Parzen Estimator, TPE) (popular em Optuna/Hyperopt)
- Substitutos de floresta aleatória (random forest) (SMAC)
Modelos substitutos (visão geral)
- Processos Gaussianos: ótimos para espaços contínuos de baixa dimensionalidade; estimativas de incerteza surgem naturalmente.
- TPE: lida bem com espaços categóricos/condicionais; escala melhor em dimensões mais altas.
- Floresta aleatória/árvores com boosting: robustas, frequentemente usadas para espaços mistos.
Funções de aquisição (intuição)
- Melhoria Esperada (Expected Improvement, EI): “Quanto esperamos superar o melhor atual?”
- Limite Superior de Confiança (Upper Confidence Bound, UCB): “Tente lugares que parecem bons ou incertos.”
- Probabilidade de Melhoria (Probability of Improvement, PI): “Quão provável é melhorar?”
Quando a BO funciona bem
- O treinamento é caro (redes profundas (deep nets), grandes conjuntos de dados, engenharia de atributos (feature engineering) pesada)
- Você pode arcar com experimentação sequencial ou em lotes sequenciais
- Você espera que o objetivo tenha “estrutura” (não seja puro ruído)
Limitações
- Mais complexa de implementar e de raciocinar do que a busca aleatória
- Pode ter dificuldades com objetivos muito ruidosos, a menos que seja bem ajustada
- A BO “pura” é tipicamente sequencial (embora muitos frameworks suportem sugestões em paralelo/em lote)
Exemplo: busca Bayesiana/TPE com Optuna
import optuna
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import GradientBoostingClassifier
def objective(trial):
params = {
"learning_rate": trial.suggest_float("learning_rate", 1e-3, 0.2, log=True),
"n_estimators": trial.suggest_int("n_estimators", 50, 600),
"max_depth": trial.suggest_int("max_depth", 1, 5),
"subsample": trial.suggest_float("subsample", 0.5, 1.0),
}
model = GradientBoostingClassifier(random_state=0, **params)
score = cross_val_score(model, X_train, y_train, cv=5, scoring="roc_auc").mean()
return score
study = optuna.create_study(direction="maximize") # default sampler is TPE
study.optimize(objective, n_trials=50)
print(study.best_params, study.best_value)
Ajuste eficiente: como obter mais sinal por unidade de computação
Ajuste eficiente de hiperparâmetros é, em grande parte, sobre gastar computação onde importa e evitar avaliações enganosas.
1) Comece com uma linha de base (baseline) forte e padrões sensatos
Antes de ajustar, estabeleça uma linha de base com:
- Um modelo simples (por exemplo, regressão logística, um ensemble de árvores pequeno (tree ensemble))
- Hiperparâmetros padrão do modelo escolhido Isso ajuda a julgar se o ajuste está realmente melhorando algo de forma significativa.
Além disso, ajuste primeiro a classe de modelo correta; ajuste de hiperparâmetros não vai salvar uma escolha ruim de modelo.
2) Ajuste um pequeno conjunto de hiperparâmetros com maior impacto
A maioria dos modelos tem algumas poucas “alavancas grandes”:
- Ensembles de árvores (XGBoost/LightGBM/RandomForest)
- taxa de aprendizado, número de árvores, profundidade máxima / número de folhas
- peso mínimo do filho / mínimo de amostras por folha
- subamostragem e amostragem de colunas
- Modelos lineares
- tipo/força de regularização (L1/L2/elastic net)
- Redes neurais (neural networks)
- taxa de aprendizado, tamanho do lote, decaimento de pesos (weight decay), tamanho da arquitetura
- dropout, escolha do otimizador (optimizer) (veja Descida do Gradiente para fundamentos de otimização)
Se você ajustar muitos controles de baixo impacto ao mesmo tempo, desperdiça tentativas.
3) Use a escala e as restrições corretas no espaço de busca
Erros comuns:
- Amostrar taxa de aprendizado uniformemente em ([0, 1]) (ruim)
- Amostrar regularização uniformemente em ([0, 1000]) (ruim)
Melhor:
- escala logarítmica (log-scale) para hiperparâmetros positivos de “taxa/força”
- impor combinações válidas (espaços de busca condicionais (conditional search spaces)), por exemplo:
- Se
solver="liblinear", entãopenaltynão pode ser"none"em algumas configurações
- Se
4) Prefira busca aleatória em vez de busca em grade em dimensões mais altas
Regra prática:
- Se você tem mais do que ~2–3 hiperparâmetros importantes, a busca aleatória geralmente é uma primeira tentativa melhor do que a busca em grade para o mesmo orçamento.
Uma receita prática:
- Fase 1: busca aleatória com intervalos amplos (por exemplo, 50–200 tentativas)
- Fase 2: estreitar os intervalos ao redor dos melhores candidatos
- Fase 3: otimização bayesiana opcional para refinar
5) Use métodos de multifidelidade: parada antecipada e redução sucessiva
Quando treinar é caro, não treine completamente todos os candidatos.
Abordagens populares:
- Parada antecipada (early stopping): interromper o treino quando o score de validação para de melhorar (comum em boosting (boosting) e em aprendizado profundo (deep learning); veja Parada Antecipada).
- Redução Sucessiva (successive halving) / Hyperband: avaliar muitas configurações de forma barata (poucas épocas / menos dados / menos árvores), manter a melhor fração e alocar mais orçamento a elas.
No scikit-learn, você pode usar redução sucessiva:
from sklearn.experimental import enable_halving_search_cv # noqa
from sklearn.model_selection import HalvingRandomSearchCV
from sklearn.ensemble import HistGradientBoostingClassifier
import numpy as np
model = HistGradientBoostingClassifier(random_state=0)
param_dist = {
"learning_rate": np.logspace(-3, -0.5, 50),
"max_depth": [None, 2, 3, 4, 5],
"max_leaf_nodes": np.arange(15, 255),
}
search = HalvingRandomSearchCV(
model,
param_dist,
factor=3, # how aggressively to prune
scoring="roc_auc",
cv=5,
n_jobs=-1,
random_state=0
)
search.fit(X_train, y_train)
print(search.best_params_, search.best_score_)
Multifidelidade é um dos maiores “multiplicadores de eficiência” em fluxos de trabalho modernos de ajuste.
6) Acerte a avaliação: validação cruzada aninhada e prevenção de vazamento
Se você ajusta hiperparâmetros e reporta o score de validação cruzada no mesmo processo de validação cruzada, pode obter estimativas otimistas porque você efetivamente “buscou” entre muitas configurações.
Duas boas práticas comuns:
- Conjunto de validação + conjunto de teste: ajustar na validação, avaliar uma vez no teste.
- Validação cruzada aninhada (nested cross-validation): uma validação cruzada interna ajusta hiperparâmetros, e uma validação cruzada externa estima o desempenho de generalização.
Validação cruzada aninhada é mais cara, mas estatisticamente mais honesta, especialmente em pesquisa ou cenários com poucos dados.
7) Paralelize com eficiência (mas não quebre o método)
- Busca em grade/aleatória paraleliza de forma trivial: avalie tentativas de forma independente em CPUs/GPUs.
- Otimização bayesiana é mais sequencial, mas pode rodar no modo em lotes (batched) (pedir múltiplas sugestões de uma vez) com alguma perda de eficiência em amostras.
Dicas práticas:
- Mantenha o treinamento determinístico quando viável (
random_state, operações determinísticas). - Registre tudo: parâmetros, versão do código, hash do conjunto de dados (dataset hash), métrica, semente.
8) Lide com ruído e variância
Seu score medido inclui ruído de:
- divisões dos dados
- inicialização aleatória
- kernels de GPU não determinísticos
- treinamento estocástico
Mitigações:
- Use validação cruzada repetida ou execuções repetidas para as melhores configurações
- Compare configurações com intervalos de confiança quando as diferenças forem pequenas
- Prefira modelos mais simples se o desempenho estiver dentro da tolerância ao ruído (robustez importa)
9) Não exagere no ajuste: pare quando os retornos diminuírem
O ajuste pode virar um “loop infinito”. Critérios práticos para parar:
- Você atingiu um orçamento de computação/tempo
- As melhorias são menores do que seu limiar prático
- As melhores configurações são estatisticamente indistinguíveis
Em muitas aplicações reais, a qualidade dos atributos e a quantidade de dados dominam pequenos ganhos de ajuste.
Grade vs Aleatória vs Bayesiana: escolhendo a ferramenta certa
Guia rápido de decisão
Busca em grade
- Melhor para: espaços minúsculos, valores “bons” conhecidos, checagens rápidas de sanidade
- Evite quando: houver mais do que poucos hiperparâmetros realmente relevantes
Busca aleatória
- Melhor para: método-base forte, espaços de alta dimensionalidade, orçamentos fixos de tentativas
- Muitas vezes é a melhor abordagem “padrão”
Otimização bayesiana
- Melhor para: treinamento caro, necessidade de eficiência em amostras, experimentação iterativa
- Funciona especialmente bem depois que você definiu um espaço de busca sensato
Uma estratégia híbrida pragmática
Um padrão eficiente comum:
- Busca aleatória ampla (encontrar regiões razoáveis)
- Otimização bayesiana para refinar localmente
- Confirmar as 3–10 melhores configurações com avaliação repetida
- Reajustar a melhor configuração e avaliar uma vez no teste
Exemplos práticos do que ajustar (por família de modelo)
Árvores com boosting de gradiente (gradient-boosted trees) (XGBoost/LightGBM/CatBoost)
Controles de alto impacto:
learning_rate(escala logarítmica)n_estimatorscom parada antecipadamax_depth/num_leavesmin_child_weight/min_data_in_leafsubsample,colsample_bytree
Dica de eficiência: use parada antecipada com um conjunto de validação; isso efetivamente ajusta n_estimators automaticamente.
Redes neurais
Controles de alto impacto:
- taxa de aprendizado e agendamento (veja Agendamentos da Taxa de Aprendizado)
- tamanho do lote
- decaimento de pesos (L2)
- tamanho da arquitetura (largura/profundidade), camadas de normalização
- dropout
Dica de eficiência: use multifidelidade (poucas épocas primeiro) e, depois, treine por mais tempo os melhores candidatos.
Modelos lineares regularizados (regularized linear models)
Controles de alto impacto:
- força de regularização (
Coualpha) (escala logarítmica) - tipo de penalidade (L1/L2/elastic net)
- pré-processamento de atributos (padronização, interações)
Dica de eficiência: ajuste o pré-processamento como parte da pipeline; ele pode importar tanto quanto o modelo.
Armadilhas comuns
- Vazamento de dados: escalonamento/seleção de atributos realizada antes das divisões de validação cruzada.
- Ajustar no conjunto de teste: invalida o teste como estimativa não enviesada.
- Métrica errada: otimizar acurácia em dados desbalanceados em vez de F1/ROC-AUC.
- Espaço de busca ruim: intervalos estreitos demais (perde o ótimo) ou amplos demais (desperdiça tentativas).
- Ignorar variância: escolher a configuração “melhor” a partir de medições ruidosas.
- Sobreajuste à validação cruzada: especialmente com orçamentos de busca enormes e conjuntos de dados pequenos.
Ajuste de hiperparâmetros no panorama maior de seleção de modelos
Ajuste de hiperparâmetros é um componente da seleção de modelos junto com:
- escolher famílias de modelos,
- engenharia de atributos,
- calibração (calibration) e definição de limiar (thresholding),
- e, às vezes, Estratégias de Ensemble (Ensembling Strategies).
Um único modelo bem ajustado pode ser forte, mas criar ensembles ou melhorar a qualidade dos dados pode trazer ganhos maiores do que tentar passar do percentil 99,0 para 99,1 via ajuste.
Principais conclusões
- Busca em grade é sistemática, mas escala mal; use-a para espaços pequenos.
- Busca aleatória é um ótimo padrão; escala bem e frequentemente supera grades com o mesmo orçamento.
- Otimização bayesiana geralmente é melhor quando as tentativas são caras e você quer eficiência em amostras.
- Ajuste eficiente depende mais de correção na avaliação, desenho do espaço de busca e alocação de recursos (parada antecipada, redução sucessiva) do que de qualquer otimizador isolado.
- Sempre se proteja contra vazamento e sobreajuste à validação/validação cruzada — caso contrário, o ajuste pode produzir números impressionantes que não generalizam.