Deep Interest | 06 Вариационные автоэнкодеры

искусственный интеллект глубокое обучение Keras
Deep Interest | 06 Вариационные автоэнкодеры

Введение

Вариационный автоэнкодер(Variational Autoencoder, VAE) — разновидность генеративной модели (Generative Model), другая распространенная генеративная модель —Генеративно-состязательные сети(генеративно-состязательная сеть, GAN)

Здесь мы вводим принцип VAE и реализуем его с помощью Keras.

принцип

У нас часто возникает необходимость научиться генерировать новые образцы на основе множества образцов.

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

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

P(X)

Но оценка распределения данных — непростая задача, особенно когда объем данных недостаточен.

Вы можете использовать скрытую переменную z, получить x из z с помощью комплексного отображения и предположить, что z подчиняется распределению Гаусса.

x=f(z;\theta)

Поэтому необходимо только узнать параметры распределения Гаусса, которым подчиняются скрытые переменные, и функцию отображения для получения распределения исходных данных.

Чтобы узнать параметры гауссовского распределения скрытых переменных, необходимо получить достаточно выборок z

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

z=Q(z|x)

Это очень похоже на автокодировщик: из самих данных путем кодирования получается представление скрытого слоя, а декодирование восстанавливается.

Но разница между VAE и AE заключается в следующем:

  • Распределение представления скрытого слоя в AE неизвестно, в то время как скрытые переменные в VAE подчиняются распределению Гаусса.
  • Кодировщик и декодер изучаются в AE, а распределение скрытых переменных, включая среднее значение и дисперсию распределения Гаусса, также изучается в VAE.
  • AE может получить соответствующий реконструированный x только из одного x
  • VAE может сгенерировать новый z и, таким образом, получить новый x, т.е. сгенерировать новые выборки

функция потерь

Помимо ошибки реконструкции, поскольку мы предполагаем, что скрытая переменная z подчиняется распределению Гаусса в ВАЭ, соответствующее кодеру условное распределение вероятностей должно быть максимально похоже на распределение Гаусса

Относительная энтропия, также известная как дивергенция KL (расхождение Кульбака-Лейблера), может использоваться для измерения разницы или расстояния между двумя распределениями, но относительная энтропияасимметричныйиз

D(f\parallel g)=\int f(x)\log\frac{f(x)}{g(x)}dx

выполнить

Взяв здесь в качестве примера MNIST, мы изучаем два параметра, среднее значение и дисперсию гауссовского распределения, которым подчиняется скрытая переменная z, так что новое z можно использовать для генерации x, которого нет в исходных данных.

Кодер и декодер используют два полностью связанных уровня, которые проще, в основном для иллюстрации реализации VAE.

загрузить библиотеку

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

from keras.layers import Input, Dense, Lambda
from keras.models import Model
from keras import backend as K
from keras import objectives
from keras.datasets import mnist

определить некоторые константы

batch_size = 100
original_dim = 784
intermediate_dim = 256
latent_dim = 2
epochs = 50

Часть кодировщика, два полностью связанных слоя, представление скрытого слоя включает среднее значение и дисперсию

x = Input(shape=(original_dim,))
h = Dense(intermediate_dim, activation='relu')(x)
z_mean = Dense(latent_dim)(h)
z_log_var = Dense(latent_dim)(h)

LambdaСлой не участвует в обучении, а только в расчете, который позже используется для генерации новых значений z.

def sampling(args):
    z_mean, z_log_var = args
    epsilon = K.random_normal(shape=(batch_size, latent_dim), mean=0.)
    return z_mean + K.exp(z_log_var / 2) * epsilon

z = Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_log_var])

Часть декодера, два полносвязных слоя,x_decoded_meanза реконструированный выпуск

decoder_h = Dense(intermediate_dim, activation='relu')
decoder_mean = Dense(original_dim, activation='sigmoid')
h_decoded = decoder_h(z)
x_decoded_mean = decoder_mean(h_decoded)

Настройте функцию общих потерь и скомпилируйте модель

def vae_loss(x, x_decoded_mean):
    xent_loss = original_dim * objectives.binary_crossentropy(x, x_decoded_mean)
    kl_loss = -0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
    return xent_loss + kl_loss

vae = Model(x, x_decoded_mean)
vae.compile(optimizer='rmsprop', loss=vae_loss)

Загружайте данные и тренируйтесь, скорость обучения процессора может быть приемлемой.

(x_train, y_train), (x_test, y_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:])))

vae.fit(x_train, x_train,
        shuffle=True,
        epochs=epochs,
        batch_size=batch_size,
        validation_data=(x_test, x_test))

Определите кодировщик и посмотрите, как данные в MNIST выглядят в скрытом слое.

encoder = Model(x, z_mean)

x_test_encoded = encoder.predict(x_test, batch_size=batch_size)
plt.figure(figsize=(6, 6))
plt.scatter(x_test_encoded[:, 0], x_test_encoded[:, 1], c=y_test)
plt.colorbar()
plt.show()

Результаты следующие, указывающие на то, что в двумерном скрытом слое разные числа хорошо разделены.

数字在隐层中的表示

Определите другой генератор, от скрытого слоя до вывода, для создания новых выборок.

decoder_input = Input(shape=(latent_dim,))
_h_decoded = decoder_h(decoder_input)
_x_decoded_mean = decoder_mean(_h_decoded)
generator = Model(decoder_input, _x_decoded_mean)

Сгенерируйте некоторые 2D-данные с помощью сетки, введите их в генератор как новый z и отобразите сгенерированный x

n = 20
digit_size = 28
figure = np.zeros((digit_size * n, digit_size * n))
grid_x = np.linspace(-4, 4, n)
grid_y = np.linspace(-4, 4, n)

for i, xi in enumerate(grid_x):
    for j, yi in enumerate(grid_y):
        z_sample = np.array([[yi, xi]])
        x_decoded = generator.predict(z_sample)
        digit = x_decoded[0].reshape(digit_size, digit_size)
        figure[(n - i - 1) * digit_size: (n - i) * digit_size,
               j * digit_size: (j + 1) * digit_size] = digit

plt.figure(figsize=(10, 10))
plt.imshow(figure)
plt.show()

Результаты следующие, что согласуется с графиком скрытого слоя, показанным ранее, и даже можно увидеть переходные состояния между некоторыми числами.

网格化隐层数据对应的输出

Из-за включения некоторых случайных факторов результаты будут отличаться каждый раз.

Если вы замените полностью связанный слой на CNN, вы должны получить лучшие результаты представления.

расширять

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

FashionMNIST数据集

Просто измените четыре строки

from keras.datasets import fashion_mnist

(x_train, y_train), (x_test, y_test) = fashion_mnist.load_data()

grid_x = np.linspace(-3, 3, n)
grid_y = np.linspace(-3, 3, n)

Полный код выглядит следующим образом

# -*- coding: utf-8 -*-

import numpy as np
import matplotlib.pyplot as plt

from keras.layers import Input, Dense, Lambda
from keras.models import Model
from keras import backend as K
from keras import objectives
from keras.datasets import fashion_mnist

batch_size = 100
original_dim = 784
intermediate_dim = 256
latent_dim = 2
epochs = 50

x = Input(shape=(original_dim,))
h = Dense(intermediate_dim, activation='relu')(x)
z_mean = Dense(latent_dim)(h)
z_log_var = Dense(latent_dim)(h)

def sampling(args):
    z_mean, z_log_var = args
    epsilon = K.random_normal(shape=(batch_size, latent_dim), mean=0.)
    return z_mean + K.exp(z_log_var / 2) * epsilon

z = Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_log_var])

decoder_h = Dense(intermediate_dim, activation='relu')
decoder_mean = Dense(original_dim, activation='sigmoid')
h_decoded = decoder_h(z)
x_decoded_mean = decoder_mean(h_decoded)

def vae_loss(x, x_decoded_mean):
    xent_loss = original_dim * objectives.binary_crossentropy(x, x_decoded_mean)
    kl_loss = -0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
    return xent_loss + kl_loss

vae = Model(x, x_decoded_mean)
vae.compile(optimizer='rmsprop', loss=vae_loss)

(x_train, y_train), (x_test, y_test) = fashion_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:])))

vae.fit(x_train, x_train,
        shuffle=True,
        epochs=epochs,
        batch_size=batch_size,
        validation_data=(x_test, x_test))

encoder = Model(x, z_mean)

x_test_encoded = encoder.predict(x_test, batch_size=batch_size)
plt.figure(figsize=(6, 6))
plt.scatter(x_test_encoded[:, 0], x_test_encoded[:, 1], c=y_test)
plt.colorbar()
plt.show()

decoder_input = Input(shape=(latent_dim,))
_h_decoded = decoder_h(decoder_input)
_x_decoded_mean = decoder_mean(_h_decoded)
generator = Model(decoder_input, _x_decoded_mean)

n = 20
digit_size = 28
figure = np.zeros((digit_size * n, digit_size * n))
grid_x = np.linspace(-3, 3, n)
grid_y = np.linspace(-3, 3, n)

for i, xi in enumerate(grid_x):
    for j, yi in enumerate(grid_y):
        z_sample = np.array([[yi, xi]])
        x_decoded = generator.predict(z_sample)
        digit = x_decoded[0].reshape(digit_size, digit_size)
        figure[(n - i - 1) * digit_size: (n - i) * digit_size,
               j * digit_size: (j + 1) * digit_size] = digit

plt.figure(figsize=(10, 10))
plt.imshow(figure)
plt.show()

Давайте взглянем на представление скрытого слоя, который также имеет хороший эффект классификации.

FashionMNIST隐层表示

Затем сгенерируйте немного графики, вы можете увидеть переход между разными видами одежды.

FashionMNIST网格化隐层数据对应的输出

Ссылаться на

видеоурок

Глубоко и интересно (1)