RSVP для вашего местного мероприятия TensorFlow Everywhere сегодня!
Эта страница переведена с помощью Cloud Translation API.
Switch to English

Переобучение классификатора изображений

Посмотреть на TensorFlow.org Запускаем в Google Colab Посмотреть на GitHub Скачать блокнот См. Модель TF Hub

Введение

Модели классификации изображений имеют миллионы параметров. Обучение их с нуля требует большого количества размеченных обучающих данных и больших вычислительных мощностей. Трансферное обучение - это метод, который во многом сокращает это, беря часть модели, которая уже была обучена для связанной задачи, и повторно используя ее в новой модели.

Этот Colab демонстрирует, как построить модель Keras для классификации пяти видов цветов с помощью предварительно обученной модели TF2 SavedModel от TensorFlow Hub для извлечения признаков изображения, обученной на гораздо большем и более общем наборе данных ImageNet. При желании экстрактор признаков может быть обучен («настроен») вместе с недавно добавленным классификатором.

Ищете вместо этого инструмент?

Это руководство по программированию на TensorFlow. Если вам нужен инструмент, который просто строит модель TensorFlow или TF Lite, взгляните на инструмент командной строки make_image_classifier, который устанавливается с помощью пакета tensorflow-hub[make_image_classifier] пакета PIP, или в этой tensorflow-hub[make_image_classifier] TF Lite.

Настроить

import itertools
import os

import matplotlib.pylab as plt
import numpy as np

import tensorflow as tf
import tensorflow_hub as hub

print("TF version:", tf.__version__)
print("Hub version:", hub.__version__)
print("GPU is", "available" if tf.test.is_gpu_available() else "NOT AVAILABLE")
TF version: 2.4.0
Hub version: 0.11.0
WARNING:tensorflow:From <ipython-input-1-0831fa394ed3>:12: is_gpu_available (from tensorflow.python.framework.test_util) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.config.list_physical_devices('GPU')` instead.
GPU is available

Выберите модуль TF2 SavedModel для использования

Для начала используйте https: //tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/4 . Один и тот же URL-адрес можно использовать в коде для идентификации SavedModel и в вашем браузере для отображения документации к нему. (Обратите внимание, что модели в формате TF1 Hub здесь не работают.)

Вы можете найти больше моделей TF2, которые генерируют векторы признаков изображения здесь .

module_selection = ("mobilenet_v2_100_224", 224)
handle_base, pixels = module_selection
MODULE_HANDLE ="https://tfhub.dev/google/imagenet/{}/feature_vector/4".format(handle_base)
IMAGE_SIZE = (pixels, pixels)
print("Using {} with input size {}".format(MODULE_HANDLE, IMAGE_SIZE))

BATCH_SIZE = 32
Using https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/4 with input size (224, 224)

Настройте набор данных Flowers

Размер входов изменяется в соответствии с выбранным модулем. Увеличение набора данных (т. Е. Случайные искажения изображения при каждом его чтении) улучшает обучение, особенно. при тонкой настройке.

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

datagen_kwargs = dict(rescale=1./255, validation_split=.20)
dataflow_kwargs = dict(target_size=IMAGE_SIZE, batch_size=BATCH_SIZE,
                   interpolation="bilinear")

valid_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    **datagen_kwargs)
valid_generator = valid_datagen.flow_from_directory(
    data_dir, subset="validation", shuffle=False, **dataflow_kwargs)

do_data_augmentation = False
if do_data_augmentation:
  train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
      rotation_range=40,
      horizontal_flip=True,
      width_shift_range=0.2, height_shift_range=0.2,
      shear_range=0.2, zoom_range=0.2,
      **datagen_kwargs)
else:
  train_datagen = valid_datagen
train_generator = train_datagen.flow_from_directory(
    data_dir, subset="training", shuffle=True, **dataflow_kwargs)
Found 731 images belonging to 5 classes.
Found 2939 images belonging to 5 classes.

Определение модели

Все, что нужно, - это поместить линейный классификатор поверх feature_extractor_layer с модулем Hub.

Для скорости мы начнем с необучаемого feature_extractor_layer , но вы также можете включить тонкую настройку для большей точности.

do_fine_tuning = False
print("Building model with", MODULE_HANDLE)
model = tf.keras.Sequential([
    # Explicitly define the input shape so the model can be properly
    # loaded by the TFLiteConverter
    tf.keras.layers.InputLayer(input_shape=IMAGE_SIZE + (3,)),
    hub.KerasLayer(MODULE_HANDLE, trainable=do_fine_tuning),
    tf.keras.layers.Dropout(rate=0.2),
    tf.keras.layers.Dense(train_generator.num_classes,
                          kernel_regularizer=tf.keras.regularizers.l2(0.0001))
])
model.build((None,)+IMAGE_SIZE+(3,))
model.summary()
Building model with https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/4
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
keras_layer (KerasLayer)     (None, 1280)              2257984   
_________________________________________________________________
dropout (Dropout)            (None, 1280)              0         
_________________________________________________________________
dense (Dense)                (None, 5)                 6405      
=================================================================
Total params: 2,264,389
Trainable params: 6,405
Non-trainable params: 2,257,984
_________________________________________________________________

Обучение модели

model.compile(
  optimizer=tf.keras.optimizers.SGD(lr=0.005, momentum=0.9), 
  loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.1),
  metrics=['accuracy'])
steps_per_epoch = train_generator.samples // train_generator.batch_size
validation_steps = valid_generator.samples // valid_generator.batch_size
hist = model.fit(
    train_generator,
    epochs=5, steps_per_epoch=steps_per_epoch,
    validation_data=valid_generator,
    validation_steps=validation_steps).history
Epoch 1/5
91/91 [==============================] - 30s 180ms/step - loss: 1.1586 - accuracy: 0.5967 - val_loss: 0.7162 - val_accuracy: 0.8580
Epoch 2/5
91/91 [==============================] - 15s 162ms/step - loss: 0.7058 - accuracy: 0.8653 - val_loss: 0.7084 - val_accuracy: 0.8665
Epoch 3/5
91/91 [==============================] - 15s 164ms/step - loss: 0.6474 - accuracy: 0.9006 - val_loss: 0.7143 - val_accuracy: 0.8580
Epoch 4/5
91/91 [==============================] - 15s 162ms/step - loss: 0.6193 - accuracy: 0.9169 - val_loss: 0.6762 - val_accuracy: 0.8651
Epoch 5/5
91/91 [==============================] - 15s 161ms/step - loss: 0.5973 - accuracy: 0.9335 - val_loss: 0.6766 - val_accuracy: 0.8778

plt.figure()
plt.ylabel("Loss (training and validation)")
plt.xlabel("Training Steps")
plt.ylim([0,2])
plt.plot(hist["loss"])
plt.plot(hist["val_loss"])

plt.figure()
plt.ylabel("Accuracy (training and validation)")
plt.xlabel("Training Steps")
plt.ylim([0,1])
plt.plot(hist["accuracy"])
plt.plot(hist["val_accuracy"])
[<matplotlib.lines.Line2D at 0x7f0025eb2278>]

PNG

PNG

Попробуйте модель на изображении из данных проверки:

def get_class_string_from_index(index):
   for class_string, class_index in valid_generator.class_indices.items():
      if class_index == index:
         return class_string

x, y = next(valid_generator)
image = x[0, :, :, :]
true_index = np.argmax(y[0])
plt.imshow(image)
plt.axis('off')
plt.show()

# Expand the validation image to (1, 224, 224, 3) before predicting the label
prediction_scores = model.predict(np.expand_dims(image, axis=0))
predicted_index = np.argmax(prediction_scores)
print("True label: " + get_class_string_from_index(true_index))
print("Predicted label: " + get_class_string_from_index(predicted_index))

PNG

True label: daisy
Predicted label: daisy

Наконец, обученную модель можно сохранить для развертывания в TF Serving или TF Lite (на мобильных устройствах) следующим образом.

saved_model_path = "/tmp/saved_flowers_model"
tf.saved_model.save(model, saved_model_path)
INFO:tensorflow:Assets written to: /tmp/saved_flowers_model/assets

INFO:tensorflow:Assets written to: /tmp/saved_flowers_model/assets

Необязательно: развертывание в TensorFlow Lite

TensorFlow Lite позволяет развертывать модели TensorFlow на мобильных устройствах и устройствах Интернета вещей. В приведенном ниже коде показано, как преобразовать обученную модель в TF Lite и применить инструменты после обучения из TensorFlow Model Optimization Toolkit . Наконец, он запускает его в интерпретаторе TF Lite, чтобы проверить качество результата.

  • Преобразование без оптимизации дает те же результаты, что и раньше (с точностью до ошибки округления).
  • Преобразование с оптимизацией без каких-либо данных квантует веса модели до 8 бит, но логический вывод по-прежнему использует вычисления с плавающей запятой для активации нейронной сети. Это уменьшает размер модели почти в 4 раза и снижает задержку ЦП на мобильных устройствах.
  • Кроме того, вычисление активаций нейронной сети также может быть квантовано до 8-битных целых чисел, если предоставляется небольшой эталонный набор данных для калибровки диапазона квантования. На мобильном устройстве это еще больше ускоряет логический вывод и позволяет работать на таких ускорителях, как EdgeTPU.

Настройки оптимизации

Wrote TFLite model of 8873044 bytes.

interpreter = tf.lite.Interpreter(model_content=lite_model_content)
# This little helper wraps the TF Lite interpreter as a numpy-to-numpy function.
def lite_model(images):
  interpreter.allocate_tensors()
  interpreter.set_tensor(interpreter.get_input_details()[0]['index'], images)
  interpreter.invoke()
  return interpreter.get_tensor(interpreter.get_output_details()[0]['index'])
num_eval_examples = 50 
eval_dataset = ((image, label)  # TFLite expects batch size 1.
                for batch in train_generator
                for (image, label) in zip(*batch))
count = 0
count_lite_tf_agree = 0
count_lite_correct = 0
for image, label in eval_dataset:
  probs_lite = lite_model(image[None, ...])[0]
  probs_tf = model(image[None, ...]).numpy()[0]
  y_lite = np.argmax(probs_lite)
  y_tf = np.argmax(probs_tf)
  y_true = np.argmax(label)
  count +=1
  if y_lite == y_tf: count_lite_tf_agree += 1
  if y_lite == y_true: count_lite_correct += 1
  if count >= num_eval_examples: break
print("TF Lite model agrees with original model on %d of %d examples (%g%%)." %
      (count_lite_tf_agree, count, 100.0 * count_lite_tf_agree / count))
print("TF Lite model is accurate on %d of %d examples (%g%%)." %
      (count_lite_correct, count, 100.0 * count_lite_correct / count))
TF Lite model agrees with original model on 50 of 50 examples (100%).
TF Lite model is accurate on 48 of 50 examples (96%).