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:
- Usa modelos de TensorFlow Hub con
tf.keras
. - Usa un modelo de clasificación de imágenes de TensorFlow Hub.
- 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
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())
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:
- Seleccione un modelo previamente entrenado de TensorFlow Hub; y
- 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")
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")
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")
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.