![]() | ![]() | ![]() | ![]() | ![]() |
Введение
Модели классификации изображений имеют миллионы параметров. Обучение их с нуля требует большого количества размеченных обучающих данных и больших вычислительных мощностей. Трансферное обучение - это метод, который во многом сокращает это, беря часть модели, которая уже была обучена для связанной задачи, и повторно используя ее в новой модели.
Этот 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>]
Попробуйте модель на изображении из данных проверки:
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))
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.
Настройки оптимизации
optimize_lite_model = False
num_calibration_examples = 60
representative_dataset = None
if optimize_lite_model and num_calibration_examples:
# Use a bounded number of training examples without labels for calibration.
# TFLiteConverter expects a list of input tensors, each with batch size 1.
representative_dataset = lambda: itertools.islice(
([image[None, ...]] for batch, _ in train_generator for image in batch),
num_calibration_examples)
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_path)
if optimize_lite_model:
converter.optimizations = [tf.lite.Optimize.DEFAULT]
if representative_dataset: # This is optional, see above.
converter.representative_dataset = representative_dataset
lite_model_content = converter.convert()
with open("/tmp/lite_flowers_model", "wb") as f:
f.write(lite_model_content)
print("Wrote %sTFLite model of %d bytes." %
("optimized " if optimize_lite_model else "", len(lite_model_content)))
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%).