pix2pix: ترجمه تصویر به تصویر با GAN شرطی

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHub دانلود دفترچه یادداشت

این آموزش نحوه ساخت و آموزش یک شبکه متخاصم مولد شرطی (cGAN) به نام pix2pix را نشان می‌دهد که نقشه‌برداری را از تصاویر ورودی به تصاویر خروجی می‌آموزد، همانطور که در ترجمه تصویر به تصویر با شبکه‌های متخاصم شرطی توسط Isola و همکاران توضیح داده شده است. (2017). pix2pix یک برنامه خاص نیست - می‌توان آن را برای طیف گسترده‌ای از وظایف، از جمله ترکیب عکس‌ها از نقشه‌های برچسب، تولید عکس‌های رنگی از تصاویر سیاه و سفید، تبدیل عکس‌های Google Maps به تصاویر هوایی، و حتی تبدیل طرح‌ها به عکس اعمال کرد.

در این مثال، شبکه شما با استفاده از پایگاه داده نمای CMP ارائه شده توسط مرکز درک ماشین در دانشگاه فنی چک در پراگ ، تصاویری از نمای ساختمان تولید می کند. برای کوتاه نگه داشتن آن، از یک کپی از پیش پردازش شده این مجموعه داده که توسط نویسندگان pix2pix ایجاد شده است استفاده خواهید کرد.

در pix2pix cGAN، تصاویر ورودی را شرط می‌کنید و تصاویر خروجی مربوطه را تولید می‌کنید. cGAN ها برای اولین بار در شبکه های متخاصم مولد مشروط پیشنهاد شدند (میرزا و اوسیندرو، 2014)

معماری شبکه شما شامل موارد زیر خواهد بود:

  • یک ژنراتور با معماری مبتنی بر U-Net .
  • یک تمایز که توسط یک طبقه‌بندی کننده PatchGAN کانولوشن ارائه می‌شود (پیشنهاد شده در مقاله pix2pix ).

توجه داشته باشید که هر دوره می تواند حدود 15 ثانیه روی یک واحد گرافیکی V100 طول بکشد.

در زیر چند نمونه از خروجی تولید شده توسط pix2pix cGAN پس از آموزش برای 200 دوره در مجموعه داده نماها (80 هزار مرحله) آورده شده است.

نمونه خروجی_1نمونه خروجی_2

TensorFlow و کتابخانه های دیگر را وارد کنید

import tensorflow as tf

import os
import pathlib
import time
import datetime

from matplotlib import pyplot as plt
from IPython import display

مجموعه داده را بارگیری کنید

داده های پایگاه داده نمای CMP (30 مگابایت) را دانلود کنید. مجموعه داده های اضافی در قالب یکسان در اینجا موجود است. در Colab می توانید مجموعه داده های دیگری را از منوی کشویی انتخاب کنید. توجه داشته باشید که برخی از مجموعه داده های دیگر به طور قابل توجهی بزرگتر هستند ( edges2handbags 8 گیگابایت است).

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/YellowLabradorLooking_new.jpg'),
 PosixPath('/home/kbuilder/.keras/datasets/facades'),
 PosixPath('/home/kbuilder/.keras/datasets/mnist.npz')]

هر تصویر اصلی در اندازه 256 x 512 شامل دو تصویر 256 x 256 است:

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 0x7f35a3653c90>

png

شما باید تصاویر واقعی نمای ساختمان را از تصاویر برچسب معماری جدا کنید - که همه آنها در اندازه 256 x 256 خواهند بود.

تابعی را تعریف کنید که فایل های تصویری را بارگیری می کند و دو تانسور تصویر را خروجی می دهد:

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

نمونه ای از تصاویر ورودی (تصویر برچسب معماری) و واقعی (عکس نمای ساختمان) را ترسیم کنید:

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 0x7f35981a4910>

png

png

همانطور که در مقاله pix2pix توضیح داده شد، برای پیش پردازش مجموعه آموزشی باید از لرزش تصادفی و آینه کاری استفاده کنید.

چندین تابع را تعریف کنید که:

  1. اندازه هر تصویر 256 x 256 را به ارتفاع و عرض بزرگتر تغییر دهید - 286 x 286 .
  2. به طور تصادفی آن را به 256 x 256 برش دهید.
  3. به طور تصادفی تصویر را به صورت افقی برگردانید، یعنی از چپ به راست (آینه کاری تصادفی).
  4. تصاویر را در محدوده [-1, 1] عادی کنید.
# 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

می توانید برخی از خروجی های از پیش پردازش شده را بررسی کنید:

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

پس از بررسی اینکه بارگذاری و پیش پردازش کار می کند، اجازه دهید چند تابع کمکی را تعریف کنیم که مجموعه های آموزشی و آزمایشی را بارگیری و پیش پردازش می کند:

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

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

ژنراتور را بسازید

مولد pix2pix cGAN شما یک U-Net اصلاح شده است. U-Net از یک رمزگذار (downsampler) و رمزگشا (upsampler) تشکیل شده است. (شما می توانید در آموزش تقسیم بندی تصویر و وب سایت پروژه U-Net در مورد آن اطلاعات بیشتری کسب کنید.)

  • هر بلوک در رمزگذار عبارت است از: Convolution -> Batch normalization -> Leaky ReLU
  • هر بلوک در رمزگشا عبارت است از: کانولوشن انتقال داده شده -> نرمال سازی دسته ای -> حذف (در 3 بلوک اول اعمال می شود) -> ReLU
  • اتصالات پرش بین رمزگذار و رمزگشا وجود دارد (مانند U-Net).

نمونه‌برگیر (رمزگذار) را تعریف کنید:

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)

نمونه‌بردار (رمزگشا) را تعریف کنید:

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)

مولد را با نمونه برداری پایین و نمونه گیری بالا تعریف کنید:

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)

معماری مدل ژنراتور را تجسم کنید:

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

png

ژنراتور را تست کنید:

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 0x7f35cfd20610>

png

تلفات ژنراتور را تعریف کنید

GAN ها اتلافی را یاد می گیرند که با داده ها سازگار است، در حالی که cGAN ها اتلاف ساختار یافته ای را می آموزند که ساختار احتمالی را که با خروجی شبکه و تصویر هدف متفاوت است جریمه می کند، همانطور که در مقاله pix2pix توضیح داده شده است.

  • تلفات مولد یک افت آنتروپی متقاطع سیگموئیدی از تصاویر تولید شده و آرایه ای از تصاویر است.
  • مقاله pix2pix همچنین از دست دادن L1 را ذکر می کند که یک MAE (میانگین خطای مطلق) بین تصویر تولید شده و تصویر هدف است.
  • این اجازه می دهد تا تصویر تولید شده از نظر ساختاری شبیه به تصویر هدف شود.
  • فرمول محاسبه تلفات کل ژنراتور gan_loss + LAMBDA * l1_loss است که در آن LAMBDA = 100 است. این مقدار توسط نویسندگان مقاله تعیین شده است.
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

روش آموزش برای ژنراتور به شرح زیر است:

تصویر به روز رسانی ژنراتور

تمایز کننده را بسازید

تمایز کننده در pix2pix cGAN یک طبقه‌بندی کننده PatchGAN کانولوشنی است - همانطور که در مقاله pix2pix توضیح داده شده است، سعی می‌کند تشخیص دهد که آیا هر وصله تصویر واقعی است یا نه.

  • هر بلوک در تشخیصگر عبارت است از: Convolution -> Batch normalization -> Leaky ReLU.
  • شکل خروجی بعد از آخرین لایه (batch_size, 30, 30, 1) است.
  • هر وصله تصویر 30 x 30 از خروجی، بخش 70 x 70 تصویر ورودی را طبقه بندی می کند.
  • تفکیک کننده 2 ورودی دریافت می کند:
    • تصویر ورودی و تصویر هدف که باید به عنوان واقعی طبقه بندی شود.
    • تصویر ورودی و تصویر تولید شده (خروجی ژنراتور) که باید به عنوان جعلی طبقه بندی شود.
    • از tf.concat([inp, tar], axis=-1) برای به هم پیوستن این 2 ورودی استفاده کنید.

بیایید متمایز کننده را تعریف کنیم:

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)

معماری مدل تفکیک کننده را تجسم کنید:

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

png

تشخیص دهنده را آزمایش کنید:

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 0x7f35cec82c50>

png

ضرر تمایز را تعریف کنید

  • تابع discriminator_loss 2 ورودی می گیرد: تصاویر واقعی و تصاویر تولید شده .
  • real_loss یک افت آنتروپی متقاطع سیگموید از تصاویر واقعی و آرایه ای از تصاویر است (زیرا اینها تصاویر واقعی هستند) .
  • generated_loss یک افت آنتروپی متقاطع سیگموئیدی از تصاویر تولید شده و آرایه ای از صفر است (زیرا این تصاویر جعلی هستند) .
  • total_loss مجموع real_loss و 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

روش آموزش برای متمایز کننده در زیر نشان داده شده است.

برای کسب اطلاعات بیشتر در مورد معماری و هایپرپارامترها می توانید به مقاله pix2pix مراجعه کنید.

تصویر به‌روزرسانی Discriminator

بهینه سازها و یک بازرسی محافظ را تعریف کنید

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)

تولید تصاویر

تابعی بنویسید تا در حین آموزش برخی از تصاویر را ترسیم کند.

  • تصاویر را از مجموعه آزمایشی به ژنراتور منتقل کنید.
  • سپس ژنراتور تصویر ورودی را به خروجی ترجمه می کند.
  • آخرین مرحله این است که پیش بینی ها و voila را ترسیم کنید!
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()

تست تابع:

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

png

آموزش

  • برای هر نمونه ورودی یک خروجی تولید می کند.
  • متمایز کننده input_image و تصویر تولید شده را به عنوان اولین ورودی دریافت می کند. ورودی دوم input_image و target_image است.
  • در مرحله بعد، مولد و تلفات تفکیک کننده را محاسبه کنید.
  • سپس، گرادیان‌های تلفات را با توجه به متغیرهای (ورودی‌های) مولد و تفکیک‌کننده محاسبه کرده و آن‌ها را برای بهینه‌ساز اعمال کنید.
  • در نهایت، تلفات را به 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)

حلقه آموزش واقعی از آنجایی که این آموزش می تواند بیش از یک مجموعه داده را اجرا کند، و مجموعه داده ها از نظر اندازه بسیار متفاوت هستند، حلقه آموزشی به گونه ای تنظیم شده است که به جای دوره ها، در مراحل کار کند.

  • در تعداد مراحل تکرار می شود.
  • هر 10 مرحله یک نقطه ( . ) چاپ کنید.
  • هر 1 هزار مرحله: صفحه نمایش را پاک کنید و generate_images را اجرا کنید تا پیشرفت را نشان دهید.
  • هر 5 هزار قدم: یک ایست بازرسی را ذخیره کنید.
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)

این حلقه آموزشی گزارش هایی را ذخیره می کند که می توانید در TensorBoard برای نظارت بر پیشرفت آموزش مشاهده کنید.

اگر روی یک ماشین محلی کار می کنید، یک فرآیند TensorBoard جداگانه راه اندازی می کنید. هنگام کار در یک نوت بوک، قبل از شروع آموزش، بیننده را برای نظارت با TensorBoard راه اندازی کنید.

برای راه اندازی بیننده موارد زیر را در یک سلول کد جایگذاری کنید:

%load_ext tensorboard
%tensorboard --logdir {log_dir}

در نهایت حلقه آموزشی را اجرا کنید:

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

png

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

اگر می‌خواهید نتایج TensorBoard را به صورت عمومی به اشتراک بگذارید، می‌توانید با کپی کردن موارد زیر در یک سلول کد، گزارش‌ها را در TensorBoard.dev آپلود کنید.

tensorboard dev upload --logdir {log_dir}

می توانید نتایج اجرای قبلی این نوت بوک را در TensorBoard.dev مشاهده کنید.

TensorBoard.dev یک تجربه مدیریت شده برای میزبانی، ردیابی و به اشتراک گذاری آزمایش های ML با همه است.

همچنین می‌تواند با استفاده از <iframe> به صورت درون خطی قرار گیرد:

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

تفسیر گزارش‌ها هنگام آموزش GAN (یا cGAN مانند pix2pix) در مقایسه با طبقه‌بندی ساده یا مدل رگرسیون ظریف‌تر است. چیزهایی که باید به دنبال آن باشید:

  • بررسی کنید که نه مولد و نه مدل تفکیک کننده "برنده" شده باشد. اگر gen_gan_loss یا disc_loss بسیار کم شود، نشانگر آن است که این مدل بر دیگری تسلط دارد و شما با موفقیت مدل ترکیبی را آموزش نمی‌دهید.
  • مقدار log(2) = 0.69 نقطه مرجع خوبی برای این تلفات است، زیرا نشان دهنده گیجی 2 است - متمایزکننده به طور متوسط ​​در مورد دو گزینه به همان اندازه نامشخص است.
  • برای disc_loss ، مقدار کمتر از 0.69 به این معنی است که تشخیص دهنده در مجموعه ترکیبی تصاویر واقعی و تولید شده بهتر از تصادفی عمل می کند.
  • برای gen_gan_loss ، مقدار زیر 0.69 به این معنی است که ژنراتور در فریب دادن متمایزکننده بهتر از تصادفی عمل می کند.
  • با پیشرفت آموزش، gen_l1_loss باید کاهش یابد.

آخرین بازرسی را بازیابی کنید و شبکه را آزمایش کنید

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 0x7f35cfd6b8d0>

با استفاده از مجموعه آزمایشی تعدادی تصویر ایجاد کنید

# 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