Transfiere el aprendizaje con TensorFlow Hub

Ver en TensorFlow.org Ejecutar en Google Colab Ver en GitHub Descargar libreta Ver modelo TF Hub

TensorFlow Hub es un repositorio de modelos de TensorFlow entrenados previamente.

Este tutorial demuestra cómo:

  1. Usa modelos de TensorFlow Hub con tf.keras .
  2. Usa un modelo de clasificación de imágenes de TensorFlow Hub.
  3. Realice un aprendizaje de transferencia simple para ajustar un modelo para sus propias clases de imágenes.

Configuración

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 clasificador de ImageNet

Comenzará usando un modelo de clasificador entrenado previamente en el conjunto de datos de referencia de ImageNet , ¡no se requiere capacitación inicial!

Descarga el clasificador

Seleccione un modelo preentrenado de MobileNetV2 de TensorFlow Hub y envuélvalo como una capa de Keras con hub.KerasLayer . Cualquier modelo de clasificador de imágenes compatible de TensorFlow Hub funcionará aquí, incluidos los ejemplos proporcionados en el menú desplegable a continuación.

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,))
])

Ejecutarlo en una sola imagen

Descargue una sola imagen para probar el modelo en:

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)

Agregue una dimensión de lote (con np.newaxis ) y pase la imagen al modelo:

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

El resultado es un vector logits de 1001 elementos, que califica la probabilidad de cada clase para la imagen.

La identificación de clase superior se puede encontrar con tf.math.argmax :

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

Decodificar las predicciones

Tome el ID de clase predicted_class (como 653 ) y obtenga las etiquetas del conjunto de datos de ImageNet para decodificar las predicciones:

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

Aprendizaje de transferencia simple

Pero, ¿qué sucede si desea crear un clasificador personalizado utilizando su propio conjunto de datos que tiene clases que no están incluidas en el conjunto de datos original de ImageNet (en el que se entrenó el modelo previamente entrenado)?

Para hacer eso, puedes:

  1. Seleccione un modelo previamente entrenado de TensorFlow Hub; y
  2. Vuelva a entrenar la capa superior (última) para reconocer las clases de su conjunto de datos personalizado.

conjunto de datos

En este ejemplo, utilizará el conjunto de datos de flores de 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

Primero, cargue estos datos en el modelo utilizando los datos de imagen fuera del disco con tf.keras.utils.image_dataset_from_directory , que generará 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.

El conjunto de datos de flores tiene cinco clases:

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

En segundo lugar, debido a que la convención de TensorFlow Hub para los modelos de imágenes es esperar entradas flotantes en el rango [0, 1] , use la capa de preprocesamiento tf.keras.layers.Rescaling para lograrlo.

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.

En tercer lugar, finalice la canalización de entrada mediante la obtención previa almacenada en búfer con Dataset.prefetch , para que pueda obtener los datos del disco sin problemas de bloqueo de E/S.

Estos son algunos de los métodos tf.data más importantes que debe usar al cargar datos. Los lectores interesados ​​pueden obtener más información sobre ellos, así como sobre cómo almacenar datos en caché en el disco y otras técnicas, en la guía Mejor rendimiento con la 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.

Ejecute el clasificador en un lote de imágenes

Ahora, ejecute el clasificador en un lote de imágenes:

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')

Compruebe cómo se alinean estas predicciones con las imágenes:

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

Los resultados están lejos de ser perfectos, pero son razonables teniendo en cuenta que estas no son las clases para las que se entrenó al modelo (excepto "daisy").

Descarga el modelo sin cabeza

TensorFlow Hub también distribuye modelos sin la capa de clasificación superior. Estos se pueden utilizar para realizar fácilmente el aprendizaje de transferencia.

Seleccione un modelo preentrenado de MobileNetV2 de TensorFlow Hub . Cualquier modelo de vector de función de imagen compatible de TensorFlow Hub funcionará aquí, incluidos los ejemplos del menú desplegable.

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

Cree el extractor de características envolviendo el modelo previamente entrenado como una capa de Keras con hub.KerasLayer . Usa el argumento trainable=False para congelar las variables, de modo que el entrenamiento solo modifique la nueva capa clasificadora:

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

El extractor de características devuelve un vector de 1280 para cada imagen (el tamaño del lote de imágenes permanece en 32 en este ejemplo):

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

Adjuntar un encabezado de clasificación

Para completar el modelo, envuelva la capa del extractor de características en un modelo tf.keras.Sequential y agregue una capa completamente conectada para la clasificación:

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])

entrenar al modelo

Use Model.compile para configurar el proceso de capacitación y agregue una devolución de llamada tf.keras.callbacks.TensorBoard para crear y almacenar registros:

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.

Ahora use el método Model.fit para entrenar el modelo.

Para acortar este ejemplo, entrenará solo durante 10 épocas. Para visualizar el progreso de la capacitación en TensorBoard más tarde, cree y almacene registros en una devolución de llamada de 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

Inicie TensorBoard para ver cómo cambian las métricas con cada época y para realizar un seguimiento de otros valores escalares:

%tensorboard --logdir logs/fit

Consulta las predicciones

Obtenga la lista ordenada de nombres de clase de las predicciones del modelo:

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']

Trazar las predicciones del modelo:

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

Exporta y recarga tu modelo

Ahora que ha entrenado el modelo, expórtelo como modelo guardado para reutilizarlo más tarde.

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'

Confirme que puede volver a cargar el modelo guardado y que el modelo puede generar los mismos resultados:

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

Próximos pasos

Puede usar el modelo guardado para cargarlo para la inferencia o convertirlo en un modelo TensorFlow Lite (para el aprendizaje automático en el dispositivo) o un modelo TensorFlow.js (para el aprendizaje automático en JavaScript).

Descubra más tutoriales para aprender a usar modelos previamente entrenados de TensorFlow Hub en tareas de imagen, texto, audio y video.