20 Déc

TensorFlow Hub

TensorFlow Hub

Concevoir et mettre au point des modèles de Machine Learning/Deep Learning nécessite d’y consacrer beaucoup de temps et de disposer de connaissances multiples et variées.

Démarrer from scratch n’a pas de sens. Il faut impérativement s’appuyer sur le travail des autres. D’où l’importance des communautés.

C’est ce qu’a bien compris Google en créant tout un écosystème autour de TensorFlow, et au sein de cet environnement, TensorFlow Hub

Le Hub est en ensemble de ressources pour se former au ML, un forum d’échanges et une mailing list sur Tf mais c’est surtout des modèles prêts à l’emploi.

Ces modèles sont répartis en trois catégories : image, texte, et vidéo.

Pour expliquer comment bénéficier des modèles sauvegardés sur le Hub, le tutoriel TF Hub for TF2: Retraining an image classifier est une bonne solution. La version que nous présentons est celle disponible sur notre Drive. Pour la version originale c’est ici.

Tutoriel

Si vous n’êtes pas familier avec le traitement d’images et avec TensorFlow 2.0, renoncez à la lecture de la suite !

Le tutoriel présente un cas de Transfer Learning pour la classification d’images de fleurs.

Imports

Tout d’abord on s’assure d’utiliser la version 2.x

try:
  # %tensorflow_version only exists in Colab.
  %tensorflow_version 2.x
except Exception:
  pass

Puis on importe les packages habituels.

import itertools
import os

import matplotlib.pylab as plt
import numpy as np

import tensorflow as tf
import tensorflow_hub as hub

print("TF version:", tf.__version__)
print("Hub version:", hub.__version__)
print("GPU is", "available" if tf.test.is_gpu_available() else "NOT AVAILABLE")
TF version: 2.1.0-rc1
Hub version: 0.7.0
GPU is available

Modèle

module_selection = ("mobilenet_v2_100_224", 224) 
#@param ["(\"mobilenet_v2_100_224\", 224)", "(\"inception_v3\", 299)"] {type:"raw", allow-input: true}

handle_base, pixels = module_selection

MODULE_HANDLE="https://tfhub.dev/google/imagenet/{}/feature_vector/4".format(handle_base)
IMAGE_SIZE = (pixels, pixels)

print("Using {} with input size {}".format(MODULE_HANDLE, IMAGE_SIZE))
BATCH_SIZE = 32 #@param {type:"integer"}
Using https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/4 with input size (224, 224)

Tout ceci requiert quelques commentaires !

Le modèle utilisé est mobilenet_v2_100_224. Ce modèle est décrit amplement ici.

This TF Hub model uses the TF-Slim implementation of mobilenet_v2 with a depth multiplier of 1.0 and an input size of 224×224 pixels.

TF2 SavedModel

L’apprentissage de ce modèle s’est fait sur ImageNet. Les images en input doivent être carrées 224.

Jeu de données

On applique le modèle à notre jeu de données.

data_dir = tf.keras.utils.get_file(
    'flower_photos',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
    untar=True)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz
228818944/228813984 [==============================] - 2s 0us/step

Les photos sont réparties en 5 catégories : daisy (marguerites), dandelion (pissenlits), roses, sunflowers (tournesols), tulips. Il y a en tout 3670 photos.

Pré-processing

datagen_kwargs = dict(rescale=1./255, validation_split=.20)
dataflow_kwargs = dict(target_size=IMAGE_SIZE, batch_size=BATCH_SIZE,
                   interpolation="bilinear")

valid_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    **datagen_kwargs)
valid_generator = valid_datagen.flow_from_directory(
    data_dir, subset="validation", shuffle=False, **dataflow_kwargs)

Les images sont normalisées (rescale=1./255), séparées en un jeu d’apprentissage et un de validation (validation_split=.20)

Le batch size est à 32 (par défaut), l’interpolation bilinéaire.

On peut ensuite choisir (ou pas) de faire de la data augmentation. Les performances dans le 1er cas seront a priori meilleures.

do_data_augmentation = False #@param {type:"boolean"}
if do_data_augmentation:
  train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
      rotation_range=40,
      horizontal_flip=True,
      width_shift_range=0.2, height_shift_range=0.2,
      shear_range=0.2, zoom_range=0.2,
      **datagen_kwargs)
else:
  train_datagen = valid_datagen
train_generator = train_datagen.flow_from_directory(
    data_dir, subset="training", shuffle=True, **dataflow_kwargs)
Found 731 images belonging to 5 classes.
Found 2939 images belonging to 5 classes.

Définition du modèle

do_fine_tuning = False #@param {type:"boolean"}

print("Building model with", MODULE_HANDLE)
model = tf.keras.Sequential([
    hub.KerasLayer(MODULE_HANDLE, trainable=do_fine_tuning),
    tf.keras.layers.Dropout(rate=0.2),
    tf.keras.layers.Dense(train_generator.num_classes, activation='softmax',
                          kernel_regularizer=tf.keras.regularizers.l2(0.0001))
])
model.build((None,)+IMAGE_SIZE+(3,))
model.summary()
Building model with https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/4
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
keras_layer (KerasLayer)     multiple                  2257984   
_________________________________________________________________
dropout (Dropout)            multiple                  0         
_________________________________________________________________
dense (Dense)                multiple                  6405      
=================================================================
Total params: 2,264,389
Trainable params: 6,405
Non-trainable params: 2,257,984

Le modèle est décrit en mode séquentiel. Tout d’abord on indique lequel on importe pour le transfer learning (mobilenet_v2), puis on ajoute à ce modèle un Dropout (0.2) et on termine par un Softmax (5 classes)

Apprentissage

Le reste est plus classique :

model.compile(
  optimizer=tf.keras.optimizers.SGD(lr=0.005, momentum=0.9), 
  loss=tf.keras.losses.CategoricalCrossentropy(label_smoothing=0.1),
  metrics=['accuracy'])
steps_per_epoch = train_generator.samples // train_generator.batch_size
validation_steps = valid_generator.samples // valid_generator.batch_size
hist = model.fit_generator(
    train_generator,
    epochs=5, steps_per_epoch=steps_per_epoch,
    validation_data=valid_generator,
    validation_steps=validation_steps).history

18 Déc

Transfer learning – l’apprentissage par transfert

L’apprentissage automatique et plus particulièrement l’apprentissage profond obtiennent aujourd’hui des performances spectaculaires, inespérées il y a quelques années, dans certains domaines comme la vision et le traitement du langage naturel.

Le « deep learning« , l’apprentissage profond à l’aide de réseaux de neurones, n’atteint ces prouesses que parce que le volume de données utilisé pour l’apprentissage est très élevé et parce que la puissance de calcul requise est désormais disponible grâce aux GPU (Graphics Processing Units) et TPU (TensorFlow Processing Units)

Les réseaux de neurones ont souvent plusieurs dizaines de couches, des centaines de milliers de paramètres et utilisent jusqu’à plusieurs centaines de milliers, voire des millions de données d’apprentissage. 

Par exemple, pour entraîner un réseau de neurones qui servira à la reconnaissance des visages, il faut disposer de plus de 1 million d’images et effectuer des calculs durant plusieurs journées. 

On pourrait légitiment penser que ces contraintes (volume de données & temps de calcul requis) annihilent toute possibilité de profiter de ces technologies des réseaux de neurones lorsque le volume de données est faible. Or il n’en est rien. Grâce au Transfer Learning.

L’apprentissage par transfert 

L’apprentissage par transfert est ce que nous faisons tous les jours, c’est profiter d’un apprentissage acquis précédemment, pour, par analogie, résoudre un problème similaire mais différent. 

Par exemple, il est plus facile d’apprendre à piloter une moto si on sait déjà faire du vélo. 

Le transfer learning des réseaux de neurones s’appuie sur le même principe. Si on a entraîné un réseau de neurones à différencier des chiens , des chats, à partir de photos, alors on pourra s’appuyer sur ce réseau pour deviner à quelle race appartient un chien. Et même encore mieux, on pourra utiliser notre réseau pour catégoriser des grenouilles !

Ceci est possible parce les réseaux de neurones sont empilés en couches, chacune apprenant de la précédente. C’est ainsi qu’un CNN (réseau de neurones par convolution) aura ses premières couches spécialisées dans la reconnaissance de formes simples (lignes horizontales, lignes verticales, diagonales, …), ses couches suivantes dédiées à la reconnaissance de formes un peu plus complexes (cercle, carré, triangle, …), ses couches suivantes orientées vers, par exemple la reconnaissance de visages, la reconnaissance de parties du corps, …. et les dernières couches se consacreront à ce qui fait l’objet de l’apprentissage de ce réseau (par exemple chiens ou chats).

Au cours de la phase d’apprentissage, le réseau de de neurones modifie ses poids.

Les poids (qui sont des nombres) et l’architecture du réseau suffisent à le caractériser (hormis quelques paramètres non décrits ici). Il est donc très facile de bénéficier d’un réseau de neurones existant, sans avoir à recalculer ce qui lui a permis d’atteindre sa configuration optimale, calculée pour le jeu de données et le problème pour lequel il a été conçu.

Exemple

ImageNet est une base de données d’images, librement accessibles (sous conditions) sur Internet. Cette base de données contient 14 millions d’images, réparties en 1000 catégories. 

Il existe depuis 2010 une compétition de machine learning, qui consiste à évaluer les meilleurs algorithmes de traitement d’images sur ce jeu de données ImageNet. Le nom de ce challenge est ILSVRC.

Depuis 2012, année du premier réseau de neurones profond à convolution (AlexNet) tous les vainqueurs utilisent le Deep Learning.

Il est d’usage de tester les nouvelles architectures de réseaux de neurones sur le jeu de données ImageNet. C’est ce qu’on fait Kaiming He & al. de Microsoft avec leur architecture dénommée ResNet.

Les réseaux ResNet obtiennent de très bonnes performances sur ImageNet (>93%) . Il existe plusieurs variations de ResNet(s) selon leur profondeur. Les équipes qui ont créé ResNet ont mis à la disposition générale leurs travaux et leurs résultats ! Ce qui nous permet d’en bénéficier pour faire du transfer learning.

Il est donc permis à chacun, sans avoir des millions d’images et sans avoir à effectuer des jours de calcul, de s’appuyer sur ResNet pour classer ses propres images. 

Il vous suffit (pour simplifier) de remplacer la ou les dernières couches du réseau ResNet par une couche dédiée à votre problème et d’entraîner le réseau sur vos données, tout en gardant (en partie) les poids calculés par ResNet.

ResNet n’est pas la seule architecture dont on peu bénéficier. Keras en propose beaucoup d’autres, comme XceptionVGG16VGG19, … DenseNetNASNet tous entraînés sur ImageNet.

Résumé

Le transfer learning est une méthode qui permet de faciliter un apprentissage à partir d’un d’un apprentissage précédent, à condition qu’il y ait une cohérence entre les deux apprentissages. 

Il va de soi qu’on ne pourra pas bénéficier de ResNet pour de la traduction automatique. 

Le cas typique d’utilisation du transfer learning est celui où vous avez peu de données (par exemple un millier de photos de champignons) et où vous apprenez d’un réseau de neurones qui a appris à reconnaître des milliers d’images (dont éventuellement des champignons) pour catégoriser vos espèces de champignons.