Voir sur TensorFlow.org | Exécuter dans Google Colab | Afficher sur GitHub | Télécharger le cahier | Voir le modèle TF Hub |
TensorFlow Hub est un référentiel de modèles TensorFlow pré-entraînés.
Ce didacticiel montre comment :
- Utilisez des modèles de TensorFlow Hub avec
tf.keras
. - Utilisez un modèle de classification d'images de TensorFlow Hub.
- Effectuez 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 commencerez par utiliser un modèle de classificateur pré-formé sur l'ensemble de données de référence ImageNet - aucune formation initiale requise !
Télécharger le classificateur
Sélectionnez un modèle pré-entraîné MobileNetV2 à partir de TensorFlow Hub et encapsulez-le en tant que couche Keras avec hub.KerasLayer
. Tout modèle de classificateur d'images compatible de 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
grace_hopper = np.array(grace_hopper)/255.0
grace_hopper.shape
(224, 224, 3)
Ajoutez une dimension de lot (avec np.newaxis
) et transmettez l'image au modèle :
result = classifier.predict(grace_hopper[np.newaxis, ...])
result.shape
(1, 1001)
Le résultat est un vecteur de logits à 1001 éléments, évaluant la probabilité de chaque classe pour l'image.
L'ID de classe supérieur 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écodez les prédictions
Prenez l'ID predicted_class
(tel que 653
) et récupérez les étiquettes de l'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())
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é-formé a été formé) ?
Pour ce faire, vous pouvez :
- Sélectionnez un modèle pré-formé à partir de TensorFlow Hub ; et
- Réentraînez la couche supérieure (dernière) pour reconnaître les classes de votre jeu de données personnalisé.
Base de données
Dans cet exemple, vous utiliserez l'ensemble de données de fleurs TensorFlow :
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 [==============================] - 7s 0us/step 228827136/228813984 [==============================] - 7s 0us/step
Tout d'abord, chargez ces données dans le modèle en utilisant les données d'image hors disque avec tf.keras.utils.image_dataset_from_directory
, qui générera 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.
Le jeu de données flowers a cinq classes :
class_names = np.array(train_ds.class_names)
print(class_names)
['daisy' 'dandelion' 'roses' 'sunflowers' 'tulips']
Deuxièmement, étant donné que la convention de TensorFlow Hub pour les modèles d'image est d'attendre des entrées flottantes dans la plage [0, 1]
, utilisez la couche de prétraitement tf.keras.layers.Rescaling
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, terminez le pipeline d'entrée en utilisant la prélecture tamponnée avec Dataset.prefetch
, afin que vous puissiez produire les données du disque sans problèmes de blocage d'E/S.
Voici quelques-unes des méthodes tf.data
les plus importantes que vous devez utiliser lors du chargement de données. Les lecteurs intéressés peuvent en savoir plus à leur sujet, ainsi que sur la façon de mettre en cache des données sur le disque et d'autres techniques, dans le guide Meilleures performances avec l'API tf.data .
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,) 2022-01-26 05:06:19.465331: 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 classifieur 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 s'alignent sur les 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")
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é (sauf pour "marguerite").
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 modèle pré-entraîné MobileNetV2 à partir de TensorFlow Hub . Tout modèle vectoriel de caractéristiques d'image compatible de TensorFlow Hub fonctionnera ici, y compris les exemples du 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éez l'extracteur de caractéristiques en enveloppant le modèle pré-formé en tant que couche Keras avec hub.KerasLayer
. Utilisez l'argument trainable=False
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 1 280 longs 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)
Joindre un chef de classement
Pour terminer le modèle, encapsulez la couche d'extraction d'entités dans un modèle tf.keras.Sequential
et ajoutez 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 ajoutez un rappel tf.keras.callbacks.TensorBoard
pour créer et stocker des journaux :
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.
Utilisez maintenant la méthode Model.fit
pour entraîner le modèle.
Pour que cet exemple soit court, vous ne vous entraînerez que pendant 10 époques. Pour visualiser ultérieurement la progression de l'entraînement dans TensorBoard, créez et stockez des journaux dans 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.7904 - acc: 0.7210 - val_loss: 0.4592 - val_acc: 0.8515 Epoch 2/10 92/92 [==============================] - 3s 33ms/step - loss: 0.3850 - acc: 0.8713 - val_loss: 0.3694 - val_acc: 0.8787 Epoch 3/10 92/92 [==============================] - 3s 33ms/step - loss: 0.3027 - acc: 0.9057 - val_loss: 0.3367 - val_acc: 0.8856 Epoch 4/10 92/92 [==============================] - 3s 33ms/step - loss: 0.2524 - acc: 0.9237 - val_loss: 0.3210 - val_acc: 0.8869 Epoch 5/10 92/92 [==============================] - 3s 33ms/step - loss: 0.2164 - acc: 0.9373 - val_loss: 0.3124 - val_acc: 0.8896 Epoch 6/10 92/92 [==============================] - 3s 33ms/step - loss: 0.1888 - acc: 0.9469 - val_loss: 0.3070 - val_acc: 0.8937 Epoch 7/10 92/92 [==============================] - 3s 33ms/step - loss: 0.1668 - acc: 0.9550 - val_loss: 0.3032 - val_acc: 0.9005 Epoch 8/10 92/92 [==============================] - 3s 33ms/step - loss: 0.1487 - acc: 0.9619 - val_loss: 0.3004 - val_acc: 0.9005 Epoch 9/10 92/92 [==============================] - 3s 33ms/step - loss: 0.1335 - acc: 0.9687 - val_loss: 0.2981 - val_acc: 0.9019 Epoch 10/10 92/92 [==============================] - 3s 33ms/step - loss: 0.1206 - acc: 0.9748 - val_loss: 0.2964 - val_acc: 0.9046
Démarrez le TensorBoard pour voir comment les métriques changent à chaque époque et pour suivre d'autres valeurs scalaires :
%tensorboard --logdir logs/fit
Vérifiez 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")
Exportez et rechargez votre modèle
Maintenant que vous avez formé le modèle, exportez-le en tant que modèle enregistré pour le réutiliser ultérieurement.
t = time.time()
export_path = "/tmp/saved_models/{}".format(int(t))
model.save(export_path)
export_path
2022-01-26 05:07:03.429901: 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/1643173621/assets INFO:tensorflow:Assets written to: /tmp/saved_models/1643173621/assets '/tmp/saved_models/1643173621'
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")
Prochaines étapes
Vous pouvez utiliser le SavedModel pour le charger à des fins d'inférence ou le convertir en un modèle TensorFlow Lite (pour l'apprentissage automatique sur appareil) ou un modèle TensorFlow.js (pour l'apprentissage automatique en JavaScript).
Découvrez d' autres didacticiels pour apprendre à utiliser des modèles pré-entraînés de TensorFlow Hub sur des tâches d'image, de texte, d'audio et de vidéo.