Optimización de Hiperparámetros
Los hiperparámetros determinan cómo aprende tu modelo. Optimizarlos correctamente puede ser la diferencia entre un modelo mediocre y uno de estado del arte. Desde Grid Search hasta optimización bayesiana, domina las técnicas que los mejores practicians usan.
¿Qué son los hiperparámetros?
En el entrenamiento de un modelo de deep learning, existen dos tipos fundamentales de variables que determinan el comportamiento del modelo:
- Parámetros del modelo (\(\theta\)): los pesos y biases de la red neuronal, que se aprenden automáticamente durante el entrenamiento mediante la optimización de la función de pérdida
- Hiperparámetros (\(\lambda\)): configuraciones que el diseñador humano elige antes del entrenamiento, y que controlan cómo se realiza el aprendizaje
Definición formal: Un hiperparámetro es cualquier variable de configuración cuyo valor se establece antes de que comience el proceso de aprendizaje, y que no se actualiza por el algoritmo de optimización (backpropagation + optimizer).
Ejemplos comunes de hiperparámetros
- Learning rate (\(\eta\))
- Batch size
- Número de épocas
- Optimizer (SGD, Adam…)
- Scheduler del LR
- Weight decay (\(\lambda\))
- Número de capas
- Neuronas por capa
- Función de activación
- Kernel size (CNNs)
- Número de heads (Transformers)
- Dimensión del embedding
- Dropout rate
- L1 / L2 penalty
- Data augmentation params
- Label smoothing
- Early stopping patience
- Gradient clipping
La elección de hiperparámetros ha sido un reto central en machine learning desde sus inicios. En los primeros días del deep learning, los practicantes confiaban casi exclusivamente en la intuición y la experiencia para ajustar estos valores. A medida que las redes crecieron en tamaño y complejidad — pasando de modelos con miles de parámetros a arquitecturas con miles de millones — la HPO sistemática se volvió no solo deseable, sino imprescindible. Un mismo modelo puede variar su rendimiento en más de 10 puntos porcentuales de accuracy simplemente cambiando el learning rate o el weight decay.
La sensibilidad del modelo a cada hiperparámetro varía enormemente. Investigaciones recientes muestran que el learning rate suele ser el hiperparámetro más crítico, seguido del batch size y la profundidad de la red. Otros, como el \(\epsilon\) de Adam, rara vez necesitan ajuste.
Es decir, buscamos los hiperparámetros \(\lambda^*\) que, una vez entrenado el modelo hasta su óptimo \(\theta^*(\lambda)\), minimicen la pérdida en el conjunto de validación, no en el de entrenamiento.
HPO vs optimización de parámetros
Aunque ambos procesos buscan «optimizar», son fundamentalmente diferentes en su naturaleza y en los algoritmos que utilizan:
| Aspecto | Parámetros (\(\theta\)) | Hiperparámetros (\(\lambda\)) |
|---|---|---|
| ¿Qué se optimiza? | Pesos y biases de la red | Configuraciones del entrenamiento y arquitectura |
| ¿Cómo se optimiza? | Gradient descent (backprop) | Grid search, random search, Bayesian opt… |
| ¿Gradientes disponibles? | ✅ Sí, \(\nabla_\theta \mathcal{L}\) es diferenciable | ❌ No en general (espacio discreto, no diferenciable) |
| Coste de evaluar | Un forward + backward pass (~ms) | Un entrenamiento completo (~horas/días) |
| Dimensionalidad | Millones–miles de millones | Típicamente 5–30 |
| Función objetivo | Pérdida en training set | Pérdida/métrica en validation set |
| Tipo de problema | Optimización continua (mayormente) | Caja negra, mixto (cont. + discreto + categórico) |
Optimización bilevel: La HPO es un problema de optimización de dos niveles. En el nivel inferior, entrenamos el modelo (optimizamos \(\theta\) con gradient descent). En el nivel superior, evaluamos la configuración de hiperparámetros y buscamos la mejor combinación de \(\lambda\). Cada evaluación del nivel superior requiere ejecutar todo el nivel inferior.
Nótese que el paso 4 (actualizar estrategia) es lo que diferencia los distintos algoritmos de HPO. En Grid y Random Search, este paso no existe realmente: los puntos a evaluar están predeterminados. En la optimización bayesiana, este paso es donde reside toda la inteligencia: el algoritmo construye un modelo probabilístico de la función objetivo y lo usa para decidir qué configuración probar a continuación. Esta capacidad de aprender de evaluaciones pasadas es lo que permite a la BO ser mucho más eficiente con el presupuesto computacional.
Esta naturaleza de evaluación costosa es la que hace tan importante elegir un algoritmo de HPO eficiente. Un enfoque ingenuo podría requerir cientos de entrenamientos completos, mientras que métodos como la optimización bayesiana pueden encontrar buenas configuraciones en 20–50 evaluaciones.
Data leakage en HPO
Uno de los errores más comunes y peligrosos en machine learning es el data leakage (fuga de datos): cuando información del conjunto de test se «filtra» al proceso de selección del modelo, produciendo métricas artificialmente optimistas.
Error crítico: Si usas el conjunto de test para elegir hiperparámetros, estás optimizando directamente sobre el test set. Tu modelo memorizará las peculiaridades del test, y las métricas reportadas no reflejarán el rendimiento real en producción. Esto invalida completamente la evaluación.
Este problema es más común de lo que parece. En una revisión de 2019 publicada en Nature Machine Intelligence, los autores encontraron que una proporción significativa de estudios publicados en biomedicina contenían alguna forma de data leakage, lo que llevó a métricas infladas y a modelos que fallaban en producción. El data leakage es especialmente insidioso en HPO porque la optimización de hiperparámetros implica muchas evaluaciones sobre los mismos datos, amplificando el riesgo de sobreajuste al conjunto de validación.
La solución: tres conjuntos de datos
Para una evaluación rigurosa, necesitamos tres conjuntos separados, cada uno con un propósito claramente definido:
Los parámetros del modelo se optimizan con estos datos
HPO evalúa aquí cada configuración
Solo se usa UNA vez al final
Regla de oro: El conjunto de test es sagrado. Nunca debe influir en ninguna decisión de diseño: ni la arquitectura, ni los hiperparámetros, ni el preprocesamiento. Si miras las métricas de test y luego vuelves a cambiar algo, ya no es test, es validación.
¿Qué pasa si tengo pocos datos?
Cuando el dataset es pequeño, reservar un 20% para validación puede ser un desperdicio. Aquí es donde entra la validación cruzada, que abordamos en la siguiente sección. También existen estrategias como:
- Stratified splitting: mantener la distribución de clases en cada split
- Time-based splitting: para series temporales, usar los datos más recientes como test
- Group splitting: asegurar que datos del mismo grupo (paciente, usuario) no aparezcan en train y test
Validación cruzada
La validación cruzada (cross-validation, CV) es una técnica que permite usar todos los datos tanto para entrenamiento como para validación, rotando qué porción sirve como validación en cada iteración. La variante más popular es el k-Fold CV.
k-Fold Cross-Validation
El dataset se divide en \(k\) particiones (folds) de tamaño similar. Se realizan \(k\) entrenamientos, usando cada vez un fold diferente como validación y los \(k-1\) restantes como entrenamiento:
La métrica final es el promedio de las \(k\) evaluaciones, con su desviación estándar como medida de variabilidad:
CV en el contexto de HPO
En HPO, la validación cruzada sustituye al validation set fijo. Para cada configuración de hiperparámetros \(\lambda\), se ejecuta un k-Fold CV completo, y la métrica promediada es la que guía la búsqueda:
Coste computacional: Con k-Fold CV, cada evaluación de hiperparámetros requiere entrenar \(k\) modelos completos. Si \(k=5\) y estás probando 100 configuraciones, son 500 entrenamientos. En deep learning, donde cada entrenamiento puede tardar horas, esto es a menudo prohibitivo. Soluciones: usar \(k\) pequeño (3 o 5), early stopping, o un holdout fijo con datos suficientes.
Variantes de cross-validation
| Variante | Descripción | Cuándo usar |
|---|---|---|
| k-Fold estándar | Divide en k particiones aleatorias | Caso general con datos suficientes |
| Stratified k-Fold | Mantiene la distribución de clases en cada fold | Clasificación con clases desbalanceadas |
| Leave-One-Out (LOO) | \(k = N\), cada muestra es un fold | Datasets muy pequeños (<100 muestras) |
| Repeated k-Fold | Repite k-Fold varias veces con semillas distintas | Cuando se necesita estimación muy robusta |
| Time Series Split | Folds temporales: entrena en pasado, valida en futuro | Series temporales (no se puede mezclar temporal) |
| Group k-Fold | Asegura que un grupo completo está en un solo fold | Datos agrupados (mismo paciente, mismo sensor…) |
En la práctica, la elección de la variante de CV depende del problema y del tamaño del dataset. Para la mayoría de problemas de deep learning con datasets grandes (>50.000 muestras), un holdout fijo (train/val/test split) suele ser suficiente y es mucho más rápido. La CV se reserva para datasets pequeños o cuando se necesita una estimación muy robusta del rendimiento. En el contexto de HPO, la CV se combina con el algoritmo de búsqueda: cada evaluación de hiperparámetros usa la métrica promediada de los folds para guiar la búsqueda, lo que produce estimaciones más estables pero a un coste computacional proporcionalmente mayor.
Grid Search
El Grid Search (búsqueda en rejilla) es el enfoque más simple e intuitivo para HPO. Consiste en definir un conjunto discreto de valores para cada hiperparámetro y evaluar todas las combinaciones posibles.
Algoritmo
Si tenemos \(d\) hiperparámetros y elegimos \(n_i\) valores para el \(i\)-ésimo hiperparámetro, el número total de evaluaciones es:
Por ejemplo, con 3 hiperparámetros y 5 valores cada uno: \(5^3 = 125\) entrenamientos. Con 6 hiperparámetros y 10 valores: \(10^6 = 1.000.000\) entrenamientos. La maldición de la dimensionalidad hace que Grid Search sea impracticable para más de 3-4 hiperparámetros.
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
# Definir la rejilla de hiperparámetros
param_grid = {
'n_estimators': [50, 100, 200, 500],
'max_depth': [5, 10, 20, None],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4],
}
# Total: 4 × 4 × 3 × 3 = 144 combinaciones
grid_search = GridSearchCV(
estimator=RandomForestClassifier(random_state=42),
param_grid=param_grid,
cv=5, # 5-fold CV → 144 × 5 = 720 entrenamientos
scoring='accuracy',
n_jobs=-1, # Paralelizar en todas las CPUs
verbose=1,
)
grid_search.fit(X_train, y_train)
print(f"Mejor score: {grid_search.best_score_:.4f}")
print(f"Mejores params: {grid_search.best_params_}")
Ventajas y desventajas
| ✅ Ventajas | ❌ Desventajas |
|---|---|
| Simple de implementar y entender | Coste exponencial con la dimensionalidad |
| Exhaustivo: garantiza encontrar el mejor punto de la rejilla | Evaluaciones redundantes en hiperparámetros poco importantes |
| Fácilmente paralelizable | Solo explora valores predefinidos (puede saltarse el óptimo) |
| Reproducible (determinista) | Impracticable con más de ~4 hiperparámetros |
A pesar de sus limitaciones, Grid Search sigue siendo útil en situaciones específicas: cuando el espacio de hiperparámetros es pequeño (2-3 hiperparámetros con pocos valores cada uno), cuando se necesita una exploración exhaustiva por requisitos regulatorios, o como primera aproximación rápida en un proyecto nuevo. Sin embargo, para la mayoría de aplicaciones prácticas de deep learning, es preferible usar Random Search o métodos más sofisticados, como veremos a continuación.
Random Search
Random Search (Bergstra & Bengio, 2012) es una alternativa sorprendentemente efectiva a Grid Search. En lugar de evaluar todas las combinaciones, muestrea configuraciones aleatoriamente del espacio de hiperparámetros.
Resultado clave de Bergstra & Bengio (2012): Para la mayoría de los problemas prácticos, Random Search con el mismo presupuesto computacional encuentra hiperparámetros igual de buenos o mejores que Grid Search. La razón es que no todos los hiperparámetros son igual de importantes.
¿Por qué funciona tan bien?
La intuición clave es que en la mayoría de problemas, solo unos pocos hiperparámetros realmente importan (el learning rate, por ejemplo, suele ser mucho más importante que el \(\epsilon\) del optimizer). Grid Search desperdicia evaluaciones en las dimensiones irrelevantes:
Formalmente, si solo \(d_{eff} \ll d\) de los \(d\) hiperparámetros son importantes, Grid Search con \(N\) evaluaciones solo explora \(N^{1/d}\) valores por dimensión, mientras que Random Search explora \(N\) valores distintos en cada dimensión:
Con \(N=100\) puntos y \(d=4\) hiperparámetros: Grid explora \(\sqrt[4]{100} \approx 3.2\) valores por dimensión, Random explora potencialmente los 100.
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import uniform, randint, loguniform
# Distribuciones continuas en vez de listas discretas
param_distributions = {
'n_estimators': randint(50, 500),
'max_depth': randint(3, 50),
'min_samples_split': randint(2, 20),
'min_samples_leaf': randint(1, 10),
'max_features': uniform(0.1, 0.9),
}
random_search = RandomizedSearchCV(
estimator=RandomForestClassifier(random_state=42),
param_distributions=param_distributions,
n_iter=100, # Solo 100 evaluaciones aleatorias
cv=5,
scoring='accuracy',
n_jobs=-1,
random_state=42,
verbose=1,
)
random_search.fit(X_train, y_train)
Comparación: Grid vs Random Search
| Aspecto | Grid Search | Random Search |
|---|---|---|
| Estrategia | Exhaustiva, todas las combinaciones | Muestreo aleatorio del espacio |
| Escalabilidad | ❌ Exponencial \(O(n^d)\) | ✅ Lineal \(O(N)\), \(N\) elegido por el usuario |
| Exploración por dimensión | Pocos valores únicos (\(n^{1/d}\)) | Muchos valores únicos (\(N\)) |
| Espacio continuo | ❌ Solo valores discretos | ✅ Puede muestrear distribuciones continuas |
| Paralelismo | ✅ Totalmente paralelizable | ✅ Totalmente paralelizable |
| Usa información pasada | ❌ No | ❌ No |
| Garantía de cobertura | Cubre toda la rejilla definida | Probabilística (alta con suficientes muestras) |
¿Cuántas evaluaciones necesita Random Search? Bergstra & Bengio demostraron que con \(N = 60\) evaluaciones aleatorias, la probabilidad de encontrar un punto en el 5% mejor del espacio es \(1 - (0.95)^{60} \approx 95\%\). Es decir, 60 evaluaciones bastan para una cobertura excelente si la función es relativamente suave.
En la práctica, Random Search es especialmente potente cuando se combina con distribuciones inteligentes. En lugar de muestrear uniformemente, conviene usar distribución log-uniforme para el learning rate (ya que valores entre \(10^{-5}\) y \(10^{-1}\) son todos plausibles y su sensibilidad es exponencial) y distribuciones categóricas para elecciones discretas como la función de activación. Esta práctica, recomendada por Bergstra & Bengio (2012), mejora significativamente la eficiencia de Random Search sin añadir complejidad.
Tanto Grid como Random Search son métodos no informados: no usan los resultados de evaluaciones anteriores para guiar las siguientes. La optimización bayesiana, que veremos a continuación, sí lo hace, y por eso es mucho más eficiente.
Referencias:
- Bergstra, J. & Bengio, Y. (2012). Random Search for Hyper-Parameter Optimization. JMLR 13.
Optimización bayesiana: la idea
La optimización bayesiana (BO) es una estrategia de optimización de caja negra diseñada para funciones que son costosas de evaluar, ruidosas y sin gradientes. Estas tres propiedades describen perfectamente la HPO en deep learning.
A diferencia de Grid y Random Search, la BO es un método secuencial informado: cada nueva evaluación se elige inteligentemente basándose en los resultados de las anteriores. Esto permite encontrar buenas configuraciones con muchas menos evaluaciones.
Idea fundamental: En lugar de evaluar la función objetivo directamente (entrenar un modelo cada vez), construimos un modelo probabilístico barato (surrogate model) que aproxima la función objetivo. Usamos este modelo barato para decidir dónde evaluar a continuación, equilibrando entre explorar regiones desconocidas y explotar regiones prometedoras.
Los dos componentes clave
La optimización bayesiana tiene dos pilares:
Opciones comunes: Gaussian Process (GP), Tree-structured Parzen Estimator (TPE), Random Forests.
• Explotación: evaluar donde el surrogate predice buenos resultados
• Exploración: evaluar donde la incertidumbre es alta
El algoritmo general
El flujo secuencial de la optimización bayesiana es:
La clave está en los pasos 1-2: entrenar el surrogate es rápido (milisegundos), y optimizar la acquisition function también es rápido. El paso costoso (3) se ejecuta solo una vez por iteración, en lugar de las cientos de veces de un Grid Search.
La optimización bayesiana fue popularizada en el contexto de HPO por el trabajo seminal de Snoek, Larochelle & Adams (2012), quienes demostraron que BO con GPs podía igualar o superar el rendimiento de expertos humanos ajustando hiperparámetros de redes neuronales, usando un orden de magnitud menos evaluaciones que Random Search. Su sistema, Spearmint, fue uno de los primeros frameworks prácticos de BO para deep learning y motivó toda una línea de investigación que continúa hoy. Desde entonces, la BO se ha convertido en el estándar de referencia para HPO cuando cada evaluación es costosa (horas o días de entrenamiento).
Procesos Gaussianos (GP)
El surrogate model más usado en la optimización bayesiana clásica es el Proceso Gaussiano (Gaussian Process, GP). Un GP es una distribución de probabilidad sobre funciones: no predice un solo valor, sino una distribución normal completa en cada punto, con media y varianza.
Definición formal
Un GP queda completamente definido por una función media \(m(\lambda)\) y una función kernel (covarianza) \(k(\lambda, \lambda')\):
En la práctica, se suele asumir \(m(\lambda) = 0\) (media cero) y se deja que el kernel capture toda la estructura. La predicción del GP en un punto nuevo \(\lambda^*\), condicionada en los datos observados \(\mathcal{D} = \{(\lambda_i, y_i)\}_{i=1}^{n}\), es:
Donde \(\mathbf{K}\) es la matriz de covarianza de los puntos observados (\(K_{ij} = k(\lambda_i, \lambda_j)\)), \(\mathbf{k}_*\) es el vector de covarianzas entre el punto nuevo y los observados, y \(\mathbf{y}\) es el vector de valores observados.
Interpretación intuitiva:
- \(\mu(\lambda^*)\) es la mejor estimación del valor de la función en \(\lambda^*\)
- \(\sigma^2(\lambda^*)\) mide la incertidumbre: es alta lejos de los puntos observados y baja cerca de ellos
- Juntos definen una «banda de confianza» alrededor de la predicción
Funciones kernel
El kernel \(k(\lambda, \lambda')\) controla las propiedades de las funciones que el GP puede representar: suavidad, periodicidad, escala de variación. Los más usados en HPO son:
Asume funciones infinitamente suaves. \(\ell\) controla la escala de variación.
Menos suave que RBF, más realista para funciones de pérdida reales.
Aún menos suave. Útil cuando la función objetivo tiene cambios bruscos.
Limitaciones de los GPs
- Coste computacional: La inversión de \(\mathbf{K}\) es \(O(n^3)\), lo que limita los GPs a unas pocas miles de observaciones. Para HPO esto no suele ser problema (tenemos <100 evaluaciones), pero limita otros usos.
- Espacios de alta dimensionalidad: Los GPs pierden efectividad cuando \(d > 20\), ya que la mayoría de los puntos están «lejos» unos de otros (curse of dimensionality).
- Variables categóricas: Los kernels estándar no manejan bien variables categóricas. Se necesitan kernels especializados o codificaciones.
Estas limitaciones han motivado el desarrollo de alternativas como TPE y Random Forests como surrogate models, que veremos en la sección de surrogate models alternativos. No obstante, los GPs siguen siendo la opción preferida cuando el espacio de búsqueda es continuo y de dimensionalidad moderada (\(d < 20\)), gracias a su elegante cuantificación de la incertidumbre y sus sólidas garantías teóricas.
🧪 Experimenta con el GP y la optimización bayesiana completa en la herramienta interactiva →Funciones de adquisición
La función de adquisición \(\alpha(\lambda)\) usa las predicciones del surrogate model (media \(\mu\) e incertidumbre \(\sigma\)) para asignar un «valor de utilidad» a cada punto del espacio de hiperparámetros. El siguiente punto a evaluar es el que maximiza esta utilidad:
La acquisition function codifica el trade-off exploración vs explotación: ¿evaluamos donde creemos que el resultado será bueno (explotación), o donde no sabemos nada (exploración)?
Expected Improvement (EI)
La función de adquisición más popular. Mide la mejora esperada respecto al mejor valor observado hasta ahora \(f^* = \min_i y_i\):
Cuando el surrogate es un GP, esta esperanza tiene una forma cerrada (no requiere simulaciones de Monte Carlo):
Donde \(\Phi\) y \(\phi\) son la CDF y PDF de la normal estándar respectivamente. El primer término favorece la explotación (valores de \(\mu\) bajos) y el segundo la exploración (valores de \(\sigma\) altos).
Otras funciones de adquisición
Probability of Improvement (PI)
La más simple: mide la probabilidad de mejorar el mejor valor actual:
Problema: PI es demasiado «greedy» (explota mucho y explora poco). Tiende a converger prematuramente a un óptimo local. Por eso EI es preferida en la práctica.
Upper Confidence Bound (UCB / LCB)
Combina media e incertidumbre con un parámetro \(\kappa\) que controla el trade-off:
El siguiente punto a evaluar es \(\arg\min \text{LCB}(\lambda)\). \(\kappa\) alto = más exploración, \(\kappa\) bajo = más explotación. Valores típicos: \(\kappa \in [1, 3]\). Ventaja: tiene garantías teóricas de convergencia (regret bounds).
Knowledge Gradient (KG)
Mide el valor de la información: ¿cuánto mejoraría nuestra decisión final si evaluáramos en el punto \(\lambda\)?
Teóricamente óptimo para un horizonte de una sola evaluación restante. Más costoso de calcular que EI pero puede ser más eficiente con presupuestos muy limitados.
Thompson Sampling
En lugar de calcular una función analítica, simplemente muestreamos una función del GP posterior y evaluamos en su mínimo:
- Muestrear \(\tilde{f} \sim \mathcal{GP}(\mu, \sigma^2)\)
- Evaluar en \(\lambda_{t+1} = \arg\min \tilde{f}(\lambda)\)
Simple, naturalmente parallelizable (muestrear varias funciones → evaluar varios puntos a la vez), y con buen equilibrio exploración/explotación. Muy usado en HPO moderno.
Comparación visual de acquisition functions
Surrogate models alternativos
Aunque los Gaussian Processes son el surrogate model clásico, tienen limitaciones (escala \(O(n^3)\), dificultad con variables categóricas). Existen alternativas importantes:
Tree-structured Parzen Estimator (TPE)
Usado por Optuna y Hyperopt. En lugar de modelar \(p(y|\lambda)\) directamente (como un GP), TPE modela las distribuciones de \(\lambda\) condicionadas en si el resultado fue «bueno» o «malo»:
Donde \(y^*\) es un cuantil (típicamente el percentil 25 de los valores observados). El siguiente punto se elige maximizando la ratio \(\ell(\lambda) / g(\lambda)\), que es equivalente a maximizar la Expected Improvement.
Ventajas de TPE:
- Maneja naturalmente variables categóricas, condicionales y jerárquicas
- Coste lineal \(O(n)\) en vez de cúbico
- Escala bien a espacios de alta dimensionalidad
- Es el motor de Optuna, la librería de HPO más popular
Random Forests (SMAC)
SMAC (Sequential Model-based Algorithm Configuration) usa Random Forests como surrogate. La incertidumbre se estima a partir de la varianza entre los árboles del ensemble. Ventajas:
- Manejo natural de variables categóricas y condicionales
- Robusto a outliers
- Usado extensamente en AutoML (Auto-WEKA, Auto-sklearn)
Comparación de surrogate models
| Surrogate | Coste | Variables categóricas | Alta dimensión | Usado por |
|---|---|---|---|---|
| Gaussian Process | \(O(n^3)\) | ⚠️ Requiere codificación | ⚠️ Problemas si \(d > 20\) | BoTorch, GPyOpt, Spearmint |
| TPE | \(O(n \log n)\) | ✅ Natural | ✅ Escala bien | Optuna, Hyperopt |
| Random Forest | \(O(n \log n)\) | ✅ Natural | ✅ Robusto | SMAC, Auto-sklearn |
| Bayesian Neural Net | \(O(n)\) (aprox.) | ✅ Con embedding | ✅ Muy bueno | BOHB, DNGO |
En la práctica, la elección del surrogate depende del tipo de espacio de búsqueda y del presupuesto computacional. Para espacios de búsqueda puramente continuos con pocas dimensiones, los GPs ofrecen la mejor incertidumbre calibrada. Para espacios mixtos (continuos + categóricos) o de alta dimensionalidad, TPE (el motor de Optuna) es la opción más pragmática. Los Random Forests (SMAC) brillan en problemas de configuración de algoritmos con muchas variables condicionales. Las BNNs son más experimentales pero prometedoras para problemas con cientos de dimensiones.
Referencias clave de optimización bayesiana:
- Snoek, J., Larochelle, H. & Adams, R. P. (2012). Practical Bayesian Optimization of Machine Learning Algorithms. NeurIPS.
- Bergstra, J. et al. (2011). Algorithms for Hyper-Parameter Optimization. NeurIPS. (Introduce TPE)
- Hutter, F., Hoos, H. & Leyton-Brown, K. (2011). Sequential Model-based Algorithm Configuration. LION. (Introduce SMAC)
- Rasmussen, C. E. & Williams, C. K. I. (2006). Gaussian Processes for Machine Learning. MIT Press.
Optimización bayesiana en la práctica
Aplicar BO en un proyecto real de deep learning requiere considerar varios aspectos prácticos que van más allá del algoritmo teórico.
Definir el espacio de búsqueda
Elegir bien el espacio de búsqueda \(\Lambda\) es crucial. Consejos:
- Escala logarítmica para el learning rate: buscar en \([10^{-5}, 10^{-1}]\) en escala log, no en escala lineal. Lo mismo para weight decay.
- Rango informado: usar conocimiento previo para acotar. Si sabes que un learning rate de \(10^{-1}\) diverge siempre, no lo incluyas.
- Variables condicionales: si solo usas dropout cuando hay más de 3 capas, define el espacio de forma condicional (Optuna lo soporta nativamente).
def objective(trial):
# ── Arquitectura ─────────────────────────────────────
n_layers = trial.suggest_int("n_layers", 2, 6)
hidden_dim = trial.suggest_categorical(
"hidden_dim", [64, 128, 256, 512]
)
activation = trial.suggest_categorical(
"activation", ["relu", "gelu", "silu"]
)
# ── Regularización (condicional) ─────────────────────
use_dropout = trial.suggest_categorical("use_dropout", [True, False])
if use_dropout:
dropout_rate = trial.suggest_float("dropout_rate", 0.1, 0.5)
# ── Entrenamiento ────────────────────────────────────
lr = trial.suggest_float("lr", 1e-5, 1e-2, log=True) # ← escala log!
weight_decay = trial.suggest_float("wd", 1e-6, 1e-2, log=True)
batch_size = trial.suggest_categorical(
"batch_size", [32, 64, 128, 256]
)
# ── Construir y entrenar modelo ──────────────────────
model = build_model(n_layers, hidden_dim, activation,
use_dropout, dropout_rate if use_dropout else 0)
val_loss = train_and_evaluate(model, lr, weight_decay, batch_size)
return val_loss # Optuna minimiza por defecto
Early stopping y pruning
Una técnica clave para acelerar la BO: detener entrenamientos malos antes de que acaben. Si después de 5 épocas la pérdida es peor que cualquier configuración previa a las 5 épocas, probablemente no va a mejorar. Esto se llama pruning.
Ahorro típico: Con pruning agresivo (como el Median Pruner de Optuna), se puede reducir el tiempo total de HPO en un 50-80%, ya que las configuraciones malas se descartan tras pocas épocas.
Warm-starting y transfer learning en HPO
Si has optimizado hiperparámetros para un problema similar antes, puedes usar esos resultados como punto de partida (warm-starting). Algunos frameworks (Optuna, BoTorch) permiten inicializar el surrogate model con observaciones de estudios anteriores.
Multi-fidelity: Hyperband y BOHB
Las técnicas multi-fidelity entrenan con presupuestos variados (pocas épocas, subsets de datos) para descartar rápidamente las configuraciones malas:
Successive Halving y Hyperband
Successive Halving: Comienza con \(N\) configuraciones y un presupuesto mínimo (ej., 1 época). Entrena todas, descarta la mitad peor, duplica el presupuesto, y repite. Al final, solo la mejor configuración ha recibido el presupuesto completo.
Hyperband (Li et al., 2017): Ejecuta múltiples rondas de Successive Halving con diferentes trade-offs entre \(N\) y el presupuesto mínimo. Algunos brackets empiezan con muchas configuraciones y poco presupuesto; otros con pocas configuraciones y mucho presupuesto.
BOHB: Bayesian Optimization + Hyperband
BOHB (Falkner et al., 2018) combina lo mejor de ambos mundos: usa un modelo bayesiano (TPE con kernel density estimation) para guiar qué configuraciones muestrear, y Hyperband para decidir cuánto presupuesto dar a cada una. Es actualmente uno de los algoritmos de HPO más eficientes.
La combinación de estas técnicas — BO informada con pruning multi-fidelity — representa el estado del arte actual en HPO para deep learning. Herramientas como Optuna implementan muchas de estas ideas de forma accesible, permitiendo a los practicantes beneficiarse de décadas de investigación en optimización con solo unas pocas líneas de código.
Referencias — Multi-fidelity y HPO moderna:
- Li, L. et al. (2017). Hyperband: A Novel Bandit-Based Approach to Hyperparameter Optimization. JMLR 18.
- Falkner, S. et al. (2018). BOHB: Robust and Efficient Hyperparameter Optimization at Scale. ICML.
- Akiba, T. et al. (2019). Optuna: A Next-generation Hyperparameter Optimization Framework. KDD.
Librerías de HPO para Deep Learning
El ecosistema de librerías para HPO ha madurado enormemente. Aquí presentamos las más utilizadas en la práctica, con sus fortalezas y casos de uso ideales.
Framework japonés de HPO con una API define-by-run muy elegante: defines el espacio de búsqueda dentro de la función objetivo, lo que permite espacios condicionales de forma natural.
- Algoritmos: TPE (defecto), CMA-ES, Grid, Random, GP
- Pruning: MedianPruner, HyperbandPruner, PercentilePruner
- Dashboard: optuna-dashboard para monitorear estudios
- Integración: PyTorch Lightning, Keras, XGBoost, LightGBM
- Distribución: Soporte nativo para ejecución distribuida con SQL/Redis
import optuna
def objective(trial):
lr = trial.suggest_float("lr", 1e-5, 1e-2, log=True)
n_layers = trial.suggest_int("n_layers", 2, 5)
dropout = trial.suggest_float("dropout", 0.1, 0.5)
model = build_model(n_layers, dropout)
val_acc = train(model, lr)
return val_acc
study = optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=100)
print(f"Best: {study.best_value:.4f}")
print(f"Params: {study.best_params}")
Parte del ecosistema Ray para computación distribuida. Ideal para HPO a gran escala con clusters de GPUs.
- Algoritmos: Integra Optuna, Hyperopt, BayesOpt, Ax, BOHB, etc.
- Schedulers: ASHA (Hyperband async), PBT (Population Based Training)
- Escala: De laptop a cluster multi-nodo sin cambiar código
- Fault tolerance: Recuperación automática si falla un worker
- Integración: PyTorch, TensorFlow, Hugging Face Transformers
from ray import tune
from ray.tune.schedulers import ASHAScheduler
search_space = {
"lr": tune.loguniform(1e-5, 1e-2),
"batch_size": tune.choice([32, 64, 128]),
"n_layers": tune.randint(2, 6),
}
scheduler = ASHAScheduler(
max_t=100, # max epochs
grace_period=5, # mínimo de épocas antes de podar
reduction_factor=3, # conservar top 1/3
)
result = tune.run(
train_fn,
config=search_space,
num_samples=50,
scheduler=scheduler,
resources_per_trial={"gpu": 1},
)
Librería oficial del equipo de Keras para HPO. La más sencilla de usar si trabajas con el ecosistema TensorFlow/Keras.
- Algoritmos: Random, Hyperband, Bayesian (GP)
- API: Similar a construir modelos Keras (HyperModel class)
- Oracle: Motor de búsqueda extensible
- Ideal para: Proyectos Keras simples a medianos
Weights & Biases ofrece HPO integrado con su plataforma de tracking. Ideal si ya usas W&B para logging de experimentos.
- Algoritmos: Grid, Random, Bayesian (GP)
- Visualización: Parallel coordinates, importance plots en el dashboard
- Early termination: Hyperband integrado
- Configuración: YAML declarativo o Python API
BoTorch es el framework de BO de Meta, construido sobre PyTorch y GPyTorch. Ax es la capa de alto nivel sobre BoTorch.
- GP flexibles: Kernels custom, multi-task, multi-objective
- Acquisition functions: EI, KG, multi-fidelity, paralelo
- Ideal para: Investigadores, HPO multi-objetivo, problemas complejos
- Limitación: Curva de aprendizaje más pronunciada
¿Cuál elegir?
Guía rápida de decisión:
- Primera opción general: Optuna — API limpia, eficiente, bien documentada
- Cluster de GPUs: Ray Tune — escalabilidad sin cambiar código
- Ecosistema Keras/TF: Keras Tuner — la más simple si usas Keras
- Ya usas W&B: W&B Sweeps — integración nativa con tracking
- Investigación / multi-objetivo: BoTorch/Ax — máxima flexibilidad
Comparación de librerías
| Librería | Algoritmo principal | Pruning | Distribuido | Dificultad |
|---|---|---|---|---|
| Optuna | TPE | ✅ Excelente | ✅ SQL/Redis | ⭐ Fácil |
| Ray Tune | Multi-backend | ✅ ASHA/PBT | ✅ Ray cluster | ⭐⭐ Media |
| Keras Tuner | Bayesian/Hyperband | ✅ Hyperband | ⚠️ Limitado | ⭐ Fácil |
| W&B Sweeps | Bayesian (GP) | ✅ Hyperband | ✅ Cloud | ⭐ Fácil |
| BoTorch/Ax | GP (BoTorch) | ⚠️ Manual | ✅ Ax + scheduler | ⭐⭐⭐ Avanzada |
Todas estas librerías pueden optimizar los hiperparámetros más importantes de tu pipeline de entrenamiento, incluyendo la elección del optimizador y del scheduler de learning rate. Para entender en profundidad qué optimizadores y schedulers existen y cuándo usar cada uno, consulta el submódulo de Optimizers y Schedulers, donde cubrimos desde SGD hasta AdamW y desde Step Decay hasta Cosine Annealing con Warmup.
Resumen y mejores prácticas
La optimización de hiperparámetros es una disciplina esencial que puede marcar la diferencia entre un modelo mediocre y uno excelente. Aquí resumimos las lecciones clave:
Receta práctica para empezar:
- Instala Optuna:
pip install optuna - Define tu función objetivo con
trial.suggest_* - Activa el
MedianPrunerpara early stopping - Ejecuta 50-100 trials
- Analiza la importancia de hiperparámetros con
optuna.visualization - Entrena el modelo final con los mejores hiperparámetros en train+validation
- Evalúa una sola vez en el test set y reporta
Lecturas recomendadas:
- Feurer, M. & Hutter, F. (2019). Hyperparameter Optimization. En AutoML: Methods, Systems, Challenges. Springer. — Revisión exhaustiva del campo.
- Yu, T. & Zhu, H. (2020). Hyper-Parameter Optimization: A Review of Algorithms and Applications. — Survey moderno con aplicaciones prácticas.
- Bischl, B. et al. (2023). Hyperparameter Optimization: Foundations, Algorithms, Best Practices and Open Challenges. WIREs Data Mining and Knowledge Discovery.