Transfer nauki z TensorFlow Hub

Zobacz na TensorFlow.org Uruchom w Google Colab Zobacz na GitHub Pobierz notatnik Zobacz model piasty TF

TensorFlow Hub to repozytorium wstępnie przeszkolonych modeli TensorFlow.

Ten samouczek pokazuje, jak:

  1. Użyj modeli z TensorFlow Hub z tf.keras .
  2. Użyj modelu klasyfikacji obrazów z TensorFlow Hub.
  3. Wykonaj proste uczenie transferu, aby dostroić model do własnych klas obrazów.

Ustawiać

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

Klasyfikator ImageNet

Zaczniesz od użycia modelu klasyfikatora wstępnie wytrenowanego w zestawie danych porównawczych ImageNet — nie jest wymagane wstępne szkolenie!

Pobierz klasyfikator

Wybierz wstępnie wytrenowany model MobileNetV2 z TensorFlow Hub i zapakuj go jako warstwę Keras za pomocą hub.KerasLayer . Tutaj będzie działał dowolny zgodny model klasyfikatora obrazu z TensorFlow Hub, w tym przykłady podane w rozwijanym menu poniżej.

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

Uruchom go na jednym obrazie

Pobierz pojedynczy obraz, aby wypróbować model:

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)

Dodaj wymiar wsadowy (za pomocą np.newaxis ) i przekaż obraz do modelu:

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

Wynikiem jest 1001-elementowy wektor logitów, oceniający prawdopodobieństwo każdej klasy dla obrazu.

Identyfikator najwyższej klasy można znaleźć w tf.math.argmax :

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

Odszyfruj przepowiednie

Weź identyfikator predicted_class (np. 653 ) i pobierz etykiety zestawu danych ImageNet, aby odszyfrować przewidywania:

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

Prosta nauka transferu

Ale co, jeśli chcesz utworzyć niestandardowy klasyfikator przy użyciu własnego zestawu danych, który zawiera klasy, które nie są zawarte w oryginalnym zestawie danych ImageNet (na którym został przeszkolony wstępnie wytrenowany model)?

Aby to zrobić, możesz:

  1. Wybierz wstępnie wytrenowany model z TensorFlow Hub; oraz
  2. Ponownie naucz górną (ostatnią) warstwę, aby rozpoznawać klasy z niestandardowego zestawu danych.

Zbiór danych

W tym przykładzie użyjesz zestawu danych kwiatów 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

Najpierw załaduj te dane do modelu za pomocą danych obrazu z dysku za pomocą tf.keras.utils.image_dataset_from_directory , co wygeneruje 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.

Zbiór danych o kwiatach ma pięć klas:

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

Po drugie, ponieważ konwencja TensorFlow Hub dla modeli obrazu polega na oczekiwaniu zmiennoprzecinkowych danych wejściowych w zakresie [0, 1] , użyj warstwy przetwarzania wstępnego tf.keras.layers.Rescaling , aby to osiągnąć.

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.

Po trzecie, zakończ potok wejściowy, używając buforowanego pobierania wstępnego z Dataset.prefetch , dzięki czemu można uzyskać dane z dysku bez problemów z blokowaniem operacji we/wy.

Oto niektóre z najważniejszych metod tf.data , których należy używać podczas ładowania danych. Zainteresowani czytelnicy mogą dowiedzieć się więcej na ich temat, a także jak buforować dane na dysku i inne techniki, w przewodniku Lepsza wydajność z tf.data API .

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.

Uruchom klasyfikator na partii obrazów

Teraz uruchom klasyfikator na partii obrazów:

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

Sprawdź, jak te przewidywania pokrywają się z obrazami:

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

Wyniki są dalekie od doskonałych, ale rozsądne, biorąc pod uwagę, że nie są to klasy, do których trenowano model (z wyjątkiem „stokrotek”).

Pobierz model bez głowy

TensorFlow Hub dystrybuuje również modele bez najwyższej warstwy klasyfikacji. Można ich użyć do łatwego przeprowadzenia uczenia transferu.

Wybierz wstępnie wytrenowany model MobileNetV2 z TensorFlow Hub . Tutaj będzie działał dowolny zgodny model wektorowy funkcji obrazu z TensorFlow Hub, w tym przykłady z menu rozwijanego.

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

Utwórz ekstraktor elementów, owijając wstępnie wytrenowany model jako warstwę Keras za pomocą hub.KerasLayer . Użyj argumentu trainable=False , aby zamrozić zmienne, dzięki czemu szkolenie modyfikuje tylko nową warstwę klasyfikatora:

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

Ekstraktor elementów zwraca wektor o długości 1280 dla każdego obrazu (rozmiar wsadu obrazu wynosi w tym przykładzie 32):

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

Dołącz głowicę klasyfikacyjną

Aby ukończyć model, owiń warstwę ekstraktora elementów w model tf.keras.Sequential i dodaj w pełni połączoną warstwę do klasyfikacji:

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

Trenuj modelkę

Użyj Model.compile , aby skonfigurować proces uczenia i dodaj wywołanie zwrotne tf.keras.callbacks.TensorBoard , aby utworzyć i przechowywać logi:

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.

Teraz użyj metody Model.fit , aby wytrenować model.

Aby ten przykład był krótki, będziesz trenować tylko przez 10 epok. Aby później zwizualizować postęp szkolenia w TensorBoard, utwórz i przechowuj logi jako wywołanie zwrotne 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

Uruchom TensorBoard, aby zobaczyć, jak metryki zmieniają się w każdej epoce i śledzić inne wartości skalarne:

%tensorboard --logdir logs/fit

Sprawdź prognozy

Uzyskaj uporządkowaną listę nazw klas z prognoz modelu:

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

Wykreśl prognozy modelu:

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

Eksportuj i odśwież swój model

Teraz, po wytrenowaniu modelu, wyeksportuj go jako SavedModel, aby użyć go później.

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'

Potwierdź, że możesz ponownie załadować SavedModel i że model jest w stanie wyprowadzić te same wyniki:

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

Następne kroki

Możesz użyć SavedModel, aby załadować w celu wnioskowania lub przekonwertować go na model TensorFlow Lite (do uczenia maszynowego na urządzeniu) lub model TensorFlow.js (do uczenia maszynowego w JavaScript).

Odkryj więcej samouczków , aby dowiedzieć się, jak używać wstępnie wytrenowanych modeli z TensorFlow Hub w zadaniach związanych z obrazami, tekstem, dźwiękiem i wideo.