Cette page a été traduite par l'API Cloud Translation.
Switch to English

Charger des images

Voir sur TensorFlow.org Exécuter dans Google Colab Afficher la source sur GitHub Télécharger le carnet

Ce didacticiel montre comment charger et prétraiter un jeu de données d'image de trois manières. Tout d'abord, vous utiliserez des utilitaires et des couches de prétraitement Keras de haut niveau pour lire un répertoire d'images sur le disque. Ensuite, vous allez écrire votre propre pipeline d'entrée à partir de zéro en utilisant tf.data . Enfin, vous téléchargerez un ensemble de données à partir du grand catalogue disponible dans les ensembles de données TensorFlow .

Installer

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

Téléchargez le jeu de données sur les fleurs

Ce tutoriel utilise un ensemble de données de plusieurs milliers de photos de fleurs. Le jeu de données Flowers contient 5 sous-répertoires, un par classe:

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)

Après le téléchargement (218 Mo), vous devriez maintenant avoir une copie des photos de fleurs disponibles. Il y a 3670 images au total:

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

Chaque répertoire contient des images de ce type de fleur. Voici quelques roses:

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

Charger à l'aide de keras.preprocessing

Chargez ces images hors du disque en utilisant image_dataset_from_directory .

Créer un jeu de données

Définissez quelques paramètres pour le chargeur:

batch_size = 32
img_height = 180
img_width = 180

Il est recommandé d'utiliser une séparation de validation lors du développement de votre modèle. Nous utiliserons 80% des images pour la formation et 20% pour la validation.

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.

Vous pouvez trouver les noms de classe dans l'attribut class_names sur ces ensembles de données.

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

Visualisez les données

Voici les 9 premières images de l'ensemble de données d'entraînement.

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

Vous pouvez entraîner un modèle à l'aide de ces ensembles de données en les transmettant à model.fit (illustré plus loin dans ce didacticiel). Si vous le souhaitez, vous pouvez également parcourir manuellement l'ensemble de données et récupérer des lots d'images:

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

L' image_batch est un tenseur de la forme (32, 180, 180, 3) . Il s'agit d'un lot de 32 images de forme 180x180x3 (la dernière dimension se réfère aux canaux de couleur RVB). Le label_batch est un tenseur de la forme (32,) , ce sont des labels correspondants aux 32 images.

Standardiser les données

Les valeurs du canal RVB sont dans la plage [0, 255] . Ce n'est pas idéal pour un réseau neuronal; en général, vous devriez chercher à réduire vos valeurs d'entrée. Ici, nous normaliserons les valeurs pour qu'elles soient dans [0, 1] en utilisant une couche de redimensionnement.

from tensorflow.keras import layers

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

Il existe deux façons d'utiliser cette couche. Vous pouvez l'appliquer à l'ensemble de données en appelant 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

Vous pouvez également inclure la couche dans votre définition de modèle pour simplifier le déploiement. Nous utiliserons ici la deuxième approche.

Configurer l'ensemble de données pour les performances

Veillons à utiliser la prélecture tamponnée afin que nous puissions générer des données à partir du disque sans que les E / S deviennent bloquantes. Ce sont deux méthodes importantes que vous devez utiliser lors du chargement de données.

.cache() garde les images en mémoire après leur chargement hors du disque au cours de la première époque. Cela garantira que l'ensemble de données ne deviendra pas un goulot d'étranglement lors de l'entraînement de votre modèle. Si votre ensemble de données est trop volumineux pour tenir dans la mémoire, vous pouvez également utiliser cette méthode pour créer un cache sur disque performant.

.prefetch() chevauche le prétraitement des données et l'exécution du modèle pendant l'entraînement.

Les lecteurs intéressés peuvent en savoir plus sur les deux méthodes, ainsi que sur la mise en cache des données sur disque dans le guide des performances des données .

AUTOTUNE = tf.data.experimental.AUTOTUNE

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

Former un mannequin

Pour être complet, nous montrerons comment entraîner un modèle simple en utilisant les jeux de données que nous venons de préparer. Ce modèle n'a en aucun cas été réglé - le but est de vous montrer les mécanismes en utilisant les jeux de données que vous venez de créer. Pour en savoir plus sur la classification des images, consultez ce didacticiel .

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 [==============================] - 7s 74ms/step - loss: 1.3679 - accuracy: 0.4131 - val_loss: 1.1740 - val_accuracy: 0.5381
Epoch 2/3
92/92 [==============================] - 1s 11ms/step - loss: 1.0772 - accuracy: 0.5623 - val_loss: 1.0466 - val_accuracy: 0.5899
Epoch 3/3
92/92 [==============================] - 1s 11ms/step - loss: 0.9490 - accuracy: 0.6349 - val_loss: 0.9824 - val_accuracy: 0.6267

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

Vous remarquerez peut-être que la précision de la validation est faible par rapport à la précision de la formation, ce qui indique que notre modèle est surajusté. Vous pouvez en savoir plus sur le surajustement et comment le réduire dans ce didacticiel .

Utilisation de tf.data pour un contrôle plus fin

Les utilitaires keras.preprocessing ci-dessus sont un moyen pratique de créer un tf.data.Dataset partir d'un répertoire d'images. Pour un contrôle plus fin du grain, vous pouvez écrire votre propre pipeline d'entrée à l'aide de tf.data . Cette section montre comment faire exactement cela, en commençant par les chemins de fichiers du zip que nous avons téléchargé précédemment.

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/tulips/13510068773_c925c5517c.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/tulips/6931748252_68f06086b3.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/daisy/1031799732_e7f4008c03.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/dandelion/18342918441_b1bb69a2fd_n.jpg'
b'/home/kbuilder/.keras/datasets/flower_photos/daisy/162362896_99c7d851c8_n.jpg'

L'arborescence des fichiers peut être utilisée pour compiler une liste 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']

Divisez l'ensemble de données en train et validation:

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

Vous pouvez voir la longueur de chaque ensemble de données comme suit:

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

Écrivez une fonction courte qui convertit un chemin de fichier en une paire (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

Utilisez Dataset.map pour créer un ensemble de données d' image, label paires d' 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:  4

Configurer l'ensemble de données pour les performances

Pour entraîner un modèle avec cet ensemble de données, vous aurez besoin des données:

  • Pour être bien mélangé.
  • Pour être groupé.
  • Les lots seront disponibles dès que possible.

Ces fonctionnalités peuvent être ajoutées à l'aide de l'API tf.data . Pour plus de détails, consultez le guide Performances du pipeline d'entrée .

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)

Visualisez les données

Vous pouvez visualiser cet ensemble de données de la même manière que celui que vous avez créé précédemment.

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

Continuer la formation du modèle

Vous avez maintenant créé manuellement un tf.data.Dataset similaire à celui créé par keras.preprocessing ci-dessus. Vous pouvez continuer à entraîner le modèle avec. Comme auparavant, nous nous entraînerons pendant quelques époques pour réduire le temps de fonctionnement.

model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=3
)
Epoch 1/3
92/92 [==============================] - 2s 20ms/step - loss: 0.8373 - accuracy: 0.6890 - val_loss: 0.8115 - val_accuracy: 0.6866
Epoch 2/3
92/92 [==============================] - 1s 12ms/step - loss: 0.6614 - accuracy: 0.7585 - val_loss: 0.7761 - val_accuracy: 0.7003
Epoch 3/3
92/92 [==============================] - 1s 11ms/step - loss: 0.4723 - accuracy: 0.8294 - val_loss: 0.8492 - val_accuracy: 0.7125

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

Utilisation des ensembles de données TensorFlow

Jusqu'à présent, ce didacticiel s'est concentré sur le chargement de données depuis le disque. Vous pouvez également trouver un ensemble de données à utiliser en explorant le vaste catalogue d'ensembles de données faciles à télécharger sur les ensembles de données TensorFlow . Comme vous avez précédemment chargé l'ensemble de données Flowers hors disque, voyons comment l'importer avec les ensembles de données TensorFlow.

Téléchargez l' ensemble de données Flowers à l'aide des ensembles de données TensorFlow.

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

L'ensemble de données des fleurs comprend cinq classes.

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

Récupérez une image de l'ensemble de données.

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

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

png

Comme auparavant, n'oubliez pas de regrouper, de mélanger et de configurer chaque ensemble de données pour les performances.

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

Vous pouvez trouver un exemple complet d'utilisation de l'ensemble de données Flowers et des ensembles de données TensorFlow en visitant le didacticiel d' augmentation des données .

Prochaines étapes

Ce didacticiel a montré deux façons de charger des images hors du disque. Tout d'abord, vous avez appris à charger et à prétraiter un jeu de données d'image à l'aide des couches et des utilitaires de prétraitement Keras. Ensuite, vous avez appris à écrire un pipeline d'entrée à partir de zéro à l'aide de tf.data. Enfin, vous avez appris à télécharger un ensemble de données à partir d'ensembles de données TensorFlow. Dans l'étape suivante, vous pouvez apprendre à ajouter une augmentation de données en visitant ce didacticiel . Pour en savoir plus sur tf.data, vous pouvez consulter ce guide .