Hoy te traigo un artículo bastante práctico en el que exploraremos algunas de las novedades introducidas en la versión 2 de TensorFlow, el framework por antonomasia de deep learning.
En particular, entrenaremos un clasificador de flores utilizando una red neuronal convolucional.
Al final de este artículo habrás aprendido:
¡ATENTO!
El artículo de hoy está inspirado en este excelente tutorial de clasificación de imágenes de la página oficial de TensorFlow.
Creación del Ambiente de Desarrollo con Anaconda
¡No, no es un error! A partir de ahora usaremos Anaconda como nuestro manejador de ambientes por defecto.
¿A qué se debe esta decisión? Como sabrás, mis artículos típicamente funcionan en Mac y en Ubuntu (es decir, en sistemas basados en Unix) porque son los sistemas operativos a los que tengo más fácil acceso.
En otras palabras, no brindo soporte a Windows… ¡Hasta ahora!
Con el fin de proveer una experiencia más homogénea para todos los seguidores de DataSmarts, independientemente del SO que usen, he optado por usar Anaconda, puesto que considero que se alinea con esta meta, ya que es una herramienta más completa y madura que virtualenv.
Instalación de Anaconda
Si no tienes Anaconda instalado en tu máquina, descárgalo y sigue las instrucciones descritas aquí.
Es posible que tengas que reiniciar sesión para que tu sistema reconozca la instalación.
Una vez te hayas cerciorado de que Anaconda funciona correctamente, puedes seguir adelante con el tutorial. Por lo pronto, veamos la estructura del proyecto:
C:\USERS\JESUS\DATASMARTS\TF2-FLOWER-CLASSIFIER\DATASMARTS flower_classifier.py
Como ves, el único archivo relevante es datasmarts/flower_classifier.py, pues allí vive la implementación de nuestro programa.
A continuación encuentras la descripción del ambiente de Anaconda del proyecto, en formato YAML:
Para crear un ambiente con esta misma configuración, solo debes correr este comando:
conda env create -f env.yml
Después, actívalo como sigue:
conda activate tf2-flower-classifier
Voila! Eso es todo. Procedamos a la siguiente sección.
Clasificación de Flores con TensorFlow 2
Abre el archivo datasmarts/flower_classifier.py e inserta estas líneas para importar las dependencias del script:
Debido a que es fundamental entender de manera visual el paulatino aprendizaje de la red durante su entrenamiento, implementaremos la función auxiliar plot_model_history(), la cual, como su nombre indica, toma la historia de entrenamiento de una red, y produce un gráfico comparativo de las curvas de pérdida y exactitud (accuracy) de la misma, tanto en el conjunto de entrenamiento como de validación:
Como verás más adelante, entender estas gráficas es una gran forma de determinar si una red sufre de sobreajuste u overfitting.
La data que usaremos se halla en DATASET_URL. Es un conjunto de alrededor de 3700 fotos de flores divididas en estas cinco categorías:
Para evitar descargar innecesariamente los datos más de una vez, los cachearemos en la ubicación especificada en CACHE_LOCATION:
Usaremos la función tf.keras.utils.get_file() para descargar y descomprimir los datos en el directorio flower_photos, dentro del CACHE_LOCATION:
Contamos el número de imágenes en el conjunto de datos y lo mostramos en pantalla:
Ahora, definimos las siguientes constantes del programa:
Una de las grandes novedades de TensorFlow 2.0 es el API tf.data.Dataset, ya que nos permite escribir de forma declarativa y funcional complejos e intrincados flujos de entrada de datos, típicamente compuestos de múltiples transformaciones.
Todo comienza definiendo una fuente u origen, como en este caso, donde especificamos mediante la función tf.keras.preprocessing.image_dataset_from_directory() que obtendremos los datos del dataset directamente desde una estructura de directorios en disco, tanto para el conjunto de validación como de entrenamiento:
Imprimimos las clases del conjunto de datos:
Mostramos una muestra aleatoria de nueve imágenes:
A continuación, sacamos provecho de la expresividad del API tf.data.Dataset de TensorFlow para:
En la primera parte de este programa crearemos una simple red neuronal estructurada así:
Compilamos el modelo. Usaremos Adam como optimizador y tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) como función de pérdida.
Debido a que las neuronas de salida de la red no fueron activadas con Softmax, como suele ser el caso, pasamos from_logits=True a SparseCategoricalCrossentropy.
Mostramos la estructura del modelo:
Entrenamos el modelo por 10 iteraciones, y visualizamos las respectivas curvas de entrenamiento y validación:
La red anterior es un tanto ingenua, por lo que sufre de overfitting. Para combatir esta problemática, usaremos dos técnicas:
- 1Aumento de datos.
- 2Dropout.
Otra de las cosas chéveres que TensorFlow 2.0 tiene para nosotros, es la posibilidad de especificar qué transformaciones queremos llevar a cabo mediante simples capas, en vez de tener que usar un objeto especial, como antiguamente en Keras (ImageDataGenerator):
A continuación mostramos un ejemplo de las transformaciones:
La red es la misma que la pasada, con estas salvedades:
Compilamos y mostramos el modelo:
Entrenamos el modelo, esta vez por 15 iteraciones:
Finalmente, mostramos las curvas pertinentes:
Corre este comando para dar vida al programa:
python datasmarts/flower_classifier.py
Si tienes una GPU, el programa debería culminar en 2 o 3 minutos. Si, en cambio, tienes acceso únicamente a una CPU, tendrás que esperar alrededor de 1 minuto por epoch, lo que se traduce en unos 25-30 minutos en total. Dicho esto, sea cual sea la espera, verás en pantalla una imagen como esta, donde se muestran algunas de las fotos que componen el conjunto de datos:
También verás este mensaje, que nos indica que contamos con 3670 imágenes en total, de las cuales 734 se usarán para validar los modelos:
Found 3670 files belonging to 5 classes. Using 734 files for validation.
La estructura de la red se puede ver a continuación:
Y las curvas de dicho modelo, aquí:
La enorme divergencia entre el accuracy y la pérdida de entrenamiento y validación es un contundente indicio de que sufrimos de overfitting. Afortunadamente, la segunda red es más robusta a esta situación. Esta es su estructura:
¿Ves que es más pequeña que la anterior? ¡Aproximadamente 4 millones de parámetros versus más de 16 millones!
Al entrenarla y analizar sus curvas, notamos que esta segunda red es más eficaz, ya que la distancia que separa las curvas de entrenamiento y de validación es mucho menor que en el caso anterior, ubicándose el pico del accuracy de entrenamiento en 80.2%, y el de validación en 73.6%. Razonable.
Resumen
Hoy aprendimos a entrenar un simple clasificador de flores usando TensorFlow 2.0.
Aunque esta tarea puede resultar, a priori, sencilla, nos fue de gran utilidad para conocer varias de las atractivas nuevas características de TensorFlow 2, como:
Con un poco de experimentación y unos tantos ajustes pudimos mejorar nuestro primero intento de clasificador, ya que sufría de overfitting, lo que se traduce en una pobre capacidad de generalizar.
Al incorporar dropout y el aumento de datos, mitigamos el sobreajuste, obteniendo un razonable 73.6% de accuracy en los datos de validación.
Nada mal, ¿eh?
Puedes descargar el código de este artículo aquí:
¡Adiós!