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()
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
Kommentar veröffentlichen