Автокодировщики на Keras

Обучаюсь на курсе «Нейронные сети на Python» в «Университете искуственного интеллекта«. Читает Дмитрий Романов. Недавно было занятие по автокодировщикам. Почитал доп. литературу и ниже написал подробно как работает простой автокодировщик с примером кода на Keras.

Import буду писать под каждый ключевой блок кода, чтобы понятно было какая библиотека нужна для поключения того или иного функционала.

Для начала импортируем тестовую базу MNIST с изображениями рукописных букв. Размер каждой картинки 28 * 28 пикселей.

from keras.datasets import mnist
import numpy as np

(x_train_src, _), (x_test_src, _) = mnist.load_data() #загружаем базу картинок MNIST

Если вывести размер загруженного массива

print("x_train: ", x_train_src.shape, "x_test: ", x_test_src.shape)
print("Размер изображения:", x_train_src.shape[1:])
print("Кол-во изображений:", len(x_train_src))
print("Размерность вектора:", np.prod(x_train.shape[1:]))

x_train:  (60000, 28, 28) x_test:  (10000, 28, 28)
Размер изображения: (28, 28)
Кол-во изображений: 60000
Размерность вектора: 784

то увидим, что в базе 60 000 картинок и каждая размером 28 х 28. Поскольку для того, чтобы подать картинку на Dense слой в Keras (многослойный перцептрон) нужен вектор, растянем двумерную матрицу в вектор размерностью (длиной) 28 x 28 = 784 с помощью reshape.

vector_d = np.prod(x_train_src.shape[1:]) # 28 * 28
x_train = x_train_src.reshape(x_train_src.shape[0], vector_d)
x_test = x_test_src.reshape(x_test_src.shape[0],  vector_d)
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.

print (x_train.shape)
print (x_test.shape)

(60000, 784)
(10000, 784)

Метод numpy.prod (анг. product — произведение) в numpy array производит перемножение элементов вектора. Можно было бы получить длину, просто перемножив количество колонок на количество строк: 28 * 28, но в случае загрузки картинок другого размера пришлось бы править код.

Приведем величину значений в векторе в диапазон от 0 до 1 ([0, 1])(нормализуем):

x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.

Encoder (кодировщик)

Первая часть автокодировщика — encoder. Размер внутреннего (скрытого) слоя H автокодировщика сделаем равным encoding_dim = 32. Т.е в случае входного вектора 784 / 32 = 24.5 — степень компрессии, т.е. во сколько раз исходное изображение будет сжато во внутреннем слое.

from keras.layers import Input, Dense
from keras.models import Model

# 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 placeholder
input_img = Input(shape=(vector_d,), name='Input')

# "encoded" is the encoded representation of the input
encoded = Dense(encoding_dim, activation='relu', name='Encoded')(input_img)
# "decoded" is the lossy reconstruction of the input
decoded = Dense(vector_d, activation='sigmoid', name='Decoded')(encoded)

# this model maps an input to its reconstruction
autoencoder = Model(inputs = input_img, outputs = decoded, name='Autoencoder')
autoencoder.summary()
Model: "Autoencoder"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
Input (InputLayer)           (None, 784)               0         
_________________________________________________________________
Encoded (Dense)              (None, 32)                25120     
_________________________________________________________________
Decoded (Dense)              (None, 784)               25872     
=================================================================
Total params: 50,992
Trainable params: 50,992
Non-trainable params: 0
_________________________________________________________________

Если модель разобрать на encoder и decoder, то для кодировщика на вход модели придет вектор размерностью 784 и сожмется до 32.

Поскольку длина вектора изображения 784, то использовать на внутреннем слое H для тренировки модели encoder-а не получится, поскольку для него нужны вектора размерностью 32.

# this model maps an input to its encoded representation
encoder = Model(inputs = input_img, outputs = encoded, name='Encoder')
encoder.summary()
Model: "Encoder"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
Input (InputLayer)           (None, 784)               0         
_________________________________________________________________
Encoded (Dense)              (None, 32)                25120     
=================================================================
Total params: 25,120
Trainable params: 25,120
Non-trainable params: 0
_________________________________________________________________

Соответственно откомпилировать эту модель можно, но вот тренировку (fit) делать не на чем. Нет данных зажатых до размерности 32.

Декодер разожмет сжатую до вектора размерностью 32 исходную последовательность снова в 784.

# create a placeholder for an encoded (32-dimensional) input
encoded_input = Input(shape=(encoding_dim,), name='DecoderInput')
# retrieve the last layer of the autoencoder model
#decoder_layer = autoencoder.layers['Encoded'-1]
decoder_layer = autoencoder.get_layer('Decoded')
decoder = Model(encoded_input, decoder_layer(encoded_input), name='Decoder')
decoder.summary()
Model: "Decoder"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
DecoderInput (InputLayer)    (None, 32)                0         
_________________________________________________________________
Decoded (Dense)              (None, 784)               25872     
=================================================================
Total params: 25,872
Trainable params: 25,872
Non-trainable params: 0
_________________________________________________________________
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')

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

После обучения получаем val_loss: ~0.1017 Восстановим изображение после обработки автокодировщиком.

Можно использовать прогноз раздельными моделями, отдельно для кодировщика и декодировщика.

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

или объединенную модель

decoded_imgs = autoencoder.predict(x_test)

Преобразовываем вектора размерностью 784 в картинки 28 х 28 используя shape исходной тестовой выборки.

decoded_imgs = decoded_imgs.reshape(x_test_src.shape)

Визуализируем оригинальные и восстановленные изображения:

import matplotlib.pyplot as plt

def plotImage(data, plt, n, i, row = 0):
    ax = plt.subplot(2, n, i + 1 + row * n)
    plt.imshow(data[i])
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

def plotImages(data1, data2, n):
  plt.figure(figsize=(20, 4))
  for i in range(n):
    plotImage(data1, plt, n, i, 0)
    plotImage(data2, plt, n, i, 1)
  plt.show()

plotImages(x_test_src, decoded_imgs, 10)

Полезные ссылки

Spread the love
Запись опубликована в рубрике IT рецепты. Добавьте в закладки постоянную ссылку.

Добавить комментарий