ترجمت واجهة Cloud Translation API‏ هذه الصفحة.
Switch to English

شبكة الخصومة التلافيفية التوليفية العميقة

عرض على TensorFlow.org تشغيل في Google Colab عرض المصدر على جيثب تحميل دفتر

يوضح هذا البرنامج التعليمي كيفية إنشاء صور للأرقام المكتوبة بخط اليد باستخدام شبكة خصومة توليفية عميقة التلافيف (DCGAN). تمت كتابة الكود باستخدام Keras Sequential API مع حلقة تدريبtf.GradientTape .

ما هي شبكات GAN؟

تعد شبكات الخصومة التوليدية (GANs) واحدة من أكثر الأفكار إثارة للاهتمام في علوم الكمبيوتر اليوم. يتم تدريب نموذجين في وقت واحد من خلال عملية عدائية. يتعلم المولد ("الفنان") إنشاء صور تبدو حقيقية ، بينما يتعلم المميّز ("الناقد الفني") تمييز الصور الحقيقية بصرف النظر عن الصور المزيفة.

رسم تخطيطي لمولد ومميز

أثناء التدريب ، يصبح المولد بشكل تدريجي أفضل في إنشاء صور تبدو حقيقية ، بينما يصبح أداة التمييز أفضل في تمييزها عن بعضها. الروافد عملية التوازن عندما الممي لم تعد قادرة على تمييز الصور الحقيقية من المزيفة.

رسم تخطيطي ثان لمولد ومميز

يوضح هذا الكمبيوتر الدفتري هذه العملية على مجموعة بيانات MNIST. تُظهر الرسوم المتحركة التالية سلسلة من الصور التي أنتجها المولد حيث تم تدريبه لمدة 50 حقبة. تبدأ الصور كضوضاء عشوائية ، وتشبه بشكل متزايد الأرقام المكتوبة بخط اليد بمرور الوقت.

إخراج العينة

لمعرفة المزيد حول شبكات GAN ، نوصي بدورة مقدمة إلى التعلم العميق من معهد ماساتشوستس للتكنولوجيا.

اقامة

import tensorflow as tf
tf.__version__
'2.3.0'
# To generate GIFs
pip install -q imageio
pip install -q git+https://github.com/tensorflow/docs
WARNING: You are using pip version 20.2.2; however, version 20.2.3 is available.
You should consider upgrading via the '/tmpfs/src/tf_docs_env/bin/python -m pip install --upgrade pip' command.
WARNING: You are using pip version 20.2.2; however, version 20.2.3 is available.
You should consider upgrading via the '/tmpfs/src/tf_docs_env/bin/python -m pip install --upgrade pip' command.

import glob
import imageio
import matplotlib.pyplot as plt
import numpy as np
import os
import PIL
from tensorflow.keras import layers
import time

from IPython import display

قم بتحميل مجموعة البيانات وتحضيرها

ستستخدم مجموعة بيانات MNIST لتدريب المولد والمميز. سيقوم المولد بإنشاء أرقام مكتوبة بخط اليد تشبه بيانات MNIST.

(train_images, train_labels), (_, _) = tf.keras.datasets.mnist.load_data()
train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')
train_images = (train_images - 127.5) / 127.5 # Normalize the images to [-1, 1]
BUFFER_SIZE = 60000
BATCH_SIZE = 256
# Batch and shuffle the data
train_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)

قم بإنشاء النماذج

يتم تعريف كل من المولد والمميز باستخدام Keras Sequential API .

المولد

يستخدم المولد tf.keras.layers.Conv2DTranspose ( tf.keras.layers.Conv2DTranspose ) لإنتاج صورة من بذرة (ضوضاء عشوائية). ابدأ بطبقة Dense تأخذ هذه البذرة كمدخل ، ثم قم بتجميعها عدة مرات حتى تصل إلى حجم الصورة المطلوب 28 × 28 × 1. لاحظ تنشيط tf.keras.layers.LeakyReLU لكل طبقة ، باستثناء طبقة الإخراج التي تستخدم tanh.

def make_generator_model():
    model = tf.keras.Sequential()
    model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(100,)))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Reshape((7, 7, 256)))
    assert model.output_shape == (None, 7, 7, 256) # Note: None is the batch size

    model.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
    assert model.output_shape == (None, 7, 7, 128)
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
    assert model.output_shape == (None, 14, 14, 64)
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
    assert model.output_shape == (None, 28, 28, 1)

    return model

استخدم المولد (الذي لم يتم تدريبه بعد) لإنشاء صورة.

generator = make_generator_model()

noise = tf.random.normal([1, 100])
generated_image = generator(noise, training=False)

plt.imshow(generated_image[0, :, :, 0], cmap='gray')
<matplotlib.image.AxesImage at 0x7f2729b9f6d8>

بي إن جي

التمييز

المُميِّز هو مُصنِّف صور قائم على CNN.

def make_discriminator_model():
    model = tf.keras.Sequential()
    model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same',
                                     input_shape=[28, 28, 1]))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3))

    model.add(layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3))

    model.add(layers.Flatten())
    model.add(layers.Dense(1))

    return model

استخدم أداة التمييز (التي لم يتم تدريبها بعد) لتصنيف الصور التي تم إنشاؤها على أنها حقيقية أو مزيفة. سيتم تدريب النموذج على إخراج القيم الإيجابية للصور الحقيقية والقيم السلبية للصور المزيفة.

discriminator = make_discriminator_model()
decision = discriminator(generated_image)
print (decision)
tf.Tensor([[0.0003284]], shape=(1, 1), dtype=float32)

تحديد الخسارة والمحسِّنون

تحديد وظائف الخسارة والمحسّنات لكلا الطرازين.

# This method returns a helper function to compute cross entropy loss
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)

خسارة مميزة

تحدد هذه الطريقة مدى قدرة أداة التمييز على التمييز بين الصور الحقيقية والمزيفة. يقارن تنبؤات أداة التمييز على الصور الحقيقية بمصفوفة من 1 ثانية ، وتنبؤات أداة التمييز على الصور المزيفة (المولدة) بمصفوفة من 0 ثانية.

def discriminator_loss(real_output, fake_output):
    real_loss = cross_entropy(tf.ones_like(real_output), real_output)
    fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output)
    total_loss = real_loss + fake_loss
    return total_loss

خسارة المولد

تحدد خسارة المولد مدى قدرته على خداع أداة التمييز. حدسيًا ، إذا كان أداء المولد جيدًا ، فسيقوم أداة التمييز بتصنيف الصور المزيفة على أنها حقيقية (أو 1). هنا ، سنقارن قرارات أدوات التمييز على الصور التي تم إنشاؤها بمصفوفة من 1 ثانية.

def generator_loss(fake_output):
    return cross_entropy(tf.ones_like(fake_output), fake_output)

يختلف المُميِّز ومُحسِّن المولد لأننا سنقوم بتدريب شبكتين بشكل منفصل.

generator_optimizer = tf.keras.optimizers.Adam(1e-4)
discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)

حفظ نقاط التفتيش

يوضح هذا الكمبيوتر الدفتري أيضًا كيفية حفظ النماذج واستعادتها ، مما قد يكون مفيدًا في حالة مقاطعة مهمة تدريب طويلة الأمد.

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)

تحديد حلقة التدريب

EPOCHS = 50
noise_dim = 100
num_examples_to_generate = 16

# We will reuse this seed overtime (so it's easier)
# to visualize progress in the animated GIF)
seed = tf.random.normal([num_examples_to_generate, noise_dim])

تبدأ حلقة التدريب بالمولد الذي يتلقى بذرة عشوائية كمدخل. تستخدم تلك البذرة لإنتاج صورة. ثم يتم استخدام أداة التمييز لتصنيف الصور الحقيقية (المستمدة من مجموعة التدريب) والصور المزيفة (التي ينتجها المولد). يتم حساب الخسارة لكل نموذج من هذه النماذج ، ويتم استخدام التدرجات لتحديث المولد والمميز.

# Notice the use of `tf.function`
# This annotation causes the function to be "compiled".
@tf.function
def train_step(images):
    noise = tf.random.normal([BATCH_SIZE, noise_dim])

    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
      generated_images = generator(noise, training=True)

      real_output = discriminator(images, training=True)
      fake_output = discriminator(generated_images, training=True)

      gen_loss = generator_loss(fake_output)
      disc_loss = discriminator_loss(real_output, fake_output)

    gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)
    gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)

    generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))
    discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))
def train(dataset, epochs):
  for epoch in range(epochs):
    start = time.time()

    for image_batch in dataset:
      train_step(image_batch)

    # Produce images for the GIF as we go
    display.clear_output(wait=True)
    generate_and_save_images(generator,
                             epoch + 1,
                             seed)

    # Save the model every 15 epochs
    if (epoch + 1) % 15 == 0:
      checkpoint.save(file_prefix = checkpoint_prefix)

    print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start))

  # Generate after the final epoch
  display.clear_output(wait=True)
  generate_and_save_images(generator,
                           epochs,
                           seed)

توليد وحفظ الصور

def generate_and_save_images(model, epoch, test_input):
  # Notice `training` is set to False.
  # This is so all layers run in inference mode (batchnorm).
  predictions = model(test_input, training=False)

  fig = plt.figure(figsize=(4,4))

  for i in range(predictions.shape[0]):
      plt.subplot(4, 4, i+1)
      plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap='gray')
      plt.axis('off')

  plt.savefig('image_at_epoch_{:04d}.png'.format(epoch))
  plt.show()

تدريب النموذج

اتصل بطريقة train() المحددة أعلاه لتدريب المولد والمميز في وقت واحد. لاحظ أن تدريب شبكات GAN يمكن أن يكون صعبًا. من المهم ألا يتغلب المولد والمميز على بعضهما البعض (على سبيل المثال ، أن يتدربوا بمعدل مماثل).

في بداية التدريب ، تبدو الصور التي تم إنشاؤها وكأنها ضوضاء عشوائية. مع تقدم التدريب ، ستبدو الأرقام الناتجة حقيقية بشكل متزايد. بعد حوالي 50 حقبة ، أصبحت تشبه أرقام MNIST. قد يستغرق هذا حوالي دقيقة واحدة / فترة مع الإعدادات الافتراضية على Colab.

train(train_dataset, EPOCHS)

بي إن جي

استعادة أحدث نقطة تفتيش.

checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))
<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f2729bc3128>

قم بإنشاء ملف GIF

# Display a single image using the epoch number
def display_image(epoch_no):
  return PIL.Image.open('image_at_epoch_{:04d}.png'.format(epoch_no))
display_image(EPOCHS)

بي إن جي

استخدم imageio لإنشاء صورة gif متحركة باستخدام الصور المحفوظة أثناء التدريب.

anim_file = 'dcgan.gif'

with imageio.get_writer(anim_file, mode='I') as writer:
  filenames = glob.glob('image*.png')
  filenames = sorted(filenames)
  for filename in filenames:
    image = imageio.imread(filename)
    writer.append_data(image)
  image = imageio.imread(filename)
  writer.append_data(image)
import tensorflow_docs.vis.embed as embed
embed.embed_file(anim_file)

gif

الخطوات التالية

أظهر هذا البرنامج التعليمي الكود الكامل اللازم لكتابة وتدريب GAN. كخطوة تالية ، قد ترغب في تجربة مجموعة بيانات مختلفة ، على سبيل المثال مجموعة بيانات سمات وجوه المشاهير واسعة النطاق (CelebA) المتوفرة على Kaggle . لمعرفة المزيد حول شبكات GAN ، نوصي بالبرنامج التعليمي NIPS 2016: شبكات الخصومة التوليدية .