Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/tutorials/images/data_augmentation.ipynb
25118 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

Aumentación de datos

Descripción general

Este tutorial muestra la aumentación de datos: una técnica para aumentar la diversidad de su conjunto de entrenamiento aplicando transformaciones aleatorias (pero realistas), como la rotación de imágenes.

Aprenderá a aplicar la aumentación de datos de dos maneras:

  • Usar las capas de preprocesamiento Keras, como tf.keras.layers.Resizing, tf.keras.layers.Rescaling, tf.keras.layers.RandomFlip, y tf.keras.layers.RandomRotation.

  • Usar los métodos tf.image, como tf.image.flip_left_right, tf.image.rgb_to_grayscale, tf.image.adjust_brightness, tf.image.central_crop, y tf.image.stateless_random*.

Preparación

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

Descargar un conjunto de datos

Este tutorial usa el conjunto de datos tf_flowers. Para mayor comodidad, descargue el conjunto de datos utilizando Conjuntos de datos de TensorFlow. Si desea conocer otras formas de importar datos, consulte el tutorial cargar 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, )

El conjunto de datos de flores tiene cinco clases.

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

Recuperemos una imagen del conjunto de datos y usémosla para demostrar la aumentación de datos.

get_label_name = metadata.features['label'].int2str image, label = next(iter(train_ds)) _ = plt.imshow(image) _ = plt.title(get_label_name(label))

Usar las capas de preprocesamiento Keras

Redimensionar y reescalar

Puede usar las capas de preprocesamiento de Keras para redimensionar sus imágenes de forma consistente (con tf.keras.layers.Resizing), y para reescalar los valores de los pixeles (con tf.keras.layers.Rescaling).

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

Nota: La capa de reescalado anterior estandariza los valores de los pixeles al rango [0, 1]. Si en su lugar quisiera que fuera [-1, 1], pudiese escribir tf.keras.layers.Rescaling(1./127.5, offset=-1).

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

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

Compruebe que los píxeles se encuentran en el intervalo [0, 1]:

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

Aumentación de datos

También puede usar las capas de preprocesamiento de Keras para aumentar datos, como tf.keras.layers.RandomFlip y tf.keras.layers.RandomRotation.

Creemos unas cuantas capas de preprocesamiento y apliquémoslas repetidamente a la misma imagen.

data_augmentation = tf.keras.Sequential([ layers.RandomFlip("horizontal_and_vertical"), layers.RandomRotation(0.2), ])
# Add the image to a batch. image = tf.cast(tf.expand_dims(image, 0), tf.float32)
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")

Puede usar diversas capas de preprocesamiento para aumentar datos, como tf.keras.layers.RandomContrast, tf.keras.layers.RandomCrop, tf.keras.layers.RandomZoom, y otras.

Dos opciones para usar las capas de preprocesamiento de Keras

Hay dos formas de usar estas capas de preprocesamiento, con importantes concesiones.

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

model = tf.keras.Sequential([ # Add the preprocessing layers you created earlier. 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:

  • La aumentación de datos se ejecutará en el dispositivo, de forma sincronizada con el resto de sus capas, y será útil gracias a la aceleración de la GPU.

  • Cuando exporte su modelo usando model.save, las capas de preprocesamiento se guardarán junto con el resto de su modelo. Si más tarde implementa este modelo, se estandarizarán automáticamente las imágenes (según la configuración de sus capas). Esto puede ahorrarle el esfuerzo de tener que reimplementar esa lógica en el lado del servidor.

Nota: La aumentación de datos está inactiva en el momento de la prueba, por lo que las imágenes de entrada sólo se aumentarán durante las llamadas a Model.fit (no a Model.evaluate o Model.predict).

Opción 2: Aplicar 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, se usa Dataset.map para crear un conjunto de datos que produzca lotes de imágenes aumentadas. En este caso:

  • La aumentación de datos se producirá de forma asíncrona 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á adjuntarlas a su modelo antes de guardarlo o reimplementarlas en el lado del servidor. Después del entrenamiento, puede adjuntar las capas de preprocesamiento antes de exportarlas.

Puede encontrar un ejemplo de la primera opción en el tutorial Clasificación de imágenes. Vamos a demostrar aquí la segunda opción.

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 Keras que creó anteriormente. También configurará los conjuntos de datos para mejorar el rendimiento, usando lecturas paralelas y preextracción en búfer para obtener lotes del disco sin que la E/S se bloquee. (Obtenga más información sobre el rendimiento de los conjuntos de datos en la guía Mejor rendimiento con la API tf.data).

Nota: La aumentación de datos sólo debe aplicarse al conjunto de entrenamiento.

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

Entrenar un modelo

Para completar, ahora entrenará un modelo usando los conjuntos de datos que acaba de preparar.

El modelo Secuencial consta de tres bloques de convolución (tf.keras.layers.Conv2D) con una capa de agrupamiento máximo (tf.keras.layers.MaxPooling2D) en cada uno de ellos. Hay una capa (tf.keras.layers.Dense) totalmente conectada (tf.keras.layers.Dense) con 128 unidades que se activa mediante una función de activación ReLU ('relu'). Este modelo no se ha ajustado para obtener precisión (la meta 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) ])

Seleccione el optimizador tf.keras.optimizers.Adam y la función de pérdida tf.keras.losses.SparseCategoricalCrossentropy. Para ver la precisión del entrenamiento y la validación de cada época de entrenamiento, pase el argumento metrics a Model.compile.

model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])

Entrene por algunas épocas:

epochs=5 history = model.fit( train_ds, validation_data=val_ds, epochs=epochs )
loss, acc = model.evaluate(test_ds) print("Accuracy", acc)

Aumentación de datos personalizados

También puede crear capas de aumentación de datos personalizadas.

Esta sección del tutorial muestra dos formas de hacerlo:

  • En primer lugar, creará una capa tf.keras.layers.Lambda. Esta es una buena manera de escribir código conciso.

  • Luego, escribirá una nueva capa por subclaseado, lo que le da más control.

Ambas capas invertirán aleatoriamente los colores de una imagen, según 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")

En seguida, implemente una capa personalizada a través de subclaseado:

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

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

Usar tf.image

Las utilidades de preprocesamiento Keras anteriores son convenientes. Pero, para un control más fino, puede escribir sus propias canalizaciones o capas de aumentación de datos usando tf.data y tf.image (también puede consultar Complemento de TensorFlow Imagen: Operaciones y TensorFlow I/O: Conversiones de Espacio de Color.)

Dado que el conjunto de datos de flores se configuró previamente con la aumentación de datos, vamos a reimportarlo para empezar de cero:

(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 con la que trabajar:

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

Usemos la siguiente función para visualizar y comparar las imágenes original y aumentada 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)

Aumentación de datos

Invertir una imagen

Invierta una imagen vertical u horizontalmente con tf.image.flip_left_right:

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

Aplicar escala de grises a una imagen

Puede aplicar escala de grises a una imagen con tf.image.rgb_to_grayscale:

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

Saturar una imagen

Sature una imagen con tf.image.adjust_saturation indicando un factor de saturación:

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

Cambiar el brillo de la imagen

Cambie el brillo de la imagen con tf.image.adjust_brightness indicando un factor de brillo:

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

Recortar una imagen al centro

Recorte la imagen desde el centro hasta la parte de la imagen que desee usando tf.image.central_crop:

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

Girar una imagen

Gire una imagen 90 grados con tf.image.rot90:

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

Transformaciones aleatorias

Advertencia: Existen dos conjuntos de operaciones de imagen aleatoria: tf.image.random* y tf.image.stateless_random*. Se desaconseja encarecidamente usar las operaciones tf.image.random*, ya que usan los antiguos RNG de TF 1.x. En su lugar, use las operaciones de imagen aleatoria introducidas en este tutorial. Para más información, consulte Generación de números aleatorios.

Aplicar transformaciones aleatorias a las imágenes puede ayudar aún más a generalizar y ampliar el conjunto de datos. La API actual tf.image ofrece ocho operaciones (ops) de imagen aleatorias de este tipo:

Estas ops de imagen aleatoria son puramente funcionales: la salida sólo depende de la entrada. Esto hace que sean fáciles de usar en canalizaciones de entrada deterministas de alto rendimiento. Requieren que se introduzca un valor seed en cada paso. Dada la misma seed, devuelven los mismos resultados independientemente de cuántas veces se les llame.

Nota: seed es un Tensor de forma (2,) cuyos valores son cualesquiera enteros.

En las siguientes secciones, usted:

  1. Repasará ejemplos de cómo usar operaciones de imagen aleatorias para transformar una imagen.

  2. Demuestre cómo aplicar transformaciones aleatorias a un conjunto de datos de entrenamiento.

Modificar aleatoriamente el brillo de la imagen

Modifique aleatoriamente el brillo de image usando tf.image.stateless_random_brightness al dar un factor de brillo y seed. El factor de brillo se elige aleatoriamente en el rango [-max_delta, max_delta) y se asocia a la seed dada.

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)

Cambiar aleatoriamente el contraste de la imagen

Cambie aleatoriamente el contraste de image usando tf.image.stateless_random_contrast al dar un intervalo de contraste y seed. El rango de contraste se elige aleatoriamente en el intervalo [lower, upper] y se asocia con la seed dada.

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)

Recortar una imagen al azar

Recorte aleatoriamente imagen usando tf.image.stateless_random_crop al dar un size y seed del objetivo. La parte que se recorta de image está en un punto elegido aleatoriamente y se asocia a la seed dada.

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)

Aplicar la aumentación a un conjunto de datos

En primer lugar, descarguemos de nuevo el conjunto de datos de imágenes por si se han modificado en las secciones anteriores.

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

A continuación, defina una función de utilidad para cambiar el tamaño y la escala de las imágenes. Esta función se usará para unificar el tamaño y la escala de las imágenes del conjunto de datos:

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

Definamos también la función augment que puede aplicar las transformaciones aleatorias a las imágenes. Esta función se usará sobre el conjunto de datos en el siguiente paso.

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

Opción 1: Usar tf.data.experimental.Counter

Cree un objeto tf.data.experimental.Counter (llamémoslo counter) y Dataset.zip se llamará el conjunto de datos con (counter, counter). Esto asegurará que cada imagen del conjunto de datos se asocie con un valor único (de forma (2,)) basado en counter que más tarde puede ser pasado a la función augment como el valor seed para transformaciones aleatorias.

# Create a `Counter` object and `Dataset.zip` it together with the training set. counter = tf.data.experimental.Counter() train_ds = tf.data.Dataset.zip((train_datasets, (counter, counter)))

Mapee la función augment al conjunto de datos de entrenamiento:

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

Opción 2: Usar tf.random.Generator

  • Cree un objeto tf.random.Generator con un valor inicial seed. Si se llama a la función make_seeds sobre el mismo objeto generador, siempre se devuelve un nuevo valor seed único.

  • Defina una función contenedora que: 1) llame a la función make_seeds; y 2) pase el valor seed recién generado a la función augment para transformaciones aleatorias.

Nota: Los objetos tf.random.Generator almacenan el estado del RNG en una tf.Variable, lo que significa que puede guardarse como un checkpoint o en un SavedModel. Para más detalles, consulte Generación de números aleatorios.

# Create a generator. rng = tf.random.Generator.from_seed(123, alg='philox')
# Create 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

Mapee la función contenedora f al conjunto de datos de entrenamiento, y la función resize_and_rescale a los conjuntos de validación y prueba:

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

Estos conjuntos de datos pueden usarse ahora para entrenar un modelo como se ha mostrado anteriormente.

Siguientes pasos

Este tutorial demostró la aumentación de datos usando capas de preprocesamiento Keras y tf.image.

  • Para aprender a incluir capas de preprocesamiento dentro de su modelo, consulte el tutorial Clasificación de imágenes.

  • También puede interesarle aprender cómo las capas de preprocesamiento pueden ayudarle a clasificar texto, como se muestra en el tutorial Clasificación básica de texto.

  • Puede aprender más sobre tf.data en esta guía, y puede aprender a configurar sus canalizaciones de entrada para mejorar el rendimiento aquí.