Aumento de dados de imagem para aprendizado profundo

Entenda o que é aumento de dados de imagem e como usá-lo usando Keras para seus projetos de aprendizado profundo

Foto por Chris Lawton on Unsplash

Se você já tentou realizar reconhecimento de imagens usando aprendizado profundo, sabe a importância de um bom conjunto de dados para treinamento. No entanto, nem sempre é fácil encontrar imagens suficientes para treinamento e a precisão do seu modelo depende diretamente da qualidade dos dados de treinamento.

Felizmente, existem técnicas que você pode usar para complementar o conjunto de dados de imagens usado para treinamento. Uma das técnicas é chamada aumento de dados de imagem. Neste artigo, discutirei o que é aumento de dados de imagem, como funciona, por que é útil no aprendizado profundo e, finalmente, como realizar aumento de dados de imagem usando a biblioteca Keras.

Aumento de dados de imagem é uma técnica que cria novas imagens a partir das existentes. Para fazer isso, você faz algumas pequenas alterações neles, como ajustar o brilho da imagem, girar a imagem ou deslocar o assunto na imagem horizontal ou verticalmente.

As técnicas de aumento de imagem permitem aumentar artificialmente o tamanho do seu conjunto de treinamento, fornecendo assim muito mais dados ao seu modelo para treinamento. Isso permite melhorar a precisão do seu modelo, aprimorando a capacidade do seu modelo de reconhecer novas variantes dos seus dados de treinamento.

Tipos de aumento de dados de imagem

O aumento de imagem vem em muitas formas, aqui estão algumas das mais comuns - deslocamento vertical, deslocamento horizontal, inversão vertical, inversão horizontal, rotação, ajuste de brilho e zoom in/out.

Demonstrarei primeiro as várias técnicas de aumento de imagem usando Python e Keras. Se você quiser experimentar, certifique-se de ter os seguintes softwares e pacotes instalados:

Depois que o Anaconda e o TensorFlow estiverem instalados, crie um novo Jupyter Notebook.

Deslocamento Vertical

A primeira técnica de aumento de imagem que quero mostrar é a deslocamento vertical. O deslocamento vertical desloca aleatoriamente a imagem verticalmente para cima ou para baixo. Para este exemplo, vou usar uma imagem chamada 747.jpg, localizado na mesma pasta do meu Jupyter Notebook.

Fonte da imagem: https://commons.wikimedia.org/wiki/File:Qantas_Boeing_747-438ER_VH-OEI_at_LAX.jpg. Este arquivo está licenciado sob a Creative Commons Attribution-Share Alike 2.0 Genérico licença.

O trecho de código a seguir usa o ImageDataGenerator classe em Keras para deslocar verticalmente a imagem.

A ImageDataGenerator classe de Keras gera lotes de dados de imagem com aumento de dados em tempo real.

#---importar os módulos---
importar numpy como np
importar matplotlib.pyplot como plt
de tensorflow.keras.preprocessing.image importação load_img
de tensorflow.keras.preprocessing.image importar img_to_array
de tensorflow.keras.preprocessing.image importar ImageDataGenerator
#---carrega a imagem---
nome_do_arquivo_imagem = '747.jpg'
img = load_img(nome_arquivo_imagem)
#---converter a imagem em array 3D---
dados_imagem = img_to_array(img)
#---converter em uma matriz 4-D de 1 elemento da matriz 3D representando
# a imagem---
dados_imagens = np.expand_dims(dados_imagem, eixo=0)
#---criar gerador de aumento de dados de imagem---
datagen = ImageDataGenerator (largura_shift_range = 0.2)
#---prepare o iterador; flow() pega um array 4D e retorna
# um iterador contendo um lote de imagens---
train_generator=datagen.flow(images_data, batch_size=1)
linhas = 5
colunas = 4
#--- plotar 5 linhas e 4 colunas ---
fig, eixos = plt.subplots(linhas,colunas)
para r no intervalo (linhas):
para c no intervalo (colunas):
#---obtém a próxima imagem do lote (uma imagem desde o lote
# tamanho é 1)---
imagem_batch = train_generator.next()

#---converter em números inteiros sem sinal para visualização---
imagem = image_batch[0].astype('uint8')

#---mostrar a imagem---
eixos[r,c].imshow(imagem)
#---definir o tamanho da figura---
fig.set_size_inches(15,10)

O trecho de código acima produz a seguinte saída:

Como você pode ver na saída acima, cada vez que você chama o next() método do train_generator objeto, você obtém uma imagem ligeiramente alterada. No trecho de código acima, uma nova imagem que é deslocada em 20% com base na altura da imagem original é retornada sempre que você chama o método next() método:

datagen=ImageDataGenerator(largura_shift_range=0.2)

Curiosamente, para esta versão do ImageDataGenerator (tensorflow.keras.preprocessing.image) classe, especificando o width_shift_range parâmetro desloca a imagem verticalmente, em vez de horizontalmente (que é o comportamento do antigoImageDataGeneratordo keras.preprocessing.image módulo). Da mesma forma, se quiser que a imagem seja deslocada horizontalmente, você precisa usar o height_shift_range parâmetro (veja a próxima seção).

Observe que o next() método retornará uma imagem aumentada quantas vezes você quiser. No trecho de código acima, chamamos isso 20 vezes (5 linhas vezes 4 colunas).

Mudança Horizontal

Agora você pode tentar deslocar a imagem horizontalmente usando o height_shift_range parâmetro:

datagen=ImageDataGenerator(intervalo_altura_deslocamento=0.2)
train_generator=datagen.flow(images_data, batch_size=1)
linhas = 5
colunas = 4
fig, eixos = plt.subplots(linhas,colunas)
para r no intervalo (linhas):
para c no intervalo (colunas):
imagem_batch = train_generator.next()
imagem = image_batch[0].astype('uint8')
eixos[r,c].imshow(imagem)
fig.set_size_inches(15,10)

O trecho de código acima produz a seguinte saída:

Flip Horizontal

Às vezes faz sentido virar a imagem horizontalmente. No caso de um avião, a frente do avião pode estar voltada para a esquerda ou para a direita:

datagen=ImageDataGenerator(horizontal_flip = Verdadeiro)
train_generator=datagen.flow(images_data, batch_size=1)
linhas = 2
colunas = 2
fig, eixos = plt.subplots(linhas,colunas)
para r no intervalo (linhas):
para c no intervalo (colunas):
imagem_batch = train_generator.next()
imagem = image_batch[0].astype('uint8')
eixos[r,c].imshow(imagem)
fig.set_size_inches(15,10)

Para o trecho de código acima, gerar quatro imagens é suficiente, pois a frente do avião pode estar voltada para a esquerda ou para a direita:

Lembre-se de que a inversão é aleatória (às vezes você obtém todas as quatro imagens originais e às vezes obtém imagens invertidas horizontalmente). É provável que as quatro imagens acima sejam todas iguais. Se isso acontecer, basta executar esse bloco de código novamente.

Virar vertical

Assim como a inversão horizontal, você também pode realizar a inversão vertical:

datagen=ImageDataGenerator(vertical_flip = Verdadeiro)
train_generator=datagen.flow(images_data, batch_size=1)
linhas = 2
colunas = 2
fig, eixos = plt.subplots(linhas,colunas)
para r no intervalo (linhas):
para c no intervalo (colunas):
imagem_batch = train_generator.next()
imagem = image_batch[0].astype('uint8')
eixos[r,c].imshow(imagem)
fig.set_size_inches(15,10)

No caso dos aviões, pode não fazer muito sentido virar o avião de cabeça para baixo! Se você estiver tentando realizar o reconhecimento de imagens, é provável que suas imagens de aviões estejam na vertical e, portanto, treinar seu modelo para reconhecer planos invertidos pode não ser muito comum. Para outros casos, a inversão vertical faz muito sentido.

rotação

A rotação, como o nome indica, gira sua imagem. Isso seria muito útil para a imagem do nosso avião. Os seguintes trechos de código giram aleatoriamente a imagem em até 50 graus:

datagen=ImageDataGenerator(intervalo_rotação=50)
train_generator=datagen.flow(imagens_dados)
linhas = 5
colunas = 4
fig, eixos = plt.subplots(linhas,colunas)
para r no intervalo (linhas):
para c no intervalo (colunas):
imagem_batch = train_generator.next()
imagem = image_batch[0].astype('uint8')
eixos[r,c].imshow(imagem)
fig.set_size_inches(15,10)

Com a rotação, a saída mostra os aviões nas diversas posições — simulando as posições de decolagem e pouso:

Brilho

Outra técnica de aumento é ajustar o brilho da imagem. O trecho de código a seguir define um intervalo de valores de mudança de brilho:

datagen=ImageDataGenerator(faixa_de brilho=[0.15,2.0])
train_generator=datagen.flow(images_data, batch_size=1)
linhas = 5
colunas = 4
fig, eixos = plt.subplots(linhas,colunas)
para r no intervalo (linhas):
para c no intervalo (colunas):
imagem_batch = train_generator.next()
imagem = image_batch[0].astype('uint8')
eixos[r,c].imshow(imagem)
fig.set_size_inches(15,10)

A saída contém uma série de imagens com brilho variável:

Zoom

Você também pode ampliar ou reduzir as imagens:

datagen=ImageDataGenerator(intervalo_zoom=[5,0.5])
train_generator=datagen.flow(images_data, batch_size=1)
linhas = 5
colunas = 4
fig, eixos = plt.subplots(linhas,colunas)
para r no intervalo (linhas):
para c no intervalo (colunas):
imagem_batch = train_generator.next()
imagem = image_batch[0].astype('uint8')
eixos[r,c].imshow(imagem)
fig.set_size_inches(15,10)

A saída mostra a imagem nas diversas taxas de zoom:

Observe que o zoom nas imagens alterará as proporções das imagens.

Combinando todos os aumentos

Claro, todas as diversas técnicas de aumento que discuti até agora podem ser combinadas:

datagen=ImageDataGenerator(largura_shift_range=0.2,
altura_shift_range = 0.2,
horizontal_flip=Verdadeiro,
intervalo_de rotação = 50,
faixa_de brilho=[0.15,2.0],
intervalo_zoom=[5,0.5]
)
train_generator=datagen.flow(images_data, batch_size=1)linhas = 8
colunas = 8
fig, eixos = plt.subplots(linhas,colunas)
para r no intervalo (linhas):
para c no intervalo (colunas):
imagem_batch = train_generator.next()
imagem = image_batch[0].astype('uint8')
eixos[r,c].imshow(imagem)
fig.set_size_inches(15,10)

Observe que deixei de fora a inversão vertical, pois não faz sentido para o nosso exemplo.

A saída agora mostra a imagem com os vários aumentos aplicados:

As seções anteriores mostraram os fundamentos do aumento de dados de imagem e como ele pode ser aplicado a uma única imagem. Na aprendizagem profunda, muitas vezes lidamos com um conjunto de imagens. Então, vamos agora ver como o aumento de imagem pode ser aplicado a um conjunto de imagens. Para ilustrações, vou assumir que na pasta que contém seu Jupyter Notebook, você tem um Frutas pasta e as seguintes subpastas:

Frutas
|__banana
|__banana1.jpg
|__banana2.jpg
|__banana3.jpg
|__ ...
|__durian
|__durian1.jpg
|__durian2.jpg
|__durian3.jpg
|__ ...
|__laranja
|__orange1.jpg
|__orange2.jpg
|__orange3.jpg
|__ ...
|__morango
|__morango1.jpg
|__morango2.jpg
|__morango3.jpg
|__ ...

Cada subpasta contém um conjunto de imagens. Por exemplo, o Banana pasta contém uma série de imagens chamadas banana1.jpg, banana2.jpg, e assim por diante. Os nomes das subpastas servirão de rótulos para as diversas imagens. Isso significa que todos os arquivos sob o Banana pasta contém imagens de banana e assim por diante.

Para carregar uma série de imagens do disco, agora você chama o método flow_from_directory() método do ImageDataGenerator instância em vez do flow() método (para carregar imagens da memória):

train_datagen=ImageDataGenerator(
horizontal_flip=Verdadeiro,
vertical_flip=Verdadeiro,
intervalo_de rotação = 50,
)
tamanho_do_lote = 8train_generator = train_datagen.flow_from_directory(
'./Frutas',
tamanho_alvo=(224,224),
color_mode='rgb',
tamanho_do_lote=tamanho_do_lote,
class_mode='categórico',
embaralhar=Verdadeiro)

Observe que agora defino o batch_size para 8. Você verá o uso do tamanho do lote em breve.

Usando o iterador retornado, posso encontrar os rótulos das diversas frutas (banana, durião, laranja e morango):

class_dictionary=train_generator.class_indices#---crie um dicionário de rótulos---
class_dictionary = {valor:chave para chave,valor em
class_dictionary.items()}
#---converter o dicionário em uma lista---
class_list = [valor para _, valor em class_dictionary.items()]
imprimir(lista_classes)

Você verá a seguinte saída:

Foram encontradas 54 imagens pertencentes a 4 classes.
['banana', 'durião', 'laranja', 'morango']

Ao todo, são um total de 54 imagens em 4 pastas. Também o class_list variável contém a lista de frutas.

Vou agora imprimir o conjunto de imagens aumentadas que são criadas pelo ImageDataGenerator aula. Definirei arbitrariamente as linhas como 10 e, para cada linha, quero imprimir o lote de imagens retornado (que é 8 neste exemplo):

linhas = 10fig, eixos = plt.subplots(linhas,batch_size)para r no intervalo (linhas):    
#---obter o lote de imagens aumentadas---
imagem_batch = train_generator.next()
#---obter o número de imagens retornadas---
contagem_imagens = lote_imagem[0].forma[0]

para c no intervalo (images_count):
#---converter em números inteiros sem sinal para visualização---
imagem = image_batch[0][c].astype('uint8')

#---exibe a imagem---
eixos[r,c].imshow(imagem)

#---exibe o rótulo da imagem---
eixos[r,c].title.set_text(
lista_classe[np.argmax(image_batch[1][c])])
#---oculta os ticks x e y---
eixos[r,c].set_xticks([])
eixos[r,c].set_yticks([])
fig.set_size_inches(15,18)

Uma vez que o batch_size agora está definido como 8 (e não mais 1), o train_generator.next() método retornará a você um fornada de oito imagens aumentadas cada vez que você liga. O número de imagens retornadas é baseado em batch_size que você definiu anteriormente no flow_from_directory() método:

train_generator=train_datagen.flow_from_directory(
'./Frutas',
tamanho_alvo=(224,224),
color_mode='rgb',
tamanho_do_lote=tamanho_do_lote, #tamanho_do_lote = 8
class_mode='categórico',
embaralhar=Verdadeiro)

O valor do image_batch variável (retornada pelo next() método) é uma tupla de dois elementos:

  • O primeiro elemento (image_batch[0]) é uma matriz de tamanho do batch imagens (matriz 4D)
  • O segundo elemento (image_batch[1]) contém os rótulos das imagens

O trecho de código acima produz a seguinte saída:

Observe que na sétima linha há dois gráficos vazios sem imagens. Lembre-se de que há um total de 54 imagens no conjunto de imagens e, como cada lote retorna 8 imagens (por linha), as primeiras sete linhas exibirão um total de 54 imagens (8×6 + 6). A figura a seguir deixa isso claro:

Observe que você pode definir rows para qualquer número e o ImageDataGenerator class continuará gerando novas imagens aumentadas para você.

Construindo um modelo usando aprendizagem por transferência

Agora você sabe como usar o ImageDataGenerator para carregar conjuntos de imagens do disco para aumento. Mas como usá-lo para treinar? O trecho de código a seguir mostra como construir um modelo de aprendizado profundo usando transferir aprendizado.

O aprendizado por transferência é um método de aprendizado de máquina em que um modelo desenvolvido para uma tarefa é reutilizado como ponto de partida para um modelo em uma segunda tarefa. A aprendizagem por transferência reduz a quantidade de tempo que você precisa gastar em treinamento.

do modelo de importação tensorflow.keras.models
de tensorflow.keras.applications importar VGG16
de tensorflow.keras.layers importar Denso, GlobalAveragePooling2D
#---número de frutas---
NO_CLASSES = max(train_generator.class_indices.values()) + 1
#---carregar o modelo VGG16 como modelo base para treinamento---
modelo_base = VGG16(include_top=Falso, input_shape=(224, 224, 3))
#---adicionar nossas próprias camadas---
x = modelo_base.saída
x = GlobalAveragePooling2D()(x)
x = Dense(1024,activation='relu')(x) # adiciona camadas densas para
# que o modelo pode
# aprenda mais complexo
# funções e
#classifique para melhor
# resultados.
x = Densa(1024,ativação='relu')(x) # camada densa 2
x = Densa(512,ativação='relu')(x) # camada densa 3
preds = Denso(NO_CLASSES,
activation='softmax')(x) # camada final com
#ativação softmax
#---crie um novo modelo com o modelo base original
# entrada e saída do novo modelo ---
modelo = Modelo (entradas = modelo_base.input, saídas = preds)
#---não treine as primeiras 19 camadas - 0..18---
para camada em model.layers[:19]:
camada.trainable=Falso
#---treine o restante das camadas - 19 em diante---
para camada em model.layers[19:]:
camada.trainable = Verdadeiro

#---compilar o modelo---
model.compile(optimizer='Adam',
perda='categorical_crossentropy',
metrics = ['precisão'])

Explicar como funciona a aprendizagem por transferência está além do escopo deste artigo. Vou deixar para outro artigo.

Usando as imagens geradas para treinamento

Para utilizar as imagens aumentadas para treinamento, passe o train_generator no fit() método do modelo:

#---treinar o modelo---
step_size_train = train_generator.n // train_generator.batch_size
modelo.fit(train_generator,
passos_por_época = passo_tamanho_trem,
épocas = 15)

A steps_per_epoch parâmetro basicamente significa quantas etapas existem em uma época - depende do número de imagens que você possui e do tamanho do lote definido anteriormente. Se você definir um número alto, estará fazendo um treinamento repetitivo. Você deve configurá-lo com base nesta fórmula:

número de imagens/tamanho do lote

No nosso exemplo, temos 54 imagens no total. E assim, em cada época, o ImageDataGenerator a aula transformará todas as 54 imagens para treinamento. Em cada época o modelo obterá diferentes variações das imagens. Se você tiver 15 épocas, um total de 15×54 variações das imagens serão geradas e alimentadas no modelo de treinamento.

A ImageDataGenerator class permite que seu modelo receba novas variações das imagens em cada época. Mas lembre-se que ele apenas retorna as imagens transformadas e não as adiciona ao conjunto de imagens que você possui.

Espero que este artigo tenha lhe dado uma boa ideia do que se trata o aumento de dados de imagem e por que você precisa deles no treinamento de seus modelos de aprendizado profundo. Em particular, demonstrei isso usando o módulo Keras na biblioteca TensorFlow.

Aumento de dados de imagem para aprendizado profundo republicado da fonte https://towardsdatascience.com/image-data-augmentation-for-deep-learning-77a87fabd2bf?source=rss—-7f60cf5620c9—4 via https://towardsdatascience.com/feed

<!–

->

Carimbo de hora:

Mais de Consultores Blockchain