Olá, boas-vindas a este curso de geração de imagens com Deep Learning utilizando TensorFlow e Keras. Meu nome é Allan Spadini.
Audiodescrição: Allan se descreve como um homem branco. Tem olhos escuros e cabelos curtos e castanhos. Usa uma camiseta preta. Ao fundo, estúdio da Alura com parede azul e estante com plantas e decorações à direita.
Neste curso, vamos aprender a gerar imagens utilizando o TensorFlow. Mais especificamente, vamos estudar sobre a geração de imagens utilizando GANs (generative adversarial network ou redes generativas adversativas) e também as redes difusoras.
Além disso, vamos aprender a utilizar o Stable Diffusion, que é um modelo pré-treinado. Desse modo, poderemos combinar tanto as potencialidades do TensorFlow quanto do modelo Stable Diffusion.
Para acompanhar este curso, é necessário já conhecer o Python e também o TensorFlow voltado para a classificação de imagens.
Ao finalizar este curso, você será capaz de gerar nossos próprios projetos, criar nossos próprios modelos geradores de imagens, além de utilizar modelos geradores de imagens como o Stable Diffusion.
Esperamos te encontrar nos próximos vídeos deste curso. Até lá!
Nós trabalhamos para uma consultoria de IA que foi contratada por uma empresa de marketing que quer ter seu próprio gerador de imagens, sem depender de uma API, garantindo que não haverá problemas com direitos autorais.
Vamos começar pensando em como construir um gerador de imagens. A empresa quer criar um gerador de imagens para produtos, especificamente roupas. Para isso, vamos estudar o uso do Fashion MNIST, um dataset que nos permitirá criar imagens de roupas.
Para iniciar nosso estudo, estamos utilizando a plataforma Lightning AI para a construção do projeto.
É possível usar tanto a Lightning AI quanto o Google Colab. Optamos por essa plataforma para agilizar o processo durante a gravação.
Na primeira célula, vamos importar a biblioteca TensorFlow com apelido tf
:
import tensorflow as tf
Em seguida, importamos a biblioteca Matplotlib, especificamente o matplotlib.pyplot
:
import matplotlib.pyplot as plt
Também importamos a biblioteca warnings
para evitar mensagens relacionadas à GPU disponível no Lightning AI.
Em seguida, vamos fazer uma chamada warnings.filterwarnings()
, passando a string ignore
.
import warnings
warnings.filterwarnings('ignore')
Utilizaremos a base de dados Fashion MNIST, que será importada diretamente através do TensorFlow. Não utilizaremos um dataset disponível localmente.
Para carregá-lo, usamos a função tf.keras.datasets.fashion_mnist.load_data()
que retorna tanto um conjunto de treino quanto um conjunto de teste.
Nesse caso, vamos armazená-lo em duas variáveis de treino, train_images
e train_labels
. Afinal, a avaliação da qualidade das imagens geradas nesse projeto será feita de forma qualitativa, analisando visualmente se estão boas ou não.
Para descartar o conjunto de teste, vamos usar o underscore (_
) como um placeholder para o segundo valor retornado que não será utilizado.
(train_images, train_labels), _ = tf.keras.datasets.fashion_mnist.load_data()
Em seguida, adicionaremos uma dimensão extra às imagens de treino e realizaremos a normalização dessas imagens. Essa dimensão extra é necessária quando trabalhamos com imagens coloridas.
Para isso, vamos criar a variável train_images
que será igual a train_images.reshape()
, passando train_images.shape[0]
, 28
, 28
, 1
. Assim, as dimensões de todas as imagens do Fashion MNIST serão 28 por 28 pixels.
Após o reshape
, faremos um astype()
para convertê-las para float32
.
train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')
Agora, normalizamos as imagens, subtraindo train_images
por 127.5
e dividindo esse resultado por 127.5
.
train_images = (train_images - 127.5) / 127.5
Esse processo ajusta os valores dos pixels para uma escala de cinza entre -1
e 1
, já que normalmente variam de 0
a 255
.
Feito isso, vamos definir o tamanho do batch, que será o tamanho dos blocos e conjuntos de dados carregados na rede neural. Definiremos um batch_size
de 256
.
batch_size = 256
Agora, embaralhamos e carregamos os dados, construindo o dataset de treino com base nesse batch_size
, que é o carregamento em blocos.
Para isso, vamos criar a variável train_ds
que será igual à função tf.data.Dataset.from_tensor_slices()
, passando train_images
como argumento.
Em seguida, aplicamos a função shuffle()
para embaralhar os dados com um valor de 60000
. Por fim, faremos um batch()
para dividir o dataset de acordo com o valor armazenado em batch_size
.
train_ds = tf.data.Dataset.from_tensor_slices(train_images).shuffle(60000).batch(batch_size)
Em resumo, estamos criando um programa de carregamento do dataset para alimentá-lo de maneira otimizada durante o treinamento da rede neural.
Além disso, podemos visualizar as imagens dentro desse dataset, utilizando o Matpolotlib, para entender que tipo de imagem estamos tentando gerar.
Primeiro, vamos definir o número de imagens a serem mostradas, criando a variável num_images_to_show
e atribuindo a ela o valor 10
.
Na próxima linha, criamos uma figura usando o plt.figure()
e estipulando o parâmetro figsize
igual a uma tupla (10, 10)
.
Depois, faremos um loop for
para percorrer as primeiras imagens do dataset. Para isso, escrevemos for i in range(num_images_to_show)
.
Para cada imagem, vamos criar um plt.subplot()
passando o argumento 1
para que todas as imagens sejam exibidas em uma única linha. Depois passamos num_images_to_show
, que é o número total de subplots. Por fim, especificamos o índice i + 1
para posicionar cada imagem em seu respectivo subplot.
Para desenhar as imagens efetivamente, vamos utilizar o plt.imshow()
, passando train_images[i].reshape(28, 28)
para garantir que as imagens sejam redimensionadas para 28x28 pixels, além de definir cmap='gray'
para exibi-las em escala de cinza.
Finalmente, como não precisamos dos eixos, vamos definir plt.axis()
como off
.
num_images_to_show = 10
plt.figure(figsize=(10, 10))
for i in range(num_images_to_show):
plt.subplot(1, num_images_to_show, i + 1)
plt.imshow(train_images[i].reshape(28, 28), cmap='gray')
plt.axis('off')
plt.show()
Ao visualizar as dez primeiras imagens do dataset, descobrimos que essa base contém fotografias de tênis, camisetas, camisas femininas, vestidos, entre outros. O gerador que vamos construir para a empresa de marketing vai gerar esse tipo de imagem.
No próximo vídeo, começaremos a construir esse gerador.
Já entendemos como são as imagens que queremos gerar. Desejamos criar essas imagens de roupas em escala de cinza.
Agora, o desafio é pensar em como definir uma rede neural que gera imagens.
Para começar a pensar nisso, vamos construir uma função geradora de imagens, que será uma rede neural.
Primeiramente, vamos importar as funções layers
e Sequential
do TensorFlow:
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
Queremos criar uma sequência de camadas de uma rede neural. Assim, vamos criar a função constroi_gerador()
. Dentro dessa função, definiremos nosso modelo. Nesse caso, o modelo
será atribuído a Sequential()
.
def constroi_gerador():
modelo = Sequential()
Agora, precisamos de uma sequência de camadas, semelhante à de um classificador.
No classificador, queremos transformar uma imagem de alta dimensionalidade (um quadrado com diversos pixels, que são diversos números) em algo menor, como, por exemplo, um único valor para indicar se estamos na classe 0 ou 1 em um problema de classificação binária.
Em contrapartida, no caso do gerador, partimos de uma classe ou de um ruído (um número aleatório) e tentamos gerar algo mais complexo, como uma imagem.
Vamos criar uma sequência de camadas da rede neural que partirá de um vetor de 100 valores aleatórios, transformando-os em algo mais complexo: uma imagem com dimensões de 28x28, como as imagens do Fashion MNIST.
Para construir a camada de entrada, usamos a função modelo.add()
, passando layers.Input()
e especificando a forma (shape
) dos dados como um vetor (100, )
.
modelo.add(layers.Input(shape=(100,)))
Desse modo, nosso input será um ruído, um vetor unidimensional de 100 valores aleatórios.
Continuando a construção da sequência de camadas, vamos adicionar uma camada densa de rede neural através da função modelo.add()
novamente.
Dessa vez, passamos layers.Dense()
, definindo o tamanho da camada que terá 7*7*256
valores. Também passamos o parâmetro use_bias
igual a False
.
modelo.add(layers.Dense(7*7*256, use_bias=False))
Assim, definimos o número de neurônios para essa camada densa, aumentando as dimensões de 100 para uma camada com mais dimensões.
Em uma imagem, temos pixels entre 0 e 255, então, temos 256 valores. E, apesar de querer chegar a uma dimensão de 28x28, começamos com valores 7x7, equivalente a uma imagem de 7x7 pixels. A medida que passamos pelas camadas da rede neural, aumentaremos esses valores.
Também adicionaremos uma camada de normalização através do modelo.add()
, passando layers.BatchNormalization()
.
modelo.add(layers.BatchNormalization())
E passaremos a função de ativação para essa camada também usando modelo.add()
e passando layers.LeakyReLU()
que é uma ReLu
(Rectified Linear Unit) com algumas funcionalidades a mais.
modelo.add(layers.LeakyReLU())
Repare que estamos passando as funções de ativação separadamente para o código ficar mais legível. Mas podemos pensar em tudo isso como sendo uma única camada que passamos de forma mais sequencial.
Seguimos com a sequência das camadas, fazendo o Reshape
da camada. Para isso, fazemos modelo.add()
, passando layers.Reshape()
com uma matriz de 7, 7, 256
.
modelo.add(layers.Reshape((7, 7, 256)))
Dessa forma, que era uma camada densa de valores 7*7*256
agora tem dimensões equivalentes a uma imagem.
Em seguida, digitamos modelo.add()
para adicionar uma nova camada layers.Conv2DTranspose()
que é uma camada de deconvolução. Assim como em uma camada convolucional, passaremos os seguintes parâmetros:
128
(5, 5)
strides
) igual a (1, 1)
padding
) igual a 'same'
use_bias
) igual a False
Assim, teremos 128 filtros quadrados de 5x5 percorrendo os conjuntos de pixels das imagens.
modelo.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
Enquanto as camadas convolucionais tendem a reduzir a dimensionalidade das imagens quando trabalhamos com a classificação de imagens, a camada de deconvolução tende a desfazer o efeito de uma convolução, aumentando a dimensão da imagem, ou seja, aumentando os pixels da imagem.
Para padronizar, aplicaremos essa camada com a sequência de camadas já aplicadas, efetuando novamente a normalização e aplicando uma ativação:
modelo.add(layers.BatchNormalization())
modelo.add(layers.LeakyReLU())
Copiando a estrutura do Conv2DTranspose()
, definiremos mais uma camada convolucional. Dessa vez, vamos aplicar 64
filtros, alterar strides
para (2, 2)
e manter o restante dos parâmetros.
Logo, aplicamos novamente uma normalização e uma ativação.
modelo.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
modelo.add(layers.BatchNormalization())
modelo.add(layers.LeakyReLU())
Não fizemos o Reshape
novamente porque ele só é necessário quando estamos convertendo os valores de uma camada densa (que organiza os dados em um formato linear, como um vetor 1D) para um formato bidimensional (2D), que se assemelha a uma imagem.
Feito isso, vamos finalizar com uma camada que deixará o resultado com apenas uma única imagem. Assim, vamos transformar as 64 imagens, resultantes da aplicação de 64 filtros, em uma única imagem.
Para isso, novamente adicionaremos uma camada convolucional, copiando a estrutura de Conv2DTranspose()
. Dessa vez, alteraremos apenas o número de filtros para 1
.
Além disso, depois do use_bias
, acrescentaremos o parâmetro activation
igual a 'tanh'
, uma tangente hiperbólica.
modelo.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
A ativação tanh
retornará valores entre -1
e 1
, lembrando que normalizamos os dados para ficarem entre esses valores.
Por fim, retornamos o modelo
na função:
def constroi_gerador():
modelo = Sequential()
modelo.add(layers.Input(shape=(100,)))
modelo.add(layers.Dense(7*7*256, use_bias=False))
modelo.add(layers.BatchNormalization())
modelo.add(layers.LeakyReLU())
modelo.add(layers.Reshape((7, 7, 256)))
modelo.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
modelo.add(layers.BatchNormalization())
modelo.add(layers.LeakyReLU())
modelo.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
modelo.add(layers.BatchNormalization())
modelo.add(layers.LeakyReLU())
modelo.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
return modelo
Executamos o código com "Shift + Enter" para construir a função.
No próximo vídeo, aplicaremos essa função para tentar gerar algum tipo de imagem. Até o próximo vídeo!
O curso TensorFlow/Keras: gerando imagens com Deep Learning possui 156 minutos de vídeos, em um total de 50 atividades. Gostou? Conheça nossos outros cursos de IA para Dados em Inteligência Artificial, ou leia nossos artigos de Inteligência Artificial.
Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você tem acesso a eventos exclusivos, grupos de estudos e mentorias com especialistas de diferentes áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Transforme a sua jornada com benefícios exclusivos e evolua ainda mais na sua carreira.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.