Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Trasferisci l'apprendimento con TensorFlow Hub

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza su GitHub Scarica notebook Vedi modello TF Hub

TensorFlow Hub è un repository di modelli TensorFlow pre-addestrati.

Questo tutorial mostra come:

  1. Utilizza i modelli di TensorFlow Hub con tf.keras
  2. Utilizza un modello di classificazione delle immagini da TensorFlow Hub
  3. 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

Un classificatore ImageNet

Inizierai utilizzando un modello di classificazione pre-addestrato per scattare un'immagine e prevedere di cosa si tratta - non è richiesta alcuna formazione!

Scarica il classificatore

Utilizza hub.KerasLayer per caricare un modello MobileNetV2 da TensorFlow Hub. Qualsiasi modello di classificatore di immagini compatibile da tfhub.dev funzionerà qui.

classifier_model ="https://tfhub.dev/google/tf2-preview/mobilenet_v2/classification/4" 
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 per 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

png

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

Aggiungi una dimensione batch e passa l'immagine al modello.

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

Il risultato è un vettore di 1001 elementi di logit, che valuta la probabilità di ciascuna classe per l'immagine.

Quindi l'ID della classe superiore può essere trovato con argmax:

predicted_class = np.argmax(result[0], axis=-1)
predicted_class
653

Decodifica le previsioni

Prendi l'ID della classe previsto e recupera le etichette 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

plt.imshow(grace_hopper)
plt.axis('off')
predicted_class_name = imagenet_labels[predicted_class]
_ = plt.title("Prediction: " + predicted_class_name.title())

png

Semplice trasferimento di apprendimento

Ma cosa succede se si desidera addestrare un classificatore per un set di dati con classi diverse? Puoi anche utilizzare un modello da TFHub per addestrare un classificatore di immagini personalizzato riqualificando il livello superiore del modello per riconoscere le classi nel nostro set di dati.

Set di dati

Per 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 [==============================] - 5s 0us/step

Il modo più semplice per caricare questi dati nel nostro modello è usare tf.keras.preprocessing.image.ImageDataGenerator ,

Le convenzioni di TensorFlow Hub per i modelli di immagine prevedono che gli input fluttuino nell'intervallo [0, 1] . Utilizzare il parametro di rescale ImageDataGenerator per ottenere ciò.

image_generator = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1/255)
image_data = image_generator.flow_from_directory(str(data_root), target_size=IMAGE_SHAPE)
Found 3670 images belonging to 5 classes.

L'oggetto risultante è un iteratore che restituisce coppie image_batch, label_batch .

for image_batch, label_batch in image_data:
  print("Image batch shape: ", image_batch.shape)
  print("Label batch shape: ", label_batch.shape)
  break
Image batch shape:  (32, 224, 224, 3)
Label batch shape:  (32, 5)

Esegui il classificatore su un batch di immagini

Ora esegui il classificatore sul batch di immagini.

result_batch = classifier.predict(image_batch)
result_batch.shape
(32, 1001)
predicted_class_names = imagenet_labels[np.argmax(result_batch, axis=-1)]
predicted_class_names
array(['daisy', 'bee', 'barn spider', 'daisy', 'balloon', 'daisy',
       'cardoon', 'daisy', 'daisy', 'diaper', 'quill', 'wreck', 'hip',
       'daisy', 'vase', 'daisy', 'daisy', 'daisy', 'cardoon', 'daisy',
       'sea urchin', 'picket fence', 'daisy', 'strawberry',
       'coral fungus', 'picket fence', 'quill', 'daisy', 'daisy', 'pot',
       'sarong', 'hair slide'], dtype='<U30')

Ora 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")

png

Consulta il file LICENSE.txt per le attribuzioni delle immagini.

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 usati per trasferire facilmente l'apprendimento.

Qualsiasi modello di vettore di funzionalità immagine compatibile da tfhub.dev funzionerà qui.

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

Crea l'estrattore di feature. Utilizzare trainable=False per congelare le variabili nel feature extractor layer, in modo che l'addestramento modifichi solo il nuovo layer di classificazione.

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

Restituisce un vettore di lunghezza 1280 per ogni immagine:

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

Allega un capo di classificazione

Ora tf.keras.Sequential livello hub in un modello tf.keras.Sequential e aggiungi un nuovo livello di classificazione.

model = tf.keras.Sequential([
  feature_extractor_layer,
  tf.keras.layers.Dense(image_data.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])

Addestra il modello

Usa compile per configurare il processo di formazione:

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

Ora usa il metodo .fit per addestrare il modello.

Per mantenere questo esempio di treno corto solo 2 epoche. Per visualizzare l'avanzamento dell'addestramento, utilizzare un callback personalizzato per registrare la perdita e l'accuratezza di ogni batch individualmente, invece della media dell'epoca.

class CollectBatchStats(tf.keras.callbacks.Callback):
  def __init__(self):
    self.batch_losses = []
    self.batch_acc = []

  def on_train_batch_end(self, batch, logs=None):
    self.batch_losses.append(logs['loss'])
    self.batch_acc.append(logs['acc'])
    self.model.reset_metrics()
steps_per_epoch = np.ceil(image_data.samples/image_data.batch_size)

batch_stats_callback = CollectBatchStats()

history = model.fit(image_data, epochs=2,
                    steps_per_epoch=steps_per_epoch,
                    callbacks=[batch_stats_callback])
Epoch 1/2
115/115 [==============================] - 12s 100ms/step - loss: 0.4156 - acc: 0.8750
Epoch 2/2
115/115 [==============================] - 12s 101ms/step - loss: 0.1960 - acc: 0.9375

Dopo, anche solo poche iterazioni di addestramento, possiamo già vedere che il modello sta facendo progressi nell'attività.

plt.figure()
plt.ylabel("Loss")
plt.xlabel("Training Steps")
plt.ylim([0,2])
plt.plot(batch_stats_callback.batch_losses)
[<matplotlib.lines.Line2D at 0x7f3ac9d00b38>]

png

plt.figure()
plt.ylabel("Accuracy")
plt.xlabel("Training Steps")
plt.ylim([0,1])
plt.plot(batch_stats_callback.batch_acc)
[<matplotlib.lines.Line2D at 0x7f3ac49b3e48>]

png

Controlla le previsioni

Per rifare la trama di prima, prima ottieni l'elenco ordinato dei nomi delle classi:

class_names = sorted(image_data.class_indices.items(), key=lambda pair:pair[1])
class_names = np.array([key.title() for key, value in class_names])
class_names
array(['Daisy', 'Dandelion', 'Roses', 'Sunflowers', 'Tulips'],
      dtype='<U10')

Eseguire il batch di immagini attraverso il modello e convertire gli indici in nomi di classi.

predicted_batch = model.predict(image_batch)
predicted_id = np.argmax(predicted_batch, axis=-1)
predicted_label_batch = class_names[predicted_id]

Traccia il risultato

label_id = np.argmax(label_batch, axis=-1)
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])
  color = "green" if predicted_id[n] == label_id[n] else "red"
  plt.title(predicted_label_batch[n].title(), color=color)
  plt.axis('off')
_ = plt.suptitle("Model predictions (green: correct, red: incorrect)")

png

Esporta il tuo modello

Dopo aver addestrato il modello, esportalo come SavedModel per utilizzarlo in seguito.

t = time.time()

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

export_path
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

Warning:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

Warning:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

Warning:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.

INFO:tensorflow:Assets written to: /tmp/saved_models/1601602065/assets

INFO:tensorflow:Assets written to: /tmp/saved_models/1601602065/assets

'/tmp/saved_models/1601602065'

Ora conferma che possiamo ricaricarlo e dà ancora 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

Questo SavedModel può essere caricato per inferenza in un secondo momento o convertito in TFLite o TFjs .

Per saperne di più

Guarda altri tutorial per l'utilizzo di modelli di immagine da TensorFlow Hub.