septiembre 15, 2021 10:00 am

Jesús

Es un hecho indiscutible que las redes neuronales profundas (deep learning) han revolucionado el campo de computer vision, NLP, entre muchos otros.

Hoy día es posible alcanzar, con relativa facilidad, altos niveles de desempeño en tareas complejas como la detección de objetos, así como la segmentación y clasificación de imágenes.

Lamentablemente, a pesar de todo su poder, una de las desventajas más patentes de las redes neuronales es su pobre interpretabilidad. 

En otras palabras, resulta increíblemente complejo entender su funcionamiento, y ni qué decir de depurarlas.

Dicho de una forma más directa, las redes neuronales, en su mayoría, son “cajas negras”, ya que se suele dar el caso en que no sabemos:

  • Qué partes de la imagen la red está “viendo”.
  • Cuáles neuronas se activan ante determinados estímulos.
  • Cómo la red arriba a su resultado final.

Afortunadamente, en los últimos tiempos han surgido más y más métodos, técnicas y mecanismos que nos ayudan en la tarea de entender mejor el funcionamiento de las redes neuronales.

Una de estas herramientas fue concebida por Selvaraju et al, y se llama Gradient-weighted Class Activation Mapping (Mapeado de Activación por Clases de Gradientes Ponderados, en español), o simplemente, Grad-CAM, y en el presente artículo los estudiaremos más a fondo.

Al finalizar este artículo habrás aprendido:

  • Qué es y cómo funciona, intuitivamente, Grad-CAM.
  • Cómo implementar Grad-CAM en TensorFlow.
  • Cómo usar Grad-CAM para examinar visualmente las activaciones de una red neuronal.

¿Qué es Grad-CAM y Por Qué Debería Importarte?

Grad-CAM, puesto de forma sencilla, es una herramienta que nos permite “debuggearvisualmente prácticamente cualquier arquitectura de redes neuronales convolucionales.

La clave aquí es visualmente, pues lo que Grad-CAM hace es crear un mapa de activaciones, donde se vislumbra dónde la red está “mirando” al momento de producir una predicción.

Si el término mapa de activaciones suena demasiado foráneo, piensa en una imagen térmica como esta:

Imagen térmica

Imagen térmica

En el mapa de activaciones, las “zonas calientes” (es decir, aquellas donde la imagen se ve roja, amarilla o naranja) denotarán los píxeles que influyeron más en la predicción final, mientras que las “zonas frías” simbolizarán píxeles que influyeron poco o nada.

¿Pero cómo funciona concretamente Grad-CAM? La respuesta es muy fácil querido lector; es un proceso sencillo compuesto de dos pasos nada más:

  1. 1
    Grad-CAM toma la última capa convolucional de una red.
  2. 2
    Se examina la información de los gradientes que fluyen hacia dicha capa.

¿Ves? ¡Fácil!

Si no estás convencido, todo quedará más claro una vez implementemos el código, así que pasemos a la siguiente sección.

Creación del Entorno de Desarrollo con Anaconda

Como de costumbre, démosle un vistazo a la estructura del proyecto:

Estructura del proyecto

Estructura del proyecto

  • Nuestra implementación vivirá dentro del archivo datasmarts/visualize.py.
  • En la carpeta resources contamos con varias imágenes de ejemplo que usaremos para demostrar el funcionamiento de Grad-CAM.

Para crear el ambiente de Anacona, solo corre este comando:

conda env create -f env.yml

Con esta instrucción habremos creado un ambiente llamado tf-grad-cam, configurado así:

Finalmente, para activar el ambiente, ejecuta:

conda activate tf-grad-cam

Perfecto, prosigamos.

Debugging Visual de Redes Neuronales con Grad-CAM en TensorFlow

Abre el archivo datasmarts/visualize.py e insertas estas líneas, las cuales importan las dependencias del script:

A continuación, comenzaremos a armar la clase GradCAM que, como habrás adivinado, implementa el algoritmo Grad-CAM para la visualización de activaciones de una red neuronal. Empecemos por el constructor:

Como vemos, esta clase recibe una red neuronal a analizar, así como opcionalmente el nombre de la última capa convolucional de la misma; si dicho argumento se omite, entonces asumiremos que la última capa de cuatro dimensiones es convolucional.

Veamos ahora el método auxiliar _create_grad_model(), que simplemente reconstruye la misma red que recibimos en la entrada, pero aparte de las predicciones, también produce las activaciones de la capa convolucional que deseamos analizar:

El siguiente método a implementar es compute_heatmap(), el cual recibe la imagen de entrada y un valor opcional de epsilon usado para impedir errores por división entre cero:

El primer paso consiste en pasar la imagen por la red, y extraer el valor de la pérdida asociado a las predicciones correspondientes a la clase que estamos analizando (determinada por class_index).

Luego, calculamos el gradiente respecto a las activaciones de la capa convolucional siendo depurada, con relación a la clase concreta que estamos analizando:

Después, calculamos el promedio ponderado de los gradientes:

Posteriormente, construimos el mapa de calor y lo normalizamos para que sus valores estén entre 0 y 1, para después retornarlo:

El siguiente y último método de la clase GradCAM es overlay_heatmap(), que simplemente se usa para superponer el mapa de calor sobre la imagen original, con el fin de facilitar la visualización de las activaciones:

Lo próximo que haremos es definir el menú del programa, que se compone de un único parámetro, -i/--image, la ruta a la imagen de entrada:

Como red de demostración, usaremos una ResNet50 entrenada en ImageNet, aunque es menester recordar que Grad-CAM funciona para cualquier CNN:

A continuación, cargamos y procesamos la imagen de entrada:

Obtenemos las predicciones y el índice de la clase más probable:

Aplicamos Grad-CAM y creamos el correspondiente mapa de calor:

Ahora superponemos el mapa de calor sobre la imagen original:

Decodificamos las predicciones de la red:

Usamos la probabilidad y la etiqueta de la clase predicha para etiquetar el resultado:

Por último, juntamos la imagen original, el mapa de color y la superposición de ambos en un mismo gráfico para mostrarlo en pantalla:

Puedes correr el script así:

python datasmarts/visualize.py -i resources/dog.jpg

Abajo vemos el resultado:

Mapa de activaciones producido por Grad-CAM para la clase Pug de ImageNet

Mapa de activaciones producido por Grad-CAM para la clase Pug de ImageNet

Podemos ver que la red clasificó a mi perro como Pug, que es, en efecto, su raza, con una confianza del 85.03%. Más aún, el mapa de calor revela que la red se activa alredeor de la nariz y los ojos en la cara de mi mascota, lo que significa que estas son características importantes para el modelo y, por tanto, se está comportando de la manera esperada.

Resumen

En este post aprendimos sobre la utilidad y el funcionamiento de Grad-CAM, un algoritmo muy útil para inspeccionar visualmente las activaciones de una red neuronal, que puede ser una forma efectiva de depurar su comportamiento, al asegurarnos de que está “mirando” las partes correctas de una imagen.

Esta es una herramienta vital, ya que puede darse el caso de que un accuracy o desempeño alto de nuestro modelo tenga que ver menos con un buen aprendizaje, y más con factores subyacentes. 

Por ejemplo, si estamos trabajando en un clasificador de animales domésticos, podríamos usar Grad-CAM para verificar que la red toma en cuenta las características inherentes a estos animales con el fin de clasificarlos adecuadamente, en vez de observar sus alrededores, el ruido de fondo o elementos menos importantes en la imagen.

¿Qué te pareció el post? ¿Lo encontraste útil? Te invito a descargarte el código para que ahondes en tu entendimiento de Grad-CAM:

¡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.