AI & GPU
Hoe GAN in PyTorch gemakkelijk te begrijpen voor beginners

Hoe GAN in PyTorch gemakkelijk te begrijpen voor beginners

I. Inleiding tot Generative Adversarial Networks (GANs) A. Definitie en belangrijke onderdelen van GANs

  • GANs zijn een klasse van machine learning modellen die bestaan uit twee neurale netwerken, een generator en een discriminator, getraind in een tegenstrijdig proces.
  • Het generator netwerk is verantwoordelijk voor het genereren van realistische monsters (bijv. afbeeldingen, tekst, audio) vanuit een latente inputruimte.
  • Het discriminator netwerk is getraind om onderscheid te maken tussen echte monsters uit de dataset en valse monsters gegenereerd door de generator.
  • De twee netwerken worden op een tegenstrijdige manier getraind, waarbij de generator de discriminator probeert te misleiden en de discriminator probeert de echte en valse monsters correct te classificeren.

B. Korte geschiedenis en evolutie van GANs

  • GANs werden voor het eerst geïntroduceerd in 2014 door Ian Goodfellow en collega's als een nieuwe benadering voor generatieve modellering.
  • Sinds hun introductie hebben GANs aanzienlijke vooruitgang geboekt en zijn ze toegepast op een breed scala aan domeinen, zoals beeldgeneratie, tekstgeneratie en zelfs audiogenese.
  • Enkele belangrijke mijlpalen in de evolutie van GANs zijn onder andere de introductie van Conditional GANs (cGANs), Deep Convolutional GANs (DCGANs), Wasserstein GANs (WGANs) en Progressive Growing of GANs (PGGANs).

II. Het opzetten van de PyTorch-omgeving A. Het installeren van PyTorch

  • PyTorch is een populair open-source machine learning bibliotheek die een flexibel en efficiënt framework biedt voor het bouwen en trainen van diepe leermodellen, inclusief GANs.
  • Om PyTorch te installeren, kunt u de officiële installatiehandleiding volgen die wordt geleverd op de PyTorch-website (https://pytorch.org/get-started/locally/ (opens in a new tab)).
  • Het installatieproces kan variëren afhankelijk van uw besturingssysteem, Python-versie en CUDA (indien u een GPU gebruikt) versie.

B. Het importeren van benodigde bibliotheken en modules

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.datasets as datasets
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np

III. Het begrijpen van de GAN-architectuur A. Het Generator Netwerk

  1. Input- en outputstructuur

    • Het generator netwerk neemt een latente inputvector (bijv. een willekeurige ruisvector) en genereert een gegenereerd monster (bijv. een afbeelding).
    • De grootte van de input latente vector en het output monster hangen af van het specifieke probleem en de gewenste output.
  2. Netwerk lagen en activatiefuncties

    • Het generator netwerk bestaat meestal uit een reeks volledig verbonden of convolutionele lagen, afhankelijk van het probleemdomein.
    • Activatiefuncties zoals ReLU, Leaky ReLU of tanh worden vaak gebruikt in het generator netwerk.
  3. Het optimaliseren van de generator

    • Het generator netwerk wordt getraind om monsters te genereren die de discriminator kunnen misleiden.
    • De loss functie voor de generator is ontworpen om de waarschijnlijkheid te maximaliseren dat de discriminator de gegenereerde monsters verkeerd classificeert als echt.

B. Het Discriminator Netwerk

  1. Input- en outputstructuur

    • Het discriminator netwerk neemt een monster (ofwel echt uit de dataset of gegenereerd door de generator) en geeft de waarschijnlijkheid van het monster als echt weer.
    • De inputgrootte van de discriminator hangt af van de grootte van de monsters (bijv. afmeting van een afbeelding), en de output is een scalaire waarde tussen 0 en 1.
  2. Netwerk lagen en activatiefuncties

    • Het discriminator netwerk bestaat meestal uit een reeks convolutionele of volledig verbonden lagen, afhankelijk van het probleemdomein.
    • Activatiefuncties zoals Leaky ReLU of sigmoid worden vaak gebruikt in het discriminator netwerk.
  3. Het optimaliseren van de discriminator

    • Het discriminator netwerk wordt getraind om echte monsters uit de dataset correct te classificeren als echt en gegenereerde monsters als vals.
    • De loss functie voor de discriminator is ontworpen om de waarschijnlijkheid te maximaliseren dat echte en valse monsters correct worden geclassificeerd.

C. Het adversariële trainingsproces

  1. Loss functies voor Generator en Discriminator

    • De generator loss functie is ontworpen om de waarschijnlijkheid te maximaliseren dat de discriminator de gegenereerde monsters als echt classificeert.
    • De discriminator loss functie is ontworpen om de waarschijnlijkheid te maximaliseren dat echte en valse monsters correct worden geclassificeerd.
  2. Afwisselende optimalisatie tussen Generator en Discriminator

    • Het trainingsproces omvat afwisselend het updaten van de generator en de discriminator netwerken.
    • Eerst wordt de discriminator getraind om zijn vermogen te verbeteren om echte en valse monsters te onderscheiden.
    • Vervolgens wordt de generator getraind om zijn vermogen te verbeteren om monsters te genereren die de discriminator kunnen misleiden.
    • Dit adversariële trainingsproces gaat door totdat de generator en de discriminator een evenwicht bereiken.

IV. Het implementeren van een eenvoudige GAN in PyTorch A. Het definiëren van de Generator en Discriminator modellen

  1. Het construeren van het Generator netwerk

    class Generator(nn.Module):
        def __init__(self, latent_dim, img_shape):
            super(Generator, self).__init__()
            self.latent_dim = latent_dim
            self.img_shape = img_shape
     
            self.model = nn.Sequential(
                nn.Linear(self.latent_dim, 256),
                nn.LeakyReLU(0.2, inplace=True),
                nn.Linear(256, 512),
                nn.LeakyReLU(0.2, inplace=True),
                nn.Linear(512, 1024),
                nn.LeakyReLU(0.2, inplace=True),
                nn.Linear(1024, np.prod(self.img_shape)),
                nn.Tanh()
            )
     
        def forward(self, z):
            img = self.model(z)
            img = img.view(img.size(0), *self.img_shape)
            return img
  2. Het construeren van het Discriminator netwerk

    class Discriminator(nn.Module):
        def __init__(self, img_shape):
            super(Discriminator, self).__init__()
            self.img_shape = img_shape
     
            self.model = nn.Sequential(
                nn.Linear(np.prod(self.img_shape), 512),
                nn.LeakyReLU(0.2, inplace=True),
                nn.Linear(512, 256),
                nn.LeakyReLU(0.2, inplace=True),
                nn.Linear(256, 1),
                nn.Sigmoid()
            )
     
        def forward(self, img):
            img_flat = img.view(img.size(0), -1)
            validity = self.model(img_flat)
            return validity

B. Het opzetten van de trainingslus

  1. Het initialiseren van de Generator en Discriminator

    latent_dim = 100
    img_shape = (1, 28, 28)  # Voorbeeld voor MNIST dataset
     
    generator = Generator(latent_dim, img_shape)
    discriminator = Discriminator(img_shape)
  2. Het definiëren van de loss functies

    adversarial_loss = nn.BCELoss()
     
    def generator_loss(fake_output):
        return adversarial_loss(fake_output, torch.ones_like(fake_output))
     
    def discriminator_loss(real_output, fake_output):
        real_loss = adversarial_loss(real_output, torch.ones_like(real_output))
        fake_loss = adversarial_loss(fake_output, torch.zeros_like(fake_output))
        return (real_loss + fake_loss) / 2
  3. Het afwisselen van de optimalisatie van de Generator en Discriminator

    num_epochs = 200
    batch_size = 64
     
    # Optimizers
    generator_optimizer = optim.Adam(generator.parameters(), lr=0.0002, betas=(0.5, 0.999))
    discriminator_optimizer = optim.Adam(discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))
     
    for epoch in range(num_epochs):
        # Train de discriminator
        discriminator.zero_grad()
        real_samples = next(iter(dataloader))[0]
        real_output = discriminator(real_samples)
        fake_noise = torch.randn(batch_size, latent_dim)
        fake_samples = generator(fake_noise)
        fake_output = discriminator(fake_samples.detach())
        d_loss = discriminator_loss(real_output, fake_output)
        d_loss.backward()
        discriminator_optimizer.step()
     
        # Train de generator
        generator.zero_grad()
        fake_noise = torch.randn(batch_size, latent_dim)
        fake_samples = generator(fake_noise)
        fake_output = discriminator(fake_samples)
        g_loss = generator_loss(fake_output)
        g_loss.backward()
        generator_optimizer.step()

C. Het monitoren van de trainingsvoortgang

  1. Het visualiseren van de gegenereerde monsters

    # Genereer monsters en plot ze
    fake_noise = torch.randn(64, latent_dim)
    fake_samples = generator(fake_noise)
    plt.figure(figsize=(8, 8))
    plt.axis("off")
    plt.imshow(np.transpose(vutils.make_grid(fake_samples.detach()[:64], padding=2, normalize=True), (1, 2, 0)))
    plt.show()
  2. Het evalueren van de prestaties van de GAN

    • Het evalueren van de prestaties van een GAN kan een uitdaging zijn, aangezien er geen enkele maatstaf is die alle aspecten van de gegenereerde monsters vastlegt.
    • Veelgebruikte maatstaven zijn onder andere de Inception Score (IS) en de Fréchet Inception Distance (FID), die de kwaliteit en diversiteit van de gegenereerde monsters meten.

V. Conditional GANs (cGANs) A. Motivatie en toepassingen van cGANs- Conditional GANs (cGANs) zijn een uitbreiding van het standaard GAN-framework waarmee men samples kan genereren op basis van specifieke invoerinformatie, zoals klasselabels, tekstbeschrijvingen of andere hulpgegevens.

  • cGANs kunnen nuttig zijn in toepassingen waarbij men samples wilt genereren met specifieke kenmerken, zoals het genereren van afbeeldingen van een bepaalde objectklasse of het genereren van tekst-naar-afbeelding vertalingen.

B. Aanpassen van de GAN-architectuur voor conditionele generatie

  1. Invoegen van labelinformatie in de Generator en Discriminator

    • In een cGAN worden de generator- en discriminator-netwerken aangepast om een extra invoer te accepteren, namelijk de conditionele informatie (bijv. klasselabel, tekstbeschrijving).
    • Dit kan worden bereikt door de conditionele invoer samen te voegen met de latente invoer voor de generator en met het echte/nep-voorbeeld voor de discriminator.
  2. Definiëren van de verliesfuncties voor cGANs

    • De verliesfuncties voor de generator en discriminator in een cGAN zijn vergelijkbaar met die van de standaard GAN, maar ze houden ook rekening met de conditionele informatie.
    • Bijvoorbeeld, het doel van het discriminator-verlies zou zijn om echte en nep-voorbeelden correct te classificeren, op basis van de verstrekte labelinformatie.

C. Implementeren van een cGAN in PyTorch

  1. Definiëren van de cGAN-modellen
    class ConditionalGenerator(nn.Module):
        def __init__(self, latent_dim, num_classes, img_shape):
            super(ConditionalGenerator, self).__init__()
            self.latent_dim = latent_dim
            self.num_classes = num_classes
            self.img_shape = img_shape
     
            self.model = nn.Sequential(
                nn.Linear(self.latent_dim + self.num_classes, 256),
                nn.LeakyReLU(0.2, inplace=True),
                nn.Linear(256, 512),
                nn.LeakyReLU(0.2, inplace=True),
                nn.Linear(512, 1024),
                nn.LeakyReLU(0.2, inplace=True),
                nn.Linear(1024, np.prod(self.img_shape)),
                nn.Tanh()
            )
     
        def forward(self, z, labels

Modeltraining

Optimizers

Optimizers spelen een cruciale rol bij het trainen van deep learning-modellen. Ze zijn verantwoordelijk voor het bijwerken van de parameters van het model tijdens het trainingsproces om de verliesfunctie te minimaliseren. Enkele veelgebruikte optimizers in deep learning zijn:

  1. Stochastic Gradient Descent (SGD): Een eenvoudige en veelgebruikte optimizer die de parameters van het model bijwerkt in de richting van de negatieve gradiënt van de verliesfunctie.
from tensorflow.keras.optimizers import SGD
 
model.compile(optimizer=SGD(learning_rate=0.01), loss='categorical_crossentropy', metrics=['accuracy'])
  1. Adam: Een adaptief optimalisatie-algoritme voor de leersnelheid dat de voordelen van momentum en RMSProp combineert.
from tensorflow.keras.optimizers import Adam
 
model.compile(optimizer=Adam(learning_rate=0.001), loss='categorical_crossentropy', metrics=['accuracy'])
  1. RMSProp: Een adaptief optimalisatie-algoritme voor de leersnelheid dat de leersnelheid deelt door een exponentieel afnemend gemiddelde van gekwadrateerde gradiënten.
from tensorflow.keras.optimizers import RMSprop
 
model.compile(optimizer=RMSprop(learning_rate=0.001), loss='categorical_crossentropy', metrics=['accuracy'])

De keuze van de optimizer hangt af van het probleem, de dataset en de modelarchitectuur. Het is vaak nuttig om te experimenteren met verschillende optimizers en hun hyperparameters af te stemmen om de best presterende optimizer voor uw specifieke geval te vinden.

Verliesfuncties

De verliesfunctie is een cruciaal onderdeel van het trainingsproces, omdat het het doel bepaalt dat het model moet optimaliseren. De keuze van de verliesfunctie hangt af van het type probleem dat u probeert op te lossen. Enkele veelgebruikte verliesfuncties die in diep leren worden gebruikt zijn:

  1. Mean Squared Error (MSE): Veel gebruikt voor regressieproblemen, waarbij het doel is om een continue doelvariabele te voorspellen.
from tensorflow.keras.losses import MeanSquaredError
 
model.compile(optimizer='adam', loss=MeanSquaredError(), metrics=['mse'])
  1. Categorical Cross-Entropy: Gebruikt voor multi-class classificatieproblemen, waarbij het model een kansverdeling voorspelt over een reeks onderling exclusieve klassen.
from tensorflow.keras.losses import CategoricalCrossentropy
 
model.compile(optimizer='adam', loss=CategoricalCrossentropy(), metrics=['accuracy'])
  1. Binary Cross-Entropy: Gebruikt voor binair classificatieproblemen, waarbij het model de kans voorspelt op een enkel binair resultaat.
from tensorflow.keras.losses import BinaryCrossentropy
 
model.compile(optimizer='adam', loss=BinaryCrossentropy(), metrics=['accuracy'])
  1. Sparse Categorical Cross-Entropy: Vergelijkbaar met Categorical Cross-Entropy, maar gebruikt wanneer de doellabels integers (klasse-indexen) zijn in plaats van one-hot gecodeerde vectoren.
from tensorflow.keras.losses import SparseCategoricalCrossentropy
 
model.compile(optimizer='adam', loss=SparseCategoricalCrossentropy(), metrics=['accuracy'])

De keuze van de verliesfunctie moet in overeenstemming zijn met het probleem dat u probeert op te lossen en de verwachte uitvoer van uw model.

Evaluatiemetrieken

Evaluatiemetrieken worden gebruikt om de prestaties van uw deep learning-model te meten. De keuze van metrieken hangt af van het probleem dat u probeert op te lossen. Enkele veelgebruikte evaluatiemetrieken zijn:

  1. Accuracy: Meet de proportie correct geclassificeerde voorbeelden.
from tensorflow.keras.metrics import Accuracy
 
acc_metric = Accuracy()
  1. Precision, Recall, F1-score: Nuttig voor het evalueren van de prestaties van classificatiemodellen.
from tensorflow.keras.metrics import Precision, Recall, F1Score
 
precision = Precision()
recall = Recall()
f1_score = F1Score()
  1. Mean Squared Error (MSE): Meet het gemiddelde gekwadrateerde verschil tussen de voorspelde en de ware waarden, vaak gebruikt voor regressieproblemen.
from tensorflow.keras.metrics import MeanSquaredError
 
mse = MeanSquaredError()
  1. R-squared (Coefficient of Determination): Meet de proportie van de variantie in de afhankelijke variabele die voorspelbaar is uit de onafhankelijke variabele(n), ook gebruikt voor regressieproblemen.
from tensorflow.keras.metrics import RSquare
 
r_squared = RSquare()

U kunt deze metrieken toevoegen aan de compilatiestap van uw model en ze worden bijgehouden en gerapporteerd tijdens het trainings- en evaluatieproces.

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy', precision, recall, f1_score])

Regularisatietechnieken

Regularisatietechnieken worden gebruikt om overfitting te voorkomen, wat optreedt wanneer een model goed presteert op de trainingsgegevens maar niet generaliseert naar nieuwe, ongeziene gegevens. Enkele veelgebruikte regularisatietechnieken zijn:

  1. L1 en L2 Regularisatie: Ook bekend als Lasso en Ridge regularisatie, respectievelijk. Deze technieken voegen een strafterm toe aan de verliesfunctie, waardoor het model schaarse of kleine gewichten leert.
from tensorflow.keras.regularizers import l1, l2
 
model.add(Dense(64, activation='relu', kernel_regularizer=l1(0.001)))
model.add(Dense(32, activation='relu', kernel_regularizer=l2(0.001)))
  1. Dropout: Zet willekeurig een fractie van de invoereenheden op 0 tijdens het trainingsproces, wat helpt om overfitting te verminderen.
from tensorflow.keras.layers import Dropout
 
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(32, activation='relu'))
  1. Early Stopping: Stopt het trainingsproces wanneer de prestaties van het model op een validatieset niet meer verbeteren, om overfitting te voorkomen.
from tensorflow.keras.callbacks import EarlyStopping
 
early_stopping = EarlyStopping(monitor='val_loss', patience=10, verbose=1)
  1. Data Augmentation: Vergroot kunstmatig de trainingsdataset door transformaties toe te passen, zoals rotatie, schaling of spiegeling, op de invoerdata.
from tensorflow.keras.preprocessing.image import ImageDataGenerator
 
data_gen = ImageDataGenerator(rotation_range=20, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.2, zoom_range=0.2, horizontal_flip=True)

Het toepassen van deze regularisatietechnieken kan de generalisatieprestaties van uw deep learning-modellen verbeteren.

Model opslaan en laden

Tijdens het trainingsproces is het belangrijk om de gewichten en architectuur van het model op te slaan om het getrainde model te kunnen gebruiken voor inferentie of verdere fine-tuning. U kunt de Keras API gebruiken om modellen op te slaan en te laden:

from tensorflow.keras.models import save_model, load_model
 
# Sla het model op
save_model(model, 'my_model.h5')
 
# Laad het model
loaded_model = load_model('my_model.h5')

U kunt ook de architectuur en gewichten van het model afzonderlijk opslaan en laden:

# Sla de modelarchitectuur op
model_json = model.to_json()
with open('model_architecture.json', 'w') as json_file:
    json_file.write(model_json)
 
# Sla de modelgewichten op
model.save_weights('model_weights.h5')
 
# Laad de modelarchitectuur en gewichten
with open('model_architecture.json', 'r') as json_file:
    loaded_model_json = json_file.read()
loaded_model = model_from_json(loaded_model_json)
loaded_model.load_weights('model_weights.h5')

Dit stelt u in staat om eenvoudig uw getrainde modellen in te zetten en ze te gebruiken voor inferentie in productieomgevingen.

ConclusieIn deze handleiding heb je geleerd over de belangrijkste componenten van het trainingsproces voor deep learning modellen, waaronder optimalisatoren, verliesfuncties, evaluatiemetrics, regularisatietechnieken en het opslaan en laden van modellen. Door deze concepten te begrijpen en toe te passen op je eigen deep learning projecten, ben je goed op weg om modellen van hoog niveau te bouwen en trainen die een breed scala aan problemen kunnen oplossen.

Onthoud dat deep learning een voortdurend evoluerend vakgebied is en dat er altijd meer te leren valt. Blijf verkennen, experimenteren en op de hoogte blijven van de nieuwste ontwikkelingen in het vakgebied. Veel succes met je toekomstige deep learning projecten!