Сохраните дату! Google I / O возвращается 18-20 мая Зарегистрируйтесь сейчас
Эта страница переведена с помощью Cloud Translation API.
Switch to English

Загрузить изображения

Посмотреть на TensorFlow.org Запускаем в Google Colab Посмотреть исходный код на GitHub Скачать блокнот

В этом руководстве показано, как загрузить и предварительно обработать набор данных изображения тремя способами. Во-первых, вы будете использовать высокоуровневые утилиты и слои предварительной обработки Keras для чтения каталога изображений на диске. Затем вы напишете свой собственный конвейер ввода с нуля, используя tf.data . Наконец, вы загрузите набор данных из большого каталога, доступного в TensorFlow Datasets .

Настраивать

import numpy as np
import os
import PIL
import PIL.Image
import tensorflow as tf
import tensorflow_datasets as tfds
print(tf.__version__)
2.4.1

Загрузите набор данных о цветах

В этом руководстве используется набор данных из нескольких тысяч фотографий цветов. Набор данных цветов содержит 5 подкаталогов, по одному на каждый класс:

flowers_photos/
  daisy/
  dandelion/
  roses/
  sunflowers/
  tulips/
import pathlib
dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file(origin=dataset_url, 
                                   fname='flower_photos', 
                                   untar=True)
data_dir = pathlib.Path(data_dir)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz
228818944/228813984 [==============================] - 5s 0us/step

После загрузки (218 МБ) у вас должна быть доступна копия фотографий цветов. Всего 3670 изображений:

image_count = len(list(data_dir.glob('*/*.jpg')))
print(image_count)
3670

Каждый каталог содержит изображения этого вида цветов. Вот несколько роз:

roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[0]))

PNG

roses = list(data_dir.glob('roses/*'))
PIL.Image.open(str(roses[1]))

PNG

Загрузить с помощью keras.preprocessing

Давайте загрузим эти изображения с диска с помощью image_dataset_from_directory .

Создать набор данных

Определите некоторые параметры для загрузчика:

batch_size = 32
img_height = 180
img_width = 180

При разработке модели рекомендуется использовать разделение валидации. Мы будем использовать 80% изображений для обучения и 20% для проверки.

train_ds = tf.keras.preprocessing.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)
Found 3670 files belonging to 5 classes.
Using 2936 files for training.
val_ds = tf.keras.preprocessing.image_dataset_from_directory(
  data_dir,
  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 734 files for validation.

Вы можете найти имена классов в атрибуте class_names в этих наборах данных.

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

Визуализируйте данные

Вот первые 9 изображений из набора обучающих данных.

import matplotlib.pyplot as plt

plt.figure(figsize=(10, 10))
for images, labels in train_ds.take(1):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")

PNG

Вы можете обучить модель, используя эти наборы данных, передав их в model.fit (показано далее в этом руководстве). Если хотите, вы также можете вручную перебирать набор данных и получать пакеты изображений:

for image_batch, labels_batch in train_ds:
  print(image_batch.shape)
  print(labels_batch.shape)
  break
(32, 180, 180, 3)
(32,)

image_batch - это тензор формы (32, 180, 180, 3) . Это пакет из 32 изображений формы 180x180x3 (последнее измерение относится к цветовым каналам RGB). label_batch - это тензор формы (32,) , это соответствующие метки для 32 изображений.

Стандартизируйте данные

Значения канала RGB находятся в диапазоне [0, 255] . Это не идеально для нейронной сети; в общем, вы должны стремиться к тому, чтобы ваши входные значения были небольшими. Здесь мы стандартизируем значения, чтобы они находились в [0, 1] , используя слой Rescaling.

from tensorflow.keras import layers

normalization_layer = tf.keras.layers.experimental.preprocessing.Rescaling(1./255)

Есть два способа использовать этот слой. Вы можете применить его к набору данных, вызвав map:

normalized_ds = train_ds.map(lambda x, y: (normalization_layer(x), y))
image_batch, labels_batch = next(iter(normalized_ds))
first_image = image_batch[0]
# Notice the pixels values are now in `[0,1]`.
print(np.min(first_image), np.max(first_image))
0.0 0.96902645

Или вы можете включить слой в определение модели, чтобы упростить развертывание. Здесь мы воспользуемся вторым подходом.

Настройте набор данных для повышения производительности

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

.cache() сохраняет изображения в памяти после их загрузки с диска в течение первой эпохи. Это гарантирует, что набор данных не станет узким местом при обучении вашей модели. Если ваш набор данных слишком велик для размещения в памяти, вы также можете использовать этот метод для создания производительного кеша на диске.

.prefetch() перекрывает предварительную обработку данных и выполнение модели во время обучения.

Заинтересованные читатели могут узнать больше об обоих методах, а также о том, как кэшировать данные на диск, в руководстве по производительности данных .

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)

Обучить модель

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

num_classes = 5

model = tf.keras.Sequential([
  layers.experimental.preprocessing.Rescaling(1./255),
  layers.Conv2D(32, 3, activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, activation='relu'),
  layers.MaxPooling2D(),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes)
])
model.compile(
  optimizer='adam',
  loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
  metrics=['accuracy'])
model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=3
)
Epoch 1/3
92/92 [==============================] - 9s 75ms/step - loss: 1.4194 - accuracy: 0.4075 - val_loss: 1.0631 - val_accuracy: 0.5899
Epoch 2/3
92/92 [==============================] - 1s 12ms/step - loss: 1.0337 - accuracy: 0.5607 - val_loss: 0.9730 - val_accuracy: 0.6322
Epoch 3/3
92/92 [==============================] - 1s 12ms/step - loss: 0.8870 - accuracy: 0.6537 - val_loss: 0.9257 - val_accuracy: 0.6485
<tensorflow.python.keras.callbacks.History at 0x7f9c35c6d1d0>

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

Использование tf.data для более точного управления

Вышеупомянутые утилиты keras.preprocessing - удобный способ создатьtf.data.Dataset из каталога изображений. Для более точного управления вы можете написать свой собственный конвейер ввода, используя tf.data . В этом разделе показано, как это сделать, начиная с путей к файлам из архива, который мы скачали ранее.

list_ds = tf.data.Dataset.list_files(str(data_dir/'*/*'), shuffle=False)
list_ds = list_ds.shuffle(image_count, reshuffle_each_iteration=False)
for f in list_ds.take(5):
  print(f.numpy())
b'/home/kbuilder/.keras/datasets/flower_photos/dandelion/10779476016_9130714dc0.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/daisy/144076848_57e1d662e3_m.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/tulips/13513616525_2ee0f049e1.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/tulips/574373182_2776669a79_n.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/daisy/515112668_a49c69455a.jpg'

Древовидная структура файлов может использоваться для составления списка class_names .

class_names = np.array(sorted([item.name for item in data_dir.glob('*') if item.name != "LICENSE.txt"]))
print(class_names)
['daisy' 'dandelion' 'roses' 'sunflowers' 'tulips']

Разделите набор данных на поезд и проверку:

val_size = int(image_count * 0.2)
train_ds = list_ds.skip(val_size)
val_ds = list_ds.take(val_size)

Вы можете увидеть длину каждого набора данных следующим образом:

print(tf.data.experimental.cardinality(train_ds).numpy())
print(tf.data.experimental.cardinality(val_ds).numpy())
2936
734

Напишите короткую функцию, которая преобразует путь к файлу в пару (img, label) :

def get_label(file_path):
  # convert the path to a list of path components
  parts = tf.strings.split(file_path, os.path.sep)
  # The second to last is the class-directory
  one_hot = parts[-2] == class_names
  # Integer encode the label
  return tf.argmax(one_hot)
def decode_img(img):
  # convert the compressed string to a 3D uint8 tensor
  img = tf.image.decode_jpeg(img, channels=3)
  # resize the image to the desired size
  return tf.image.resize(img, [img_height, img_width])
def process_path(file_path):
  label = get_label(file_path)
  # load the raw data from the file as a string
  img = tf.io.read_file(file_path)
  img = decode_img(img)
  return img, label

Используйте Dataset.map чтобы создать набор данных image, label пары image, label :

# Set `num_parallel_calls` so multiple images are loaded/processed in parallel.
train_ds = train_ds.map(process_path, num_parallel_calls=AUTOTUNE)
val_ds = val_ds.map(process_path, num_parallel_calls=AUTOTUNE)
for image, label in train_ds.take(1):
  print("Image shape: ", image.numpy().shape)
  print("Label: ", label.numpy())
Image shape:  (180, 180, 3)
Label:  2

Настроить набор данных для повышения производительности

Чтобы обучить модель с помощью этого набора данных, вам понадобятся данные:

  • Чтобы хорошо перетасовать.
  • Для дозирования.
  • Пакеты будут доступны как можно скорее.

Эти функции могут быть добавлены с tf.data API tf.data . Дополнительные сведения см. В руководстве по производительности входного конвейера .

def configure_for_performance(ds):
  ds = ds.cache()
  ds = ds.shuffle(buffer_size=1000)
  ds = ds.batch(batch_size)
  ds = ds.prefetch(buffer_size=AUTOTUNE)
  return ds

train_ds = configure_for_performance(train_ds)
val_ds = configure_for_performance(val_ds)

Визуализируйте данные

Вы можете визуализировать этот набор данных аналогично тому, который вы создали ранее.

image_batch, label_batch = next(iter(train_ds))

plt.figure(figsize=(10, 10))
for i in range(9):
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(image_batch[i].numpy().astype("uint8"))
  label = label_batch[i]
  plt.title(class_names[label])
  plt.axis("off")

PNG

Продолжить обучение модели

Теперь вы вручную создали наборtf.data.Dataset аналогичныйtf.data.Dataset который был создан с помощью keras.preprocessing выше. Вы можете продолжить обучение модели с его помощью. Как и раньше, мы будем тренироваться всего несколько эпох, чтобы время бега было коротким.

model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=3
)
Epoch 1/3
92/92 [==============================] - 3s 22ms/step - loss: 0.8030 - accuracy: 0.6918 - val_loss: 0.7237 - val_accuracy: 0.7044
Epoch 2/3
92/92 [==============================] - 1s 13ms/step - loss: 0.6538 - accuracy: 0.7531 - val_loss: 0.7045 - val_accuracy: 0.7248
Epoch 3/3
92/92 [==============================] - 1s 13ms/step - loss: 0.5219 - accuracy: 0.8113 - val_loss: 0.7486 - val_accuracy: 0.6921
<tensorflow.python.keras.callbacks.History at 0x7f9ccdc286a0>

Использование наборов данных TensorFlow

До сих пор это руководство было сосредоточено на загрузке данных с диска. Вы также можете найти набор данных для использования, изучив большой каталог простых для загрузки наборов данных на сайте TensorFlow Datasets . Поскольку вы ранее загрузили набор данных Flowers с диска, давайте посмотрим, как импортировать его с помощью наборов данных TensorFlow.

Загрузите набор данных цветов с помощью TensorFlow Datasets.

(train_ds, val_ds, test_ds), metadata = tfds.load(
    'tf_flowers',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

Набор данных цветов состоит из пяти классов.

num_classes = metadata.features['label'].num_classes
print(num_classes)
5

Получить изображение из набора данных.

get_label_name = metadata.features['label'].int2str

image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))

PNG

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

train_ds = configure_for_performance(train_ds)
val_ds = configure_for_performance(val_ds)
test_ds = configure_for_performance(test_ds)

Вы можете найти полный пример работы с набором данных цветов и наборами данных TensorFlow, посетив учебник по увеличению данных .

Следующие шаги

В этом руководстве показано два способа загрузки изображений с диска. Во-первых, вы узнали, как загрузить и предварительно обработать набор данных изображения с помощью слоев предварительной обработки и утилит Keras. Затем вы узнали, как написать конвейер ввода с нуля, используя tf.data. Наконец, вы узнали, как загрузить набор данных из TensorFlow Datasets. В качестве следующего шага вы можете узнать, как добавить увеличение данных, посетив это руководство . Чтобы узнать больше о tf.data, вы можете посетить это руководство .