Ana içeriğe geç

Generative Adversarial Nets (GAN'lar) Anlaşılır Kılınıyor

Matematiğin detaylarına girmeden Generative Adversarial Networks'ün ne olduğunu öğrenin ve rakamlar oluşturabilen basit bir GAN kodlayın!
· 9 dk. oku

Yapay Zeka ile Keşfedin

Bu eğitimde, matematiğin detaylarına girmeden Generative Adversarial Networks'ün (GAN'lar) ne olduğunu öğreneceksiniz. Ardından, rakamlar üretebilen basit bir GAN'ı nasıl kodlayacağınızı öğreneceksiniz!

Benzetme

GAN'ların ne olduğunu anlamanın en kolay yolu basit bir benzetmeden geçer:

Diyelim ki müşterilerden belirli türde şaraplar satın alıp daha sonra bunları tekrar satan bir dükkân var.

analogy

Ne var ki, para kazanmak için sahte şarap satan kötü niyetli müşteriler de var. Bu durumda, dükkân sahibinin sahte ve gerçek şarapları ayırt edebilmesi gerekir.

analogy

Başlangıçta sahtekârın sahte şarabı satmaya çalışırken birçok hata yapacağını ve dükkân sahibinin şarabın gerçek olmadığını kolayca anlayacağını düşünebilirsiniz. Bu başarısızlıklar nedeniyle sahtekâr, gerçek şarapları taklit etmek için farklı teknikler denemeye devam edecek ve bunlardan bazıları eninde sonunda başarılı olacaktır. Sahtekâr, belirli tekniklerin dükkân sahibinin kontrollerinden geçtiğini öğrendiğinde, bu tekniklere dayanarak sahte şarapları daha da geliştirmeye başlayabilir.

Aynı zamanda dükkân sahibi de muhtemelen diğer dükkân sahiplerinden veya şarap uzmanlarından, elindeki bazı şarapların orijinal olmadığına dair geri bildirim alacaktır. Bu, dükkân sahibinin bir şarabın sahte mi yoksa gerçek mi olduğunu belirleme yöntemini geliştirmesi gerektiği anlamına gelir. Sahtekârın hedefi, gerçek olanlardan ayırt edilemeyen şaraplar üretmek; dükkân sahibinin hedefi ise bir şarabın gerçek olup olmadığını doğru biçimde söylemektir.

Bu karşılıklı çekişme, GAN'ların arkasındaki ana fikirdir.

Bir Generative Adversarial Network'ün Bileşenleri

Yukarıdaki örneği kullanarak bir GAN'ın mimarisini oluşturabiliriz.

gan

GAN'larda iki ana bileşen vardır: üretici (generator) ve ayrıştırıcı (discriminator). Örnekteki dükkân sahibi, bir ayrıştırıcı ağdır ve genellikle (GAN'lar çoğunlukla görsel görevlerde kullanıldığından) bir evrişimsel sinir ağıdır; görselin gerçek olduğuna dair bir olasılık atar.

Sahtekâr ise üretici ağ olarak bilinir ve o da tipik olarak ( dekonvolüsyon katmanları ile) bir evrişimsel sinir ağıdır. Bu ağ bir gürültü vektörünü alır ve bir görüntü üretir. Üretici ağ eğitilirken, ayrıştırıcının ürettiği görüntüleri gerçeğinden ayırt etmesini zorlaştırmak için görselin hangi bölgelerini iyileştirip/değiştirmesi gerektiğini öğrenir.

Üretici ağ, gerçek görüntülere görünüm olarak gittikçe yaklaşan görseller üretmeye devam ederken ayrıştırıcı ağ, gerçek ve sahte görseller arasındaki farkları bulmaya çalışır. Nihai hedef, gerçek olanlardan ayırt edilemeyen görseller üretebilen bir üretici ağa sahip olmaktır.

Keras ile Basit Bir Generative Adversarial Network

Artık GAN'ların ne olduğunu ve ana bileşenlerini anladığınıza göre, çok basit bir tane kodlamaya başlayabiliriz. Keras kullanacaksınız; bu Python kütüphanesine aşina değilseniz devam etmeden önce bu eğitimi okumalısınız. Bu eğitim, burada geliştirilen GAN'a dayanmaktadır.

Yapmanız gereken ilk şey, aşağıdaki paketleri pip aracılığıyla kurmaktır

  • keras
  • matplotlib
  • tensorflow
  • tqdm

matplotlib'i çizim için, tensorflow'u Keras arka uç kütüphanesi olarak ve tqdm'yi her dönem (iterasyon) için şık bir ilerleme çubuğu göstermek amacıyla kullanacaksınız.

Bir sonraki adım bir Python betiği oluşturmak. Bu betikte, önce kullanacağınız tüm modül ve fonksiyonları içe aktarmanız gerekir. Her biri kullanıldıkça açıklanacaktır.

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

Şimdi bazı değişkenleri ayarlamak istiyorsunuz:

# 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

Ayrıştırıcı ve üreticiyi oluşturmaya başlamadan önce verileri toplamalı ve ön işlemden geçirmelisiniz. 0 ile 9 arasındaki tek haneli rakamların görüntülerinden oluşan popüler MNIST veri setini kullanacaksınız.

mnist dataset

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)

Not: mnist.load_data() Keras'ın bir parçasıdır ve MNIST veri setini çalışma alanınıza kolayca aktarmanızı sağlar.

Şimdi üretici ve ayrıştırıcı ağlarınızı oluşturabilirsiniz. Her iki ağ için de Adam eniyileyicisini kullanacaksınız. Üretici ve ayrıştırıcı için, etkinleştirme fonksiyonu Leaky ReLU olan üç gizli katmanlı bir sinir ağı oluşturacaksınız. Ayrıca, ayrıştırıcının görülmemiş görüntüler üzerindeki sağlamlığını artırmak için dropout katmanları eklemelisiniz.

# 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

Nihayet üretici ve ayrıştırıcıyı bir araya getirme zamanı!

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

Tamlık için, üretilen görüntülerinizi her 20 dönemde bir kaydeden bir fonksiyon oluşturabilirsiniz. Bu dersin ana konusu olmadığından, fonksiyonu tamamen anlamanız gerekmez.

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

Artık ağınızın büyük kısmını kodladınız. Geriye sadece bu ağı eğitmek ve oluşturduğunuz görsellere bakmak kaldı.

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 dönem eğitimin ardından, üretilen görselleri görüntüleyebilirsiniz. İlk dönemden sonra üretilen görsellere baktığınızda gerçek bir yapı olmadığını görürsünüz; 40 dönemden sonraki görsellere baktığınızda rakamlar şekillenmeye başlar ve son olarak 400 dönemden sonra üretilen görseller, birkaç tanesi hâlâ seçilemese de, net rakamlar gösterir.

1 dönem sonrası sonuçlar40 dönem sonrası sonuçlar400 dönem sonrası sonuçlar
!images1images2images3

Bu kod, bir CPU üzerinde dönem başına yaklaşık 2 dakika sürer ve bu, bu kodun seçilmesinin başlıca nedenidir. Daha fazla dönem kullanarak ve hem üreticiye hem de ayrıştırıcıya daha fazla (ve farklı) katmanlar ekleyerek deney yapabilirsiniz. Ancak, daha karmaşık ve derin mimariler kullanırken yalnızca CPU kullanıyorsanız çalışma süresi de artacaktır. Yine de bu, denemekten sizi alıkoymasın!

Sonuç

Tebrikler, bu eğitimin sonuna geldiniz; burada Generative Adversarial Networks'ün (GAN'ların) temellerini sezgisel bir şekilde öğrendiniz! Ayrıca, Keras kütüphanesinin yardımıyla ilk modelinizi uyguladınız. Python ile derin öğrenme hakkında daha fazla bilgi edinmek isterseniz, DataCamp'in Python ile Derin Öğrenmeye Giriş kursunu değerlendirebilirsiniz.

Konular

İlgili