Réseaux de neurones convolutifs, avec Keras et des TPU

1. Présentation

Dans cet atelier, vous allez apprendre à assembler une couche convolutive dans un modèle de réseau de neurones capable de reconnaître des fleurs. Cette fois, vous allez créer vous-même le modèle à partir de zéro et exploiter la puissance du TPU pour l'entraîner en quelques secondes et itérer sa conception.

Cet atelier comprend les explications théoriques nécessaires concernant les réseaux de neurones convolutifs. Il constitue un bon point de départ pour les développeurs qui se familiarisent avec le deep learning.

Cet atelier constitue la troisième partie de la série "Keras sur TPU". Vous pouvez les effectuer dans l'ordre suivant ou indépendamment.

ca8cc21f6838eccc.png

Points abordés

  • Créer un classificateur d'images convolutif à l'aide d'un modèle Keras Sequential
  • Pour entraîner votre modèle Keras sur un TPU
  • Affiner votre modèle avec un bon choix de couches convolutives

Commentaires

Si vous remarquez quelque chose d'anormal dans cet atelier de programmation, veuillez nous en informer. Vous pouvez envoyer vos commentaires via les problèmes GitHub [ lien de commentaires].

2. Guide de démarrage rapide de Google Colaboratory

Cet atelier utilise Google Colaboratory et ne nécessite aucune configuration de votre part. Colaboratory est une plate-forme de notebook en ligne à des fins pédagogiques. Il propose un entraînement gratuit sur les processeurs, les GPU et les TPU.

688858c21e3beff2.png

Vous pouvez ouvrir cet exemple de notebook et exécuter quelques cellules pour vous familiariser avec Colaboratory.

c3df49e90e5a654f.png Welcome to Colab.ipynb

Sélectionner un backend TPU

8832c6208c99687d.png

Dans le menu Colab, sélectionnez Exécution > Modifier le type d'exécution, puis TPU. Dans cet atelier de programmation, vous allez utiliser un TPU (Tensor Processing Unit) puissant compatible avec l'entraînement accéléré par matériel. La connexion à l'environnement d'exécution se fera automatiquement lors de la première exécution. Vous pouvez également utiliser le bouton "Connecter" en haut à droite.

Exécution du notebook

76d05caa8b4db6da.png

Pour exécuter les cellules une par une, cliquez dessus et utilisez Maj + ENTRÉE. Vous pouvez également exécuter l'intégralité du notebook en sélectionnant Environnement d'exécution > Tout exécuter.

Sommaire

429f106990037ec4.png

Tous les notebooks comportent une table des matières. Vous pouvez l'ouvrir à l'aide de la flèche noire sur la gauche.

Cellules masquées

edc3dba45d26f12a.png

Certaines cellules n'affichent que leur titre. Il s'agit d'une fonctionnalité de notebook spécifique à Colab. Vous pouvez double-cliquer dessus pour voir le code à l'intérieur, mais ce n'est généralement pas très intéressant. Elles sont généralement compatibles avec les fonctions de visualisation ou de compatibilité. Vous devez toujours exécuter ces cellules pour que les fonctions qu'elles contiennent soient définies.

Authentification

cdd4b41413100543.png

Colab peut accéder à vos buckets Google Cloud Storage privés à condition que vous vous authentifiiez avec un compte autorisé. L'extrait de code ci-dessus déclenche un processus d'authentification.

3. [INFO] What are Tensor Processing Units (TPUs) ?

En résumé

f88cf6facfc70166.png

Code permettant d'entraîner un modèle sur un TPU dans Keras (et de passer au GPU ou au CPU si un TPU n'est pas disponible) :

try: # detect TPUs
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model = tf.keras.Sequential( ... )
  model.compile( ... )

# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

Nous allons aujourd'hui utiliser des TPU pour créer et optimiser un classificateur de fleurs à des vitesses interactives (minutes par exécution d'entraînement).

688858c21e3beff2.png

Pourquoi utiliser des TPU ?

Les GPU modernes sont organisés autour de "noyaux" programmables, une architecture très flexible qui leur permet de gérer diverses tâches telles que le rendu 3D, le deep learning, les simulations physiques, etc. Les TPU, en revanche, associent un processeur vectoriel classique à une unité de multiplication matricielle dédiée et excellent dans toutes les tâches où les grandes multiplications matricielles dominent, comme les réseaux de neurones.

8eb3e718b8e2ed08.png

Illustration: couche de réseau de neurones dense sous forme de multiplication matricielle, avec un lot de huit images traitées simultanément via le réseau de neurones. Veuillez effectuer une multiplication ligne x colonne pour vérifier qu'il s'agit bien d'une somme pondérée de toutes les valeurs de pixels d'une image. Les couches convolutives peuvent également être représentées par des multiplications matricielles, bien que cela soit un peu plus compliqué ( explication ici, section 1).

Matériel

MXU et VPU

Un cœur de TPU v2 est composé d'une unité matricielle (MXU, Matrix Multiply Unit) qui exécute les multiplications matricielles et d'une unité de traitement vectoriel (VPU) pour toutes les autres tâches telles que les activations, softmax, etc. Le VPU gère les calculs float32 et int32. En revanche, l'unité matricielle fonctionne dans un format à virgule flottante 16 à 32 bits à précision mixte.

7d68944718f76b18.png

Valeurs à virgule flottante de précision mixte et bfloat16

L'unité matricielle calcule les multiplications matricielles à l'aide des entrées bfloat16 et des sorties float32. Les accumulations intermédiaires sont effectuées avec une précision float32.

19c5fc432840c714.png

L'entraînement des réseaux de neurones est généralement résistant au bruit introduit par une précision réduite à virgule flottante. Dans certains cas, le bruit contribue même à la convergence de l'optimiseur. La précision à virgule flottante 16 bits est traditionnellement utilisée pour accélérer les calculs, mais les formats float16 et float32 ont des plages très différentes. Réduire la précision de float32 à float16 entraîne généralement des dépassements et des sous-dépassements. Des solutions existent, mais un travail supplémentaire est généralement nécessaire pour que float16 fonctionne.

C'est pourquoi Google a introduit le format bfloat16 dans les TPU. bfloat16 est un float32 tronqué avec exactement les mêmes bits d'exposant et la même plage que float32. En plus du fait que les TPU calculent les multiplications matricielles en précision mixte avec des entrées bfloat16, mais des sorties float32, cela signifie qu'en règle générale, aucune modification de code n'est nécessaire pour bénéficier des gains de performances de la précision réduite.

Tableau systolique

La MMX implémente des multiplications de matrices en matériel à l'aide d'une architecture appelée "tableau systolique", dans laquelle les éléments de données circulent à travers un tableau d'unités de calcul matérielles. (En médecine, le terme « systolique » fait référence aux contractions cardiaques et au flux sanguin, ici au flux de données.)

L'élément de base d'une multiplication matricielle est un produit scalaire entre une ligne d'une matrice et une colonne de l'autre matrice (voir l'illustration en haut de cette section). Pour une multiplication matricielle Y=X*W, un élément du résultat serait:

Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]

Sur un GPU, il faut programmer ce produit scalaire dans un "cœur" de GPU, puis l'exécuter en parallèle sur autant de "cœurs" que possible pour essayer de calculer simultanément toutes les valeurs de la matrice obtenue. Si la matrice résultante est de 128 x 128, 128 x 128 = 16 k "cœurs" doivent être disponibles, ce qui n'est généralement pas possible. Les GPU les plus volumineux possèdent environ 4 000 cœurs. En revanche, un TPU utilise le strict minimum de matériel pour les unités de calcul de la MXU : uniquement des accumulateurs de multiplication bfloat16 x bfloat16 => float32, rien d'autre. Elles sont si petites qu'un TPU peut en implémenter 16K dans une unité matricielle de 128 x 128 et traiter cette multiplication matricielle en une seule fois.

f1b283fc45966717.gif

Illustration: tableau systolique MXU. Les éléments de calcul sont des multiplicateurs-accumulateurs. Les valeurs d'une matrice sont chargées dans le tableau (points rouges). Les valeurs de l'autre matrice circulent dans le tableau (points gris). Les lignes verticales propagent les valeurs vers le haut. Les lignes horizontales propagent des sommes partielles. Il revient à l'utilisateur de vérifier qu'au fur et à mesure que les données circulent dans le tableau, vous obtenez le résultat de la multiplication matricielle depuis le côté droit.

De plus, pendant que les produits scalaires sont calculés dans une unité matricielle, les sommes intermédiaires circulent simplement entre les unités de calcul adjacentes. Ils n'ont pas besoin d'être stockés et récupérés vers/depuis la mémoire ou même un fichier d'enregistrement. Au final, l'architecture de tableau systolique des TPU présente un avantage significatif en termes de densité et de puissance, ainsi qu'un avantage non négligeable en termes de vitesse par rapport à un GPU lors du calcul des multiplications matricielles.

Cloud TPU

Lorsque vous demandez un Cloud TPU v2 sur Google Cloud Platform, vous obtenez une machine virtuelle (VM) dotée d'une carte TPU PCI. La carte TPU comporte quatre puces TPU à deux cœurs. Chaque cœur de TPU comprend une unité vectorielle (VPU) et une unité matricielle (MXU) de 128 x 128. Ce "Cloud TPU" est ensuite généralement connecté via le réseau à la VM à l'origine de la demande. Voici à quoi ressemble l'image complète :

dfce5522ed644ece.png

Illustration : votre VM avec un accélérateur "Cloud TPU" connecté au réseau. Le "Cloud TPU" lui-même est constitué d'une VM dotée d'une carte TPU associée à un PCI et de quatre puces TPU double cœur.

Pods TPU

Dans les centres de données de Google, les TPU sont connectés à une interconnexion de calcul hautes performances (HPC, High Performance Computing), ce qui peut les faire apparaître comme un très grand accélérateur. Google les appelle des pods. Ils peuvent comporter jusqu'à 512 cœurs de TPU v2 ou 2 048 cœurs de TPU v3.

2ec1e0d341e7fc34.jpeg

Illustration: un pod TPU v3. Cartes et racks TPU connectés via une interconnexion HPC.

Pendant l'entraînement, les gradients sont échangés entre les cœurs de TPU à l'aide de l'algorithme all-reduce ( une bonne explication ici). Le modèle en cours d'entraînement peut tirer parti du matériel en s'entraînant sur des lots de grande taille.

d97b9cc5d40fdb1d.gif

Illustration: synchronisation des gradients lors de l'entraînement à l'aide de l'algorithme all-reduce sur le réseau HPC de maillage toroïdal 2D de Google TPU

Logiciel

Entraînement de lots de grande taille

La taille de lot idéale pour les TPU est de 128 éléments de données par cœur de TPU, mais le matériel peut déjà présenter une bonne utilisation à partir de 8 éléments de données par cœur de TPU. Rappelez-vous qu'un Cloud TPU possède huit cœurs.

Dans cet atelier de programmation, nous allons utiliser l'API Keras. Dans Keras, le lot que vous spécifiez correspond à la taille de lot globale pour l'ensemble du TPU. Vos lots seront automatiquement divisés en huit et exécutés sur les huit cœurs du TPU.

da534407825f01e3.png

Pour obtenir d'autres conseils sur les performances, consultez le Guide sur les performances des TPU. Pour les très grands lots, une attention particulière peut être nécessaire dans certains modèles. Pour en savoir plus, consultez LARSOptimizer.

En arrière-plan : XLA

Les programmes TensorFlow définissent des graphiques de calcul. Le TPU n'exécute pas directement le code Python, mais le graphe de calcul défini par votre programme TensorFlow. En arrière-plan, un compilateur appelé XLA (Acceleated Linear Algebra compiler) transforme le graphe TensorFlow des nœuds de calcul en code de machine TPU. Ce compilateur effectue également de nombreuses optimisations avancées sur votre code et votre mise en page de la mémoire. La compilation s'effectue automatiquement à mesure que le travail est envoyé au TPU. Vous n'avez pas besoin d'inclure XLA explicitement dans votre chaîne de compilation.

edce61112cd57972.png

Illustration: Pour s'exécuter sur TPU, le graphe de calcul défini par votre programme TensorFlow est d'abord traduit en représentation XLA (acceleated Linear Algebra compiler), puis compilé par XLA en code machine TPU.

Utiliser des TPU dans Keras

Les TPU sont compatibles avec l'API Keras depuis TensorFlow 2.1. La compatibilité avec Keras fonctionne sur les TPU et les pods TPU. Voici un exemple qui fonctionne sur les TPU, les GPU et les processeurs :

try: # detect TPUs
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model = tf.keras.Sequential( ... )
  model.compile( ... )

# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

Dans cet extrait de code:

  • TPUClusterResolver().connect() trouve le TPU sur le réseau. Elle fonctionne sans paramètres sur la plupart des systèmes Google Cloud (tâches AI Platform, Colaboratory, Kubeflow, VM de deep learning créées via l'utilitaire "gsutil up"). Ces systèmes savent où se trouve leur TPU grâce à une variable d'environnement TPU_NAME. Si vous créez un TPU manuellement, définissez la variable d'environnement TPU_NAME sur la VM à partir de laquelle vous l'utilisez ou appelez TPUClusterResolver avec des paramètres explicites: TPUClusterResolver(tp_uname, zone, project)
  • TPUStrategy est la partie qui implémente l'algorithme de synchronisation de gradient "all-reduce" ;
  • La stratégie est appliquée via une portée. Le modèle doit être défini dans le champ d'application de la stratégie.
  • La fonction tpu_model.fit attend un objet tf.data.Dataset en entrée pour l'entraînement TPU.

Tâches de portage TPU courantes

  • Bien qu'il existe de nombreuses façons de charger des données dans un modèle TensorFlow, l'utilisation de l'API tf.data.Dataset est obligatoire pour les TPU.
  • Les TPU sont très rapides et l'ingestion de données devient souvent le goulot d'étranglement lors de leur exécution. Vous trouverez des outils permettant de détecter les goulots d'étranglement des données et d'autres conseils de performances dans le guide des performances des TPU.
  • Les nombres int8 ou int16 sont traités comme des int32. Le TPU n'a pas de matériel entier fonctionnant sur moins de 32 bits.
  • Certaines opérations TensorFlow ne sont pas compatibles. Cliquez ici pour consulter la liste. La bonne nouvelle est que cette limitation ne s'applique qu'au code d'entraînement, c'est-à-dire à la propagation avant et arrière de votre modèle. Vous pouvez toujours utiliser toutes les opérations TensorFlow dans votre pipeline d'entrée de données, car il sera exécuté sur le processeur.
  • tf.py_func n'est pas compatible avec TPU.

4. [INFO] Principes de base du classificateur de réseaux de neurones

En résumé

Si vous connaissez déjà tous les termes en gras du paragraphe suivant, vous pouvez passer à l'exercice suivant. Si vous débutez dans le deep learning, bienvenue et poursuivez votre lecture.

Pour les modèles créés sous la forme d'une séquence de couches, Keras propose l'API Sequential. Par exemple, un classificateur d'images utilisant trois couches denses peut être écrit en Keras comme suit:

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=[192, 192, 3]),
    tf.keras.layers.Dense(500, activation="relu"),
    tf.keras.layers.Dense(50, activation="relu"),
    tf.keras.layers.Dense(5, activation='softmax') # classifying into 5 classes
])

# this configures the training of the model. Keras calls it "compiling" the model.
model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy']) # % of correct answers

# train the model
model.fit(dataset, ... )

688858c21e3beff2.png

Réseau de neurones dense

Il s'agit du réseau de neurones le plus simple pour la classification des images. Elle est constituée de "neurones" disposés en couches. La première couche traite les données d'entrée et transmet ses sorties à d'autres couches. Elle est appelée "dense", car chaque neurone est connecté à tous les neurones de la couche précédente.

c21bae6dade487bc.png

Vous pouvez alimenter un tel réseau en aplatissant les valeurs RVB de tous ses pixels dans un vecteur long et en les utilisant comme entrées. Ce n'est pas la meilleure technique pour la reconnaissance d'images, mais nous l'améliorerons plus tard.

Neurones, activations, ReLU

Un "neurone" calcule une somme pondérée de toutes ses entrées, ajoute une valeur appelée "biais" et alimente le résultat via une "fonction d'activation". Les pondérations et le biais sont inconnus au début. Elles seront initialisées de manière aléatoire et "apprises" en entraînant le réseau de neurones sur de nombreuses données connues.

644f4213a4ee70e5.png

La fonction d'activation la plus populaire est appelée RELU, ou unité de rectification linéaire. Comme vous pouvez le voir sur le graphique ci-dessus, il s'agit d'une fonction très simple.

Activation Softmax

Le réseau ci-dessus se termine par une couche à cinq neurones, car nous classons les fleurs en cinq catégories (rose, tulipe, pissenlit, marguerite, tournesol). Les neurones des couches intermédiaires sont activés à l'aide de la fonction d'activation RELU classique. Dans la dernière couche, nous souhaitons calculer des nombres compris entre 0 et 1 représentant la probabilité que cette fleur soit une rose, une tulipe, etc. Pour cela, nous allons utiliser une fonction d'activation appelée "softmax".

Pour appliquer la fonction softmax à un vecteur, vous devez prendre l'exponentielle de chaque élément, puis normaliser le vecteur, généralement à l'aide de la norme L1 (somme des valeurs absolues) afin que les valeurs totalisent 1 et puissent être interprétées comme des probabilités.

ef0d98c0952c262d.png d51252f75894479e.gif

Perte d'entropie croisée

Maintenant que notre réseau de neurones produit des prédictions à partir des images d'entrée, nous devons mesurer leur qualité, c'est-à-dire la distance entre ce que le réseau nous dit et les bonnes réponses, souvent appelées "libellés". N'oubliez pas que nous disposons d'étiquettes correctes pour toutes les images de l'ensemble de données.

N'importe quelle distance peut fonctionner, mais pour les problèmes de classification, la "distance d'entropie croisée" est la plus efficace. Nous appellerons cela notre fonction d'erreur ou "loss" :

7bdf8753d20617fb.png

Descente de gradient

"Entraîner" le réseau de neurones signifie en réalité utiliser des images et des étiquettes d'entraînement pour ajuster les poids et les biais afin de minimiser la fonction de perte d'entropie croisée. Voici comment cela fonctionne.

L'entropie croisée est une fonction des poids, des biais, des pixels de l'image d'entraînement et de sa classe connue.

Si nous calculons les dérivées partielles de l'entropie croisée par rapport à tous les poids et à tous les biais, nous obtenons un "gradient", calculé pour une image, un libellé et une valeur actuelle donnés des poids et des biais. N'oubliez pas que nous pouvons avoir des millions de poids et de biais. Le calcul du gradient semble donc être une tâche ardue. Heureusement, Tensorflow s'en charge pour nous. La propriété mathématique d'un dégradé est qu'il pointe "vers le haut". Puisque nous voulons aller là où l'entropie croisée est faible, nous allons dans la direction opposée. Nous mettons à jour les pondérations et les biais selon une fraction du gradient. Nous répétons ensuite la même chose à l'aide des prochains lots d'images et de libellés d'entraînement, dans une boucle d'entraînement. Espérons que cela converge vers un point où l'entropie croisée est minimale, même si rien ne garantit que ce minimum est unique.

gradient descent2.png

Mini-lot et momentum

Vous pouvez calculer votre gradient sur un seul exemple d'image et mettre à jour les poids et les biais immédiatement, mais le faire sur un lot de 128 images, par exemple, donne un gradient qui représente mieux les contraintes imposées par les différents exemples d'images et est donc susceptible de converger vers la solution plus rapidement. La taille du mini-lot est un paramètre ajustable.

Cette technique, parfois appelée "descente stochastique du gradient", présente un autre avantage plus pratique : travailler avec des lots signifie également travailler avec des matrices plus grandes, qui sont généralement plus faciles à optimiser sur les GPU et les TPU.

La convergence peut encore être un peu chaotique et peut même s'arrêter si le vecteur de gradient n'est que des zéros. Cela signifie-t-il que nous avons trouvé un minimum ? Non. Un composant de dégradé peut avoir une valeur minimale ou maximale égale à zéro. Avec un vecteur de gradient contenant des millions d'éléments, si tous sont des zéros, la probabilité que chaque zéro corresponde à un minimum et qu'aucun ne corresponde à un point maximal est assez faible. Dans un espace à plusieurs dimensions, les points d'équilibre sont assez courants, et nous ne voulons pas nous y arrêter.

52e824fe4716c4a0.png

Illustration : point de selle. Le dégradé est de 0, mais ce n'est pas un minimum dans toutes les directions. (Attribution de l'image Wikimedia: By Nicoguaro - Own work, CC BY 3.0)

La solution consiste à ajouter un peu d'élan à l'algorithme d'optimisation afin qu'il puisse passer les points d'inflection sans s'arrêter.

Glossaire

par lot ou par mini-lot : l'entraînement est toujours effectué sur des lots de données d'entraînement et d'étiquettes. Cela contribue à la convergence de l'algorithme. La dimension "lot" est généralement la première dimension des tenseurs de données. Par exemple, un tenseur de forme [100, 192, 192, 3] contient 100 images de 192 x 192 pixels avec trois valeurs par pixel (RVB).

perte d'entropie croisée: fonction de perte spéciale, souvent utilisée dans les classificateurs.

couche dense: couche de neurones où chaque neurone est connecté à tous les neurones de la couche précédente.

caractéristiques : les entrées d'un réseau de neurones sont parfois appelées "caractéristiques". L'art de déterminer quelles parties d'un ensemble de données (ou combinaisons de parties) doivent être transmises à un réseau de neurones pour obtenir de bonnes prédictions s'appelle l'ingénierie des caractéristiques.

Libellés : autre nom des "classes" ou des réponses correctes dans un problème de classification supervisée

taux d'apprentissage : fraction du gradient par laquelle les poids et les biais sont mis à jour à chaque itération de la boucle d'entraînement.

Logits : les sorties d'une couche de neurones avant l'application de la fonction d'activation sont appelées "logits". Ce terme vient de "fonction logistique" ou "fonction sigmoïde" qui était autrefois la fonction d'activation la plus populaire. L'expression "sorties de neurones avant la fonction logistique" a été raccourcie en "logits".

perte : fonction d'erreur qui compare les sorties du réseau de neurones aux bonnes réponses

neurone : calcule la somme pondérée de ses entrées, ajoute un biais et transmet le résultat via une fonction d'activation.

Encodage one-hot : la classe 3 sur 5 est encodée sous la forme d'un vecteur de cinq éléments, tous nuls, sauf le troisième, qui est égal à 1.

relu: unité de rectification linéaire. Fonction d'activation populaire pour les neurones.

sigmoïde : autre fonction d'activation qui était populaire autrefois et qui est toujours utile dans des cas particuliers.

softmax: fonction d'activation spéciale qui agit sur un vecteur, augmente la différence entre la composante la plus grande et les autres, et normalise également le vecteur pour obtenir une somme égale à 1, de sorte qu'il puisse être interprété comme un vecteur de probabilités. Utilisé comme dernière étape des classificateurs.

Tensor: un "Tensor" est semblable à une matrice, mais avec un nombre arbitraire de dimensions. Un Tensor unidimensionnel est un vecteur. Un tenseur à deux dimensions est une matrice. Vous pouvez également avoir des tenseurs à trois, quatre, cinq dimensions ou plus.

5. [NOUVELLE INFO] Réseaux de neurones convolutifs

En résumé

Si vous connaissez déjà tous les termes en gras dans le paragraphe suivant, vous pouvez passer à l'exercice suivant. Si vous débutez avec les réseaux de neurones convolutifs, poursuivez votre lecture.

convolutional.gif

Illustration: filtrer une image avec deux filtres successifs composés chacun de 4x4x3=48 pondérations apprises.

Voici à quoi ressemble un réseau de neurones convolutif simple dans Keras:

model = tf.keras.Sequential([
  # input: images of size 192x192x3 pixels (the three stands for RGB channels)
  tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu', input_shape=[192, 192, 3]),
  tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=6, padding='same', activation='relu'),
  tf.keras.layers.Flatten(),
  # classifying into 5 categories
  tf.keras.layers.Dense(5, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy'])

688858c21e3beff2.png

Introduction aux réseaux de neurones convolutifs

Dans une couche d'un réseau convolutif, un "neurone" effectue une somme pondérée des pixels juste au-dessus de lui, sur une petite région de l'image uniquement. Elle ajoute un biais et alimente la somme via une fonction d'activation, tout comme le ferait un neurone d'une couche dense standard. Cette opération est ensuite répétée sur l'ensemble de l'image à l'aide des mêmes poids. Souvenez-vous que dans les couches denses, chaque neurone avait ses propres pondérations. Ici, un seul "patch" de poids glisse sur l'image dans les deux sens (une "convolution"). La sortie comporte autant de valeurs qu'il y a de pixels dans l'image (un remplissage est toutefois nécessaire au niveau des bords). Il s'agit d'une opération de filtrage utilisant un filtre de 4x4x3 = 48 pondérations.

En revanche, 48 pondérations ne seront pas suffisantes. Pour ajouter d'autres degrés de liberté, nous répétons la même opération avec un nouvel ensemble de poids. Un nouvel ensemble de sorties de filtre est alors généré. Appelons-le "canal" de sorties,par analogie avec les canaux R,V et B de l'image d'entrée.

Screen Shot 2016-07-29 at 16.02.37.png

Les deux (ou plusieurs) ensembles de pondérations peuvent être additionnés sous la forme d'un seul Tensor en ajoutant une nouvelle dimension. Cela nous donne la forme générique du Tensor des pondérations pour une couche convolutive. Étant donné que le nombre de canaux d'entrée et de sortie sont des paramètres, nous pouvons commencer à empiler et à enchaîner des couches convolutives.

d1b557707bcd1cb9.png

Illustration: un réseau de neurones convolutif transforme des "cubes" de données en d'autres "cubes" de données.

Convolutions avec pas, pooling max

En effectuant les convolutions avec un pas de 2 ou 3, nous pouvons également réduire le cube de données résultant dans ses dimensions horizontales. Vous disposez pour cela de deux méthodes courantes:

  • Convolution échelonnée: un filtre glissant comme ci-dessus, mais avec un pas supérieur à 1
  • Max pooling: fenêtre mobile qui applique l'opération MAX (généralement sur des patches 2x2, répétés tous les deux pixels)

2b2d4263bb8470b.gif

Illustration : faire glisser la fenêtre de calcul de trois pixels réduit le nombre de valeurs de sortie. Les convolutions stylisées ou le pooling maximal (max. sur une fenêtre de 2x2 glissant d'un pas de 2) sont un moyen de réduire le cube de données dans les dimensions horizontales.

Classificateur convolutif

Enfin, nous ajoutons une tête de classification en aplatissant le dernier cube de données et en le transmettant via une couche dense activée par softmax. Un classificateur convolutif typique peut se présenter comme suit:

4a61aaffb6cba3d1.png

Illustration : un classificateur d'images utilisant des couches convolutives et softmax. Il utilise des filtres 3x3 et 1x1. Les couches maxpool prennent la valeur maximale de groupes de points de données 2x2. La tête de classification est implémentée avec une couche dense avec une activation softmax.

Dans Keras

La pile convolutive illustrée ci-dessus peut être écrite dans Keras comme suit:

model = tf.keras.Sequential([
  # input: images of size 192x192x3 pixels (the three stands for RGB channels)    
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu', input_shape=[192, 192, 3]),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=16, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=8, padding='same', activation='relu'),
  tf.keras.layers.Flatten(),
  # classifying into 5 categories
  tf.keras.layers.Dense(5, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy'])

6. Votre réseau de neurones convolutif personnalisé

Pratiquer

Voyons comment créer et entraîner un réseau de neurones convolutif de A à Z. L'utilisation d'un TPU nous permettra d'itérer très rapidement. Veuillez ouvrir le notebook suivant, exécuter les cellules (Maj+Entrée) et suivre les instructions chaque fois que le libellé "TRAVAIL REQUIS" s'affiche.

c3df49e90e5a654f.png Keras_Flowers_TPU (playground).ipynb

L'objectif est de battre la justesse de 75% du modèle d'apprentissage par transfert. Ce modèle avait un avantage, car il avait été pré-entraîné sur un ensemble de données de millions d'images, alors que nous n'en avons que 3 670 ici. Pouvez-vous au moins l'égaler ?

Informations supplémentaires

Combien de couches, quelle taille ?

Le choix de la taille des calques est plus un art qu’une science. Vous devez trouver le bon équilibre entre trop peu et trop de paramètres (pondérations et biais). Avec trop peu de poids, le réseau de neurones ne peut pas représenter la complexité des formes de fleurs. Si elles sont trop nombreuses, l'apprentissage peut être sujet à un surapprentissage, c'est-à-dire qu'il peut se spécialiser dans les images d'entraînement et ne pas être capable de généraliser. Avec de nombreux paramètres, l'entraînement du modèle est également lent. Dans Keras, la fonction model.summary() affiche le nombre de structures et de paramètres de votre modèle:

Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 192, 192, 16)      448       
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 192, 192, 30)      4350      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 96, 96, 30)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 96, 96, 60)        16260     
_________________________________________________________________
 ... 
_________________________________________________________________
global_average_pooling2d (Gl (None, 130)               0         
_________________________________________________________________
dense (Dense)                (None, 90)                11790     
_________________________________________________________________
dense_1 (Dense)              (None, 5)                 455       
=================================================================
Total params: 300,033
Trainable params: 300,033
Non-trainable params: 0
_________________________________________________________________

Voici quelques conseils:

  • Les réseaux de neurones "profonds" sont efficaces grâce à plusieurs couches. Pour ce problème simple de reconnaissance de fleurs, cinq à dix couches sont adaptées.
  • Utilisez des filtres de petite taille. En règle générale, les filtres 3x3 sont adaptés partout.
  • Les filtres 1x1 peuvent aussi être utilisés et sont peu coûteux. Ils ne "filtrent" rien, mais calculent des combinaisons linéaires de canaux. Remplacez-les par de vrais filtres. (Plus d'informations sur les "convolutions 1x1" dans la section suivante.)
  • Pour un problème de classification comme celui-ci, sous-échantillonnez fréquemment avec des couches de pooling maximal (ou des convolutions avec un pas supérieur à 1). Vous ne vous souciez pas de l'emplacement de la fleur, mais seulement du fait qu'il s'agit d'une rose ou d'un pissenlit. Il n'est donc pas important de perdre les informations X et Y, et le filtrage de petites zones est moins coûteux.
  • Le nombre de filtres devient généralement similaire au nombre de classes à la fin du réseau (pourquoi ? voir l'astuce "pooling moyen global" ci-dessous). Si vous effectuez une classification en centaines de classes, augmentez progressivement le nombre de filtres dans les couches consécutives. Pour l'ensemble de données sur les fleurs comportant cinq classes, filtrer avec seulement cinq filtres ne suffirait pas. Vous pouvez utiliser le même nombre de filtres dans la plupart des calques (par exemple, 32) et le réduire vers la fin.
  • La ou les couches denses finales sont coûteuses. Elles peuvent avoir plus de pondérations que toutes les couches convolutives combinées. Par exemple, même avec un résultat très raisonnable provenant du dernier cube de données de 24 x 24 x 10 points de données, une couche dense de 100 neurones coûte 24 x 24 x 10 x 100=576 000 pondérations. Essayez de réfléchir, ou essayez le pooling moyen global (voir ci-dessous).

Pooling moyen global

Au lieu d'utiliser une couche dense coûteuse à la fin d'un réseau de neurones convolutifs, vous pouvez diviser le "cube" de données entrantes en autant de parties que vous avez de classes, calculer la moyenne de leurs valeurs et les transmettre via une fonction d'activation softmax. Cette méthode de création de la tête de classification ne coûte aucune pondération. Dans Keras, la syntaxe est tf.keras.layers.GlobalAveragePooling2D().

93240029f59df7c2.png

Solution

Voici le notebook de la solution. Vous pouvez l'utiliser si vous êtes bloqué.

c3df49e90e5a654f.png Keras_Flowers_TPU (solution).ipynb

Points abordés

  • 🤔 Jeux avec des couches convolutives
  • 🤓 Expérimenté avec le pooling maximal, les pas, le pooling moyen mondial...
  • des itérations rapides sur un modèle réel, sur TPU

Veuillez prendre quelques instants pour passer en revue cette checklist.

7. Félicitations !

Vous avez créé votre premier réseau de neurones convolutif moderne et l'avez entraîné avec une précision de plus de 80 %, en itérant sur son architecture en quelques minutes grâce aux TPU. Veuillez passer au prochain atelier pour en savoir plus sur les architectures convolutives modernes:

TPU en pratique

Les TPU et les GPU sont disponibles sur Cloud AI Platform :

Enfin, vos commentaires nous intéressent. Veuillez nous indiquer si vous constatez une anomalie dans cet atelier ou si vous pensez qu'elle doit être améliorée. Vous pouvez nous faire part de vos commentaires via GitHub [lien de commentaires].

HR.png

Martin Görner ID small.jpg
Auteur : Martin Görner
Twitter : @martin_gorner

tensorflow logo.jpg
www.tensorflow.org