Datenerweiterung

Auf TensorFlow.org ansehen In Google Colab ausführen Quelle auf GitHub anzeigen Notizbuch herunterladen

Überblick

In diesem Tutorial wird die Datenerweiterung demonstriert: eine Technik, mit der Sie die Vielfalt Ihres Trainingssatzes durch zufällige (aber realistische) Transformationen wie die Bilddrehung erhöhen können. Sie erfahren, wie Sie die Datenerweiterung auf zwei Arten anwenden. Als erstes müssen Sie verwenden Keras Preprocessing Ebenen . Als nächstes werden Sie verwenden tf.image .

Installieren

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import tensorflow_datasets as tfds

from tensorflow.keras import layers
2021-07-31 01:20:29.398577: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0

Einen Datensatz herunterladen

Dieses Tutorial verwendet die tf_flowers Dataset. Der Einfachheit halber, laden Sie die Datenmenge mit TensorFlow Datensammlungen . Wenn Sie möchten , über andere Möglichkeiten, den Import von Daten lernen, die sehen Bilder laden Tutorial.

(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,
)
2021-07-31 01:20:32.658409: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcuda.so.1
2021-07-31 01:20:33.245494: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.246357: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-07-31 01:20:33.246390: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-07-31 01:20:33.249453: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
2021-07-31 01:20:33.249541: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11
2021-07-31 01:20:33.250610: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcufft.so.10
2021-07-31 01:20:33.250929: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcurand.so.10
2021-07-31 01:20:33.251983: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusolver.so.11
2021-07-31 01:20:33.252852: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcusparse.so.11
2021-07-31 01:20:33.253031: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudnn.so.8
2021-07-31 01:20:33.253121: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.253980: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.254770: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-07-31 01:20:33.255502: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-07-31 01:20:33.256126: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.256945: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1733] Found device 0 with properties: 
pciBusID: 0000:00:05.0 name: Tesla V100-SXM2-16GB computeCapability: 7.0
coreClock: 1.53GHz coreCount: 80 deviceMemorySize: 15.78GiB deviceMemoryBandwidth: 836.37GiB/s
2021-07-31 01:20:33.257035: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.257857: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.258642: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1871] Adding visible gpu devices: 0
2021-07-31 01:20:33.258683: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
2021-07-31 01:20:33.827497: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1258] Device interconnect StreamExecutor with strength 1 edge matrix:
2021-07-31 01:20:33.827531: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1264]      0 
2021-07-31 01:20:33.827538: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1277] 0:   N 
2021-07-31 01:20:33.827734: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.828649: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.829480: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-07-31 01:20:33.830357: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1418] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 14646 MB memory) -> physical GPU (device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0)

Der Blumen-Datensatz hat fünf Klassen.

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

Lassen Sie uns ein Bild aus dem Dataset abrufen und es verwenden, um die Datenerweiterung zu demonstrieren.

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

image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
2021-07-31 01:20:33.935374: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:176] None of the MLIR Optimization Passes are enabled (registered 2)
2021-07-31 01:20:33.935908: I tensorflow/core/platform/profile_utils/cpu_utils.cc:114] CPU Frequency: 2000160000 Hz
2021-07-31 01:20:34.470092: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

png

Keras-Vorverarbeitungsebenen verwenden

Größe ändern und skalieren

Sie können Vorverarbeitung Schichten verwenden , um die Größe Ihrer Bilder auf eine konsistente Form und rescale Pixelwerte.

IMG_SIZE = 180

resize_and_rescale = tf.keras.Sequential([
  layers.experimental.preprocessing.Resizing(IMG_SIZE, IMG_SIZE),
  layers.experimental.preprocessing.Rescaling(1./255)
])

Sie können das Ergebnis der Anwendung dieser Ebenen auf ein Bild sehen.

result = resize_and_rescale(image)
_ = plt.imshow(result)

png

Sie können die Pixel in verifizieren [0-1] .

print("Min and max pixel values:", result.numpy().min(), result.numpy().max())
Min and max pixel values: 0.0 1.0

Datenerweiterung

Sie können Vorverarbeitungsschichten auch für die Datenerweiterung verwenden.

Lassen Sie uns einige Vorverarbeitungsebenen erstellen und diese wiederholt auf dasselbe Bild anwenden.

data_augmentation = tf.keras.Sequential([
  layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
  layers.experimental.preprocessing.RandomRotation(0.2),
])
# Add the image to a batch
image = tf.expand_dims(image, 0)
plt.figure(figsize=(10, 10))
for i in range(9):
  augmented_image = data_augmentation(image)
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(augmented_image[0])
  plt.axis("off")

png

Es gibt eine Vielzahl von Vorverarbeitung Schichten Sie für die Datenvergrößerung einschließlich verwenden können layers.RandomContrast , layers.RandomCrop , layers.RandomZoom und andere.

Zwei Optionen zur Verwendung der Vorverarbeitungsebenen

Es gibt zwei Möglichkeiten, diese Vorverarbeitungsebenen zu verwenden, mit wichtigen Kompromissen.

Option 1: Machen Sie die Vorverarbeitungsebenen zu einem Teil Ihres Modells

model = tf.keras.Sequential([
  resize_and_rescale,
  data_augmentation,
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  # Rest of your model
])

In diesem Fall sind zwei wichtige Punkte zu beachten:

  • Die Datenerweiterung wird auf dem Gerät synchron mit den restlichen Ebenen ausgeführt und profitiert von der GPU-Beschleunigung.

  • Wenn Sie Ihr Modell exportieren model.save , werden die Vorverarbeitung Schichten zusammen mit dem Rest des Modells gespeichert werden. Wenn Sie dieses Modell später bereitstellen, werden Bilder automatisch standardisiert (entsprechend der Konfiguration Ihrer Layer). Dies kann Ihnen den Aufwand ersparen, diese Logik serverseitig neu implementieren zu müssen.

Option 2: Wenden Sie die Vorverarbeitungs-Layer auf Ihr Dataset an

aug_ds = train_ds.map(
  lambda x, y: (resize_and_rescale(x, training=True), y))

Mit diesem Ansatz verwenden Sie Dataset.map einen Datensatz , dass die Renditen Chargen von Augmented Bilder zu erstellen. In diesem Fall:

  • Die Datenerweiterung erfolgt asynchron auf der CPU und ist nicht blockierend. Sie können die Ausbildung Ihres Modells überlappen auf der GPU mit Datenvorverarbeitung mit Dataset.prefetch unten gezeigt.
  • In diesem Fall ist die prepreprocessing Schichten nicht mit dem Modell exportiert werden , wenn Sie anrufen model.save . Sie müssen sie an Ihr Modell anhängen, bevor Sie es speichern oder serverseitig neu implementieren. Nach dem Training können Sie die Vorverarbeitungsebenen vor dem Export anhängen.

Sie können ein Beispiel für die erste Option in dem finden Bildklassifizierungs- Tutorial. Lassen Sie uns hier die zweite Option demonstrieren.

Wenden Sie die Vorverarbeitungs-Layer auf die Datensätze an

Konfigurieren Sie die Trainings-, Validierungs- und Test-Datasets mit den oben erstellten Vorverarbeitungs-Layern. Sie konfigurieren die Datasets auch für die Leistung, indem Sie parallele Lesevorgänge und gepuffertes Prefetching verwenden, um Batches von der Festplatte zu erhalten, ohne dass E/A blockiert wird. Sie können mehr Daten - Set Leistung in der lernen Besseren Leistung mit der tf.data API Führung.

batch_size = 32
AUTOTUNE = tf.data.AUTOTUNE

def prepare(ds, shuffle=False, augment=False):
  # Resize and rescale all datasets
  ds = ds.map(lambda x, y: (resize_and_rescale(x), y), 
              num_parallel_calls=AUTOTUNE)

  if shuffle:
    ds = ds.shuffle(1000)

  # Batch all datasets
  ds = ds.batch(batch_size)

  # Use data augmentation only on the training set
  if augment:
    ds = ds.map(lambda x, y: (data_augmentation(x, training=True), y), 
                num_parallel_calls=AUTOTUNE)

  # Use buffered prefecting on all datasets
  return ds.prefetch(buffer_size=AUTOTUNE)
train_ds = prepare(train_ds, shuffle=True, augment=True)
val_ds = prepare(val_ds)
test_ds = prepare(test_ds)

Trainiere ein Modell

Der Vollständigkeit halber trainieren Sie nun ein Modell mit diesen Datensätzen. Dieses Modell wurde nicht auf Genauigkeit abgestimmt (das Ziel ist es, Ihnen die Mechanik zu zeigen).

model = tf.keras.Sequential([
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes)
])
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
epochs=5
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)
Epoch 1/5
2021-07-31 01:20:39.448244: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudnn.so.8
2021-07-31 01:20:41.475212: I tensorflow/stream_executor/cuda/cuda_dnn.cc:359] Loaded cuDNN version 8100
2021-07-31 01:20:46.496035: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublas.so.11
2021-07-31 01:20:46.860481: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcublasLt.so.11
92/92 [==============================] - 17s 66ms/step - loss: 1.3434 - accuracy: 0.4271 - val_loss: 1.1534 - val_accuracy: 0.5368
Epoch 2/5
92/92 [==============================] - 3s 27ms/step - loss: 1.0960 - accuracy: 0.5565 - val_loss: 1.0718 - val_accuracy: 0.5695
Epoch 3/5
92/92 [==============================] - 3s 26ms/step - loss: 1.0115 - accuracy: 0.5988 - val_loss: 1.0322 - val_accuracy: 0.6022
Epoch 4/5
92/92 [==============================] - 3s 27ms/step - loss: 0.9503 - accuracy: 0.6202 - val_loss: 0.8811 - val_accuracy: 0.6730
Epoch 5/5
92/92 [==============================] - 3s 27ms/step - loss: 0.8758 - accuracy: 0.6570 - val_loss: 0.8760 - val_accuracy: 0.6485
loss, acc = model.evaluate(test_ds)
print("Accuracy", acc)
12/12 [==============================] - 1s 13ms/step - loss: 0.8319 - accuracy: 0.6812
Accuracy 0.6811988949775696

Benutzerdefinierte Datenerweiterung

Sie können auch benutzerdefinierte Datenerweiterungs-Layer erstellen. Dieses Tutorial zeigt zwei Möglichkeiten, dies zu tun. Als erstes müssen Sie eine erstellen layers.Lambda Schicht. Dies ist eine gute Möglichkeit, prägnanten Code zu schreiben. Als nächstes werden Sie eine neue Ebene über schreiben Subklassifizieren , die Ihnen mehr Kontrolle. Beide Ebenen invertieren die Farben in einem Bild mit einer gewissen Wahrscheinlichkeit zufällig.

def random_invert_img(x, p=0.5):
  if  tf.random.uniform([]) < p:
    x = (255-x)
  else:
    x
  return x
def random_invert(factor=0.5):
  return layers.Lambda(lambda x: random_invert_img(x, factor))

random_invert = random_invert()
plt.figure(figsize=(10, 10))
for i in range(9):
  augmented_image = random_invert(image)
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(augmented_image[0].numpy().astype("uint8"))
  plt.axis("off")

png

Als nächstes wird eine eigene Schicht , die durch Umsetzung von Unterklassen .

class RandomInvert(layers.Layer):
  def __init__(self, factor=0.5, **kwargs):
    super().__init__(**kwargs)
    self.factor = factor

  def call(self, x):
    return random_invert_img(x)
_ = plt.imshow(RandomInvert()(image)[0])

png

Beide Ebenen können wie in den Optionen 1 und 2 oben beschrieben verwendet werden.

tf.image verwenden

Die oben layers.preprocessing Dienstprogramme sind bequem. Für eine feinere Steuerung, können Sie Ihre eigenen Daten Augmentation Pipelines oder Schichten mit schreiben tf.data und tf.image . Sie können auch zu prüfen , TensorFlow Addons Bild: Operationen und TensorFlow I / O: Farbraumkonvertierungen

Da das Blumen-Dataset zuvor mit Datenerweiterung konfiguriert wurde, importieren wir es erneut, um neu zu beginnen.

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

Rufen Sie ein Bild ab, mit dem Sie arbeiten möchten.

image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
2021-07-31 01:21:08.829596: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

png

Lassen Sie uns die folgende Funktion verwenden, um die Original- und Augmented-Bilder nebeneinander zu visualisieren und zu vergleichen.

def visualize(original, augmented):
  fig = plt.figure()
  plt.subplot(1,2,1)
  plt.title('Original image')
  plt.imshow(original)

  plt.subplot(1,2,2)
  plt.title('Augmented image')
  plt.imshow(augmented)

Datenerweiterung

Spiegeln des Bildes

Spiegeln Sie das Bild entweder vertikal oder horizontal.

flipped = tf.image.flip_left_right(image)
visualize(image, flipped)

png

Graustufen des Bildes

Graustufen eines Bildes.

grayscaled = tf.image.rgb_to_grayscale(image)
visualize(image, tf.squeeze(grayscaled))
_ = plt.colorbar()

png

Sättigen Sie das Bild

Sättigen Sie ein Bild, indem Sie einen Sättigungsfaktor angeben.

saturated = tf.image.adjust_saturation(image, 3)
visualize(image, saturated)

png

Bildhelligkeit ändern

Ändern Sie die Helligkeit des Bildes, indem Sie einen Helligkeitsfaktor angeben.

bright = tf.image.adjust_brightness(image, 0.4)
visualize(image, bright)

png

Bild mittig zuschneiden

Beschneiden Sie das Bild von der Mitte bis zum gewünschten Bildteil.

cropped = tf.image.central_crop(image, central_fraction=0.5)
visualize(image,cropped)

png

Bild drehen

Drehen Sie ein Bild um 90 Grad.

rotated = tf.image.rot90(image)
visualize(image, rotated)

png

Zufällige Transformationen

Durch das Anwenden zufälliger Transformationen auf die Bilder kann das Dataset weiter verallgemeinert und erweitert werden. Current tf.image API stellt 8 eine solche Zufallsbild - Operationen (ops):

Diese zufälligen Bildoperationen sind rein funktional: Die Ausgabe hängt nur von der Eingabe ab. Dies macht sie einfach in leistungsstarken, deterministischen Eingabepipelines zu verwenden. Sie benötigen einen seed Wert eingegeben werden , jeder Schritt. Bei gleichem seed , kehren sie die gleichen Ergebnisse unabhängig davon , wie oft sie aufgerufen werden.

In den folgenden Abschnitten werden Sie:

  1. Gehen Sie Beispiele für die Verwendung zufälliger Bildoperationen durch, um ein Bild zu transformieren; und
  2. Demonstrieren Sie, wie Sie zufällige Transformationen auf ein Trainings-Dataset anwenden.

Bildhelligkeit zufällig ändern

Ändern zufall die Helligkeit des image durch einen Helligkeitsfaktor und Bereitstellen seed . Der Helligkeitsfaktor wird zufällig in dem Bereich gewählt [-max_delta, max_delta) und ist mit dem zugehörigen gegebenen seed .

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_brightness = tf.image.stateless_random_brightness(
      image, max_delta=0.95, seed=seed)
  visualize(image, stateless_random_brightness)

png

png

png

Bildkontrast zufällig ändern

Ändern zufall den Kontrast des image durch einen Kontrastbereich und die Bereitstellung seed . Der Kontrastbereich wird zufällig in dem Intervall gewählt , [lower, upper] und wird mit den zugeordneten gegebenen seed .

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_contrast = tf.image.stateless_random_contrast(
      image, lower=0.1, upper=0.9, seed=seed)
  visualize(image, stateless_random_contrast)

png

png

png

Ein Bild zufällig zuschneiden

Ernte Randomly image durch genauere size und seed . Der Teil, der aus beschnitten wird image ist an einem zufällig gewählten Versatz und ist mit dem zugehörigen gegebenen seed .

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_crop = tf.image.stateless_random_crop(
      image, size=[210, 300, 3], seed=seed)
  visualize(image, stateless_random_crop)

png

png

png

Anwenden von Erweiterungen auf ein Dataset

Laden wir zunächst den Bilddatensatz erneut herunter, falls er in den vorherigen Abschnitten geändert wurde.

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

Lassen Sie uns eine Dienstprogrammfunktion zum Ändern der Größe und Skalierung der Bilder definieren. Diese Funktion wird verwendet, um die Größe und den Maßstab der Bilder im Datensatz zu vereinheitlichen:

def resize_and_rescale(image, label):
  image = tf.cast(image, tf.float32)
  image = tf.image.resize(image, [IMG_SIZE, IMG_SIZE])
  image = (image / 255.0)
  return image, label

Lassen Sie uns auch definieren augment Funktion, die die Zufalls Transformationen auf die Bilder anwenden können. Diese Funktion wird im nächsten Schritt für den Datensatz verwendet.

def augment(image_label, seed):
  image, label = image_label
  image, label = resize_and_rescale(image, label)
  image = tf.image.resize_with_crop_or_pad(image, IMG_SIZE + 6, IMG_SIZE + 6)
  # Make a new seed
  new_seed = tf.random.experimental.stateless_split(seed, num=1)[0, :]
  # Random crop back to the original size
  image = tf.image.stateless_random_crop(
      image, size=[IMG_SIZE, IMG_SIZE, 3], seed=seed)
  # Random brightness
  image = tf.image.stateless_random_brightness(
      image, max_delta=0.5, seed=new_seed)
  image = tf.clip_by_value(image, 0, 1)
  return image, label

Option 1: Mit tf.data.experimental.Counter()

Erstellen Sie eine tf.data.experimental.Counter() Objekt (nennen wir es counter ) und zip den Datensatz mit (counter, counter) . Dadurch wird sichergestellt , dass jedes Bild in dem Datensatz mit einem eindeutigen Wert zugeordnet wird (der Form (2,) ) , basierend auf counter , die in die vergangen später bekommen augment Funktion als seed Wert für Zufall Transformationen.

# Create counter and zip together with train dataset
counter = tf.data.experimental.Counter()
train_ds = tf.data.Dataset.zip((train_datasets, (counter, counter)))

Ordnen Sie die augment Funktion auf die Trainingsdaten.

train_ds = (
    train_ds
    .shuffle(1000)
    .map(augment, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
val_ds = (
    val_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
test_ds = (
    test_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)

Option 2: Verwenden tf.random.Generator

Erstellen Sie ein tf.random.Generator Objekt mit einem anfänglichen seed Wert. Aufruf make_seeds Funktion auf dem gleichen Generator Objekt gibt einen neuen, einzigartigen seed Wert immer. Definieren eine Wrapper - Funktion , dass 1) ruft make_seeds Funktion und dass 2) übergibt den neu erzeugten seed Wert in die augment Funktion für Zufall Transformationen.

# Create a generator
rng = tf.random.Generator.from_seed(123, alg='philox')
# A wrapper function for updating seeds
def f(x, y):
  seed = rng.make_seeds(2)[0]
  image, label = augment((x, y), seed)
  return image, label

Ordnen Sie die Wrapper - Funktion f auf die Trainingsdaten.

train_ds = (
    train_datasets
    .shuffle(1000)
    .map(f, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
val_ds = (
    val_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
test_ds = (
    test_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)

Diese Datensätze können nun verwendet werden, um ein Modell wie zuvor gezeigt zu trainieren.

Nächste Schritte

Dieses Tutorial Augmentation Daten mit Keras Preprocessing Layers und tf.image . Um zu erfahren , wie man eine Vorverarbeitung Schichten in Ihrem Modell enthält, finden Sie in der Bildklassifizierung Tutorial. Sie können auch lernen , wie Vorverarbeitung Schichten interessieren können Sie klassifizieren Text helfen, wie in der gezeigten Grundtextklassifikation Tutorial. Sie können mehr darüber erfahren , tf.data in dieser Anleitung , und Sie können lernen , wie Sie Ihre Eingangsleitungen für die Leistung konfigurieren hier .