Skip to content

GANs: Generator ve Discriminator ile Veri Üretimi

Published: at 09:26 PMSuggest an edit

GAN’ler, üretici modelleri anlamak için iyi bir başlangıç noktasıdır çünkü problemi iki ağ arasındaki rekabet üzerinden görünür hale getirir. Bu yazıda meseleye “AI nasıl yaratıcı oluyor?” gibi geniş bir yerden değil, generator ile discriminator arasındaki dengenin nasıl kurulduğu üzerinden bakacağız.

GANs Nedir?

GANs, 2014 yılında Ian Goodfellow tarafından önerilen bir deep learning architecture’ı. Temel mantığı çok basit ama dahiyane: iki neural network’ü birbirine karşı yarıştırmak.

Düşünün ki bir sanatçı var (Generator) ve bir sanat eleştirmeni var (Discriminator). Sanatçı sürekli sahte tablolar yapıyor, eleştirmen de bunları gerçek tablodan ayırt etmeye çalışıyor. Sonunda sanatçı o kadar iyi oluyor ki, eleştirmen bile farkı anlayamıyor!

Mimari Nasıl Çalışıyor?

Generator Network

Discriminator Network

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.transforms as transforms
from torch.utils.data import DataLoader

class Generator(nn.Module):
    def __init__(self, noise_dim=100, img_channels=3, features_g=64):
        super(Generator, self).__init__()
        self.net = nn.Sequential(
            # Input: N x noise_dim x 1 x 1
            self._block(noise_dim, features_g * 16, 4, 1, 0),  # img: 4x4
            self._block(features_g * 16, features_g * 8, 4, 2, 1),  # img: 8x8
            self._block(features_g * 8, features_g * 4, 4, 2, 1),  # img: 16x16
            self._block(features_g * 4, features_g * 2, 4, 2, 1),  # img: 32x32
            nn.ConvTranspose2d(
                features_g * 2, img_channels, kernel_size=4, stride=2, padding=1
            ),
            # Output: N x img_channels x 64 x 64
            nn.Tanh(),
        )

    def _block(self, in_channels, out_channels, kernel_size, stride, padding):
        return nn.Sequential(
            nn.ConvTranspose2d(
                in_channels, out_channels, kernel_size, stride, padding, bias=False,
            ),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(),
        )

    def forward(self, x):
        return self.net(x)

class Discriminator(nn.Module):
    def __init__(self, img_channels=3, features_d=64):
        super(Discriminator, self).__init__()
        self.disc = nn.Sequential(
            # input: N x img_channels x 64 x 64
            nn.Conv2d(img_channels, features_d, kernel_size=4, stride=2, padding=1),
            nn.LeakyReLU(0.2),
            # _block(in_channels, out_channels, kernel_size, stride, padding)
            self._block(features_d, features_d * 2, 4, 2, 1),
            self._block(features_d * 2, features_d * 4, 4, 2, 1),
            self._block(features_d * 4, features_d * 8, 4, 2, 1),
            # After all _block img output is 4x4 (Conv2d below makes into 1x1)
            nn.Conv2d(features_d * 8, 1, kernel_size=4, stride=2, padding=0),
            nn.Sigmoid(),
        )

    def _block(self, in_channels, out_channels, kernel_size, stride, padding):
        return nn.Sequential(
            nn.Conv2d(
                in_channels, out_channels, kernel_size, stride, padding, bias=False,
            ),
            nn.BatchNorm2d(out_channels),
            nn.LeakyReLU(0.2),
        )

    def forward(self, x):
        return self.disc(x)

Training Süreci

GANs training’i oldukça tricky bir süreç. İki network’ü aynı anda eğitmek zorundayız:

def train_gan(dataloader, generator, discriminator, lr=0.0002, num_epochs=100):
    # Optimizers
    opt_gen = optim.Adam(generator.parameters(), lr=lr, betas=(0.5, 0.999))
    opt_disc = optim.Adam(discriminator.parameters(), lr=lr, betas=(0.5, 0.999))

    # Loss function
    criterion = nn.BCELoss()

    # Constants
    noise_dim = 100
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    for epoch in range(num_epochs):
        for batch_idx, (real, _) in enumerate(dataloader):
            real = real.to(device)
            batch_size = real.shape[0]

            ### Train Discriminator ###
            discriminator.zero_grad()

            # Train with real data
            label_real = torch.ones((batch_size,)).to(device)
            output_real = discriminator(real).view(-1)
            loss_disc_real = criterion(output_real, label_real)

            # Train with fake data
            noise = torch.randn(batch_size, noise_dim, 1, 1).to(device)
            fake = generator(noise)
            label_fake = torch.zeros((batch_size,)).to(device)
            output_fake = discriminator(fake.detach()).view(-1)
            loss_disc_fake = criterion(output_fake, label_fake)

            # Total discriminator loss
            loss_disc = (loss_disc_real + loss_disc_fake) / 2
            loss_disc.backward()
            opt_disc.step()

            ### Train Generator ###
            generator.zero_grad()

            # Generate fake data and fool discriminator
            output = discriminator(fake).view(-1)
            loss_gen = criterion(output, label_real)  # Want discriminator to think fake is real
            loss_gen.backward()
            opt_gen.step()

            if batch_idx % 100 == 0:
                print(f"Epoch [{epoch}/{num_epochs}] Batch {batch_idx}/{len(dataloader)} "
                      f"Loss D: {loss_disc:.4f}, Loss G: {loss_gen:.4f}")

GANs’in Çeşitleri

1. Vanilla GAN

2. DCGAN (Deep Convolutional GAN)

3. Conditional GAN (cGAN)

4. CycleGAN

5. StyleGAN

Training Zorlukları

GANs’i train etmek oldukça zor. Başlıca problemler:

Mode Collapse

Generator sürekli aynı tip output üretir.

# Mode collapse'ı tespit etmek için
def calculate_inception_score(generated_images):
    # Diversity ve kaliteyi ölçer
    pass

def check_mode_collapse(generated_samples):
    # Sample diversity'sini kontrol et
    unique_samples = len(set([hash(img.tobytes()) for img in generated_samples]))
    total_samples = len(generated_samples)
    diversity_ratio = unique_samples / total_samples

    if diversity_ratio < 0.5:
        print("Warning: Possible mode collapse detected!")

Vanishing Gradients

Discriminator çok iyi olursa, generator öğrenemez.

# Gradient penalty eklemek (WGAN-GP'de kullanılır)
def gradient_penalty(discriminator, real_samples, fake_samples, device):
    batch_size, C, H, W = real_samples.shape
    epsilon = torch.rand((batch_size, 1, 1, 1)).repeat(1, C, H, W).to(device)
    interpolated = (epsilon * real_samples + ((1 - epsilon) * fake_samples)).requires_grad_(True)

    mixed_scores = discriminator(interpolated)
    gradient = torch.autograd.grad(
        inputs=interpolated,
        outputs=mixed_scores,
        grad_outputs=torch.ones_like(mixed_scores),
        create_graph=True,
        retain_graph=True,
    )[0]

    gradient = gradient.view(gradient.shape[0], -1)
    gradient_norm = gradient.norm(2, dim=1)
    gradient_penalty = torch.mean((gradient_norm - 1) ** 2)
    return gradient_penalty

Practical Applications

GANs’in gerçek hayattaki kullanım alanları:

1. Image Generation

# StyleGAN ile portrait generation
def generate_faces(generator, num_faces=10):
    with torch.no_grad():
        noise = torch.randn(num_faces, 512).to(device)
        fake_faces = generator(noise)
        return fake_faces

2. Data Augmentation

# Training data'yı artırmak için
def augment_dataset(original_dataset, generator, augment_ratio=0.5):
    augmented_data = []
    for _ in range(int(len(original_dataset) * augment_ratio)):
        noise = torch.randn(1, 100, 1, 1)
        synthetic_sample = generator(noise)
        augmented_data.append(synthetic_sample)
    return augmented_data

3. Art ve Creativity

Best Practices

GANs ile çalışırken dikkat edilmesi gerekenler:

# 1. Learning rate'leri balanced tutun
lr_gen = 0.0001
lr_disc = 0.0004  # Discriminator biraz daha hızlı

# 2. Batch normalization kullanın (generator'da)
# 3. LeakyReLU activation kullanın (discriminator'da)

# 4. Progressive training
def progressive_training(generator, discriminator, epochs_per_resolution):
    resolutions = [4, 8, 16, 32, 64, 128]
    for resolution in resolutions:
        print(f"Training at {resolution}x{resolution}")
        # Adjust network for current resolution
        train_at_resolution(generator, discriminator, resolution, epochs_per_resolution)

Evaluation Metrics

GANs’i nasıl değerlendiririz?

1. Inception Score (IS)

def inception_score(generated_images, splits=10):
    # Yüksek IS = iyi kalite + diversity
    inception_model = load_inception_model()
    scores = []

    for i in range(splits):
        part = generated_images[i*len(generated_images)//splits:(i+1)*len(generated_images)//splits]
        predictions = inception_model(part)
        scores.append(calculate_kl_divergence(predictions))

    return np.mean(scores), np.std(scores)

2. Fréchet Inception Distance (FID)

def calculate_fid(real_images, generated_images):
    # Düşük FID = gerçek data'ya yakın
    real_features = extract_features(real_images)
    gen_features = extract_features(generated_images)

    fid_score = frechet_distance(real_features, gen_features)
    return fid_score

Son Sözler

GANs gerçekten de AI’ın en etkileyici achievement’larından biri. Hiç yoktan meaningful content üretebilmesi insanın yaratıcılığına meydan okuyor.

Tabii ki perfect değiller - training süreçleri zor, bazen instable olabiliyorlar. Ama technology hızla gelişiyor. Özellikle Diffusion Models gibi yeni yaklaşımlar GANs’e güçlü alternatifler sunuyor.

Eğer GANs ile experiment yapmak istiyorsanız, küçük bir dataset ile DCGAN’den başlamanızı öneririm. MNIST veya CIFAR-10 gibi standart dataset’ler ideal başlangıç noktaları.

Ve tabii ki, GPU’suz GANs training yapmaya çalışmayın - sabırınız tükenir! 😄

Happy CODING! 🎨🤖



Previous Post
PixelCNN: Pixel Pixel Görüntü Üretme Sanatı
Next Post
Server-Side Rendering (SSR): Ne Zaman Gerekli, Ne Zaman Gereksiz?