agosto 4, 2021 10:00 am

Jesús

En este articulo implementaremos una red neuronal convolucional para clasificar fotos de nuestros mejores amigos: gatos y perros. 

Aunque esta es una aplicación sencilla de deep learning, nos servirá para repasar los conceptos básicos de un clasificador binario de imágenes, así como una que otra característica interesante de TensorFlow 2.0

Al final de este artículo habrás aprendido (entre otras cosas):

  • Cómo descargar el conjunto de datos Cats vs. Dogs directamente desde TensorFlow.
  • Cómo implementar una red neuronal convolucional para clasificar perros y gatos usando TensorFlow.
  • Cómo realizar aumento de datos usando capas experimentales de TensorFlow.

¿Estás listo? ¡Comencemos!

Creación del Entorno de Desarrollo con Anaconda

Empecemos echándole un vistazo a la estructura del proyecto:

Estructura del proyecto

Estructura del proyecto

En datasmarts/train.py vivirá la totalidad de nuestra solución, como veremos en la próxima sección.

Para crear el ambiente de Anaconda, ejecuta el siguiente comando:

conda env create -f env.yml

Dicha instrucción habrá creado un ambiente llamado tf-dog-cat-classifier, correspondiente a este archivo de configuración:

Activa el ambiente así:

conda activate tf-dog-cat-classifier

Buenísimo, pasemos a la siguiente parte.

Implementación de un Clasificador de Perros y Gatos con TensorFlow 2.0

Como suele ser costumbre, inserta las siguientes líneas al principio del archivo datasmarts/train.py para importar las dependencias del script:

En el siguiente extracto definimos la URL de dónde descargaremos Cats vs Dogs, así como la ubicación en nuestra sistema donde lo almacenaremos una vez lo hayamos bajado. Siéntete libre de ajustar este parámetro a tu conveniencia:

Usando la función auxiliar tf.keras.utils.get_file(), descargamos Cats vs Dogs y de una vez lo descomprimimos:

Es buena práctica, cada vez que trabajamos con conjuntos de datos, bien se compongan de imágenes o de cualquier otro tipo de dato, remover instancias corruptas, de manera que nuestra red o clasificador no aprenda patrones de data errónea. En el siguiente bloque de código, eliminamos las imágenes que no contengan el header JFIF, ya que esto es un indicador de fotos corruptas:

Las imágenes que le pasaremos a la red serán de 180x180. Cada lote estará compuesto por 32 imágenes:

Definiremos un pipeline de TensorFlow para cargar desde el sistema de archivos, tanto las imágenes del conjunto de entrenamiento, como las del de validación. A pesar de que  se trata de un problema de clasificación binaria, lo trataremos como uno de clasificación multiclase, solo que tenemos únicamente dos clases: Cats y Dogs (los nombres de los directorios donde se hallan las fotos correspondientes a cada categoría).

Para que TensorFlow extraiga y codifique las clases, pasamos label_mode=’categorical’ a la función preprocessing.image_dataset_from_directory():

Mostramos en pantalla una selección aleatoria de imágenes del conjunto de entrenamiento:

Creamos un pipeline de aumento de datos, compuesto por capas experimentales de Keras, la primera, RandomFlip(‘horizontal’), para realizar giros horizontales aleatorios, y la segunda, RandomRotation(0.1), para ejecutar rotaciones aleatorias de a lo sumo 10% de la imagen.

También aprovechamos para mostrar variaciones de una imagen de prueba producto de este pipeline:

A continuación, definimos la función auxiliar create_network(), que como su nombre indica, construye la red clasificadora de mascotas. Empezamos definiendo la capa de entrada, y en caso de haber recibido un pipeline de data_augmentation, lo aplicamos:

Definimos el primer bloque, compuesto por dos grupos de convoluciones seguidas por capas de normalización por lotes. Dichas capas las activamos con ReLU:

Fíjate que en el extracto anterior almacenamos una conexión residual, la cual usaremos en breve. 

Ahora crearemos bloques similares, con convoluciones cada vez más profundas. También proyectamos las conexiones residuales al final de cada iteración:

Añadimos una última capa convolucional de 1024 filtros, seguida de una GlobalAveragePooling2D() para reducir la dimensionalidad. Finalmente, añadimos una capa densa, activada con Softmax, para producir la distribución de probabilidad:

Creamos el modelo e imprimimos su estructura:

Compramos y entrenamos la red por 15 epochs:

Probamos la red sobre una imagen del dataset, e imprimimos la distribución de probabilidad arrojada por el clasificador. Nota que la imagen se corresponde a un gato:

Podemos correr el script así:

python datasmarts/train.py

En la consola veremos este mensaje, que nos informa cuántas imágenes corruptas fueron eliminadas del dataset:

Eliminadas 1578 imágenes corruptas.

Después, veremos una muestra del dataset:

Y posteriormente, un ejemplo de aumento de imágenes utilizando las capas experimentales de Keras que definimos párrafos arriba:

Después de mucho tiempo, la red habrá culminado su entrenamiento, obteniendo aproximadamente un 95.19% de precisión en el conjunto de entrenamiento, y 91.97% en el de validación. Bastante bueno, ¿no te parece?

Para finalizar, vemos el veredicto de la red sobre esta imagen:

Esta imagen es 0.00% *perro*, y 100.00% *gato*.

Indudablemente, se trata de un gato y a la red no le queda ninguna duda al respecto ;).

Resumen

En este artículo aprendimos a implementar un clasificador de perros y gatos utilizando TensorFlow 2.0.

Empezamos descargando y depurando el dataset, eliminando aquellas imágenes corruptas que podrían haber impactado negativamente el desempeño de nuestro clasificador.

Posteriormente, implementamos una red con conexiones residuales, lo cual permite que pueda aprender más y mejores características a partir de las fotos en el conjunto de entrenamiento, a raíz de la profundidad de su arquitectura.

Recordemos que las conexiones residuales combaten uno de los problemas más comunes en deep learning: la fuga de gradientes, una situación que se ocurre cuando la magnitud del gradiente que se propaga hacia atrás se hace cada vez más pequeño, haciendo que las capas iniciales de la red aprendan poco o nada en el proceso.

Finalmente, después de entrenar nuestro modelo por 15 epochs, validamos su desempeño sobre una imagen de prueba, obteniendo una certeza del 100% en la predicción.

¿Qué te pareció el post de hoy? ¿Te animas a adaptar la red para que use una única neurona de salida (en vez de dos)? De ser así, ¿qué cambios tendrías que hacer? 

Si te animas, descarga el  código a continuación:

Hasta pronto.

Sobre el Autor

Jesús Martínez es el creador de DataSmarts, un lugar para los apasionados por computer vision y machine learning. Cuando no se encuentra bloggeando, jugando con algún algoritmo o trabajando en un proyecto (muy) cool, disfruta escuchar a The Beatles, leer o viajar por carretera.

Paso 2/2: Celebra tu NUEVO EMPLEO en Machine Learning ?

A %d blogueros les gusta esto: