В чем магия автоэнкодеров? Приводим примеры кода!

В предыдущей статье (если вы пропустили ее, вот ссылка) я объяснил потенциальные варианты использования автокодировщиков и кратко объяснил, что такое автокодеры. В этой статье я хотел бы объяснить два типа автоэнкодеров и дать их некоторую кодовую реализацию на Python и Keras.

Начнем с объяснения того, как они работают.

Неполные автоэнкодеры.

Основная задача неполных автоэнкодеров - не просто копировать ввод в вывод, а вместо этого изучать полезные свойства вводимых данных.

Один из простейших способов создания автокодировщиков - ограничить количество узлов в скрытых слоях, чтобы количество узлов в скрытых слоях было меньше, чем во входном слое, которым ограничивается поток информации через сеть. Таким образом, мы получаем скрытое представление h исходных входных данных. Автоэнкодер, размер кода которого (скрытое представление входных данных) меньше размера входных данных, называется неполным. Этот тип автоэнкодера позволяет нам фиксировать наиболее важные особенности обучающих данных.

Функция потерь неполных автокодировщиков - это просто их функция потерь:

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

где L - функция потерь, которая наказывает g (f (x)) за отличие от x, например среднеквадратичную ошибку.

Признавая, что нейронные сети могут изучать нелинейные отношения в данных, неполные автокодеры становятся более мощной и нелинейной формой PCA для данных более высокой размерности, автокодеры способны изучать сложное представление данных, которое затем может использоваться для визуализации в низком масштабе. -размерное пространство.

Для глубоких автоэнкодеров мы также должны знать о возможностях кодировщика и декодера. Даже если у нас есть узкое место, если один узел в скрытом слое, кодировщик и декодер все равно могут научиться копировать входные данные в выходные, а не изучать важные функции и представление о входных данных. Таким образом, мы также должны обратить внимание на то, насколько велики наши кодеры и декодеры, а также контроль

Варианты автоэнкодеров

Вариационные автоэнкодеры - это типы генеративных моделей. Чтобы лучше понять концепцию VAE, давайте представим модель автоэнкодера, которая была обучена на большом наборе данных изображений самолетов с размерностью кодирования 5. Типичный автоэнкодер изучит описательные атрибуты самолетов, такие как крылья, шестерни, фюзеляж и т. Д. и другие описательные атрибуты, чтобы можно было описать наблюдение в более сжатой форме.

В приведенном выше примере атрибуты объекта (в нашем случае это плоскость) описываются одним значением. Но что это будет значить для вас? В вариационных автоэнкодерах эти значения могут быть определены как диапазон возможных значений для каждого атрибута.

В этом примере мы теперь можем представить каждый скрытый атрибут как распределение вероятностей. После этого мы можем случайным образом выполнить выборку из этого распределения для каждого атрибута, чтобы затем его можно было передать в качестве входных данных в декодер.

Поскольку модель кодировщика выводит распределение вероятностей, мы делаем постоянное, гладкое представление скрытого пространства. Значения, близкие друг к другу по распределению вероятностей, могут привести к аналогичной деконструкции этих скрытых атрибутов. Другими словами, чем ближе значения друг к другу, тем более похожий вывод декодера мы получаем.

Python и Керас

Не забудьте опробовать этот код в своей среде IDE!

Настраивать:

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)

Классные статьи:





«MusicVAE: иерархическая скрытая векторная модель»

Заключение:

Спасибо за прочтение! Если вам понравилась эта статья, нажмите кнопку хлопка 👏 столько раз, сколько сможете. Это будет много значить и побудит меня продолжать писать подобные истории. Давайте подключимся в Твиттере! 🐦