Ayuda a proteger la Gran Barrera de Coral con TensorFlow en Kaggle Únete Challenge

pix2pix: traducción de imagen a imagen con una GAN condicional

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Este tutorial muestra cómo construir y entrenar a un llamado pix2pix condicional generativa de confrontación de red (CGAN) que aprende un mapeo de imágenes de entrada para emitir imágenes, tal como se describe en la traducción de imagen a imagen con las redes adversarias condicionadas por Isola et al. (2017). pix2pix no es una aplicación específica; se puede aplicar a una amplia gama de tareas, incluida la síntesis de fotografías a partir de mapas de etiquetas, la generación de fotografías coloreadas a partir de imágenes en blanco y negro, la conversión de fotografías de Google Maps en imágenes aéreas e incluso la transformación de bocetos en fotografías.

En este ejemplo, la red va a generar imágenes de la construcción de fachadas utilizando el Base de Datos de CMP Fachada proporcionada por el Centro de Percepción de la máquina en la Universidad Técnica Checa de Praga . Para hacerlo breve, va a utilizar una copia preprocesado de este conjunto de datos creado por los autores pix2pix.

En pix2pix cGAN, usted condiciona las imágenes de entrada y genera las imágenes de salida correspondientes. cGANs se propusieron por primera vez en condicional generativo Acusatorio Nets (Mirza y Osindero, 2014)

La arquitectura de su red contendrá:

  • Un generador con un T-Net basados en la arquitectura.
  • Un discriminador representado por un clasificador PatchGAN convolucional (propuesto en el documento pix2pix ).

Tenga en cuenta que cada época puede tardar alrededor de 15 segundos en una sola GPU V100.

A continuación se muestran algunos ejemplos de la salida generada por pix2pix cGAN después del entrenamiento durante 200 épocas en el conjunto de datos de fachadas (80k pasos).

salida de muestra_1muestra output_2

Importar TensorFlow y otras bibliotecas

import tensorflow as tf

import os
import pathlib
import time
import datetime

from matplotlib import pyplot as plt
from IPython import display

Cargar el conjunto de datos

Descargue los datos de la base de datos de fachadas CMP (30 MB). Conjuntos de datos adicionales están disponibles en el mismo formato aquí . En Colab, puede seleccionar otros conjuntos de datos en el menú desplegable. Tenga en cuenta que algunos de los otros conjuntos de datos son significativamente más grandes ( edges2handbags es de 8 GB).

dataset_name = "facades"
_URL = f'http://efrosgans.eecs.berkeley.edu/pix2pix/datasets/{dataset_name}.tar.gz'

path_to_zip = tf.keras.utils.get_file(
    fname=f"{dataset_name}.tar.gz",
    origin=_URL,
    extract=True)

path_to_zip  = pathlib.Path(path_to_zip)

PATH = path_to_zip.parent/dataset_name
Downloading data from http://efrosgans.eecs.berkeley.edu/pix2pix/datasets/facades.tar.gz
30171136/30168306 [==============================] - 19s 1us/step
30179328/30168306 [==============================] - 19s 1us/step
list(PATH.parent.iterdir())
[PosixPath('/home/kbuilder/.keras/datasets/facades.tar.gz'),
 PosixPath('/home/kbuilder/.keras/datasets/facades')]

Cada imagen original es de un tamaño 256 x 512 que contiene dos 256 x 256 imágenes:

sample_image = tf.io.read_file(str(PATH / 'train/1.jpg'))
sample_image = tf.io.decode_jpeg(sample_image)
print(sample_image.shape)
(256, 512, 3)
plt.figure()
plt.imshow(sample_image)
<matplotlib.image.AxesImage at 0x7f1585832250>

png

Es necesario separar las imágenes fachada del edificio real a partir de las imágenes de todas las etiquetas de arquitectura que serán de tamaño 256 x 256 .

Defina una función que cargue archivos de imagen y genere dos tensores de imagen:

def load(image_file):
  # Read and decode an image file to a uint8 tensor
  image = tf.io.read_file(image_file)
  image = tf.io.decode_jpeg(image)

  # Split each image tensor into two tensors:
  # - one with a real building facade image
  # - one with an architecture label image 
  w = tf.shape(image)[1]
  w = w // 2
  input_image = image[:, w:, :]
  real_image = image[:, :w, :]

  # Convert both images to float32 tensors
  input_image = tf.cast(input_image, tf.float32)
  real_image = tf.cast(real_image, tf.float32)

  return input_image, real_image

Trace una muestra de las imágenes de entrada (imagen de etiqueta de arquitectura) y reales (foto de fachada de edificio):

inp, re = load(str(PATH / 'train/100.jpg'))
# Casting to int for matplotlib to display the images
plt.figure()
plt.imshow(inp / 255.0)
plt.figure()
plt.imshow(re / 255.0)
<matplotlib.image.AxesImage at 0x7f1584af6dd0>

png

png

Como se describe en el documento de pix2pix , es necesario aplicar fluctuación aleatoria y de modo paralelo a preprocesar el conjunto de entrenamiento.

Defina varias funciones que:

  1. Cambiar el tamaño de cada una 256 x 256 imagen a una altura mayor y anchura- 286 x 286 .
  2. Aleatoriamente recortar de nuevo a 256 x 256 .
  3. Voltea la imagen de forma aleatoria horizontalmente, es decir, de izquierda a derecha (duplicación aleatoria).
  4. Normalizar las imágenes a la [-1, 1] gama.
# The facade training set consist of 400 images
BUFFER_SIZE = 400
# The batch size of 1 produced better results for the U-Net in the original pix2pix experiment
BATCH_SIZE = 1
# Each image is 256x256 in size
IMG_WIDTH = 256
IMG_HEIGHT = 256
def resize(input_image, real_image, height, width):
  input_image = tf.image.resize(input_image, [height, width],
                                method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)
  real_image = tf.image.resize(real_image, [height, width],
                               method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)

  return input_image, real_image
def random_crop(input_image, real_image):
  stacked_image = tf.stack([input_image, real_image], axis=0)
  cropped_image = tf.image.random_crop(
      stacked_image, size=[2, IMG_HEIGHT, IMG_WIDTH, 3])

  return cropped_image[0], cropped_image[1]
# Normalizing the images to [-1, 1]
def normalize(input_image, real_image):
  input_image = (input_image / 127.5) - 1
  real_image = (real_image / 127.5) - 1

  return input_image, real_image
@tf.function()
def random_jitter(input_image, real_image):
  # Resizing to 286x286
  input_image, real_image = resize(input_image, real_image, 286, 286)

  # Random cropping back to 256x256
  input_image, real_image = random_crop(input_image, real_image)

  if tf.random.uniform(()) > 0.5:
    # Random mirroring
    input_image = tf.image.flip_left_right(input_image)
    real_image = tf.image.flip_left_right(real_image)

  return input_image, real_image

Puede inspeccionar algunos de los resultados preprocesados:

plt.figure(figsize=(6, 6))
for i in range(4):
  rj_inp, rj_re = random_jitter(inp, re)
  plt.subplot(2, 2, i + 1)
  plt.imshow(rj_inp / 255.0)
  plt.axis('off')
plt.show()

png

Una vez comprobado que la carga y el preprocesamiento funcionan, definamos un par de funciones auxiliares que cargan y preprocesan los conjuntos de entrenamiento y prueba:

def load_image_train(image_file):
  input_image, real_image = load(image_file)
  input_image, real_image = random_jitter(input_image, real_image)
  input_image, real_image = normalize(input_image, real_image)

  return input_image, real_image
def load_image_test(image_file):
  input_image, real_image = load(image_file)
  input_image, real_image = resize(input_image, real_image,
                                   IMG_HEIGHT, IMG_WIDTH)
  input_image, real_image = normalize(input_image, real_image)

  return input_image, real_image

Construir una tubería de entrada con tf.data

train_dataset = tf.data.Dataset.list_files(str(PATH / 'train/*.jpg'))
train_dataset = train_dataset.map(load_image_train,
                                  num_parallel_calls=tf.data.AUTOTUNE)
train_dataset = train_dataset.shuffle(BUFFER_SIZE)
train_dataset = train_dataset.batch(BATCH_SIZE)
try:
  test_dataset = tf.data.Dataset.list_files(str(PATH / 'test/*.jpg'))
except tf.errors.InvalidArgumentError:
  test_dataset = tf.data.Dataset.list_files(str(PATH / 'val/*.jpg'))
test_dataset = test_dataset.map(load_image_test)
test_dataset = test_dataset.batch(BATCH_SIZE)

Construye el generador

El generador de la pix2pix CGAN es una versión modificada T-Net . Un U-Net consta de un codificador (muestreador reducido) y un decodificador (muestreador superior). (Usted puede encontrar más información al respecto en la segmentación de imagen tutorial y en el sitio web de T-Net proyecto .)

  • Cada bloque en el codificador es: Convolución -> Normalización de lote -> ReLU con fugas
  • Cada bloque en el decodificador es: Convolución transpuesta -> Normalización de lote -> Abandono (aplicado a los primeros 3 bloques) -> ReLU
  • Hay conexiones de salto entre el codificador y el descodificador (como en U-Net).

Defina el submuestreador (codificador):

OUTPUT_CHANNELS = 3
def downsample(filters, size, apply_batchnorm=True):
  initializer = tf.random_normal_initializer(0., 0.02)

  result = tf.keras.Sequential()
  result.add(
      tf.keras.layers.Conv2D(filters, size, strides=2, padding='same',
                             kernel_initializer=initializer, use_bias=False))

  if apply_batchnorm:
    result.add(tf.keras.layers.BatchNormalization())

  result.add(tf.keras.layers.LeakyReLU())

  return result
down_model = downsample(3, 4)
down_result = down_model(tf.expand_dims(inp, 0))
print (down_result.shape)
(1, 128, 128, 3)

Defina el upsampler (decodificador):

def upsample(filters, size, apply_dropout=False):
  initializer = tf.random_normal_initializer(0., 0.02)

  result = tf.keras.Sequential()
  result.add(
    tf.keras.layers.Conv2DTranspose(filters, size, strides=2,
                                    padding='same',
                                    kernel_initializer=initializer,
                                    use_bias=False))

  result.add(tf.keras.layers.BatchNormalization())

  if apply_dropout:
      result.add(tf.keras.layers.Dropout(0.5))

  result.add(tf.keras.layers.ReLU())

  return result
up_model = upsample(3, 4)
up_result = up_model(down_result)
print (up_result.shape)
(1, 256, 256, 3)

Defina el generador con el downsampler y el upsampler:

def Generator():
  inputs = tf.keras.layers.Input(shape=[256, 256, 3])

  down_stack = [
    downsample(64, 4, apply_batchnorm=False),  # (batch_size, 128, 128, 64)
    downsample(128, 4),  # (batch_size, 64, 64, 128)
    downsample(256, 4),  # (batch_size, 32, 32, 256)
    downsample(512, 4),  # (batch_size, 16, 16, 512)
    downsample(512, 4),  # (batch_size, 8, 8, 512)
    downsample(512, 4),  # (batch_size, 4, 4, 512)
    downsample(512, 4),  # (batch_size, 2, 2, 512)
    downsample(512, 4),  # (batch_size, 1, 1, 512)
  ]

  up_stack = [
    upsample(512, 4, apply_dropout=True),  # (batch_size, 2, 2, 1024)
    upsample(512, 4, apply_dropout=True),  # (batch_size, 4, 4, 1024)
    upsample(512, 4, apply_dropout=True),  # (batch_size, 8, 8, 1024)
    upsample(512, 4),  # (batch_size, 16, 16, 1024)
    upsample(256, 4),  # (batch_size, 32, 32, 512)
    upsample(128, 4),  # (batch_size, 64, 64, 256)
    upsample(64, 4),  # (batch_size, 128, 128, 128)
  ]

  initializer = tf.random_normal_initializer(0., 0.02)
  last = tf.keras.layers.Conv2DTranspose(OUTPUT_CHANNELS, 4,
                                         strides=2,
                                         padding='same',
                                         kernel_initializer=initializer,
                                         activation='tanh')  # (batch_size, 256, 256, 3)

  x = inputs

  # Downsampling through the model
  skips = []
  for down in down_stack:
    x = down(x)
    skips.append(x)

  skips = reversed(skips[:-1])

  # Upsampling and establishing the skip connections
  for up, skip in zip(up_stack, skips):
    x = up(x)
    x = tf.keras.layers.Concatenate()([x, skip])

  x = last(x)

  return tf.keras.Model(inputs=inputs, outputs=x)

Visualice la arquitectura del modelo del generador:

generator = Generator()
tf.keras.utils.plot_model(generator, show_shapes=True, dpi=64)

png

Pruebe el generador:

gen_output = generator(inp[tf.newaxis, ...], training=False)
plt.imshow(gen_output[0, ...])
Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).
<matplotlib.image.AxesImage at 0x7f1540686790>

png

Definir la pérdida del generador

GAN aprenden una pérdida que se adapte a los datos, mientras que cGANs aprenden una pérdida estructurado que penaliza a una posible estructura que difiere de la imagen del objetivo y salida de red, como se describe en el documento de pix2pix .

  • La pérdida del generador es una pérdida de entropía cruzada sigmoide de las imágenes generadas y una variedad de otros.
  • El papel pix2pix también menciona la pérdida L1, que es un MAE (error absoluto medio) entre la imagen generada y la imagen objetivo.
  • Esto permite que la imagen generada se vuelva estructuralmente similar a la imagen de destino.
  • La fórmula para calcular la pérdida total del generador es gan_loss + LAMBDA * l1_loss , donde LAMBDA = 100 . Este valor fue decidido por los autores del artículo.
LAMBDA = 100
loss_object = tf.keras.losses.BinaryCrossentropy(from_logits=True)
def generator_loss(disc_generated_output, gen_output, target):
  gan_loss = loss_object(tf.ones_like(disc_generated_output), disc_generated_output)

  # Mean absolute error
  l1_loss = tf.reduce_mean(tf.abs(target - gen_output))

  total_gen_loss = gan_loss + (LAMBDA * l1_loss)

  return total_gen_loss, gan_loss, l1_loss

El procedimiento de entrenamiento para el generador es el siguiente:

Imagen de actualización del generador

Construye el discriminador

El discriminador en el pix2pix CGAN es un convolucional PatchGAN clasificador-intenta clasificar si cada parche de imagen es real o no real, como se describe en el documento pix2pix .

  • Cada bloque en el discriminador es: Convolución -> Normalización de lote -> ReLU con fugas.
  • La forma de la salida después de la última capa es (batch_size, 30, 30, 1) .
  • Cada 30 x 30 parche de imagen de la salida clasifica un 70 x 70 porción de la imagen de entrada.
  • El discriminador recibe 2 entradas:
    • La imagen de entrada y la imagen de destino, que debe clasificar como real.
    • La imagen de entrada y la imagen generada (la salida del generador), que debe clasificar como falsa.
    • Uso tf.concat([inp, tar], axis=-1) para concatenar estos 2 entradas juntos.

Definamos el discriminador:

def Discriminator():
  initializer = tf.random_normal_initializer(0., 0.02)

  inp = tf.keras.layers.Input(shape=[256, 256, 3], name='input_image')
  tar = tf.keras.layers.Input(shape=[256, 256, 3], name='target_image')

  x = tf.keras.layers.concatenate([inp, tar])  # (batch_size, 256, 256, channels*2)

  down1 = downsample(64, 4, False)(x)  # (batch_size, 128, 128, 64)
  down2 = downsample(128, 4)(down1)  # (batch_size, 64, 64, 128)
  down3 = downsample(256, 4)(down2)  # (batch_size, 32, 32, 256)

  zero_pad1 = tf.keras.layers.ZeroPadding2D()(down3)  # (batch_size, 34, 34, 256)
  conv = tf.keras.layers.Conv2D(512, 4, strides=1,
                                kernel_initializer=initializer,
                                use_bias=False)(zero_pad1)  # (batch_size, 31, 31, 512)

  batchnorm1 = tf.keras.layers.BatchNormalization()(conv)

  leaky_relu = tf.keras.layers.LeakyReLU()(batchnorm1)

  zero_pad2 = tf.keras.layers.ZeroPadding2D()(leaky_relu)  # (batch_size, 33, 33, 512)

  last = tf.keras.layers.Conv2D(1, 4, strides=1,
                                kernel_initializer=initializer)(zero_pad2)  # (batch_size, 30, 30, 1)

  return tf.keras.Model(inputs=[inp, tar], outputs=last)

Visualice la arquitectura del modelo discriminador:

discriminator = Discriminator()
tf.keras.utils.plot_model(discriminator, show_shapes=True, dpi=64)

png

Pruebe el discriminador:

disc_out = discriminator([inp[tf.newaxis, ...], gen_output], training=False)
plt.imshow(disc_out[0, ..., -1], vmin=-20, vmax=20, cmap='RdBu_r')
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x7f158494f550>

png

Definir la pérdida del discriminador

  • El discriminator_loss función toma 2 entradas: imágenes reales e imágenes generadas.
  • real_loss es una pérdida de entropía cruzada sigmoide de las imágenes reales y una serie de otros (ya que estas son las imágenes reales).
  • generated_loss es una pérdida de entropía cruzada sigmoide de las imágenes generadas y una serie de ceros (ya que estas son las imágenes falsas).
  • El total_loss es la suma de real_loss y generated_loss .
def discriminator_loss(disc_real_output, disc_generated_output):
  real_loss = loss_object(tf.ones_like(disc_real_output), disc_real_output)

  generated_loss = loss_object(tf.zeros_like(disc_generated_output), disc_generated_output)

  total_disc_loss = real_loss + generated_loss

  return total_disc_loss

El procedimiento de entrenamiento para el discriminador se muestra a continuación.

Para obtener más información sobre la arquitectura y los hiperparámetros se puede hacer referencia al papel pix2pix .

Imagen de actualización del discriminador

Defina los optimizadores y un protector de puntos de control

generator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)
discriminator_optimizer = tf.keras.optimizers.Adam(2e-4, beta_1=0.5)
checkpoint_dir = './training_checkpoints'
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
checkpoint = tf.train.Checkpoint(generator_optimizer=generator_optimizer,
                                 discriminator_optimizer=discriminator_optimizer,
                                 generator=generator,
                                 discriminator=discriminator)

Generar imágenes

Escribe una función para trazar algunas imágenes durante el entrenamiento.

  • Pase imágenes del equipo de prueba al generador.
  • El generador luego traducirá la imagen de entrada a la salida.
  • El último paso consiste en trazar las predicciones y listo!
def generate_images(model, test_input, tar):
  prediction = model(test_input, training=True)
  plt.figure(figsize=(15, 15))

  display_list = [test_input[0], tar[0], prediction[0]]
  title = ['Input Image', 'Ground Truth', 'Predicted Image']

  for i in range(3):
    plt.subplot(1, 3, i+1)
    plt.title(title[i])
    # Getting the pixel values in the [0, 1] range to plot.
    plt.imshow(display_list[i] * 0.5 + 0.5)
    plt.axis('off')
  plt.show()

Pruebe la función:

for example_input, example_target in test_dataset.take(1):
  generate_images(generator, example_input, example_target)

png

Capacitación

  • Para cada ejemplo, la entrada genera una salida.
  • El discriminador recibe input_image y la imagen generada como la primera entrada. La segunda entrada es la input_image y la target_image .
  • A continuación, calcule la pérdida del generador y del discriminador.
  • Luego, calcule los gradientes de pérdida con respecto tanto al generador como a las variables discriminadoras (entradas) y aplíquelos al optimizador.
  • Finalmente, registre las pérdidas en TensorBoard.
log_dir="logs/"

summary_writer = tf.summary.create_file_writer(
  log_dir + "fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
@tf.function
def train_step(input_image, target, step):
  with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
    gen_output = generator(input_image, training=True)

    disc_real_output = discriminator([input_image, target], training=True)
    disc_generated_output = discriminator([input_image, gen_output], training=True)

    gen_total_loss, gen_gan_loss, gen_l1_loss = generator_loss(disc_generated_output, gen_output, target)
    disc_loss = discriminator_loss(disc_real_output, disc_generated_output)

  generator_gradients = gen_tape.gradient(gen_total_loss,
                                          generator.trainable_variables)
  discriminator_gradients = disc_tape.gradient(disc_loss,
                                               discriminator.trainable_variables)

  generator_optimizer.apply_gradients(zip(generator_gradients,
                                          generator.trainable_variables))
  discriminator_optimizer.apply_gradients(zip(discriminator_gradients,
                                              discriminator.trainable_variables))

  with summary_writer.as_default():
    tf.summary.scalar('gen_total_loss', gen_total_loss, step=step//1000)
    tf.summary.scalar('gen_gan_loss', gen_gan_loss, step=step//1000)
    tf.summary.scalar('gen_l1_loss', gen_l1_loss, step=step//1000)
    tf.summary.scalar('disc_loss', disc_loss, step=step//1000)

El ciclo de entrenamiento real. Dado que este tutorial puede ejecutar más de un conjunto de datos, y los conjuntos de datos varían mucho en tamaño, el ciclo de entrenamiento está configurado para funcionar en pasos en lugar de épocas.

  • Itera sobre el número de pasos.
  • Cada 10 pasos imprimir un punto ( . ).
  • Cada 1k pasos: borrar la pantalla y se ejecutan generate_images para mostrar el progreso.
  • Cada 5000 pasos: guarda un punto de control.
def fit(train_ds, test_ds, steps):
  example_input, example_target = next(iter(test_ds.take(1)))
  start = time.time()

  for step, (input_image, target) in train_ds.repeat().take(steps).enumerate():
    if (step) % 1000 == 0:
      display.clear_output(wait=True)

      if step != 0:
        print(f'Time taken for 1000 steps: {time.time()-start:.2f} sec\n')

      start = time.time()

      generate_images(generator, example_input, example_target)
      print(f"Step: {step//1000}k")

    train_step(input_image, target, step)

    # Training step
    if (step+1) % 10 == 0:
      print('.', end='', flush=True)


    # Save (checkpoint) the model every 5k steps
    if (step + 1) % 5000 == 0:
      checkpoint.save(file_prefix=checkpoint_prefix)

Este ciclo de entrenamiento guarda registros que puedes ver en TensorBoard para monitorear el progreso del entrenamiento.

Si trabaja en una máquina local, iniciaría un proceso de TensorBoard por separado. Cuando trabaje en una computadora portátil, inicie el visor antes de comenzar el entrenamiento para monitorear con TensorBoard.

Para iniciar el visor, pegue lo siguiente en una celda de código:

%load_ext tensorboard
%tensorboard --logdir {log_dir}

Finalmente, ejecute el ciclo de entrenamiento:

fit(train_dataset, test_dataset, steps=40000)
Time taken for 1000 steps: 35.57 sec

png

Step: 39k
....................................................................................................

Si desea compartir los resultados TensorBoard públicamente, puede cargar los registros a TensorBoard.dev copiando el siguiente en una celda de código.

tensorboard dev upload --logdir {log_dir}

Puede ver los resultados de una ejecución anterior de este bloc de notas en TensorBoard.dev .

TensorBoard.dev es una experiencia administrada para alojar, rastrear y compartir experimentos de AA con todos.

También se incluyeron el uso de una línea <iframe> :

display.IFrame(
    src="https://tensorboard.dev/experiment/lZ0C6FONROaUMfjYkVyJqw",
    width="100%",
    height="1000px")

La interpretación de los registros es más sutil cuando se entrena una GAN (o una cGAN como pix2pix) en comparación con un modelo simple de clasificación o regresión. Cosas a buscar:

  • Compruebe que ni el modelo generador ni el discriminador hayan "ganado". Si bien el gen_gan_loss o la disc_loss pone muy bajo, es un indicador de que este modelo está dominando al otro, y no se está entrenando con éxito el modelo combinado.
  • El valor de log(2) = 0.69 es un punto de referencia bueno para estas pérdidas, ya que indica una perplejidad de 2 - el discriminador es, en promedio, igualmente seguro acerca de las dos opciones.
  • Para el disc_loss , un valor inferior a 0.69 mediante el discriminador está haciendo mejor que el azar en el conjunto combinado de imágenes reales y generados.
  • Para el gen_gan_loss , un valor inferior a 0.69 mediante el generador está haciendo mejor que el azar en engañar al discriminador.
  • Dado que la formación progresa, el gen_l1_loss debe ir hacia abajo.

Restaure el último punto de control y pruebe la red

ls {checkpoint_dir}
checkpoint          ckpt-5.data-00000-of-00001
ckpt-1.data-00000-of-00001  ckpt-5.index
ckpt-1.index            ckpt-6.data-00000-of-00001
ckpt-2.data-00000-of-00001  ckpt-6.index
ckpt-2.index            ckpt-7.data-00000-of-00001
ckpt-3.data-00000-of-00001  ckpt-7.index
ckpt-3.index            ckpt-8.data-00000-of-00001
ckpt-4.data-00000-of-00001  ckpt-8.index
ckpt-4.index
# Restoring the latest checkpoint in checkpoint_dir
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f10c4317a90>

Genere algunas imágenes usando el conjunto de prueba

# Run the trained model on a few examples from the test set
for inp, tar in test_dataset.take(5):
  generate_images(generator, inp, tar)

png

png

png

png

png