Se usó la API de Cloud Translation para traducir esta página.
Switch to English

Aumento de datos

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Visión general

Este tutorial demuestra el aumento de datos: una técnica para aumentar la diversidad de su conjunto de entrenamiento mediante la aplicación de transformaciones aleatorias (pero realistas) como la rotación de imágenes. Aprenderá a aplicar el aumento de datos de dos formas. Primero, utilizará las capas de preprocesamiento de Keras . A continuación, utilizará tf.image .

Preparar

pip install -q tf-nightly
WARNING: You are using pip version 20.2.2; however, version 20.2.3 is available.
You should consider upgrading via the '/tmpfs/src/tf_docs_env/bin/python -m pip install --upgrade pip' command.

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

from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist

Descarga un conjunto de datos

Este tutorial usa el conjunto de datos tf_flowers . Para mayor comodidad, descargue el conjunto de datos con TensorFlow Datasets . Si desea conocer otras formas de importar datos, consulte el tutorial de carga de imágenes .

(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,
)
Downloading and preparing dataset tf_flowers/3.0.1 (download: 218.21 MiB, generated: 221.83 MiB, total: 440.05 MiB) to /home/kbuilder/tensorflow_datasets/tf_flowers/3.0.1...

Warning:absl:Dataset tf_flowers is hosted on GCS. It will automatically be downloaded to your
local data directory. If you'd instead prefer to read directly from our public
GCS bucket (recommended if you're running on GCP), you can instead pass
`try_gcs=True` to `tfds.load` or set `data_dir=gs://tfds-data/datasets`.


Dataset tf_flowers downloaded and prepared to /home/kbuilder/tensorflow_datasets/tf_flowers/3.0.1. Subsequent calls will reuse this data.

El conjunto de datos de flores tiene cinco clases.

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

Recuperemos una imagen del conjunto de datos y usémosla para demostrar el aumento de datos.

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

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

png

Utilice capas de preprocesamiento de Keras

Cambiar el tamaño y la escala

Puede utilizar capas de preprocesamiento para cambiar el tamaño de sus imágenes a una forma coherente y para cambiar la escala de los valores de píxeles.

IMG_SIZE = 180

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

Puede ver el resultado de aplicar estas capas a una imagen.

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

png

Puede verificar que los píxeles están en [0-1] .

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

Aumento de datos

También puede utilizar capas de preprocesamiento para el aumento de datos.

Creemos algunas capas de preprocesamiento y aplíquelas repetidamente a la misma imagen.

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

Hay una variedad de capas de preprocesamiento que puede utilizar para el aumento de datos, incluidas las layers.RandomContrast , layers.RandomCrop , layers.RandomZoom , layers.RandomContrast , layers.RandomCrop , layers.RandomZoom y otras.

Dos opciones para usar las capas de preprocesamiento

Hay dos formas de utilizar estas capas de preprocesamiento, con importantes compensaciones.

Opción 1: haga que las capas de preprocesamiento formen parte de su modelo

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

Hay dos puntos importantes a tener en cuenta en este caso:

  • El aumento de datos se ejecutará en el dispositivo, de forma sincrónica con el resto de sus capas, y se beneficiará de la aceleración de la GPU.

  • Cuando exporta su modelo usando model.save , las capas de preprocesamiento se guardarán junto con el resto de su modelo. Si luego implementas este modelo, automáticamente estandarizará las imágenes (según la configuración de tus capas). Esto puede ahorrarle el esfuerzo de tener que volver a implementar esa lógica del lado del servidor.

Opción 2: aplique las capas de preprocesamiento a su conjunto de datos

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

Con este enfoque, usa Dataset.map para crear un conjunto de datos que produce lotes de imágenes aumentadas. En este caso:

  • El aumento de datos se realizará de forma asincrónica en la CPU y no se bloqueará. Puede superponer el entrenamiento de su modelo en la GPU con el preprocesamiento de datos, usando Dataset.prefetch , que se muestra a continuación.
  • En este caso, las capas de preprocesamiento no se exportarán con el modelo cuando llame a model.save . Deberá adjuntarlos a su modelo antes de guardarlo o volver a implementarlos en el servidor. Después del entrenamiento, puede adjuntar las capas de preprocesamiento antes de exportar.

Puede encontrar un ejemplo de la primera opción en el tutorial de clasificación de imágenes . Demostremos la segunda opción aquí.

Aplicar las capas de preprocesamiento a los conjuntos de datos

Configure los conjuntos de datos de entrenamiento, validación y prueba con las capas de preprocesamiento que creó anteriormente. También configurará los conjuntos de datos para el rendimiento, utilizando lecturas paralelas y captación previa en búfer para generar lotes del disco sin que la E / S se bloquee. Puede obtener más información sobre el rendimiento del conjunto de datos en la guía Mejor rendimiento con la API tf.data .

batch_size = 32
AUTOTUNE = tf.data.experimental.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)

Entrena un modelo

Para completar, ahora entrenará un modelo usando estos conjuntos de datos. Este modelo no se ha ajustado para la precisión (el objetivo es mostrarle la mecánica).

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
92/92 [==============================] - 30s 315ms/step - loss: 1.5078 - accuracy: 0.3428 - val_loss: 1.0809 - val_accuracy: 0.6240
Epoch 2/5
92/92 [==============================] - 28s 303ms/step - loss: 1.0781 - accuracy: 0.5724 - val_loss: 0.9762 - val_accuracy: 0.6322
Epoch 3/5
92/92 [==============================] - 28s 295ms/step - loss: 1.0083 - accuracy: 0.5900 - val_loss: 0.9570 - val_accuracy: 0.6376
Epoch 4/5
92/92 [==============================] - 28s 300ms/step - loss: 0.9537 - accuracy: 0.6116 - val_loss: 0.9081 - val_accuracy: 0.6485
Epoch 5/5
92/92 [==============================] - 28s 301ms/step - loss: 0.8816 - accuracy: 0.6525 - val_loss: 0.8353 - val_accuracy: 0.6594

loss, acc = model.evaluate(test_ds)
print("Accuracy", acc)
12/12 [==============================] - 1s 83ms/step - loss: 0.8226 - accuracy: 0.6567
Accuracy 0.6566757559776306

Aumento de datos personalizado

También puede crear capas de aumento de datos personalizadas. Este tutorial muestra dos formas de hacerlo. Primero, creará una capa layers.Lambda . Esta es una buena forma de escribir código conciso. A continuación, escribirá una nueva capa a través de subclases , lo que le dará más control. Ambas capas invertirán aleatoriamente los colores de una imagen, de acuerdo con cierta probabilidad.

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

A continuación, implemente una capa personalizada mediante subclases .

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

Ambas capas se pueden utilizar como se describe en las opciones 1 y 2 anteriores.

Usando tf.image

Las layers.preprocessing anteriores de layers.preprocessing utilidades de layers.preprocessing son convenientes. Para un control más tf.data , puede escribir sus propios tf.data o capas de aumento de datos utilizando tf.data y tf.image . También puede consultar la imagen de los complementos de TensorFlow: operaciones y E / S de TensorFlow: conversiones de espacio de color

Dado que el conjunto de datos de flores se configuró previamente con el aumento de datos, volvamos a importarlo para comenzar de nuevo.

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

Recupere una imagen para trabajar.

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

png

Usemos la siguiente función para visualizar y comparar las imágenes originales y aumentadas una al lado de la otra.

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)

Aumento de datos

Voltear la imagen

Voltea la imagen vertical u horizontalmente.

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

png

Escala de grises la imagen

Escala de grises una imagen.

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

png

Saturar la imagen

Sature una imagen proporcionando un factor de saturación.

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

png

Cambiar el brillo de la imagen

Cambie el brillo de la imagen proporcionando un factor de brillo.

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

png

Centro recorta la imagen

Recorta la imagen desde el centro hasta la parte de la imagen que desees.

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

png

Rotar la imagen

Gire una imagen 90 grados.

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

png

Aplicar aumento a un conjunto de datos

Como antes, aplique el aumento de datos a un conjunto de datos utilizando Dataset.map .

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
def augment(image,label):
  image, label = resize_and_rescale(image, label)
  # Add 6 pixels of padding
  image = tf.image.resize_with_crop_or_pad(image, IMG_SIZE + 6, IMG_SIZE + 6) 
   # Random crop back to the original size
  image = tf.image.random_crop(image, size=[IMG_SIZE, IMG_SIZE, 3])
  image = tf.image.random_brightness(image, max_delta=0.5) # Random brightness
  image = tf.clip_by_value(image, 0, 1)
  return image, label

Configurar los conjuntos de datos

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

Estos conjuntos de datos ahora se pueden usar para entrenar un modelo como se mostró anteriormente.

Próximos pasos

Este tutorial demostró el aumento de datos utilizando las capas de preprocesamiento de Keras y tf.image . Para aprender a incluir capas de preprocesamiento dentro de su modelo, consulte el tutorial de clasificación de imágenes . También puede estar interesado en aprender cómo el procesamiento previo de capas puede ayudarlo a clasificar texto, como se muestra en el tutorial de clasificación de texto básica . Puede obtener más información sobre tf.data en esta guía y puede aprender a configurar sus canalizaciones de entrada para el rendimiento aquí .