شبکه های کانوولوشن مولد تخاصمی عمیق GAN + پیاده سازی + ویدئو معرفی

نمونه ای از استفاده از Gans برای تولید تصاویر هنری

در این پست من در ابتدا به معرفی مختصر Gan میپردازم و در ادامه یک مدل کانوولوشن عمیق GAN یا به اختصار DCGAN را برای تولید تصاویر رقم های دست نویس با دیتاست MNIST خواهم ساخت که در این کد از API ترتیبی ( یا Sequential ) کتابخانه کراس به همراه ماژول tf.GradientTape استفاده میکنم. در آخر هم میتوانید ویدئوی Gans for Good که توسط بزرگانی چون Andrew Ng و Ian Goodfellow ارائه شده را مشاهده کرده تا به قدرت این مدل و کاربرد هایی که در پژوهشات شما میتواند داشته باشد پی ببرید. دیدن این ویدئو را به شدت به همه مهندس ها، دانشمندان و هنرمندان پیشنهاد میکنم چون حاوی اطلاعات و ایده های بسیار خوبی برای کار شما هست.

Gan چیست؟

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

A diagram of a generator and discriminator
مدل هنرمند سعی میکند عکس گربه هایی را تولید کند که واقعی بنظر برسند و در مقابل با دادن هزاران عکس لیبل زده شده “گربه” به مدل منتقد سعی میکند عکس های واقعی را از جعلی تفکیک کند.

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

A second diagram of a generator and discriminator
نمایی از جریان آموزش و ارتقای مدل های تولید کننده و منتقد در طول زمان

کد های زیر این فرایند را به جای عکس گربه ها بر روی دیتاست MNIST که مجوعه رقم های دست نویس هستند و برای تشخیص رقم از روی دستخط افراد استفاده میشود ، اجرا خواهد کرد. و مدلی تولید خواهیم کرد که با دست خط خاص خود قادر به نوشتن ارقام باشد. انیمیشن زیر مجموعه ای از عکس هایی که توسط مدل تولید کننده در طول پنجاه Epoch تولید شده است را نمایش میدهد. این عکس ها در ابتدا یکسری نویز بی معنی هستند و به مرور زمان ارقامی دست نویس را نشان خواهند داد.

نمایی از بهبود مدل تولید کننده در طول پنجاه epoch

اگر دوست دارید اطلاعات بیشتری از Gan ها و یادگیری عمیق بدست بیاورید حتما این دوره را از دست ندید.

راه اندازی

برای شروع کار کد های زیر را وارد کنید تا کتاب خانه های مورد نیاز وارد برنامه شوند.

import tensorflow as tf
tf.__version__

output:

‘2.3.0’

# To generate GIFs
!pip install -q imageio
!pip install -q git+https://github.com/tensorflow/docs

output:

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 برای آموزش تولید کننده و منتقد استفاده و تولید کننده ارقام دست نویس مشابه این دیتاست را تولید خواهد کرد.

(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)

ساخت مدل ها

در این مرحله هر دو مدل تولید کننده و منتقد را با API ترتیبی کراس خواهیم ساخت.

تولید کننده

برای ساخت تولید کننده ما از لایه های tf.keras.layers.Conv2DTranspose برای تولید یک عکس از روی یک دانه یا همان یک نویز رندم استفاده میکنیم. مدل با یک لایه Dense شروع میشود که بعنوان ورودی همان دانه را میگیرد و چندین بار نمونه برداری (Upsampling) میکند تا به سایز مورد نظر یعنی 28x28x1 برسد. توجه داشته باشید که تمام لایه ها از فعال ساز 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)

output:

tf.Tensor([[0.0003284]], shape=(1, 1), dtype=float32)

تعریف Loss و Optimizer ها

کد زیر تابع Loss و بهینه ساز ها را تعریف میکند.

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

Loss برای منتقد

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

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

Loss برای تولید کننده

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

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)

تعریف حلقه آموزش

تعداد Epoch ها و سایر پارامتر های اولیه اینجا تنظیم میشوند.

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])

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

# 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 ها بعضی اوقات حساس میشود چرا که باید دقت کنیم تا تولید کننده و منتقد نسبت به دیگری قوی تر نشود و با هم دیگر رشد کنند. در ابتدا تصاویر تولید شده بصورت نویز های برفکی رندم هستند ولی به مرور زمان تصاویر بسیار خوبی و بسیار نزدیک به واقعیت تولید میکند.

train(train_dataset, EPOCHS)

اکنون آخرین مدلی که ذخیره شده را بارگزاری میکنیم.

checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))

Output: 

<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f2729bc3128>

ساخت یک GIF

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

# 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)

Gans برای رضای خدا

در زیر وبینار Gans for Good که در روز 9 مهر که برای معرفی Gan و کاربرد های آن در هنر ، مهندسی و پزشکی برگزار شد و نشان داده میشود که چطور با استفاده از این مدل میتوان در صنعت برای طراحی های هوشمند، در هنربرای تولید نقاشی ها و تصاویر هنری حیرت انگیز و در پزشکی برای طراحی ایمپلنت ها و سایر کاربرد ها استفاده کرد. این وبینار توسط بزرگانی همچون ایان گودفلو سازنده Gan ، دکتر Andrew Ng، دکتر Anima Anandkumar مدیر تحقیقات یادگیری ماشین در Nvidia، دکتر Alexie Efros استاد دانشگاه برکلی و خانم Sharon Zhou دانشجو دکترا استنفورد برگزار شد. دیدن این وبینار را حتما پیشنهاد میکنم.

دیدگاه خود را بنویسید:

آدرس ایمیل شما نمایش داده نخواهد شد.

فوتر سایت

سایدبار کشویی

بایگانی‌ها

دسته‌ها