Path: blob/master/site/pt-br/tutorials/generative/pix2pix.ipynb
25118 views
Copyright 2019 The TensorFlow Authors.
Licensed under the Apache License, Version 2.0 (the "License");
pix2pix: tradução de imagem para imagem com um GAN condicional
Este tutorial demonstra como construir e treinar uma rede adversária generativa condicional (cGAN) chamada pix2pix que aprende um mapeamento de imagens de entrada para imagens de saída, conforme descrito em Tradução de imagem para imagem com redes adversárias condicionais{:.external} por Isola et al. (2017). O pix2pix não é específico para uma aplicação – ele pode ser aplicado a uma ampla gama de tarefas, incluindo sintetizar fotos a partir de mapas de etiquetas, gerar fotos coloridas a partir de imagens em preto e branco, transformar fotos do Google Maps em imagens aéreas e até mesmo transformar esboços em fotos.
Neste exemplo, sua rede gerará imagens de fachadas de edifícios usando o banco de dados de fachadas CMP fornecido pelo Center for Machine Perception{:.external} da Universidade Técnica Tcheca em Praga{:.external}. Para ser breve, você usará uma cópia pré-processada{:.external} deste dataset criado pelos autores do pix2pix.
Na cGAN pix2pix, você condiciona as imagens de entrada e gera as imagens de saída correspondentes. As cGANs foram propostas pela primeira vez em Redes Adversarias Gerativas Condicionais (Mirza e Osindero, 2014)
A arquitetura da sua rede conterá:
Um gerador com arquitetura baseada em U-Net{:.external}.
Um discriminador representado por um classificador convolucional PatchGAN (proposto no artigo pix2pix{:.external}).
Observe que cada época pode levar cerca de 15 segundos em uma única GPU V100.
Abaixo estão alguns exemplos da saída gerada pelo pix2pix cGAN após treinamento por 200 épocas no dataset de fachadas (80k etapas).
Importe o TensorFlow e outras bibliotecas
Carregue o dataset
Baixe os dados do CMP Facade Database (30 MB). Datasets adicionais estão disponíveis no mesmo formato aqui {:.external}. No Colab você pode selecionar outros datasets no menu suspenso. Observe que alguns dos outros datasets são significativamente maiores (edges2handbags
tem 8 GB).
Cada imagem original tem tamanho 256 x 512
contendo duas imagens 256 x 256
:
Você precisa separar as imagens reais da fachada do edifício das imagens do rótulo de arquitetura – todas terão o tamanho 256 x 256
.
Defina uma função que carregue arquivos de imagem e produza dois tensores de imagem:
Plote uma amostra das imagens de entrada (imagem do rótulo de arquitetura) e reais (foto da fachada do edifício):
Conforme descrito no artigo pix2pix{:.external}, você precisa aplicar jitter e espelhamento aleatórios para pré-processar o conjunto de treinamento.
Defina várias funções que:
Redimensionem cada imagem de
256 x 256
para uma altura e largura maiores de286 x 286
.Recortem a imagem para
256 x 256
de forma aleatória.Virem a imagem aleatoriamente na horizontal, ou seja, da esquerda para a direita (espelhamento aleatório).
Normalizem as imagens para o intervalo
[-1, 1]
.
Você pode inspecionar algumas das saídas pré-processadas:
Depois de verificar se o carregamento e o pré-processamento funcionam, vamos definir algumas funções helper que carregam e pré-processam os datasets de treinamento e teste:
Crie um pipeline de entrada com tf.data
Construa o gerador
O gerador do seu pix2pix cGAN é uma U-Net modificada{:.external}. Uma U-Net consiste em um encoder (downsampler) e um decoder (upsampler). (Você pode descobrir mais sobre ela no tutorial Segmentação de imagens e no site do projeto U-Net{:.external}.)
Cada bloco no encoder é: Convolution -> Batch normalization -> Leaky ReLU
Cada bloco no decoder é: Transposed convolution -> Batch normalization -> Dropout (aplicado aos primeiros 3 blocos) -> ReLU
Existem conexões de salto entre o encoder e o decoder (como no U-Net).
Defina o downsampler (encoder):
Defina o upsampler (decoder):
Defina o gerador com o downsampler e o upsampler:
Visualize a arquitetura do modelo do gerador:
Teste o gerador:
Defina a perda do gerador
As GANs aprendem uma perda que se adapta aos dados, enquanto que as cGANs aprendem uma perda estruturada que penaliza uma possível estrutura diferente da saída da rede e da imagem alvo, conforme descrito no artigo pix2pix{:.external}.
A perda do gerador é uma perda de entropia cruzada sigmóide das imagens geradas e de um array de uns.
O artigo pix2pix também menciona a perda L1, que é um MAE (erro médio absoluto) entre a imagem gerada e a imagem alvo.
Isto permite que a imagem gerada se torne estruturalmente semelhante à imagem alvo.
A fórmula para calcular a perda total do gerador é
gan_loss + LAMBDA * l1_loss
, ondeLAMBDA = 100
. Este valor foi decidido pelos autores do artigo.
O procedimento de treinamento do gerador é o seguinte:
Treine o discriminador.
O discriminador na cGAN pix2pix é um classificador convolucional PatchGAN - ele tenta classificar se cada patch de imagem é real ou não, conforme descrito no artigo pix2pix{:.external}.
Cada bloco no discriminador é: Convolution -> Batch normalization -> Leaky ReLU.
O formato da saída após a última camada é
(batch_size, 30, 30, 1)
.Cada patch de imagem
30 x 30
da saída classifica uma porção70 x 70
da imagem de entrada.O discriminador recebe duas entradas:
A imagem de entrada e a imagem de destino, que deve ser classificada como real.
A imagem de entrada e a imagem gerada (saída do gerador), que deve ser classificada como falsa.
Use
tf.concat([inp, tar], axis=-1)
para concatenar essas duas entradas.
Vamos definir o discriminador:
Visualize a arquitetura do modelo do discriminador:
Teste o discriminador:
Defina a perda do discriminador
A função
discriminator_loss
recebe duas entradas: imagens reais e imagens geradas.real_loss
é uma perda de entropia cruzada sigmóide das imagens reais e de um array de uns (já que essas são as imagens reais).generated_loss
é uma perda de entropia cruzada sigmóide das imagens geradas e um array de zeros (já que essas são as imagens falsas).A
total_loss
é a soma dereal_loss
egenerated_loss
.
O procedimento de treinamento para o discriminador é mostrado abaixo.
Para saber mais sobre a arquitetura e os hiperparâmetros você pode consultar o artigo pix2pix{:.external}.
Defina os otimizadores e um gravador de checkpoints
Gere as imagens
Escreva uma função para plotar algumas imagens durante o treinamento.
Passe imagens do dataset de testes para o gerador.
O gerador irá então traduzir a imagem de entrada na saída.
O último passo é plotar um gráfico das previsões e voilà!
Observação: O training=True
é intencional aqui, pois o que você quer são as estatísticas do lote ao executar o modelo no dataset de teste. Se você usar training=False
, obterá as estatísticas acumuladas aprendidas no dataset de treinamento (o que não é o que você quer).
Teste a função:
Treinamento
Para cada exemplo a entrada gera uma saída.
O discriminador recebe a
input_image
e a imagem gerada como primeira entrada. A segunda entrada éinput_image
e atarget_image
.Em seguida, calcule o gerador e a perda do discriminador.
Depois, calcule os gradientes de perda em relação às variáveis do gerador e do discriminador (entradas) e aplique-os ao otimizador.
Por fim, registre as perdas no TensorBoard.
O ciclo de treinamento propriamente dito. Como este tutorial pode ser executado em mais de um dataset, e os datasets variam muito em tamanho, o loop de treinamento é configurado para funcionar em passos em vez de épocas.
Itera sobre o número de passos.
A cada 10 passos imprime um ponto (
.
).A cada 1000 etapas: limpe a tela e execute
generate_images
para mostrar o progresso.A cada 5000 passos: grave um checkpoint.
Este loop de treinamento salva logs que você pode visualizar no TensorBoard para monitorar o progresso do treinamento.
Se você trabalha numa máquina local, você iniciaria um processo TensorBoard separado. Ao trabalhar num notebook, inicie o visualizador antes de iniciar o treinamento para monitorar com o TensorBoard.
Inicie o TensorBoard Viewer (desculpe, isto não é mostrado no tensorflow.org):
Você pode ver os resultados de uma execução anterior deste notebook em TensorBoard.dev.
Finalmente, execute o loop de treinamento:
A interpretação dos logs é mais sutil ao treinar uma GAN (ou uma cGAN como pix2pix) em comparação com um modelo simples de classificação ou regressão. Eis algumas coisas que você pode procurar:
Verifique que nem o gerador nem o modelo discriminador "ganharam". Se
gen_gan_loss
oudisc_loss
ficar muito baixo, é um indicador de que este modelo está dominando o outro e você não está treinando com sucesso o modelo combinado.O valor
log(2) = 0.69
é um bom ponto de referência para estas perdas, pois indica uma perplexidade de 2. O discriminador é, em média, igualmente incerto sobre as duas opções.Para a
disc_loss
, um valor abaixo de0.69
significa que o discriminador está se saindo melhor do que o aleatório no conjunto combinado de imagens reais e geradas.Para a
gen_gan_loss
, um valor abaixo de0.69
significa que o gerador está se saindo melhor do que o aleatório em enganar o discriminador.À medida que o treinamento avança,
gen_l1_loss
deve diminuir.