Bilder laden und vorverarbeiten

Auf TensorFlow.org ansehen Quelle auf GitHub anzeigen Notizbuch herunterladen

In diesem Tutorial wird gezeigt, wie Sie einen Bilddatensatz auf drei Arten laden und vorverarbeiten. Als erstes müssen Sie auf hohe Ebene Keras Vorverarbeitung verwenden Dienstprogramme und Schichten ein Verzeichnis der Bilder auf der Festplatte zu lesen. Als nächstes werden Sie Ihre eigenen Eingang Pipeline von Grund auf neu schreiben mit tf.data . Schließlich werden Sie einen Datensatz aus dem großen Download - Katalog verfügbar in TensorFlow Datensätze .

Installieren

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

Laden Sie den Blumen-Datensatz herunter

Dieses Tutorial verwendet einen Datensatz mit mehreren Tausend Fotos von Blumen. Der Blumen-Datensatz enthält 5 Unterverzeichnisse, eines pro Klasse:

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

Nach dem Download (218 MB) sollten Sie nun eine Kopie der Blumenfotos zur Verfügung haben. Es gibt insgesamt 3.670 Bilder:

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

Jedes Verzeichnis enthält Bilder dieser Blumenart. Hier sind einige Rosen:

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

Laden mit tf.keras.preprocessing

Lassen Sie uns Last diese Bilder aus Festplatte mit tf.keras.preprocessing.image_dataset_from_directory .

Erstellen Sie einen Datensatz

Definieren Sie einige Parameter für den Loader:

batch_size = 32
img_height = 180
img_width = 180

Es empfiehlt sich, bei der Entwicklung Ihres Modells einen Validierungssplit zu verwenden. Sie verwenden 80 % der Bilder für das Training und 20 % für die Validierung.

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.

Sie können die Klassennamen in dem finden class_names Attribut auf dieser Datensätze.

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

Visualisieren Sie die Daten

Hier sind die ersten 9 Bilder aus dem Trainingsdatensatz.

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

Sie können ein Modell mit diesen Datensatz trainieren , indem sie vorbei model.fit (gezeigt später in diesem Tutorial). Wenn Sie möchten, können Sie den Datensatz auch manuell durchlaufen und Bildstapel abrufen:

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

Der image_batch ein Tensor der Form (32, 180, 180, 3) . Dies ist eine Charge von 32 Bildern von Form 180x180x3 (die letzte Dimension referes zu Farbkanälen RGB). Der label_batch ein Tensor der Form (32,) , das sind die entsprechenden Etiketten auf die 32 Bilder.

Standardisieren Sie die Daten

Die RGB - Kanal - Werte sind in dem [0, 255] Bereich. Dies ist für ein neuronales Netzwerk nicht ideal; Im Allgemeinen sollten Sie versuchen, Ihre Eingabewerte klein zu halten. Hier finden Sie Werte standardisieren in der sein [0, 1] Bereich durch die Verwendung tf.keras.layers.experimental.preprocessing.Rescaling Schicht.

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

Es gibt zwei Möglichkeiten, diese Ebene zu verwenden. Sie können es auf das Dataset anwenden, indem Sie map aufrufen:

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

Oder Sie können den Layer in Ihre Modelldefinition einschließen, um die Bereitstellung zu vereinfachen. Sie werden hier den zweiten Ansatz verwenden.

Konfigurieren Sie das Dataset für die Leistung

Stellen Sie sicher, dass Sie gepuffertes Prefetching verwenden, damit Sie Daten von der Festplatte abrufen können, ohne dass die E/A blockiert wird. Dies sind zwei wichtige Methoden, die Sie beim Laden von Daten verwenden sollten.

.cache() hält die Bilder im Speicher , nachdem sie während der ersten Epoche aus der Festplatte geladen ist. Dadurch wird sichergestellt, dass das Dataset beim Trainieren Ihres Modells nicht zu einem Engpass wird. Wenn Ihr Dataset zu groß ist, um in den Arbeitsspeicher zu passen, können Sie mit dieser Methode auch einen leistungsfähigen Cache auf der Festplatte erstellen.

.prefetch() überlappt Datenvorverarbeitung und Modellausführung während des Trainings.

Interessierte Leser können mehr über die beiden Methoden, als auch, wie auf Cache - Daten auf die Festplatte in der Lerndaten Performance Guide .

AUTOTUNE = tf.data.AUTOTUNE

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

Trainiere ein Modell

Der Vollständigkeit halber zeigen Sie, wie Sie ein einfaches Modell mit den soeben vorbereiteten Datensätzen trainieren. Dieses Modell wurde in keiner Weise optimiert - das Ziel ist es, Ihnen die Mechanismen anhand der soeben erstellten Datensätze zu zeigen. Um mehr zu erfahren über die Bildklassifikation, besuchen Sie diese Anleitung .

num_classes = 5

model = tf.keras.Sequential([
  tf.keras.layers.experimental.preprocessing.Rescaling(1./255),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Conv2D(32, 3, activation='relu'),
  tf.keras.layers.MaxPooling2D(),
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation='relu'),
  tf.keras.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 [==============================] - 11s 27ms/step - loss: 1.3361 - accuracy: 0.4486 - val_loss: 1.1087 - val_accuracy: 0.5286
Epoch 2/3
92/92 [==============================] - 1s 11ms/step - loss: 1.0482 - accuracy: 0.5872 - val_loss: 1.0247 - val_accuracy: 0.5913
Epoch 3/3
92/92 [==============================] - 1s 11ms/step - loss: 0.9310 - accuracy: 0.6383 - val_loss: 0.9354 - val_accuracy: 0.6267
<tensorflow.python.keras.callbacks.History at 0x7fe9ad142dd0>

Möglicherweise stellen Sie fest, dass die Validierungsgenauigkeit im Vergleich zur Trainingsgenauigkeit niedrig ist, was darauf hindeutet, dass Ihr Modell überangepasst ist. Sie können erfahren Sie mehr über Überanpassung und wie es in diesen reduzieren Tutorial .

Mit tf.data für eine feinere Kontrolle

Die oben tf.keras.preprocessing Dienstprogramme sind ein bequemer Weg zur Schaffung eines tf.data.Dataset aus einem Verzeichnis von Bildern. Für feinere Kornsteuerung können Sie Ihre eigenen Eingang Pipeline mit schreiben tf.data . Dieser Abschnitt zeigt, wie Sie genau das tun, beginnend mit den Dateipfaden aus der TGZ-Datei, die Sie zuvor heruntergeladen haben.

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/16970837587_4a9d8500d7.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/roses/8337607102_d9e0fa887e.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/sunflowers/5032376020_2ed312306c.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/tulips/7166606598_5d2cd307c3.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/sunflowers/235651658_a7b3e7cbdd.jpg'

Die Baumstruktur der Dateien kann verwendet werden , um eine zu kompilieren class_names Liste.

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

Teilen Sie das Dataset in Training und Validierung auf:

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

Sie können die Länge jedes Datensatzes wie folgt sehen:

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

Schreibe eine kurze Funktion , die einen Dateipfad zu einem umwandelt (img, label) Paar:

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.io.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

Verwendung Dataset.map zu einem Datensatz von erstellen 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

Dataset für Leistung konfigurieren

Um ein Modell mit diesem Datensatz zu trainieren, benötigen Sie die Daten:

  • Gut gemischt sein.
  • Gestapelt werden.
  • Chargen sollen so schnell wie möglich verfügbar sein.

Diese Funktionen können mit dem hinzugefügt werden tf.data API. Weitere Details, die Eingang Pipeline Performance Führung.

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)

Visualisieren Sie die Daten

Sie können dieses Dataset ähnlich wie das zuvor erstellte visualisieren.

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

Trainieren Sie das Modell weiter

Sie haben nun ein ähnliches manuell gebaut tf.data.Dataset den von dem erstellten keras.preprocessing oben. Sie können das Modell damit weiter trainieren. Nach wie vor trainierst du nur wenige Epochen, um die Laufzeit kurz zu halten.

model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=3
)
Epoch 1/3
92/92 [==============================] - 2s 20ms/step - loss: 0.8191 - accuracy: 0.6734 - val_loss: 0.7638 - val_accuracy: 0.7221
Epoch 2/3
92/92 [==============================] - 1s 12ms/step - loss: 0.6748 - accuracy: 0.7432 - val_loss: 0.8300 - val_accuracy: 0.6744
Epoch 3/3
92/92 [==============================] - 1s 12ms/step - loss: 0.5102 - accuracy: 0.8099 - val_loss: 0.7650 - val_accuracy: 0.7016
<tensorflow.python.keras.callbacks.History at 0x7fe9acfb0d50>

Verwenden von TensorFlow-Datensätzen

Bisher hat sich dieses Tutorial auf das Laden von Daten von der Festplatte konzentriert. Sie können auch einen Datensatz zu verwenden , indem die Erkundung der großen finden Katalog von easy-to-Download - Datensätze bei TensorFlow Datensätze . Nachdem Sie das Flowers-Dataset zuvor von der Festplatte geladen haben, sehen wir uns an, wie Sie es mit TensorFlow-Datasets importieren.

Laden Sie die Blumen Dataset mit TensorFlow Datensätze.

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

Der Blumen-Datensatz hat fünf Klassen.

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

Rufen Sie ein Bild aus dem Dataset ab.

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

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

png

Denken Sie wie zuvor daran, jedes Dataset für die Leistung zu stapeln, zu mischen und zu konfigurieren.

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

Sie können ein vollständiges Beispiel für die Arbeit mit dem Blumen - Datensatz und TensorFlow Datensätze durch den Besuch finden Daten Augmentation Tutorial.

Nächste Schritte

In diesem Tutorial wurden zwei Möglichkeiten zum Laden von Bildern von der Festplatte gezeigt. Zuerst haben Sie gelernt, wie Sie ein Bild-Dataset mit Keras-Vorverarbeitungsebenen und -Dienstprogrammen laden und vorverarbeiten. Als nächstes haben Sie gelernt , wie eine Eingangsleitung von Grund auf neu zu schreiben , mit tf.data . Schließlich haben Sie gelernt, wie Sie einen Datensatz von TensorFlow-Datensätzen herunterladen. Als nächsten Schritt können Sie lernen , wie man Daten Augmentation hinzufügen , indem Sie diese besuchen Tutorial . Um mehr zu erfahren über tf.data , können Sie den Besuch tf.data: Erstellen TensorFlow Eingangsleitungen führen.