Weiter zum Inhalt

Generative Adversarial Nets (GANs) verständlich erklärt

Lerne, was Generative Adversarial Networks sind – ohne Mathe-Details – und programmiere ein einfaches GAN, das Ziffern erzeugen kann!
Aktualisiert 18. Sept. 2026  · 9 Min. lesen

Mit KI erkunden

ChatGPTClaudePerplexity

In diesem Tutorial lernst du, was Generative Adversarial Networks (GANs) sind – ganz ohne Mathe-Details. Anschließend programmierst du ein einfaches GAN, das Ziffern erzeugen kann!

Analogie

Am einfachsten verstehst du GANs über eine kleine Analogie:

Stell dir einen Laden vor, der bestimmte Weinsorten von Kundinnen und Kunden ankauft, um sie später weiterzuverkaufen.

analogy

Allerdings gibt es windige Gestalten, die Fälschungen verkaufen, um an Geld zu kommen. Die Ladenbesitzerin muss also echte von gefälschten Weinen unterscheiden können.

analogy

Anfangs macht der Fälscher viele Fehler, und es fällt der Besitzerin leicht zu erkennen, dass der Wein nicht echt ist. Aus diesen Fehlschlägen lernt der Fälscher, probiert neue Techniken aus, um echte Weine nachzuahmen, und einige davon funktionieren. Sobald er weiß, welche Tricks die Kontrollen der Besitzerin passieren, verfeinert er seine Fälschungen weiter.

Gleichzeitig bekommt die Ladenbesitzerin Feedback von anderen Läden oder Weinexpertinnen, dass einige ihrer Weine nicht original sind. Also verbessert sie ihre Prüfmethoden, um echte und falsche Weine sicher zu unterscheiden. Ziel des Fälschers ist es, Weine herzustellen, die von echten nicht zu unterscheiden sind. Ziel der Besitzerin ist es, echte und falsche zuverlässig zu erkennen.

Dieses Hin und Her ist die Grundidee hinter GANs.

Bestandteile eines Generative Adversarial Network

Anhand des Beispiels oben lässt sich die Architektur eines GANs ableiten.

gan

GANs bestehen aus zwei Hauptkomponenten: Generator und Diskriminator. Die Ladenbesitzerin entspricht dem Diskriminatornetz und ist in der Regel ein Convolutional Neural Network (da GANs vor allem für Bildaufgaben genutzt werden), das die Wahrscheinlichkeit bewertet, ob ein Bild echt ist.

Der Fälscher ist das Generatornetz und ebenfalls meist ein Convolutional Neural Network (mit Deconvolution-Layern). Dieses Netz nimmt einen Rauschvektor als Eingabe und gibt ein Bild aus. Beim Training lernt der Generator, welche Bildbereiche er verbessern oder verändern muss, damit es dem Diskriminator schwerer fällt, seine generierten Bilder von echten zu unterscheiden.

Der Generator produziert nach und nach Bilder, die echten immer ähnlicher sehen, während der Diskriminator versucht, die Unterschiede zwischen echten und falschen Bildern herauszuarbeiten. Am Ende soll der Generator Bilder erzeugen, die von echten nicht zu unterscheiden sind.

Ein einfaches Generative Adversarial Network mit Keras

Jetzt, da du GANs und ihre Hauptkomponenten kennst, kannst du ein sehr einfaches Netz programmieren. Du verwendest Keras. Falls du diese Python-Bibliothek noch nicht kennst, lies vorab dieses Tutorial. Die Vorlage für dieses Tutorial basiert auf dem hier entwickelten GAN: hier.

Installiere zunächst die folgenden Pakete via pip:

  • keras
  • matplotlib
  • tensorflow
  • tqdm

matplotlib nutzt du zum Plotten, tensorflow als Keras-Backend und tqdm für eine komfortable Fortschrittsanzeige pro Epoche (Iteration).

Als Nächstes erstellst du ein Python-Skript. Darin importierst du zuerst alle Module und Funktionen, die du nutzt. Die Erklärungen folgen jeweils beim Einsatz.

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

Jetzt setzt du ein paar Variablen:

# 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

Bevor du den Diskriminator und den Generator baust, sammelst und bereitest du die Daten vor. Du verwendest den populären MNIST-Datensatz mit Bildern einzelner Ziffern von 0 bis 9.

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)

Hinweis: mnist.load_data() ist Teil von Keras und ermöglicht dir, den MNIST-Datensatz bequem in deinen Workspace zu laden.

Jetzt erstellst du die Generator- und Diskriminator-Netze. Du verwendest für beide den Adam-Optimizer. Sowohl Generator als auch Diskriminator bestehen aus drei Hidden-Layern mit der Aktivierungsfunktion Leaky ReLU. Für den Diskriminator fügst du außerdem Dropout-Layer hinzu, um ihn gegenüber unbekannten Bildern robuster zu machen.

# 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

Jetzt führst du Generator und Diskriminator zusammen!

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

Der Vollständigkeit halber kannst du noch eine Funktion erstellen, die alle 20 Epochen die generierten Bilder speichert. Da dies nicht der Kern der Lektion ist, musst du sie nicht im Detail verstehen.

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

Damit ist der Großteil deines Netzes programmiert. Jetzt musst du es nur noch trainieren und dir die erzeugten Bilder ansehen.

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)

Nach 400 Epochen Training kannst du die generierten Bilder betrachten. Nach der ersten Epoche ist noch keine echte Struktur zu erkennen. Nach 40 Epochen nehmen die Ziffern Form an. Und nach 400 Epochen sind die Ziffern deutlich zu erkennen – auch wenn ein paar noch unleserlich sind.

Ergebnisse nach 1 Epoche Ergebnisse nach 40 Epochen Ergebnisse nach 400 Epochen
!images1 images2 images3

Dieser Code benötigt auf einer CPU etwa 2 Minuten pro Epoche – das ist der Hauptgrund, warum wir ihn ausgewählt haben. Du kannst mit mehr Epochen experimentieren und dem Generator wie auch dem Diskriminator weitere (oder andere) Layer hinzufügen. Bedenke aber: Mit komplexeren, tieferen Architekturen steigt die Laufzeit auf einer reinen CPU. Lass dich davon trotzdem nicht vom Ausprobieren abhalten!

Fazit

Glückwunsch, du hast es bis zum Ende geschafft und die Grundlagen von Generative Adversarial Networks (GANs) auf intuitive Weise kennengelernt! Außerdem hast du dein erstes Modell mit der Keras-Bibliothek implementiert. Wenn du mehr über Deep Learning mit Python erfahren möchtest, schau dir den DataCamp-Kurs Deep Learning in Python an.

Themen
Deep Learning
Künstliche Intelligenz
Maschinelles Lernen

Mehr über Python und Deep Learning lernen

Kurs

Einführung in Deep Learning mit Python

4 Std.
264.6K
Lerne die Grundlagen neuronaler Netzwerke und wie du Deep-Learning-Modelle mit Keras 2.0 in Python erstellst.
Details anzeigenRight Arrow
Kurs Starten
Mehr anzeigenRight Arrow