Programmer facilement GradCam – Au cœur de VGG16 !

Dans cet article, nous allons voir comment visualiser les points d’intérêt (sous forme de heatmap) qui permettent à VGG16 de faire de la reconnaissance d’image en Python. Ce module s’appelle: GradCam.

L’implémentation que nous réalisons est décrite dans Grad-CAM : Visual Explanations from Deep Networks via Gradient-based Localization (Explications visuelles des réseaux profonds via la localisation par gradient).

Nous allons présenter cette technique en utilisant le réseau pré-entraîné VGG16. Pour ceux qui voudrait l’implémenter, un tutoriel a déjà été mis en ligne ici.

Vous pouvez directement télécharger le code sur github ou bien suivre, ici, le tutoriel.

Photo by Jerome on Unsplash

Que fait GradCam ?

En théorie

Le GradCam est une technique de visualisation : elle est utile pour comprendre quelles parties d’une image donnée ont conduit un convnet à sa décision finale de classification.

Elle est utile pour déboguer le processus de décision d’un convnet, en particulier dans le cas d’une erreur de classification. Elle vous permet également de localiser des objets spécifiques dans une image.

Cette technique provient d’une catégorie plus générale de procédés appelée visualisation de class activation map (CAM).

Elle consiste à produire des heatmap représentant les classes d’activation sur les images d’entrée. Une class activation heatmap est associée à une classe de sortie spécifique(comme vu ici VGG16 possède 1000 classes de sortie).

Ces classes sont calculée pour chaque pixel d’une image d’entrée, indiquant l’importance de chaque pixel par rapport à la classe considérée.

Par exemple, si une image est utilisée dans un convnet chiens/chats, la visualisation CAM vous permet de générer une carte thermique pour la classe « chat », indiquant à quel point les différentes parties de l’image ressemblent à un chat, et également une carte thermique pour la classe « chien », indiquant à quel point les parties de l’image ressemblent à un chien.

En pratique

En pratique, nous allons prendre la dernier couche de convolution de VGG16, le bloc5_conv3.

Cette couche va nous donner ce qu’on appelle des feature-maps, en fait la couche retourne une matrice contenant 1000 images.

Chaque image est associée au 1000 classes de VGG16.

Sur ces images est représenté sous forme de heatmap les parties de l’image ayant permis de détecter chaque classe.

Exemple: Imaginons que la première classe de VGG16 soit une voiture. Alors, sur la première image de la matrice, plus les pixels seront jaune, plus ces mêmes pixels auront permis à VGG16 de détecter une voiture.

Dans notre cas, nous allons détecter un dalmatien. Il faudra donc:

  • Connaître le numéro de la classe de ‘dalmatien’
  • Prélever la feature-map correspondant à ce numéro

Ce processus est réalisé dans cette partie de l’article.

Comment implémenter GradCam ?

Import des données et preprocessing

Avant de commencer vérifier, bien que votre version de TensorFlow est la 2.4.0.

import tensorflow as tf
tf.__version__

Ensuite nous pouvons commencer à coder ! 😉

Pour cela nous prenons l’image d’un dalmatien que nous transformons en variable d’entrée compréhensible pour VGG16image de taille 224 x 224

Il faut aussi prétraiter l’image selon quelques règles qui sont incluses dans la fonction preprocess_input de la librairie keras.applications.vgg16.

Il faut donc charger l’image, la redimensionner à 224 × 224, la convertir en un tenseur Numpy float32 et appliquer ces règles de prétraitement.


CRÉER TON APPLICATION IA !

Reçois tes 5 JOURS De Formation GRATUITE Pour Apprendre À Créer Ton APPLICATION d’INTELLIGENCE ARTIFICIELLE !

Tous les fondamentaux de la création d’Application IA : les approches, les outils et techniques, les librairies et framework, et bien d'autres ! Découvres étape par étape la création d’application de Deep Learning (tu apprendras même à trouver des idées d’appli !). En bonus, tu recevras notre Guide Ultime du Deep Learning !


from tensorflow.keras.applications.vgg16 import VGG16 model = VGG16(weights='imagenet')
from PIL import Image
im = (Image.open('/Dalmatian.jpg'))
im
Photo by Alireza Roudbarmohammadi on Unsplash
import tensorflow as tf
import numpy as np from keras.applications.imagenet_utils
import preprocess_input
def preprocess(img):
 img = tf.keras.preprocessing.image.img_to_array(img)
 img = np.expand_dims(img,axis=0)
 img = preprocess_input(img)
 return img

image = preprocess((Image.open("/Dalmatian.jpg")).resize((224, 224), Image.ANTIALIAS))

Prédiction

Nous pouvons maintenant lancer le réseau pré-entraîné VGG16 sur l’image. Puis décoder son vecteur de prédiction pour le ramener dans un format compréhensible pour nous.

from keras.applications.imagenet_utils import decode_predictions
predict = model.predict(image)
print('Predicted:', decode_predictions(predict,top=3))

On obtient un top 3 de classes détecté associer à une probabilité:

  • 1er – ‘Dalmatien’ – probabilité: 99.9%
  • 2ème – ‘Dogue allemand’ – probabilité: 0.02%
  • 3ème ‘Braque allemand probabilité: 0.00007%

On peut voir que VGG16 est déjà entraîné à reconnaître les races de chiens. Le réseau a identifié que l’image contenait un dalmatien.

Pour comprendre plus en profondeur comment marche le réseau, on peut afficher les entrées du vecteur de prédiction (ces entrées s’activent lorsqu’elles repèrent une classe correspondant à la leur).

Ici on voit que l’entrée qui a été activée au maximum est celle correspondant à la classe « dalmatian », à l’indice 251.

target_class = np.argmax(predict[0])
print("Target Class = %d"%target_class)

Target Class = 251

Feature-map et Gradient

Pour visualiser les parties de l’image qui ressemblent le plus à un dalmatien, nous allons mettre en place Grad-CAM.

Pour cela nous prenons:

  • l’entrée « dalmatien » dans le vecteur de prédiction
  • les feature-maps de sortie de la couche block5_conv3, la dernière couche convolutionnelle du VGG16
dogRace_output = model.output[:, target_class]
last_conv_layer = model.get_layer('block5_conv3')

Nous prenons le gradient de la classe « dalmatien »(TensorShape([None, 14, 14, 512])) par rapport aux feature-maps de sortie du bloc5_conv3.

Nous créons ensuite un vecteur de dimension (512,), où chaque entrée est l’intensité moyenne du gradient sur un canal spécifique aux feature-maps.

Lors l’exécution Suite à des problèmes de version de Keras, s’il y a un problème à la ligne suivante: ré-executer le code depuis le début .

from keras import backend as K
tf.compat.v1.disable_eager_execution()

grads = K.gradients(dogRace_output, last_conv_layer.output)[0]
pooled_grads = K.mean(grads, axis=(0, 1, 2))

Ensuite, nous créons la variable iterate qui permet d’accéder aux valeurs des quantités que nous venons de définir : pooled_grads et les feature-maps de sortie du bloc5_conv3, à partir d’un échantillion(image).

Nous récupérons donc la valeurs de pooled_grads et les feature-maps de sortie du bloc5_conv3(en numpy.arrays) à partir de notre image de base.

iterate = K.function([model.input], [pooled_grads, last_conv_layer.output[0]])

pooled_grads_value, conv_layer_output_value = iterate([image])

Heatmap et Visualisation

Nous multiplions chaque canal de la feature-map par « l’importance de ce canal » par rapport à la classe « dalmatien ».

Puis nous calculons la moyenne par canal de la feature-map ce qui nous donne la heatmap (carte thermique) de la classe d’activation.

for i in range(512):
  conv_layer_output_value[:, :, i] *= pooled_grads_value[i]

heatmap = np.mean(conv_layer_output_value, axis=-1)

À des fins de visualisation, nous allons également normaliser la carte thermique entre 0 et 1.

import matplotlib.pyplot as plt

heatmap = np.maximum(heatmap, 0)
heatmap /= np.max(heatmap)
plt.matshow(heatmap)

Finalement, nous utilisons OpenCV pour générer une image qui superpose la heatmap que nous avons obtenu à l’image originale.

import cv2
from google.colab.patches import cv2_imshow

img = cv2.imread('/Dalmatian.jpg')
heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
heatmap = np.uint8(255 * heatmap)
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
superimposed_img = heatmap * 0.4 + img
cv2_imshow(superimposed_img)

On peut ensuite sauvegarder, d’une part, la heatmap et d’une autre, l’image finale ! 🙂

cv2.imwrite('/Dalmatian_heatmap.jpg', heatmap)
cv2.imwrite('/Dalmatian_GradCam.jpg', superimposed_img)

Et voilà, cet article sur les heat map et GradCam est terminé ! J’espère qu’il vous a plu !


CRÉER TON APPLICATION IA !

Reçois tes 5 JOURS De Formation GRATUITE Pour Apprendre À Créer Ton APPLICATION d’INTELLIGENCE ARTIFICIELLE !

Tous les fondamentaux de la création d’Application IA : les approches, les outils et techniques, les librairies et framework, et bien d'autres ! Découvres étape par étape la création d’application de Deep Learning (tu apprendras même à trouver des idées d’appli !). En bonus, tu recevras notre Guide Ultime du Deep Learning !


Tom Keldenich
Tom Keldenich

Data Engineer & passionné d'Intelligence Artificielle !

Fondateur du site Inside Machine Learning

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.