Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/pt-br/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.

Ampliação de dados

Visão geral

Este tutorial demonstra a ampliação de dados, uma técnica para aumentar a diversidade do conjunto de treinamento por meio da aplicação de transformações aleatórias (mas realistas), como rotação de imagem.

Você aprenderá a aplicar a ampliação de dados de duas maneiras:

  • Usando as camadas de pré-processamento do Keras, como tf.keras.layers.Resizing, tf.keras.layers.Rescaling, tf.keras.layers.RandomFlip e tf.keras.layers.RandomRotation.

  • Usando os métodos do tf.image, como tf.image.flip_left_right, tf.image.rgb_to_grayscale, tf.image.adjust_brightness, tf.image.central_crop e tf.image.stateless_random*.

Configuração

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

Baixar um dataset

Este tutorial usa o dataset tf_flowers. Para sua conveniência, baixe o dataset usando os TensorFlow Datasets. Se você quiser saber mais sobre outras formar de importar dados, confira o tutorial Carregar imagens.

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

O dataset Flowers tem cinco classes.

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

Vamos recuperar uma imagem do dataset e usá-la para demonstrar a ampliação de dados.

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

Usar as camadas de pré-processamento do Keras

Redimensionamento e reescalonamento

Você pode usar as camadas de pré-processamento do Keras para redimensionar suas imagens para um formato consistente (com tf.keras.layers.Resizing) e para reescalonar valores de pixels (com tf.keras.layers.Rescaling).

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

Observação: a camada de reescalonamento acima padroniza os valores de pixel no intervalo [0, 1]. Se, em vez disso, você quiser que seja [-1, 1], pode escrever tf.keras.layers.Rescaling(1./127.5, offset=-1).

Você pode visualizar o resultado da aplicação dessas camadas em uma imagem.

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

Verifique se os pixels estão no intervalo [0, 1]:

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

Ampliação de dados

Você também pode usar as camadas de pré-processamento do Keras para fazer ampliação de dados, como tf.keras.layers.RandomFlip e tf.keras.layers.RandomRotation.

Vamos criar algumas camadas de pré-processamento e aplicá-las repetidamente à mesma imagem.

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

Há diversas camadas de pré-processamento que você pode usar para fazer ampliação de dados, incluindo tf.keras.layers.RandomContrast, tf.keras.layers.RandomCrop, tf.keras.layers.RandomZoom, entre outras.

Duas opções de uso das camadas de pré-processamento do Keras

Existem duas formas de usar essas camadas de pré-processamento, com contrapartidas importantes.

Opção 1: tornar as camadas de pré-processamento parte do seu 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. ])

É importante ficar ciente destes dois pontos importantes nesse caso:

  • A ampliação de dados será executada no dispositivo de forma síncrona com o restante das suas camadas e se beneficiará da aceleração de GPU.

  • Ao exportar o modelo usando model.save, as camadas de pré-processamento serão salvas junto com o restante do modelo. Se você implantar esse modelo posteriormente, ele vai padronizar as imagens de forma automática (de acordo com a configuração das suas camadas). Assim, você não precisará reimplementar essa lógica no servidor, poupando esforços.

Observação: a ampliação de dados fica inativa no momento do teste, então as imagens de entrada serão ampliadas somente durante chamadas a Model.fit (e não a Model.evaluate ou a Model.predict).

Opção 2: aplicar as camadas de pré-processamento ao seu dataset

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

Com esta estratégia, você usa Dataset.map para criar um dataset que gera lotes de imagens ampliadas. Neste caso:

  • A ampliação de dados acontecerá de forma assíncrona na CPU e não causa bloqueios. Você pode sobrepor o treinamento do modelo na GPU com pré-processamento de dados usando Dataset.prefetch, conforme exibido abaixo.

  • Neste caso, as camadas de pré-processamento não serão exportadas com o modelo ao chamar Model.save. Você precisará anexá-las ao modelo antes de salvá-lo e reimplementá-las no servidor. Após o treinamento, você pode anexar as camadas de pré-processamento antes da exportação.

Confira um exemplo da primeira opção no tutorial Classificação de imagens. Demonstraremos a segunda opção aqui.

Aplicar as camadas de pré-processamento aos datasets

Configure os datasets de treinamento, validação e teste com as camadas de pré-processamento do Keras criadas anteriormente. Você também vai configurar os datasets para melhor desempenho usando leituras paralelas e pré-busca em buffers para gerar lotes pelo disco sem bloqueio de I/O (saiba mais sobre o desempenho do dataset no guia Desempenho melhor com a API tf.data).

Observação: a ampliação de dados deve ser aplicada somente ao conjunto de treinamento.

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)

Treinar um modelo

Para completar, agora você treinará um modelo simples usando os datasets que acabou de preparar.

O modelo Sequential consiste em três blocos de convolução (tf.keras.layers.Conv2D) com uma camada de pooling máximo (tf.keras.layers.MaxPooling2D) em cada um. Há uma camada totalmente conectada (tf.keras.layers.Dense) com 128 unidades sobre ela, que é ativada por uma função de ativação ReLU ('relu'). Esse modelo não foi ajustado para exatidão (o objetivo é mostrar as mecânicas).

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

Escolha o otimizador tf.keras.optimizers.Adam e a função de perda tf.keras.losses.SparseCategoricalCrossentropy. Para ver a exatidão do treinamento e da validação para cada época de treinamento, passe o argumento metrics para Model.compile.

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

Treine com algumas épocas:

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

Ampliação de dados personalizada

Você também pode criar camadas personalizadas de ampliação de dados.

Esta seção do tutorial mostra duas maneiras de fazer isso:

  • Primeiro, você criará uma camada tf.keras.layers.Lambda. Essa é uma boa maneira de escrever códigos concisos.

  • Em seguida, você escreverá uma nova camada fazendo uma subclasse, o que oferece um controle maior.

As duas camadas inverterão aleatoriamente as cores de uma imagem de acordo com uma determinada probabilidade.

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

Agora, implemente uma camada personalizada fazendo uma subclasse:

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

As duas camadas podem ser usadas conforme descrito nas opções 1 e 2 acima.

Uso de tf.image

Os utilitários de pré-processamento do Keras acima são convenientes, mas, para ter um controle mais granular, você pode escrever seus próprios pipelines ou camadas de ampliação de dados usando tf.data e tf.image (talvez você queira verificar também Imagem dos complementos do TensorFlow: operações e I/O do TensorFlow: conversões do espaço de cores).

Como o dataset Flowers foi configurado anteriormente com ampliação de dados, vamos reimportá-lo para que tenha a configuração original:

(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 uma imagem para trabalhar com ela:

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

Vamos usar a seguinte função para visualizar e comparar lado a lado as imagens original e ampliada:

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)

Ampliação de dados

Inverter uma imagem

Inverta uma imagem vertical ou horizontalmente com tf.image.flip_left_right:

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

Mudar uma imagem para escala de cinza

Você pode mudar uma imagem para escala de cinza com tf.image.rgb_to_grayscale:

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

Saturar uma imagem

Sature uma imagem com tf.image.adjust_saturation, fornecendo um fator de saturação:

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

Alterar o brilho da imagem

Altere o brilho da imagem com tf.image.adjust_brightness, fornecendo um fator de brilho:

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

Recorte uma imagem a partir do centro

Recorte a imagem a partir do centro até a parte desejada usando tf.image.central_crop:

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

Girar uma imagem

Gire um imagem em 90 graus com tf.image.rot90:

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

Transformações aleatórias

Atenção: há dois conjuntos de operações aleatórias de imagens: tf.image.random* e tf.image.stateless_random*. É altamente desaconselhável usar as operações de tf.image.random*, pois elas usam os RNGs antigos do TF 1.x. Em vez disso, use as operações aleatórias de imagens apresentadas neste tutorial. Confira mais informações em Geração de números aleatórios.

A aplicação de transformações aleatórias às imagens pode generalizar e expandir o dataset ainda mais. A API tf.image atual fornece oito operações aleatórias de imagens (também chamadas de ops):

Essas operações aleatórias de imagens são puramente funcionais: a saída depende somente da entrada, o que simplifica seu uso em pipelines de entrada determinísticos de alto desempenho. Elas requerem que um valor de seed (semente) seja a entrada em cada passo. Dada a mesma seed, elas retornam os mesmos resultados, não importa quantas vezes sejam chamadas.

Observação: seed é um Tensor de tamanho (2,) cujos valores são números inteiros.

Nas próximas seções, você:

  1. Verá exemplos de como usar operações aleatórias de imagens para transformar uma imagem.

  2. Demonstrará como aplicar transformações aleatórias a um dataset de treinamento.

Alterar o brilho da imagem aleatoriamente

Altere o brilho da image aleatoriamente usando tf.image.stateless_random_brightness ao fornecer um fator de brilho e uma seed. O fator de brilho é escolhido aleatoriamente no intervalo [-max_delta, max_delta) e está associado à seed fornecida.

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)

Alterar o contraste da imagem aleatoriamente

Altere o contraste da image aleatoriamente usando tf.image.stateless_random_contrast ao fornecer um fator de contraste e uma seed. O fator de contraste é escolhido aleatoriamente no intervalo [lower, upper] e está associado à seed fornecida.

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 uma imagem aleatoriamente

Recorte uma image aleatoriamente usando tf.image.stateless_random_crop ao fornecer o size (tamanho) e a seed (semente) alvos. A parte da image recortada tem um deslocamento escolhido aleatoriamente e está associada à seed fornecida.

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 ampliação a um dataset

Primeiro, vamos baixar o dataset de imagens novamente caso tenha sido modificado nas seções 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, )

Agora, defina uma função utilitária para redimensionar e reescalonar as imagens. Essa função será usada para unificar o tamanho e a escala das imagens no dataset:

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

Também vamos definir a função augment, que pode aplicar as transformações aleatórias às imagens. Esta função será usada no dataset no próximo passo.

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

Opção 1: usando tf.data.experimental.Counter

Crie um objeto tf.data.experimental.Counter (vamos chamá-lo de counter) (contador) e compacte (Dataset.zip) o conjunto com (counter, counter). Isso garantirá que cada imagem do dataset seja associada a um valor único (de formato (2,)) com base no counter, que depois poderá ser passado para a função augment como o valor de seed para transformações aleatórias.

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

Mapeie a função augment para o dataset de treinamento:

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

Opção 2: usando tf.random.Generator

  • Crie um objeto tf.random.Generator com um valor inicial de seed. Ao chamar a função make_seeds no mesmo objeto gerador, sempre será retornado um novo valor de seed único.

  • Defina uma função de encapsulamento que: 1) chame a função make_seeds; e 2) passe o valor de seed recém-gerado para a função augment para que sejam feitas transformações aleatórias.

Observação: objetos tf.random.Generator armazenam o estado RNG em um tf.Variable e, portanto, ele pode ser salvo como um checkpoint ou em um SavedModel. Confira mais detalhes em Geração de números aleatórios.

# 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

Mapeie a função de encapsulamento f para o dataset de treinamento, e a função resize_and_rescale para os conjuntos de validação e teste.

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

Agora, esses datasets podem ser usados para treinar um modelo conforme mostrado anteriormente.

Próximos passos

Este tutorial demonstrou a ampliação de dados usando as camadas de pré-processamento do Keras e tf.image.

  • Para ver como incluir camadas de pré-processamento dentro do seu modelo, confira o tutorial Classificação de imagens.

  • Se tiver interesse em aprender como as camadas de pré-processamento podem ajudar a classificar o texto, confira o tutorial Classificação básica de texto.

  • Saiba mais sobre o tf.data neste guia e veja como configurar seus pipelines de entrada para melhor desempenho aqui.