कोर्स
इस ट्यूटोरियल में, आप बिना गणित के विवरण में गए समझेंगे कि जनरेटिव एडवर्सेरियल नेटवर्क्स (GANs) क्या होते हैं। इसके बाद, आप ऐसा एक साधारण GAN कोड करना सीखेंगे जो अंकों की छवियां बना सके!
उपमा
GANs को समझने का सबसे आसान तरीका एक सरल उपमा के ज़रिए है:
मान लीजिए एक दुकान है जो ग्राहकों से कुछ खास तरह की वाइन खरीदती है, जिसे वे बाद में फिर बेचेंगे।

लेकिन कुछ धूर्त ग्राहक पैसे कमाने के लिए नकली वाइन बेचते हैं। ऐसे में, दुकान मालिक को असली और नकली वाइन में फर्क करने में सक्षम होना होगा।

आप कल्पना कर सकते हैं कि शुरुआत में जालसाज़ नकली वाइन बेचने की कोशिश में कई गलतियां करेगा और दुकान मालिक के लिए यह पहचानना आसान होगा कि वाइन असली नहीं है। इन नाकामियों के कारण, जालसाज़ असली वाइन की नकल करने के लिए अलग-अलग तकनीकें आज़माता रहेगा और कुछ अंततः सफल भी होंगी। अब जब जालसाज़ जान गया कि कुछ तकनीकें दुकान मालिक की जांच से गुजर गईं, तो वह उन्हीं के आधार पर नकली वाइन को और बेहतर बना सकता है।
उसी समय, दुकान मालिक को शायद दूसरे दुकानदारों या वाइन विशेषज्ञों से फीडबैक मिलेगा कि उसके पास मौजूद कुछ वाइन असली नहीं हैं। इसका मतलब है कि दुकान मालिक को यह तय करने के अपने तरीके में सुधार करना होगा कि वाइन नकली है या असली। जालसाज़ का लक्ष्य है ऐसी वाइन बनाना जो असली से अलग न दिखे, और दुकान मालिक का लक्ष्य है सही-सही बताना कि वाइन असली है या नहीं।
यही आगे-पीछे की प्रतिस्पर्धा GANs के पीछे की मुख्य अवधारणा है।
जनरेटिव एडवर्सेरियल नेटवर्क के घटक
ऊपर दिए गए उदाहरण का उपयोग करके, हम GAN की संरचना समझ सकते हैं।

GANs के दो मुख्य घटक होते हैं: जेनरेटर और डिस्क्रिमिनेटर। उदाहरण में दुकान मालिक डिस्क्रिमिनेटर नेटवर्क है और आम तौर पर यह एक कन्वोल्यूशनल न्यूरल नेटवर्क होता है (क्योंकि GANs मुख्यतः इमेज से जुड़े कार्यों में उपयोग होते हैं) जो यह संभावना सौंपता है कि छवि असली है।
जालसाज़ को जनरेटिव नेटवर्क कहा जाता है, और यह भी प्रायः एक कन्वोल्यूशनल न्यूरल नेटवर्क होता है (जिसमें डीकन्वोल्यूशन लेयर्स होती हैं)। यह नेटवर्क कुछ शोर वेक्टर लेता है और एक छवि आउटपुट करता है। जेनरेटिव नेटवर्क को प्रशिक्षित करते समय, यह सीखता है कि छवि के किन हिस्सों को सुधारना/बदलना है ताकि डिस्क्रिमिनेटर के लिए इसकी जनरेट की गई छवियों को असली से अलग करना मुश्किल हो जाए।
जनरेटिव नेटवर्क लगातार ऐसी छवियां बनाता रहता है जो असली छवियों के और करीब दिखें, जबकि डिस्क्रिमिनेटिव नेटवर्क असली और नकली छवियों के बीच के फर्क को पहचानने की कोशिश करता रहता है। अंतिम लक्ष्य एक ऐसा जनरेटिव नेटवर्क पाना है जो असली जैसी पहचान न की जा सकने वाली छवियां बना सके।
Keras के साथ एक सरल जनरेटिव एडवर्सेरियल नेटवर्क
अब जब आप समझ चुके हैं कि GANs क्या हैं और उनके मुख्य घटक कौन से हैं, तो हम अब एक बहुत सरल कोड लिखना शुरू कर सकते हैं। आप Keras का उपयोग करेंगे, और यदि आप इस Python लाइब्रेरी से परिचित नहीं हैं, तो आगे बढ़ने से पहले यह ट्यूटोरियल पढ़ लें। यह ट्यूटोरियल यहां विकसित किए गए GAN पर आधारित है।
सबसे पहले आपको pip के ज़रिए निम्नलिखित पैकेज इंस्टॉल करने होंगे
kerasmatplotlibtensorflowtqdm
आप प्लॉटिंग के लिए matplotlib, Keras के बैकएंड के रूप में tensorflow और हर epoch (आवृत्ति) के लिए सुंदर प्रोग्रेस बार दिखाने हेतु tqdm का उपयोग करेंगे।
अगला कदम एक Python स्क्रिप्ट बनाना है। इस स्क्रिप्ट में, आपको सबसे पहले वे सभी मॉड्यूल और फ़ंक्शन इम्पोर्ट करने होंगे जिनका आप उपयोग करेंगे। जैसे-जैसे उनका उपयोग होगा, प्रत्येक का स्पष्टीकरण दिया जाएगा।
import os
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
from keras.layers import Input
from keras.models import Model, Sequential
from keras.layers.core import Dense, Dropout
from keras.layers.advanced_activations import LeakyReLU
from keras.datasets import mnist
from keras.optimizers import Adam
from keras import initializers
अब आप कुछ वेरिएबल सेट करना चाहेंगे:
# Let Keras know that we are using tensorflow as our backend engine
os.environ["KERAS_BACKEND"] = "tensorflow"
# To make sure that we can reproduce the experiment and get the same results
np.random.seed(10)
# The dimension of our random noise vector.
random_dim = 100
डिस्क्रिमिनेटर और जेनरेटर बनाने से पहले, आपको पहले डेटा इकट्ठा करना और प्री-प्रोसेस करना चाहिए। आप लोकप्रिय MNIST डेटासेट का उपयोग करेंगे, जिसमें 0 से 9 तक के एकल अंकों की छवियां होती हैं।

def load_minst_data():
# load the data
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# normalize our inputs to be in the range[-1, 1]
x_train = (x_train.astype(np.float32) - 127.5)/127.5
# convert x_train with a shape of (60000, 28, 28) to (60000, 784) so we have
# 784 columns per row
x_train = x_train.reshape(60000, 784)
return (x_train, y_train, x_test, y_test)
ध्यान दें कि mnist.load_data() Keras का हिस्सा है और आपको MNIST डेटासेट अपने वर्कस्पेस में आसानी से आयात करने की सुविधा देता है।
अब, आप अपने जेनरेटर और डिस्क्रिमिनेटर नेटवर्क बना सकते हैं। आप दोनों नेटवर्क के लिए Adam ऑप्टिमाइज़र का उपयोग करेंगे। जेनरेटर और डिस्क्रिमिनेटर, दोनों के लिए, आप तीन हिडन लेयर वाला एक न्यूरल नेटवर्क बनाएंगे, जिसमें एक्टिवेशन फ़ंक्शन Leaky ReLU होगा। आपको अनदेखी छवियों पर इसकी मजबूती बढ़ाने के लिए डिस्क्रिमिनेटर में ड्रॉपआउट लेयर्स भी जोड़नी चाहिए।
# You will use the Adam optimizer
def get_optimizer():
return Adam(lr=0.0002, beta_1=0.5)
def get_generator(optimizer):
generator = Sequential()
generator.add(Dense(256, input_dim=random_dim, kernel_initializer=initializers.RandomNormal(stddev=0.02)))
generator.add(LeakyReLU(0.2))
generator.add(Dense(512))
generator.add(LeakyReLU(0.2))
generator.add(Dense(1024))
generator.add(LeakyReLU(0.2))
generator.add(Dense(784, activation='tanh'))
generator.compile(loss='binary_crossentropy', optimizer=optimizer)
return generator
def get_discriminator(optimizer):
discriminator = Sequential()
discriminator.add(Dense(1024, input_dim=784, kernel_initializer=initializers.RandomNormal(stddev=0.02)))
discriminator.add(LeakyReLU(0.2))
discriminator.add(Dropout(0.3))
discriminator.add(Dense(512))
discriminator.add(LeakyReLU(0.2))
discriminator.add(Dropout(0.3))
discriminator.add(Dense(256))
discriminator.add(LeakyReLU(0.2))
discriminator.add(Dropout(0.3))
discriminator.add(Dense(1, activation='sigmoid'))
discriminator.compile(loss='binary_crossentropy', optimizer=optimizer)
return discriminator
आखिरकार जेनरेटर और डिस्क्रिमिनेटर को एक साथ लाने का समय आ गया है!
def get_gan_network(discriminator, random_dim, generator, optimizer):
# We initially set trainable to False since we only want to train either the
# generator or discriminator at a time
discriminator.trainable = False
# gan input (noise) will be 100-dimensional vectors
gan_input = Input(shape=(random_dim,))
# the output of the generator (an image)
x = generator(gan_input)
# get the output of the discriminator (probability if the image is real or not)
gan_output = discriminator(x)
gan = Model(inputs=gan_input, outputs=gan_output)
gan.compile(loss='binary_crossentropy', optimizer=optimizer)
return gan
पूर्णता के लिए, आप एक ऐसा फ़ंक्शन बना सकते हैं जो हर 20 epochs पर आपकी जनरेट की गई छवियों को सेव करेगा। चूंकि यह इस पाठ का मुख्य भाग नहीं है, इसलिए आपको इस फ़ंक्शन को पूरी तरह समझने की ज़रूरत नहीं है।
# Create a wall of generated MNIST images
def plot_generated_images(epoch, generator, examples=100, dim=(10, 10), figsize=(10, 10)):
noise = np.random.normal(0, 1, size=[examples, random_dim])
generated_images = generator.predict(noise)
generated_images = generated_images.reshape(examples, 28, 28)
plt.figure(figsize=figsize)
for i in range(generated_images.shape[0]):
plt.subplot(dim[0], dim[1], i+1)
plt.imshow(generated_images[i], interpolation='nearest', cmap='gray_r')
plt.axis('off')
plt.tight_layout()
plt.savefig('gan_generated_image_epoch_%d.png' % epoch)
अब आपने अपने नेटवर्क का अधिकांश कोड लिख लिया है। अब बस इस नेटवर्क को ट्रेन करना और बनी हुई छवियों पर नज़र डालना बाकी है।
def train(epochs=1, batch_size=128):
# Get the training and testing data
x_train, y_train, x_test, y_test = load_minst_data()
# Split the training data into batches of size 128
batch_count = x_train.shape[0] / batch_size
# Build our GAN netowrk
adam = get_optimizer()
generator = get_generator(adam)
discriminator = get_discriminator(adam)
gan = get_gan_network(discriminator, random_dim, generator, adam)
for e in xrange(1, epochs+1):
print '-'*15, 'Epoch %d' % e, '-'*15
for _ in tqdm(xrange(batch_count)):
# Get a random set of input noise and images
noise = np.random.normal(0, 1, size=[batch_size, random_dim])
image_batch = x_train[np.random.randint(0, x_train.shape[0], size=batch_size)]
# Generate fake MNIST images
generated_images = generator.predict(noise)
X = np.concatenate([image_batch, generated_images])
# Labels for generated and real data
y_dis = np.zeros(2*batch_size)
# One-sided label smoothing
y_dis[:batch_size] = 0.9
# Train discriminator
discriminator.trainable = True
discriminator.train_on_batch(X, y_dis)
# Train generator
noise = np.random.normal(0, 1, size=[batch_size, random_dim])
y_gen = np.ones(batch_size)
discriminator.trainable = False
gan.train_on_batch(noise, y_gen)
if e == 1 or e % 20 == 0:
plot_generated_images(e, generator)
if __name__ == '__main__':
train(400, 128)
400 epochs तक ट्रेन करने के बाद, आप जनरेट की गई छवियों को देख सकते हैं। पहले epoch के बाद बनी छवियों को देखें तो उनमें कोई असल संरचना नहीं दिखती, 40 epochs के बाद अंकों का आकार दिखने लगता है और अंत में, 400 epochs के बाद बनी छवियों में साफ अंक दिखते हैं, भले ही कुछ अब भी पहचान में न आएं।
| 1 epoch के बाद के परिणाम | 40 epochs के बाद के परिणाम | 400 epochs के बाद के परिणाम |
|---|---|---|
!![]() |
![]() |
![]() |
यह कोड CPU पर प्रति epoch लगभग 2 मिनट लेता है और यही इस कोड के चुने जाने का मुख्य कारण है। आप अधिक epochs का उपयोग करके और जेनरेटर व डिस्क्रिमिनेटर दोनों में और (व अलग) लेयर्स जोड़कर प्रयोग कर सकते हैं। हालांकि, अधिक जटिल और गहन आर्किटेक्चर का उपयोग करने पर, यदि आप केवल CPU का उपयोग कर रहे हैं, तो रनटाइम भी बढ़ जाएगा। फिर भी, इसे प्रयोग करने से आपको रोकने न दें!
निष्कर्ष
बधाई हो, आप इस ट्यूटोरियल के अंत तक पहुंच गए, जिसमें आपने सहज तरीके से जनरेटिव एडवर्सेरियल नेटवर्क्स (GANs) की मूल बातें सीखीं! साथ ही, आपने Keras लाइब्रेरी की मदद से अपना पहला मॉडल भी इम्प्लीमेंट किया। यदि आप Python के साथ डीप लर्निंग के बारे में और जानना चाहते हैं, तो DataCamp का Deep Learning in Python कोर्स करने पर विचार करें।


