Visualizza su TensorFlow.org | Esegui in Google Colab | Visualizza su GitHub | Scarica quaderno | Vedi modello TF Hub |
TensorFlow Hub è un repository di modelli TensorFlow pre-addestrati.
Questo tutorial mostra come:
- Usa i modelli di TensorFlow Hub con
tf.keras
. - Utilizzare un modello di classificazione delle immagini da TensorFlow Hub.
- Esegui un semplice trasferimento di apprendimento per mettere a punto un modello per le tue classi di immagini.
Impostare
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 classificatore ImageNet
Inizierai utilizzando un modello di classificatore pre-addestrato sul set di dati benchmark ImageNet , senza necessità di formazione iniziale!
Scarica il classificatore
Seleziona un modello MobileNetV2 pre-addestrato da TensorFlow Hub e avvolgilo come un livello Keras con hub.KerasLayer
. Qualsiasi modello di classificatore di immagini compatibile di TensorFlow Hub funzionerà qui, inclusi gli esempi forniti nel menu a discesa seguente.
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,))
])
Eseguilo su una singola immagine
Scarica una singola immagine su cui provare il modello:
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)
Aggiungi una dimensione batch (con np.newaxis
) e passa l'immagine al modello:
result = classifier.predict(grace_hopper[np.newaxis, ...])
result.shape
(1, 1001)
Il risultato è un vettore di logit a 1001 elementi, che valuta la probabilità di ciascuna classe per l'immagine.
L'ID della classe superiore può essere trovato con tf.math.argmax
:
predicted_class = tf.math.argmax(result[0], axis=-1)
predicted_class
<tf.Tensor: shape=(), dtype=int64, numpy=653>
Decodifica le previsioni
Prendi il predicted_class
ID (come 653
) e recupera le etichette del set di dati ImageNet per decodificare le previsioni:
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())
Semplice trasferimento di apprendimento
Ma cosa succede se si desidera creare un classificatore personalizzato utilizzando il proprio set di dati con classi che non sono incluse nel set di dati ImageNet originale (su cui è stato addestrato il modello pre-addestrato)?
Per farlo, puoi:
- Seleziona un modello pre-addestrato da TensorFlow Hub; e
- Riaddestra il livello superiore (ultimo) per riconoscere le classi dal tuo set di dati personalizzato.
Set di dati
In questo esempio, utilizzerai il set di dati dei fiori 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
Innanzitutto, carica questi dati nel modello utilizzando i dati dell'immagine fuori disco con tf.keras.utils.image_dataset_from_directory
, che genererà 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.
Il set di dati dei fiori ha cinque classi:
class_names = np.array(train_ds.class_names)
print(class_names)
['daisy' 'dandelion' 'roses' 'sunflowers' 'tulips']
In secondo luogo, poiché la convenzione di TensorFlow Hub per i modelli di immagine prevede input float nell'intervallo [0, 1]
, utilizzare il livello di preelaborazione tf.keras.layers.Rescaling
per ottenere questo risultato.
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.
In terzo luogo, termina la pipeline di input utilizzando il precaricamento nel buffer con Dataset.prefetch
, in modo da poter restituire i dati dal disco senza problemi di blocco I/O.
Questi sono alcuni dei metodi tf.data
più importanti che dovresti usare durante il caricamento dei dati. I lettori interessati possono saperne di più su di loro, nonché su come memorizzare nella cache i dati su disco e altre tecniche, nella guida all'API tf.data per prestazioni migliori .
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.
Esegui il classificatore su un batch di immagini
Ora, esegui il classificatore su un batch di immagini:
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')
Controlla come queste previsioni si allineano con le immagini:
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")
I risultati sono tutt'altro che perfetti, ma ragionevoli considerando che queste non sono le classi per le quali il modello è stato addestrato (tranne "daisy").
Scarica il modello senza testa
TensorFlow Hub distribuisce anche modelli senza il livello di classificazione superiore. Questi possono essere utilizzati per eseguire facilmente l'apprendimento di trasferimento.
Seleziona un modello MobileNetV2 pre-addestrato da TensorFlow Hub . Qualsiasi modello vettoriale di funzionalità dell'immagine compatibile da TensorFlow Hub funzionerà qui, inclusi gli esempi dal menu a discesa.
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
Crea l'estrattore di funzionalità avvolgendo il modello pre-addestrato come un livello Keras con hub.KerasLayer
. Usa l'argomento trainable=False
per bloccare le variabili, in modo che l'addestramento modifichi solo il nuovo livello del classificatore:
feature_extractor_layer = hub.KerasLayer(
feature_extractor_model,
input_shape=(224, 224, 3),
trainable=False)
L'estrattore di funzionalità restituisce un vettore lungo 1280 per ogni immagine (in questo esempio la dimensione del batch dell'immagine rimane a 32):
feature_batch = feature_extractor_layer(image_batch)
print(feature_batch.shape)
(32, 1280)
Allega una testata di classificazione
Per completare il modello, avvolgi il livello dell'estrattore di funzionalità in un modello tf.keras.Sequential
e aggiungi un livello completamente connesso per la classificazione:
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])
Allena il modello
Utilizzare Model.compile
per configurare il processo di addestramento e aggiungere un callback tf.keras.callbacks.TensorBoard
per creare e archiviare i registri:
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.
Ora usa il metodo Model.fit
per addestrare il modello.
Per mantenere questo esempio breve, ti allenerai solo per 10 epoche. Per visualizzare l'avanzamento della formazione in TensorBoard in un secondo momento, creare e archiviare i registri e una richiamata 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
Avvia TensorBoard per visualizzare come cambiano le metriche a ogni epoca e per tenere traccia di altri valori scalari:
%tensorboard --logdir logs/fit
Controlla le previsioni
Ottieni l'elenco ordinato dei nomi delle classi dalle previsioni del modello:
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']
Traccia le previsioni del modello:
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")
Esporta e ricarica il tuo modello
Ora che hai addestrato il modello, esportalo come SavedModel per riutilizzarlo in seguito.
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'
Conferma che puoi ricaricare SavedModel e che il modello è in grado di produrre gli stessi risultati:
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")
Prossimi passi
Puoi utilizzare SavedModel per caricare per l'inferenza o convertirlo in un modello TensorFlow Lite (per l'apprendimento automatico sul dispositivo) o in un modello TensorFlow.js (per l'apprendimento automatico in JavaScript).
Scopri altri tutorial per imparare a utilizzare i modelli pre-addestrati da TensorFlow Hub su attività di immagini, testo, audio e video.