Direkt zum Hauptbereich

Autoencoder verstehen (Teil II)

Was ist die Magie hinter Autoencodern? Mit Code-Beispiele! 

 In diesem Artikel möchte ich zwei Arten von Autoencodern erklären und eine Code-Implementierung in Python und Keras geben.

Im vorherigen Artikel (falls Sie ihn verpasst haben, hier ist der Link) habe ich die möglichen Anwendungsfälle von Autoencodern erklärt und kurz erläutert, was Autoencoder sind.


Unterkomplette Autoencoder

Die Hauptaufgabe von Undercomplete-Autoencodern ist nicht nur das Kopieren der Eingabe in die Ausgabe, sondern das Erlernen nützlicher Eigenschaften der Eingabedaten.


Eine der einfachsten Möglichkeiten, Autoenkoder zu konstruieren, besteht darin, die Anzahl der Knoten in den versteckten Schichten so einzuschränken, dass die Anzahl der Knoten in den versteckten Schichten geringer ist als in der Eingabeschicht, wodurch der Informationsfluss durch das Netzwerk begrenzt wird.


Auf diese Weise erhalten wir eine latente Repräsentation der ursprünglichen Eingabedaten. Autoencoder, deren Code (latente Repräsentation der Eingabedaten) Dimension kleiner als die Eingabedimension ist, nennt man unterkomplett.


Diese Art von Autoencoder ermöglicht es uns, die auffälligsten Merkmale der Trainingsdaten zu erfassen.


Die Verlustfunktion von unvollständigen Autoencodern ist einfach ihre Verlustfunktion:

        L(x,g(f(x))).

wobei L eine Verlustfunktion ist, die g(f(x)) dafür bestraft, dass es unähnlich zu x ist, wie z. B. der mittlere quadratische Fehler.


Durch die Annahme, dass neuronale Netzwerke nichtlineare Beziehungen in Daten lernen können, werden tiefe Autokoder zu einer leistungsfähigeren und nichtlinearen Form der PCA für höherdimensionale Daten, Autokoder sind in der Lage, komplexe Repräsentationen von Daten zu lernen, die dann bei der Visualisierung im niedrigdimensionalen Raum verwendet werden können.


Bei tiefen Autoencodern sollten wir uns auch über die Kapazität von Encoder und Decoder im Klaren sein. Selbst wenn wir einen Engpass bei einem Knoten in einer versteckten Schicht haben, ist es immer noch möglich, dass Kodierer und Dekodierer das Kopieren der Eingabe zur Ausgabe lernen, anstatt wichtige Merkmale und Repräsentationen über die Eingabedaten zu lernen. Daher sollten wir auch darauf achten, wie groß unsere Encoder und Decoder sind und diese dann Steuerung.

 

Einfacher Autoencoder 

Python & Keras

import keras
from keras import layers

# This is the size of our encoded representations
encoding_dim = 32  # 32 floats -> compression of factor 24.5, assuming the input is 784 floats

# This is our input image
input_img = keras.Input(shape=(784,))
# "encoded" is the encoded representation of the input
encoded = layers.Dense(encoding_dim, activation='relu')(input_img)
# "decoded" is the lossy reconstruction of the input
decoded = layers.Dense(784, activation='sigmoid')(encoded)

# This model maps an input to its reconstruction
autoencoder = keras.Model(input_img, decoded)

# This model maps an input to its encoded representation
encoder = keras.Model(input_img, encoded)

# This is our encoded (32-dimensional) input
encoded_input = keras.Input(shape=(encoding_dim,))
# Retrieve the last layer of the autoencoder model
decoder_layer = autoencoder.layers[-1]
# Create the decoder model
decoder = keras.Model(encoded_input, decoder_layer(encoded_input))

autoencoder.compile(optimizer='adam', loss='binary_crossentropy')

from keras.datasets import mnist
import numpy as np
(x_train, _), (x_test, _) = mnist.load_data()

x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))
print(x_train.shape)
print(x_test.shape)

autoencoder.fit(x_train, x_train,
                epochs=50,
                batch_size=256,
                shuffle=True,
                validation_data=(x_test, x_test))

# Encode and decode some digits
# Note that we take them from the *test* set
encoded_imgs = encoder.predict(x_test)
decoded_imgs = decoder.predict(encoded_imgs)

# Use Matplotlib (don't ask)
import matplotlib.pyplot as plt

n = 10  # How many digits we will display
plt.figure(figsize=(20, 4))
for i in range(n):
    # Display original
    ax = plt.subplot(2, n, i + 1)
    plt.imshow(x_test[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    # Display reconstruction
    ax = plt.subplot(2, n, i + 1 + n)
    plt.imshow(decoded_imgs[i].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
    
plt.show()


Variationale Autoencoder

Variationale Autoencoder sind Typen von generativen Modellen. Um das Konzept der VAEs besser zu verstehen, stellen wir uns ein Autoencoder-Modell vor, das auf einem großen Bilddatensatz von Flugzeugen mit einer Kodierungsdimension von 5 trainiert wurde. Der typische Autoencoder lernt die beschreibenden Attribute von Flugzeugen wie Flügel, Getriebe, Rumpf und andere beschreibende Attribute, so dass er eine Beobachtung in komprimierterer Darstellung beschreiben könnte.


Mit diesem Beispiel können wir nun jedes latente Attribut als Wahrscheinlichkeitsverteilung darstellen. Danach können wir für jedes Attribut eine Zufallsstichprobe aus dieser Verteilung ziehen, so dass sie dann als Eingabe für den Decoder verwendet werden kann.


Da das Kodierermodell eine Wahrscheinlichkeitsverteilung ausgibt, stellen wir eine konstante, glatte latente Raumdarstellung her. Die Werte, die in der Wahrscheinlichkeitsverteilung nahe beieinander liegen, können zu einer ähnlichen Dekonstruktion dieser latenten Attribute führen. Mit anderen Worten, je näher die Werte beieinander liegen, desto ähnlicher ist die Ausgabe des Decoders.


Python & Keras

import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

class Sampling(layers.Layer):
    """Uses (z_mean, z_log_var) to sample z, the vector encoding a digit."""
    def call(self, inputs):
        z_mean, z_log_var = inputs
        batch = tf.shape(z_mean)[0]
        dim = tf.shape(z_mean)[1]
        epsilon = tf.keras.backend.random_normal(shape=(batch, dim))
        return z_mean + tf.exp(0.5 * z_log_var) * epsilon

latent_dim = 2

encoder_inputs = keras.Input(shape=(28, 28, 1))
x = layers.Conv2D(32, 3, activation="relu", strides=2, padding="same")(encoder_inputs)
x = layers.Conv2D(64, 3, activation="relu", strides=2, padding="same")(x)
x = layers.Flatten()(x)
x = layers.Dense(16, activation="relu")(x)
z_mean = layers.Dense(latent_dim, name="z_mean")(x)
z_log_var = layers.Dense(latent_dim, name="z_log_var")(x)
z = Sampling()([z_mean, z_log_var])
encoder = keras.Model(encoder_inputs, [z_mean, z_log_var, z], name="encoder")
encoder.summary()

latent_inputs = keras.Input(shape=(latent_dim,))
x = layers.Dense(7 * 7 * 64, activation="relu")(latent_inputs)
x = layers.Reshape((7, 7, 64))(x)
x = layers.Conv2DTranspose(64, 3, activation="relu", strides=2, padding="same")(x)
x = layers.Conv2DTranspose(32, 3, activation="relu", strides=2, padding="same")(x)
decoder_outputs = layers.Conv2DTranspose(1, 3, activation="sigmoid", padding="same")(x)
decoder = keras.Model(latent_inputs, decoder_outputs, name="decoder")
decoder.summary()

(x_train, _), (x_test, _) = keras.datasets.mnist.load_data()
mnist_digits = np.concatenate([x_train, x_test], axis=0)
mnist_digits = np.expand_dims(mnist_digits, -1).astype("float32") / 255
vae = VAE(encoder, decoder)

vae.compile(optimizer=keras.optimizers.Adam())
vae.fit(mnist_digits, epochs=30, batch_size=128)


import matplotlib.pyplot as plt

def plot_latent(encoder, decoder):
    # display a n*n 2D manifold of digits
    n = 30
    digit_size = 28
    scale = 2.0
    figsize = 15
    figure = np.zeros((digit_size * n, digit_size * n))
    # linearly spaced coordinates corresponding to the 2D plot
    # of digit classes in the latent space
    grid_x = np.linspace(-scale, scale, n)
    grid_y = np.linspace(-scale, scale, n)[::-1]
    for i, yi in enumerate(grid_y):
        for j, xi in enumerate(grid_x):
            z_sample = np.array([[xi, yi]])
            x_decoded = decoder.predict(z_sample)
            digit = x_decoded[0].reshape(digit_size, digit_size)
            figure[
                i * digit_size : (i + 1) * digit_size,
                j * digit_size : (j + 1) * digit_size,
            ] = digit
    plt.figure(figsize=(figsize, figsize))
    start_range = digit_size // 2
    end_range = n * digit_size + start_range + 1
    pixel_range = np.arange(start_range, end_range, digit_size)
    sample_range_x = np.round(grid_x, 1)
    sample_range_y = np.round(grid_y, 1)
    plt.xticks(pixel_range, sample_range_x)
    plt.yticks(pixel_range, sample_range_y)
    plt.xlabel("z[0]")
    plt.ylabel("z[1]")
    plt.imshow(figure, cmap="Greys_r")
    plt.show()

plot_latent(encoder, decoder)

Kommentare

Beliebte Posts aus diesem Blog

Autoencoder verstehen (Teil I)

Warum sollten wir Autoencoder verwenden und was sind die Vorteile von Autoencodern . Wenn man sich andere Beschreibungen und Erklärungen anschaut, was Autoencoder sind, fängt man bald an, durcheinander zu kommen , warum Autoencoder so nützlich sind und warum sie versuchen, von den Eingabedaten zur Ausgabe mit minimalem Verlust zu reproduzieren.

Einfaches Reinforcement Learning: Q-learning

Einer meiner Lieblingsalgorithmen, den ich während eines Reinforcement-Learning-Kurses gelernt habe, war das q-learning. Wahrscheinlich, weil er für mich am einfachsten zu verstehen und zu programmieren war, aber auch, weil er mir sinnvoll erschien. In diesem kurzen Beitrag werde ich q-learning besprechen und den grundlegenden Hintergrund zum Verständnis des Algorithmus vermitteln.