El desempeño de un modelo de machine learning, bien sea de la vertiente tradicional, como un árbol de decisión o regresión logística, o una red neuronal profunda (deep learning), está íntimamente atado a la correcta selección de hiperparámetros.
Afortunadamente, para el caso de modelos de machine learning, contamos con una cornucopia de herramientas para optimizar la búsqueda de los mejores hiperparámetros de un modelo dado.
¿De qué herramientas hablamos? Pues, de GridSearchCV y RandomSearchCV en scikit-learn, así como alternativas equivalentes en OpenCV.
¿Pero qué hay de las redes neuronales? ¿Hay alguna herramienta similar que podamos usar en TensorFlow?
¡Sí! Se llama Keras Tuner y en este artículo la estudiaremos a fondo.
Al finalizar este artículo habrás aprendido:
¿Preparado? ¡Vamos a allá!
¡ATENTO!
Este post está basado en este tutorial oficial de TensorFlow. Échale un ojo, vale la pena.
No sé si te pase como a mí, pero con frecuencia me vuelvo un ocho cuando hablo de parámetros e hiperparámetros, y a veces uso los términos intercambiablemente, lo cual está mal, pues no son sinónimos.
Sin embargo, he aquí una serie de distinciones que me han sido de utilidad y, con suerte, te harán la vida más fácil a ti también:
En pocas palabras, los parámetros son los elementos internos de un determinado modelo que, mediante el entrenamiento, queremos ajustar de manera tal que el modelo sea lo más preciso posible.
Por su parte, los hiperparámetros son los botones, palancas e interruptores que podemos prender, apagar, ajustar para dirigir al modelo en la dirección deseada.
Si un modelo es un carro, los parámetros vendrían siendo las llantas, el motor, los frenos y demás componentes mecánicos, mientras que los hiperparámetros serían el volante y los pedales.
¿Se entiende?
Tipos de Hiperparámetros
Cuando hablamos de hiperparámetros, tenemos dos sabores:
- 1Hiperparámetros del modelo: Son aquellos que influencian la estructura misma del modelo, como el número de neuronas o la cantidad de capas en una red neuronal.
- 2Hiperparámetros del algoritmo: Son aquellos que afectan el proceso mediante el cual entrenamos un modelo. Ejemplos claros son el learning rate en Stochastic Gradient Descent (SGD) o el número de iteraciones que entrenaremos un modelo.
Suficiente teoría. Hora de arremangarse y ponerse manos a la obra.
Creación del Ambiente de Desarrollo con Anaconda
Nuestro proyecto es bastante sencillo, pues la implementación vive en un archivo llamado tune.py, dentro de la carpeta datasmarts, como ya es costumbre:
C:\USERS\JESUS\DATASMARTS\TF2-KERAS-TUNER\DATASMARTS tune.py
Para crear el ambiente, necesitarás tener Anaconda instalado en tu máquina. A continuación vemos el archivo de definición del ambiente en formato YAML:
Para crear un ambiente a partir de esta configuración, ejecuta:
conda env create -f env.yml
Y actívalo así:
conda activate tf2-keras-tuner
Perfecto. Continuemos.
Optimización de Hiperparámetros con Keras Tuner
Abre el archivo datasmarts/tune.py e inserta estas líneas, las cuales importan las dependencias del programa:
Para efectos ilustrativos, usaremos el ya bien conocido conjunto de datos, Fashion-MNIST, que podemos descargar con una simple instrucción, como vemos a continuación:
Evidentemente, para evitar problemas de estabilidad numérica, normalizamos los píxeles de las imágenes para que caigan en el rango [0, 1]:
La magia de Keras Tuner viene a continuación. Hay dos conceptos que tenemos que tener en cuenta:
La función model_builder(), expuesta en el siguiente extracto, define un hipermodelo en el que optimizaremos dos hiperparámetros:
Ahora tenemos que definir el algoritmo de optimización como tal. En Keras Tuner contamos con varias opciones (que exploraremos en otros artículos futuros), siendo una de ellas Hyperband.
¿Cómo funciona? Similar a un torneo de eliminación, (como los octavos, cuartos, etc, de la Champions League o la Copa Mundial de la FIFA). En este caso, los parámetros que tenemos que pasar a kt.Hyperband(), son:
Hyperband es a Keras Tuner lo que GridSearchCV es a scikit-learn.
Pararemos la optimización si no vemos mejoría por más de 5 iteraciones consecutivas. Para ello instanciamos un callback EarlyStopping, así:
Ahora, iniciaremos la búsqueda invocando el método .search():
¡ATENTO!
Los 15 epochs definidos en kt.Hyperband aplican para cada posible modelo candidato, mientras que los 50 epochs pasados al método .search() significa que correremos 50 iteraciones del algoritmo de búsqueda.
Extraemos los mejores hiperparámetros arrojados por la búsqueda:
Imprimimos un mensaje con los valores óptimos de dichos hiperparámetros:
Ahora, construimos un modelo con los mejores hiperparámetros y lo entrenamos por 50 epochs:
De este modelo recién entrenado extraeremos el número de epochs óptimo, con base al valor de val_accuracy:
Teniendo los mejores hiperparámetros como resultado de la búsqueda con Hyperband, y el número de epochs óptimo, entrenemos el mejor modelo posible:
Finalmente, evaluemos el mejor modelo en los datos de prueba:
Corre el programa así (ubicado en la raíz del proyecto):
python datasmarts/tune.py
¡ATENTO!
Lo mejor es que uses una GPU, de ser posible, para correr el programa, puesto que de lo contrario, demorará horas. En mi GPU se tomó unos 15 minutos en finalizar.
Veremos en la terminal el siguiente mensaje:
La búsqueda de hiperparámetros se ha completado. El número óptimo de neuronas en la primera capa de la red es 352 y el learning rate ideal para el optimizador es 0.001
También notaremos que el número ideal de epochs es 30:
Número óptimo de epochs: 30
Finalmente, los resultados de la evaluación en el conjunto de pruebas es:
Pérdida de prueba: 0.44900094513595107 Exactitud de prueba: 88.26%
Nada mal, ¿eh? Especialmente si consideramos lo chiquita que es la red.
Resumen
Hoy aprendimos que, al igual que en machine learning, y en librerías seminales como scikit-learn y OpenCV, podemos optimizar los hiperparámetros de una red neuronal directamente en TensorFlow, todo gracias a Keras Tuner.
Sin embargo, como todo en el mundo de deep learning, establecer las bases o la estructura de dicha estructura no es tan directo como quisiéramos, aunque, la verdad sea dicha, tampoco es tan traumático.
¿Qué necesitamos hacer? Principalmente dos cosas:
Al final nuestra búsqueda nos condujo a una red 88.26% precisa, lo cual no está mal, considerando su reducido tamaño.
Ahora bien, ¿por qué no te animas a modificar el código para optimizar un hipermodelo de una red convolucional? Después de todo, las CNNs son las más adecuadas para trabajar con imágenes. Aquí te dejo el código:
¡Nos vemos!