Google I / O 18-20 मई को लौटता है! जगह आरक्षित करें और अपना शेड्यूल बनाएं अभी रजिस्टर करें

डीप कंफ्यूजेशनल जेनरेटिव एडवरसरी नेटवर्क

TensorFlow.org पर देखें GitHub पर स्रोत देखें नोटबुक डाउनलोड करें

यह ट्यूटोरियल प्रदर्शित करता है कि कैसे डीप कन्वेन्शनल जेनरेटिव एडवरसैरियल नेटवर्क (DCGAN) का उपयोग करके हस्तलिखित अंकों की छवियों को उत्पन्न किया जाए। कोड कोtf.GradientTape प्रशिक्षण लूप के साथtf.GradientTape अनुक्रमिक एपीआई का उपयोग करके लिखा गया है।

GAN क्या हैं?

आज कंप्यूटर विज्ञान में सबसे दिलचस्प विचारों में से एक जेनेरिक एडवांसरियल नेटवर्क (GAN) हैं। दो मॉडल एक साथ एक प्रतिकूल प्रक्रिया द्वारा प्रशिक्षित होते हैं। एक जनरेटर ("कलाकार") छवियों को बनाने के लिए सीखता है जो वास्तविक दिखते हैं, जबकि एक भेदभाव करनेवाला ("कला समीक्षक") वास्तविक छवियों को नकली के अलावा बताने के लिए सीखता है।

एक जनरेटर और भेदभाव करनेवाला का आरेख

प्रशिक्षण के दौरान, जनरेटर वास्तविक रूप से दिखने वाली छवियां बनाने में बेहतर हो जाता है, जबकि विभेदक उन्हें अलग बताने में बेहतर हो जाता है। प्रक्रिया पहुँच संतुलित रूप जब discriminator अब नकली से असली छवियों भेद कर सकते हैं।

एक जनरेटर और भेदभाव करनेवाला का दूसरा आरेख

यह नोटबुक MNIST डेटासेट पर इस प्रक्रिया को प्रदर्शित करता है। निम्नलिखित एनीमेशन जनरेटर द्वारा उत्पादित छवियों की एक श्रृंखला को दर्शाता है क्योंकि यह 50 युगों के लिए प्रशिक्षित किया गया था। छवियां यादृच्छिक शोर के रूप में शुरू होती हैं, और समय के साथ तेजी से हाथ से लिखे अंकों के समान होती हैं।

नमूना उत्पादन

जीएएन के बारे में अधिक जानने के लिए, एमआईटी के इंट्रो टू डीप लर्निंग कोर्स देखें।

सेट अप

import tensorflow as tf
tf.__version__
'2.4.1'
# To generate GIFs
pip install -q imageio
pip install -q git+https://github.com/tensorflow/docs
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()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz
11493376/11490434 [==============================] - 0s 0us/step
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)

मॉडल बनाएं

जनरेटर और विभेदक दोनों को केरस अनुक्रमिक एपीआई का उपयोग करके परिभाषित किया गया है

जेनरेटर

जनरेटर एक बीज (यादृच्छिक शोर) से एक छवि का उत्पादन करने के लिए tf.keras.layers.Conv2DTranspose (upsampling) परतों का उपयोग करता है। एक Dense परत के साथ शुरू करें जो इस बीज को इनपुट के रूप में लेती है, फिर कई बार अपक्षय करती है जब तक आप वांछित छवि आकार 28x28x1 तक नहीं पहुंचते। प्रत्येक परत के लिए tf.keras.layers.LeakyReLU सक्रियण पर ध्यान दें, आउटपुट परत को छोड़कर जो tf.keras.layers.LeakyReLU का उपयोग करती है।

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

पींग

भेदभाव करनेवाला

भेदभाव करने वाला एक सीएनएन-आधारित छवि क्लासिफायरियर है।

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.00033125]], 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)

भेदभाव करने वाला नुकसान

यह विधि निर्धारित करती है कि विवेकशील वास्तविक छवियों को नकली से अलग करने में सक्षम है। यह वास्तविक छवि पर भेदभाव करने वाले की भविष्यवाणियों की तुलना 1s के सरणी में करता है, और नकली की जनक की भविष्यवाणियों पर (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) के रूप में वर्गीकृत करेगा। यहां, उत्पन्न छवियों पर भेदभाव करने वाले निर्णयों की तुलना 1s के सरणी से करें।

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

# You 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 you 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 अंकों से मिलते जुलते हैं। यह कोलाब पर डिफ़ॉल्ट सेटिंग्स के साथ लगभग एक मिनट / युग ले सकता है।

train(train_dataset, EPOCHS)

पींग

नवीनतम चेकपॉइंट को पुनर्स्थापित करें।

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

एक 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 बनाने के लिए imageio का उपयोग करें।

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)

जिफ़

अगला कदम

इस ट्यूटोरियल ने GAN लिखने और प्रशिक्षित करने के लिए आवश्यक पूरा कोड दिखाया है। अगले चरण के रूप में, आप एक अलग डेटासेट के साथ प्रयोग करना पसंद कर सकते हैं, उदाहरण के लिए कागले पर उपलब्ध बड़े पैमाने पर सेलेब फ़ेस एट्रीब्यूट्स (सेलेबए) डेटासेट। गण के बारे में अधिक जानने के लिए एनआईपीएस 2016 ट्यूटोरियल देखें: जनरेटिव एडवरसरीअल नेटवर्क