Chuyển giao việc học với TensorFlow Hub

Xem trên TensorFlow.org Chạy trong Google Colab Xem trên GitHub Tải xuống sổ ghi chép Xem mô hình TF Hub

TensorFlow Hub là một kho lưu trữ các mô hình TensorFlow được đào tạo trước.

Hướng dẫn này trình bày cách:

  1. Sử dụng các mô hình từ TensorFlow Hub với tf.keras .
  2. Sử dụng mô hình phân loại hình ảnh từ TensorFlow Hub.
  3. Thực hiện học chuyển tiếp đơn giản để tinh chỉnh một mô hình cho các lớp hình ảnh của riêng bạn.

Thành lập

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

Bộ phân loại ImageNet

Bạn sẽ bắt đầu bằng cách sử dụng mô hình phân loại được đào tạo trước trên tập dữ liệu điểm chuẩn ImageNet — không cần đào tạo ban đầu!

Tải xuống trình phân loại

Chọn một mô hình được đào tạo trước MobileNetV2 từ TensorFlow Hub và bọc nó dưới dạng lớp Keras với hub.KerasLayer . Mọi mô hình phân loại hình ảnh tương thích từ TensorFlow Hub sẽ hoạt động ở đây, bao gồm các ví dụ được cung cấp trong menu thả xuống bên dưới.

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

Chạy nó trên một hình ảnh duy nhất

Tải xuống một hình ảnh duy nhất để thử mô hình trên:

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)

Thêm thứ nguyên lô (với np.newaxis ) và chuyển hình ảnh vào mô hình:

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

Kết quả là một vectơ gồm 1001 phần tử của logits, đánh giá xác suất của từng lớp cho hình ảnh.

ID lớp hàng đầu có thể được tìm thấy với tf.math.argmax :

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

Giải mã các dự đoán

Lấy ID predicted_class (chẳng hạn như 653 ) và tìm nạp các nhãn tập dữ liệu ImageNet để giải mã các dự đoán:

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

Học chuyển tiếp đơn giản

Nhưng điều gì sẽ xảy ra nếu bạn muốn tạo một bộ phân loại tùy chỉnh bằng cách sử dụng tập dữ liệu của riêng bạn mà có các lớp không được bao gồm trong tập dữ liệu ImageNet ban đầu (mô hình được đào tạo trước đã được đào tạo)?

Để làm điều đó, bạn có thể:

  1. Chọn một mô hình được đào tạo trước từ TensorFlow Hub; và
  2. Đào tạo lại lớp trên cùng (cuối cùng) để nhận ra các lớp từ tập dữ liệu tùy chỉnh của bạn.

Dataset

Trong ví dụ này, bạn sẽ sử dụng tập dữ liệu hoa 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

Đầu tiên, tải dữ liệu này vào mô hình bằng cách sử dụng dữ liệu hình ảnh trên đĩa với tf.keras.utils.image_dataset_from_directory , sẽ tạo ra một 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.

Tập dữ liệu về hoa có năm lớp:

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

Thứ hai, vì quy ước của TensorFlow Hub cho các mô hình hình ảnh là mong đợi các đầu vào float trong phạm vi [0, 1] , hãy sử dụng lớp tiền xử lý tf.keras.layers.Rescaling để đạt được điều này.

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.

Thứ ba, hoàn thành đường dẫn đầu vào bằng cách sử dụng tìm nạp trước bộ đệm với Dataset.prefetch , vì vậy bạn có thể cung cấp dữ liệu từ đĩa mà không gặp vấn đề về chặn I / O.

Đây là một số phương pháp tf.data quan trọng nhất mà bạn nên sử dụng khi tải dữ liệu. Bạn đọc quan tâm có thể tìm hiểu thêm về chúng, cũng như cách lưu dữ liệu vào bộ nhớ cache vào đĩa và các kỹ thuật khác, trong phần Hiệu suất tốt hơn với hướng dẫn 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.

Chạy trình phân loại trên một loạt hình ảnh

Bây giờ, hãy chạy trình phân loại trên một lô hình ảnh:

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

Kiểm tra xem các dự đoán này sắp xếp như thế nào với các hình ảnh:

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

Các kết quả còn lâu mới hoàn hảo, nhưng hợp lý khi xét rằng đây không phải là các lớp mà mô hình được đào tạo (ngoại trừ "daisy").

Tải xuống mô hình không đầu

TensorFlow Hub cũng phân phối các mô hình không có lớp phân loại trên cùng. Chúng có thể được sử dụng để dễ dàng thực hiện việc học chuyển tiếp.

Chọn một mô hình được đào tạo trước MobileNetV2 từ TensorFlow Hub . Mọi mô hình vectơ đặc trưng hình ảnh tương thích từ TensorFlow Hub sẽ hoạt động ở đây, bao gồm các ví dụ từ trình đơn thả xuống.

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

Tạo trình trích xuất tính năng bằng cách bao bọc mô hình được đào tạo trước dưới dạng lớp Keras với hub.KerasLayer . Sử dụng đối số trainable=False để đóng băng các biến, để quá trình huấn luyện chỉ sửa đổi lớp phân loại mới:

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

Trình trích xuất tính năng trả về một vectơ dài 1280 cho mỗi hình ảnh (kích thước lô hình ảnh vẫn ở mức 32 trong ví dụ này):

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

Đính kèm đầu phân loại

Để hoàn thành mô hình, hãy bọc lớp trích xuất tính năng trong một mô hình tf.keras.Sequential và thêm một lớp được kết nối đầy đủ để phân loại:

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

Đào tạo mô hình

Sử dụng Model.compile để định cấu hình quá trình đào tạo và thêm lệnh gọi lại tf.keras.callbacks.TensorBoard để tạo và lưu trữ nhật ký:

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.

Bây giờ sử dụng phương thức Model.fit để đào tạo mô hình.

Để giữ cho ví dụ này ngắn gọn, bạn sẽ được đào tạo chỉ trong 10 kỷ. Để hình dung tiến trình đào tạo trong TensorBoard sau này, hãy tạo và lưu trữ nhật ký một lệnh gọi lại 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

Khởi động TensorBoard để xem các chỉ số thay đổi như thế nào theo từng kỷ nguyên và để theo dõi các giá trị vô hướng khác:

%tensorboard --logdir logs/fit

Kiểm tra các dự đoán

Nhận danh sách có thứ tự các tên lớp từ các dự đoán của mô hình:

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

Vẽ đồ thị dự đoán mô hình:

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

Xuất và tải lại mô hình của bạn

Bây giờ bạn đã đào tạo mô hình, hãy xuất nó dưới dạng SavedModel để sử dụng lại sau này.

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'

Xác nhận rằng bạn có thể tải lại SavedModel và mô hình có thể xuất ra kết quả tương tự:

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

Bước tiếp theo

Bạn có thể sử dụng SavedModel để tải để suy luận hoặc chuyển đổi nó thành mô hình TensorFlow Lite (dành cho máy học trên thiết bị) hoặc mô hình TensorFlow.js (cho máy học trong JavaScript).

Khám phá thêm các hướng dẫn để tìm hiểu cách sử dụng các mô hình được đào tạo trước từ TensorFlow Hub cho các tác vụ hình ảnh, văn bản, âm thanh và video.