Aide à protéger la Grande barrière de corail avec tensorflow sur Kaggle Rejoignez Défi

Transférer l'apprentissage avec TensorFlow Hub

Voir sur TensorFlow.org Exécuter dans Google Colab Voir sur GitHub Télécharger le cahier Voir le modèle TF Hub

Tensorflow Hub est un référentiel de modèles de pré tensorflow formés.

Ce tutoriel montre comment :

  1. Utiliser des modèles de tensorflow Hub avec tf.keras .
  2. Utilisez un modèle de classification d'images de TensorFlow Hub.
  3. Faites un apprentissage par transfert simple pour affiner un modèle pour vos propres classes d'images.

Installer

import numpy as np
import time

import PIL.Image as Image
import matplotlib.pylab as plt

import tensorflow as tf
import tensorflow_hub as hub

import datetime

%load_ext tensorboard

Un classificateur ImageNet

Vous allez commencer à l'aide d' un modèle de classificateur pré-formé sur le IMAGEnet ensemble de données sans référence formation initiale requise!

Télécharger le classificateur

Sélectionnez un MobileNetV2 modèle pré-formé à partir tensorflow Hub et l' envelopper comme une couche Keras avec hub.KerasLayer . Tout modèle de classificateur d'image compatible à partir tensorflow Hub fonctionnera ici, y compris les exemples fournis dans le menu déroulant ci - dessous.

mobilenet_v2 ="https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/4"
inception_v3 = "https://tfhub.dev/google/imagenet/inception_v3/classification/5"

classifier_model = mobilenet_v2
IMAGE_SHAPE = (224, 224)

classifier = tf.keras.Sequential([
    hub.KerasLayer(classifier_model, input_shape=IMAGE_SHAPE+(3,))
])

Exécutez-le sur une seule image

Téléchargez une seule image pour essayer le modèle sur :

grace_hopper = tf.keras.utils.get_file('image.jpg','https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg')
grace_hopper = Image.open(grace_hopper).resize(IMAGE_SHAPE)
grace_hopper
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg
65536/61306 [================================] - 0s 0us/step
73728/61306 [====================================] - 0s 0us/step

png

grace_hopper = np.array(grace_hopper)/255.0
grace_hopper.shape
(224, 224, 3)

Ajouter une dimension de lot (avec np.newaxis ) et de transmettre l'image au modèle:

result = classifier.predict(grace_hopper[np.newaxis, ...])
result.shape
(1, 1001)

Le résultat est un vecteur de 1001 éléments de logits, évaluant la probabilité de chaque classe pour l'image.

L'ID de classe supérieure peut être trouvé avec tf.math.argmax :

predicted_class = tf.math.argmax(result[0], axis=-1)
predicted_class
<tf.Tensor: shape=(), dtype=int64, numpy=653>

Décoder les prédictions

Prenez le predicted_class ID (tel que 653 ) et récupérer les étiquettes ensemble de données IMAGEnet pour décoder les prédictions:

labels_path = tf.keras.utils.get_file('ImageNetLabels.txt','https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())
Downloading data from https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt
16384/10484 [==============================================] - 0s 0us/step
24576/10484 [======================================================================] - 0s 0us/step
plt.imshow(grace_hopper)
plt.axis('off')
predicted_class_name = imagenet_labels[predicted_class]
_ = plt.title("Prediction: " + predicted_class_name.title())

png

Apprentissage par transfert simple

Mais que se passe-t-il si vous souhaitez créer un classificateur personnalisé à l'aide de votre propre ensemble de données contenant des classes qui ne sont pas incluses dans l'ensemble de données ImageNet d'origine (sur lequel le modèle pré-entraîné a été entraîné) ?

Pour ce faire, vous pouvez :

  1. Sélectionnez un modèle pré-entraîné dans TensorFlow Hub ; et
  2. Réentraînez la (dernière) couche supérieure pour reconnaître les classes de votre ensemble de données personnalisé.

Base de données

Dans cet exemple, vous utiliserez l'ensemble de données TensorFlow Flowers :

data_root = 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 [==============================] - 11s 0us/step
228827136/228813984 [==============================] - 11s 0us/step

Tout d' abord, charger ces données dans le modèle en utilisant les données d'image de disque avec tf.keras.utils.image_dataset_from_directory , qui va générer un tf.data.Dataset :

batch_size = 32
img_height = 224
img_width = 224

train_ds = tf.keras.utils.image_dataset_from_directory(
  str(data_root),
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size
)

val_ds = tf.keras.utils.image_dataset_from_directory(
  str(data_root),
  validation_split=0.2,
  subset="validation",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size
)
Found 3670 files belonging to 5 classes.
Using 2936 files for training.
Found 3670 files belonging to 5 classes.
Using 734 files for validation.

L'ensemble de données Flowers comporte cinq classes :

class_names = np.array(train_ds.class_names)
print(class_names)
['daisy' 'dandelion' 'roses' 'sunflowers' 'tulips']

En second lieu , parce que la convention de tensorflow Hub pour les modèles d'image est d'attendre les entrées de flotteur dans le [0, 1] plage, utilisez la tf.keras.layers.Rescaling couche prétraiter pour y parvenir.

normalization_layer = tf.keras.layers.Rescaling(1./255)
train_ds = train_ds.map(lambda x, y: (normalization_layer(x), y)) # Where x—images, y—labels.
val_ds = val_ds.map(lambda x, y: (normalization_layer(x), y)) # Where x—images, y—labels.

Troisièmement, terminer la canalisation d'entrée à l'aide préchargement avec tamponnée Dataset.prefetch , de sorte que vous pouvez obtenir les données à partir du disque sans E / S des problèmes de blocage.

Voici quelques - unes des plus importantes tf.data méthodes que vous devez utiliser lorsque les données de chargement. Les lecteurs intéressés peuvent en apprendre davantage à leur sujet, ainsi que la façon dont les données du cache sur le disque et d' autres techniques, dans la Meilleure performance avec l'API tf.data guide.

AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
for image_batch, labels_batch in train_ds:
  print(image_batch.shape)
  print(labels_batch.shape)
  break
(32, 224, 224, 3)
(32,)
2021-12-04 02:22:15.303629: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

Exécuter le classificateur sur un lot d'images

Maintenant, exécutez le classificateur sur un lot d'images :

result_batch = classifier.predict(train_ds)
predicted_class_names = imagenet_labels[tf.math.argmax(result_batch, axis=-1)]
predicted_class_names
array(['daisy', 'coral fungus', 'rapeseed', ..., 'daisy', 'daisy',
       'birdhouse'], dtype='<U30')

Vérifiez comment ces prédictions correspondent aux images :

plt.figure(figsize=(10,9))
plt.subplots_adjust(hspace=0.5)
for n in range(30):
  plt.subplot(6,5,n+1)
  plt.imshow(image_batch[n])
  plt.title(predicted_class_names[n])
  plt.axis('off')
_ = plt.suptitle("ImageNet predictions")

png

Les résultats sont loin d'être parfaits, mais raisonnables étant donné que ce ne sont pas les classes pour lesquelles le modèle a été formé (à l'exception de "daisy").

Télécharger le modèle sans tête

TensorFlow Hub distribue également des modèles sans la couche de classification supérieure. Ceux-ci peuvent être utilisés pour effectuer facilement un apprentissage par transfert.

Sélectionnez un MobileNetV2 modèle pré-formé à partir tensorflow Hub . Tout modèle caractéristique d'image compatible vecteur de tensorflow Hub fonctionnera ici, y compris les exemples dans le menu déroulant.

mobilenet_v2 = "https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4"
inception_v3 = "https://tfhub.dev/google/tf2-preview/inception_v3/feature_vector/4"

feature_extractor_model = mobilenet_v2

Créer l'extracteur de fonction en enveloppant le modèle pré-formé en tant que couche Keras avec hub.KerasLayer . Utilisez le trainable=False argument pour geler les variables, de sorte que la formation ne modifie que la nouvelle couche de classificateur:

feature_extractor_layer = hub.KerasLayer(
    feature_extractor_model,
    input_shape=(224, 224, 3),
    trainable=False)

L'extracteur de caractéristiques renvoie un vecteur de 1280 long pour chaque image (la taille du lot d'images reste à 32 dans cet exemple) :

feature_batch = feature_extractor_layer(image_batch)
print(feature_batch.shape)
(32, 1280)

Attacher une tête de classement

Pour compléter le modèle, envelopper la couche d'extraction de caractéristique dans un tf.keras.Sequential modèle et ajouter une couche entièrement connectée pour la classification:

num_classes = len(class_names)

model = tf.keras.Sequential([
  feature_extractor_layer,
  tf.keras.layers.Dense(num_classes)
])

model.summary()
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 keras_layer_1 (KerasLayer)  (None, 1280)              2257984   
                                                                 
 dense (Dense)               (None, 5)                 6405      
                                                                 
=================================================================
Total params: 2,264,389
Trainable params: 6,405
Non-trainable params: 2,257,984
_________________________________________________________________
predictions = model(image_batch)
predictions.shape
TensorShape([32, 5])

Former le modèle

Utilisez Model.compile pour configurer le processus de formation et d' ajouter un tf.keras.callbacks.TensorBoard rappel pour créer des journaux de magasin:

model.compile(
  optimizer=tf.keras.optimizers.Adam(),
  loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
  metrics=['acc'])

log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(
    log_dir=log_dir,
    histogram_freq=1) # Enable histogram computation for every epoch.

Maintenant , utilisez la Model.fit méthode pour former le modèle.

Pour garder cet exemple court, vous vous entraînerez pour seulement 10 époques. Pour visualiser la progression de la formation dans TensorBoard plus tard, créer et stocker enregistre un un rappel TensorBoard .

NUM_EPOCHS = 10

history = model.fit(train_ds,
                    validation_data=val_ds,
                    epochs=NUM_EPOCHS,
                    callbacks=tensorboard_callback)
Epoch 1/10
92/92 [==============================] - 7s 42ms/step - loss: 0.7709 - acc: 0.7262 - val_loss: 0.4437 - val_acc: 0.8597
Epoch 2/10
92/92 [==============================] - 3s 31ms/step - loss: 0.3763 - acc: 0.8774 - val_loss: 0.3496 - val_acc: 0.8842
Epoch 3/10
92/92 [==============================] - 3s 31ms/step - loss: 0.2950 - acc: 0.9074 - val_loss: 0.3159 - val_acc: 0.8965
Epoch 4/10
92/92 [==============================] - 3s 31ms/step - loss: 0.2459 - acc: 0.9278 - val_loss: 0.2997 - val_acc: 0.8978
Epoch 5/10
92/92 [==============================] - 3s 31ms/step - loss: 0.2110 - acc: 0.9387 - val_loss: 0.2906 - val_acc: 0.9019
Epoch 6/10
92/92 [==============================] - 3s 32ms/step - loss: 0.1842 - acc: 0.9503 - val_loss: 0.2850 - val_acc: 0.9074
Epoch 7/10
92/92 [==============================] - 3s 32ms/step - loss: 0.1626 - acc: 0.9595 - val_loss: 0.2813 - val_acc: 0.9074
Epoch 8/10
92/92 [==============================] - 3s 31ms/step - loss: 0.1448 - acc: 0.9653 - val_loss: 0.2788 - val_acc: 0.9114
Epoch 9/10
92/92 [==============================] - 3s 31ms/step - loss: 0.1298 - acc: 0.9707 - val_loss: 0.2770 - val_acc: 0.9142
Epoch 10/10
92/92 [==============================] - 3s 31ms/step - loss: 0.1169 - acc: 0.9741 - val_loss: 0.2758 - val_acc: 0.9142

Démarrez TensorBoard pour voir comment les métriques changent à chaque époque et pour suivre d'autres valeurs scalaires :

%tensorboard --logdir logs/fit

Consulter les pronostics

Obtenez la liste ordonnée des noms de classe à partir des prédictions du modèle :

predicted_batch = model.predict(image_batch)
predicted_id = tf.math.argmax(predicted_batch, axis=-1)
predicted_label_batch = class_names[predicted_id]
print(predicted_label_batch)
['roses' 'dandelion' 'tulips' 'sunflowers' 'dandelion' 'roses' 'dandelion'
 'roses' 'tulips' 'dandelion' 'tulips' 'tulips' 'sunflowers' 'tulips'
 'dandelion' 'roses' 'daisy' 'tulips' 'dandelion' 'dandelion' 'dandelion'
 'tulips' 'sunflowers' 'roses' 'sunflowers' 'dandelion' 'tulips' 'roses'
 'roses' 'sunflowers' 'tulips' 'sunflowers']

Tracez les prédictions du modèle :

plt.figure(figsize=(10,9))
plt.subplots_adjust(hspace=0.5)

for n in range(30):
  plt.subplot(6,5,n+1)
  plt.imshow(image_batch[n])
  plt.title(predicted_label_batch[n].title())
  plt.axis('off')
_ = plt.suptitle("Model predictions")

png

Exportez et rechargez votre modèle

Maintenant que vous avez entraîné le modèle, exportez-le en tant que SavedModel pour le réutiliser ultérieurement.

t = time.time()

export_path = "/tmp/saved_models/{}".format(int(t))
model.save(export_path)

export_path
2021-12-04 02:23:00.315867: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/saved_models/1638584578/assets
INFO:tensorflow:Assets written to: /tmp/saved_models/1638584578/assets
'/tmp/saved_models/1638584578'

Confirmez que vous pouvez recharger le SavedModel et que le modèle est capable de générer les mêmes résultats :

reloaded = tf.keras.models.load_model(export_path)
result_batch = model.predict(image_batch)
reloaded_result_batch = reloaded.predict(image_batch)
abs(reloaded_result_batch - result_batch).max()
0.0
reloaded_predicted_id = tf.math.argmax(reloaded_result_batch, axis=-1)
reloaded_predicted_label_batch = class_names[reloaded_predicted_id]
print(reloaded_predicted_label_batch)
['roses' 'dandelion' 'tulips' 'sunflowers' 'dandelion' 'roses' 'dandelion'
 'roses' 'tulips' 'dandelion' 'tulips' 'tulips' 'sunflowers' 'tulips'
 'dandelion' 'roses' 'daisy' 'tulips' 'dandelion' 'dandelion' 'dandelion'
 'tulips' 'sunflowers' 'roses' 'sunflowers' 'dandelion' 'tulips' 'roses'
 'roses' 'sunflowers' 'tulips' 'sunflowers']
plt.figure(figsize=(10,9))
plt.subplots_adjust(hspace=0.5)
for n in range(30):
  plt.subplot(6,5,n+1)
  plt.imshow(image_batch[n])
  plt.title(reloaded_predicted_label_batch[n].title())
  plt.axis('off')
_ = plt.suptitle("Model predictions")

png

Prochaines étapes

Vous pouvez utiliser le SavedModel à la charge pour l' inférence ou le convertir en un tensorflow Lite modèle (pour l' apprentissage de la machine sur l'appareil) ou un TensorFlow.js modèle (pour l' apprentissage de la machine en JavaScript).

Découvrez plus de tutoriels pour apprendre à utiliser des modèles pré-formés à partir tensorflow Hub sur l' image, texte, audio et vidéo tâches.