TensorFlow.org'da görüntüleyin | Google Colab'da çalıştırın | Kaynağı GitHub'da görüntüleyin | Not defterini indir |
Bu öğretici, bir Derin Evrişimli Üretken Düşman Ağı (DCGAN) kullanarak el yazısı rakamların görüntülerinin nasıl oluşturulacağını gösterir. Kod, bir tf.GradientTape
eğitim döngüsü ile Keras Sequential API kullanılarak yazılmıştır.
GAN'lar nelerdir?
Üretken Düşman Ağları (GAN'lar), günümüzde bilgisayar bilimindeki en ilginç fikirlerden biridir. İki model, çekişmeli bir süreçle aynı anda eğitilir. Bir üretici ("sanatçı") gerçek görünen görüntüler yaratmayı öğrenirken, bir ayrımcı ("sanat eleştirmeni") gerçek görüntüleri sahte olanlardan ayırmayı öğrenir.
Eğitim sırasında, üretici gerçek görünen görüntüler yaratmada giderek daha iyi hale gelirken, ayrımcı bunları ayırt etmede daha iyi hale gelir. Ayrımcı artık gerçek görüntüleri sahtelerden ayırt edemediğinde süreç dengeye ulaşır.
Bu not defteri, bu işlemi MNIST veri kümesinde gösterir. Aşağıdaki animasyon, jeneratör tarafından 50 dönem boyunca eğitilirken üretilen bir dizi görüntüyü göstermektedir. Görüntüler rastgele gürültü olarak başlar ve zamanla giderek artan şekilde elle yazılmış rakamlara benzer.
GAN'lar hakkında daha fazla bilgi edinmek için MIT'nin Derin Öğrenmeye Giriş kursuna bakın.
Kurmak
import tensorflow as tf
tf.__version__
'2.8.0-rc1'
# To generate GIFs
pip install imageio
pip install 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
Veri kümesini yükleyin ve hazırlayın
Üreteci ve ayrımcıyı eğitmek için MNIST veri setini kullanacaksınız. Jeneratör, MNIST verilerine benzeyen el yazısı rakamları üretecektir.
(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]
yer tutucu7 l10n-yerBUFFER_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)
Modelleri oluşturun
Hem oluşturucu hem de ayırıcı, Keras Sıralı API'si kullanılarak tanımlanır.
Jeneratör
Oluşturucu, bir tohumdan (rastgele gürültü) bir görüntü üretmek için tf.keras.layers.Conv2DTranspose
(üst örnekleme) katmanlarını kullanır. Bu çekirdeği girdi olarak alan bir Dense
katmanla başlayın, ardından istediğiniz 28x28x1 görüntü boyutuna ulaşana kadar birkaç kez üst örnek alın. Tanh kullanan çıktı katmanı dışında her katman için tf.keras.layers.LeakyReLU
aktivasyonuna dikkat edin.
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
Bir görüntü oluşturmak için (henüz eğitimsiz) oluşturucuyu kullanın.
generator = make_generator_model()
noise = tf.random.normal([1, 100])
generated_image = generator(noise, training=False)
plt.imshow(generated_image[0, :, :, 0], cmap='gray')
tutucu11 l10n-yer<matplotlib.image.AxesImage at 0x7f6fe7a04b90>
Ayrımcı
Ayırıcı, CNN tabanlı bir görüntü sınıflandırıcıdır.
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
Oluşturulan görüntüleri gerçek veya sahte olarak sınıflandırmak için (henüz eğitilmemiş) ayırıcıyı kullanın. Model, gerçek görüntüler için pozitif değerler ve sahte görüntüler için negatif değerler verecek şekilde eğitilecektir.
discriminator = make_discriminator_model()
decision = discriminator(generated_image)
print (decision)
tutucu14 l10n-yertf.Tensor([[-0.00339105]], shape=(1, 1), dtype=float32)
Kaybı ve optimize edicileri tanımlayın
Her iki model için de kayıp fonksiyonlarını ve optimize edicileri tanımlayın.
# This method returns a helper function to compute cross entropy loss
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)
Ayrımcı kaybı
Bu yöntem, ayırıcının gerçek görüntüleri sahtelerden ne kadar iyi ayırt edebildiğini ölçer. Ayırt edicinin gerçek görüntüler üzerindeki tahminlerini bir dizi 1 ile ve ayırt edicinin sahte (oluşturulan) görüntüler üzerindeki tahminlerini bir dizi 0 ile karşılaştırır.
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
Jeneratör kaybı
Jeneratörün kaybı, ayrımcıyı ne kadar iyi kandırabildiğini ölçer. Sezgisel olarak, oluşturucu iyi performans gösteriyorsa, ayrımcı sahte görüntüleri gerçek (veya 1) olarak sınıflandırır. Burada, oluşturulan görüntüler üzerindeki ayrımcı kararlarını 1'lik bir diziyle karşılaştırın.
def generator_loss(fake_output):
return cross_entropy(tf.ones_like(fake_output), fake_output)
Ayrımcı ve jeneratör optimize ediciler, iki ağı ayrı ayrı eğiteceğiniz için farklıdır.
generator_optimizer = tf.keras.optimizers.Adam(1e-4)
discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)
Kontrol noktalarını kaydet
Bu not defteri ayrıca, uzun süredir devam eden bir eğitim görevinin kesintiye uğraması durumunda yardımcı olabilecek modellerin nasıl kaydedileceğini ve geri yükleneceğini gösterir.
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)
Eğitim döngüsünü tanımlayın
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])
Eğitim döngüsü, jeneratörün girdi olarak rastgele bir tohum almasıyla başlar. Bu tohum bir görüntü üretmek için kullanılır. Ayırıcı daha sonra gerçek görüntüleri (eğitim setinden alınan) ve sahte görüntüleri (jeneratör tarafından üretilen) sınıflandırmak için kullanılır. Bu modellerin her biri için kayıp hesaplanır ve gradyanlar, üreteci ve ayırıcıyı güncellemek için kullanılır.
# 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))
tutucu22 l10n-yerdef 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)
Görüntüler oluşturun ve kaydedin
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()
Modeli eğit
Üreteci ve ayırıcıyı aynı anda eğitmek için yukarıda tanımlanan train()
yöntemini çağırın. GAN'ların eğitiminin zor olabileceğini unutmayın. Jeneratör ve ayrımcının birbirine üstün gelmemesi önemlidir (örneğin, benzer bir hızda antrenman yapmaları).
Eğitimin başında oluşturulan görüntüler rastgele gürültü gibi görünür. Eğitim ilerledikçe, oluşturulan rakamlar giderek daha gerçekçi görünecek. Yaklaşık 50 çağdan sonra MNIST rakamlarına benziyorlar. Bu, Colab'daki varsayılan ayarlarla yaklaşık bir dakika/dönem alabilir.
train(train_dataset, EPOCHS)
En son kontrol noktasını geri yükleyin.
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))
tutucu26 l10n-yer<tensorflow.python.training.tracking.util.CheckpointLoadStatus at 0x7f6ee8136950>
GIF oluştur
# 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))
tutucu28 l10n-yerdisplay_image(EPOCHS)
Eğitim sırasında kaydedilen görüntüleri kullanarak hareketli bir gif oluşturmak için imageio
kullanın.
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)
tutucu30 l10n-yerimport tensorflow_docs.vis.embed as embed
embed.embed_file(anim_file)
Sonraki adımlar
Bu öğretici, bir GAN yazmak ve eğitmek için gereken kodun tamamını göstermiştir. Bir sonraki adım olarak, farklı bir veri kümesiyle denemeler yapmak isteyebilirsiniz, örneğin Kaggle'da bulunan Büyük Ölçekli Ünlü Yüzleri Nitelikleri ( CelebA ) veri kümesi. GAN'lar hakkında daha fazla bilgi edinmek için NIPS 2016 Eğitimi: Üretken Düşman Ağları'na bakın.