Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

Załaduj obrazki

Zobacz na TensorFlow.org Uruchom w Google Colab Wyświetl źródło na GitHub Pobierz notatnik

W tym samouczku pokazano, jak ładować i wstępnie przetwarzać zestaw danych obrazu na dwa sposoby. Najpierw użyjesz narzędzi i warstw Keras do wstępnego przetwarzania. Następnie napiszesz od podstaw swój własny potok wejściowy przy użyciu tf.data .

Ustawiać

 import numpy as np
import os
import PIL
import PIL.Image
import tensorflow as tf
 
 print(tf.__version__)
 
2.3.0

Pobierz zestaw danych o kwiatach

W tym samouczku wykorzystano zbiór danych zawierający kilka tysięcy zdjęć kwiatów. Zbiór danych flowers zawiera 5 podkatalogów, po jednym na klasę:

 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)
 

Po pobraniu (218 MB) powinieneś mieć dostępną kopię zdjęć kwiatów. Łącznie jest 3670 zdjęć:

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

Każdy katalog zawiera obrazy tego rodzaju kwiatów. Oto kilka róż:

 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

Załaduj za pomocą keras.preprocessing

Załadujmy te obrazy z dysku za pomocą image_dataset_from_directory .

Utwórz zbiór danych

Zdefiniuj niektóre parametry programu ładującego:

 batch_size = 32
img_height = 180
img_width = 180
 

Podczas opracowywania modelu dobrą praktyką jest używanie podziału na walidację. Będziemy używać 80% obrazów do szkolenia, a 20% do walidacji.

 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.

Nazwy klas można znaleźć w atrybucie class_names w tych class_names danych.

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

Wizualizuj dane

Oto pierwsze 9 obrazów z zestawu danych szkoleniowych.

 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

Możesz wytrenować model przy użyciu tych zestawów danych, przekazując je do model.fit (pokazane w dalszej części tego samouczka). Jeśli chcesz, możesz również ręcznie iterować zestaw danych i pobierać partie obrazów:

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

image_batch to tensor kształtu (32, 180, 180, 3) . Jest to 180x180x3 32 obrazów o kształcie 180x180x3 (ostatni wymiar odnosi się do kanałów kolorów RGB). Element label_batch jest tensorem kształtu (32,) , są to etykiety odpowiadające 32 obrazom.

Standaryzuj dane

Wartości kanałów RGB mieszczą się w zakresie [0, 255] . Nie jest to idealne rozwiązanie dla sieci neuronowej; Ogólnie powinieneś starać się, aby wartości wejściowe były małe. Tutaj ustandaryzujemy wartości tak, aby znajdowały się w przedziale [0, 1] , używając warstwy Rescaling.

 from tensorflow.keras import layers

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

Istnieją dwa sposoby korzystania z tej warstwy. Możesz zastosować go do zbioru danych, wywołując 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

Lub możesz dołączyć warstwę do definicji modelu, aby uprościć wdrażanie. Użyjemy tutaj drugiego podejścia.

Skonfiguruj zbiór danych pod kątem wydajności

Upewnijmy się, że korzystamy z buforowanego pobierania wstępnego, abyśmy mogli pobierać dane z dysku bez blokowania we / wy. Są to dwie ważne metody, których należy używać podczas ładowania danych.

.cache() przechowuje obrazy w pamięci po ich załadowaniu z dysku podczas pierwszej epoki. Dzięki temu zestaw danych nie stanie się wąskim gardłem podczas trenowania modelu. Jeśli zestaw danych jest zbyt duży, aby zmieścić się w pamięci, możesz również użyć tej metody do utworzenia wydajnej pamięci podręcznej na dysku.

.prefetch() nakłada się na przetwarzanie .prefetch() danych i wykonywanie modelu podczas uczenia.

Zainteresowani czytelnicy mogą dowiedzieć się więcej o obu metodach, a także o tym, jak buforować dane na dysku w przewodniku po wydajności danych .

 AUTOTUNE = tf.data.experimental.AUTOTUNE

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

Wytrenuj model

Dla kompletności pokażemy, jak wytrenować prosty model przy użyciu właśnie przygotowanych zestawów danych. Ten model nie został w żaden sposób dostrojony - celem jest pokazanie mechaniki przy użyciu właśnie utworzonych zestawów danych. Aby dowiedzieć się więcej o klasyfikacji obrazów, odwiedź ten samouczek .

 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 [==============================] - 6s 66ms/step - loss: 1.3282 - accuracy: 0.4240 - val_loss: 1.1035 - val_accuracy: 0.5804
Epoch 2/3
92/92 [==============================] - 1s 11ms/step - loss: 1.0304 - accuracy: 0.5913 - val_loss: 0.9515 - val_accuracy: 0.6267
Epoch 3/3
92/92 [==============================] - 1s 11ms/step - loss: 0.8712 - accuracy: 0.6689 - val_loss: 0.9268 - val_accuracy: 0.6471

<tensorflow.python.keras.callbacks.History at 0x7f86d80ad128>

Możesz zauważyć, że dokładność walidacji jest niska w porównaniu z dokładnością treningu, co wskazuje, że nasz model jest nadmiernie dopasowany. Możesz dowiedzieć się więcej o nadmiernym dopasowaniu i jak go zmniejszyć w tym samouczku .

Korzystanie z tf.data dla lepszej kontroli

Powyższe narzędzia keras.preprocessing są wygodnym sposobem tworzenia tf.data.Dataset z katalogu obrazów. Aby uzyskać dokładniejszą kontrolę ziarna, możesz napisać własny potok wejściowy za pomocą tf.data . Ta sekcja pokazuje, jak to zrobić, zaczynając od ścieżek plików z pliku zip, który pobraliśmy wcześniej.

 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/roses/1445228333_59a07e0801.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/dandelion/14128835667_b6a916222c.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/roses/7551637034_55ae047756_n.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/dandelion/4574736702_b15ecf97d0_m.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/roses/6867597533_d65d1c39fb_n.jpg'

Struktura drzewa plików może zostać użyta do skompilowania listy 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']

Podziel zbiór danych na pociąg i walidację:

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

Możesz zobaczyć długość każdego zbioru danych w następujący sposób:

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

Napisz krótką funkcję, która konwertuje ścieżkę do pliku na parę (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
 

Użyj Dataset.map aby utworzyć zestaw danych image, label par 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

Skonfiguruj zbiór danych pod kątem wydajności

Aby wytrenować model z tym zestawem danych, będziesz potrzebować danych:

  • Być dobrze przetasowanym.
  • Do partii.
  • Partie mają być dostępne jak najszybciej.

Te funkcje można dodać za pomocą interfejsu API tf.data . Aby uzyskać więcej informacji, zobacz przewodnik dotyczący wydajności potoku wejściowego .

 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)
 

Wizualizuj dane

Możesz wizualizować ten zbiór danych podobnie do utworzonego wcześniej.

 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

Kontynuuj trenowanie modelu

tf.data.Dataset teraz ręcznie podobny tf.data.Dataset do tego utworzonego przez powyższy keras.preprocessing . Możesz dalej trenować z nim model. Tak jak poprzednio, będziemy trenować tylko przez kilka epok, aby skrócić czas biegu.

 model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=3
)
 
Epoch 1/3
92/92 [==============================] - 2s 19ms/step - loss: 0.7267 - accuracy: 0.7272 - val_loss: 0.7963 - val_accuracy: 0.7098
Epoch 2/3
92/92 [==============================] - 1s 11ms/step - loss: 0.5384 - accuracy: 0.7987 - val_loss: 0.8067 - val_accuracy: 0.6894
Epoch 3/3
92/92 [==============================] - 1s 11ms/step - loss: 0.3382 - accuracy: 0.8770 - val_loss: 1.0317 - val_accuracy: 0.6662

<tensorflow.python.keras.callbacks.History at 0x7f87cd496320>

Następne kroki

W tym samouczku pokazano dwa sposoby ładowania obrazów z dysku. Najpierw nauczyłeś się, jak ładować i wstępnie przetwarzać zestaw danych obrazu za pomocą warstw i narzędzi Keras wstępnie przetwarzających. Następnie nauczyłeś się, jak napisać potok wejściowy od podstaw przy użyciu tf.data. W następnym kroku możesz dowiedzieć się, jak dodać rozszerzenie danych, odwiedzając ten samouczek . Aby dowiedzieć się więcej o tf.data, możesz odwiedzić ten przewodnik .