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
- Random noise’dan anlamlı data üretir
- Örneğin: 100 boyutlu random vector → 256x256 resim
- Hedefi: Discriminator’ı kandırmak
Discriminator Network
- Gerçek ve sahte veriyi ayırt etmeye çalışır
- Binary classification yapar (0: fake, 1: real)
- Hedefi: Generator’dan gelen fake’leri yakalamak
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
- Orijinal GAN implementation’ı
- Basit ama unstable training
2. DCGAN (Deep Convolutional GAN)
- Convolutional layer’lar kullanır
- Görüntü generation için çok etkili
3. Conditional GAN (cGAN)
- Belirli bir condition ile generation
- Örneğin: “mavi gözlü kedi” üret
4. CycleGAN
- Image-to-image translation
- Örneğin: at resmini zebra yapma
5. StyleGAN
- NVIDIA’nın state-of-the-art modeli
- İnanılmaz gerçekçi yüzler üretir
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
- Deep fake videolar
- Sanatsal stil transferi
- Müzik composition
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! 🎨🤖