Приводится пример реализации на Keras автокодировщика, обучаемого на MNIST генерировать изображения рукописных цифр (рис. 1).
Рис. 1. Исходные и сгенерированные цифры
На вход обученного автокодировщика подаются случайно выбранные изображения проверочного множества MNIST (рис. 1, а), на выходе модель с определенной точностью воспроизводит эти изображения (рис. 1, б).
MNIST загружается из библиотеки tensorflow.keras.datasets:
from tensorflow.keras.datasets import mnist
(x_trn, y_trn), (x_tst, y_tst) = mnist.load_data()
x_trn = x_trn / 255
x_tst = x_tst / 255
len_tst = len(y_tst)
x_trn = x_trn.reshape(len(y_trn), 784)
x_tst = x_tst.reshape(len_tst, 784)
После загрузки выводится случайный пример из обучающего множества:
from matplotlib import pyplot as plt
import numpy as np
# Случайное изображение элемента обучающего множества
i = np.random.randint(len(y_trn))
img = x_trn[i].reshape(28, 28)
def one_plt(img):
plt.figure(figsize = (2, 2))
plt.imshow(img, cmap = 'gray')
plt.axis('off')
plt.show()
one_plt(img)
Кодер и декодер автокодировщика построены из блоков, формируемых процедурой one_part:
from tensorflow.keras.layers import Input, Dense, LeakyReLU, Dropout
from tensorflow.keras.models import Model
def one_part(units, x):
x = Dense(units)(x)
x = LeakyReLU()(x)
return Dropout(0.25)(x)
Формирование модели автокодировщика:
latent_size = 32 # Размер латентного пространста
inp = Input(shape = (784))
x = one_part(512, inp)
x = one_part(256, x)
x = one_part(128, x)
x = one_part(64, x)
x = Dense(latent_size)(x)
encoded = LeakyReLU()(x)
x = one_part(64, encoded)
x = one_part(128, x)
x = one_part(256, x)
x = one_part(512, x)
decoded = Dense(784, activation = 'sigmoid')(x)
model = Model(inputs = inp, outputs = decoded)
model.compile('adam', loss = 'binary_crossentropy') # nadam
model.summary()
Используемая функция потерь – binary_crossentropy
Состав модели показан в табл. 1:
Layer (type) | Output Shape | Param # |
---|---|---|
input_1 (InputLayer) | [(None, 784)] | 0 |
dense (Dense) | (None, 512) | 401920 |
leaky_re_lu (LeakyReLU) | (None, 512) | 0 |
dropout (Dropout) | (None, 512) | 0 |
dense_1 (Dense) | (None, 256) | 131328 |
leaky_re_lu_1 (LeakyReLU) | (None, 256) | 0 |
dropout_1 (Dropout) | (None, 256) | 0 |
dense_2 (Dense) | (None, 128) | 32896 |
leaky_re_lu_2 (LeakyReLU) | (None, 128) | 0 |
dropout_2 (Dropout) | (None, 128) | 0 |
dense_3 (Dense) | (None, 64) | 8256 |
leaky_re_lu_3 (LeakyReLU) | (None, 64) | 0 |
dropout_3 (Dropout) | (None, 64) | 0 |
dense_4 (Dense) | (None, 32) | 2080 |
leaky_re_lu_4 (LeakyReLU) | (None, 32) | 0 |
dense_5 (Dense) | (None, 64) | 2112 |
leaky_re_lu_5 (LeakyReLU) | (None, 64) | 0 |
dropout_4 (Dropout) | (None, 64) | 0 |
dense_6 (Dense) | (None, 128) | 8320 |
leaky_re_lu_6 (LeakyReLU) | (None, 128) | 0 |
dropout_5 (Dropout) | (None, 128) | 0 |
dense_7 (Dense) | (None, 256) | 33024 |
leaky_re_lu_7 (LeakyReLU) | (None, 256) | 0 |
dropout_6 (Dropout) | (None, 256) | 0 |
dense_8 (Dense) | (None, 512) | 131584 |
leaky_re_lu_8 (LeakyReLU) | (None, 512) | 0 |
dropout_7 (Dropout) | (None, 512) | 0 |
dense_9 (Dense) | (None, 784) | 402192 |
На вход модели подается изображение MNIST. Задача кодировщика – повторить это изображение.
Цикл обучения:
import numpy as np
plt_epoch = not False
epochs = 90 # Число эпох
for epoch in range(epochs):
print('epoch:', epoch + 1)
model.fit(x = x_trn, y = x_trn)
# Выводим, если работаем в IPython, Jupyter или Colab
if plt_epoch and epoch > 0 and epoch % 5 == 0:
display.clear_output()
arr_idx = np.random.randint(0, len_tst, 16) # class 'numpy.ndarray'
imgs_for_test = x_tst[arr_idx].reshape(16, 784) # class 'numpy.ndarray'
some_plts(imgs_for_test)
imgs_pedicted = model.predict(imgs_for_test)
some_plts(imgs_pedicted) # imgs_pedicted.shape = (16, 784)
Если plt_epoch = True, то после каждой 5-й эпохи будeт показаны эталонные и генерируемые изображения (см. рис. 1). Используется следующая процедура:
from matplotlib import pyplot as plt
# Для очистки области вывода в IPython, Jupyter, Colab
from IPython import display
def some_plts(imgs):
fig, axs = plt.subplots(4, 4)
k = -1
for i in range(4):
for j in range(4):
k += 1
img = imgs[k].reshape(28, 28)
axs[i, j].imshow(img, cmap = 'gray')
axs[i, j].axis('off')
plt.subplots_adjust(wspace = 1, hspace = 0)
plt.show()
С использованием приведенных сведений студентам надлежит:
# https://towardsdatascience.com/how-to-make-an-autoencoder-2f2d99cd5103
# https://habr.com/ru/post/417405/
from sys import exit
from tensorflow.keras.datasets import mnist
from tensorflow.keras.layers import Input, Dense, LeakyReLU, Dropout
from tensorflow.keras.models import Model
from matplotlib import pyplot as plt
# Для очистки области вывода в IPython, Jupyter, Colab
from IPython import display
import numpy as np
plt_epoch = not False
epochs = 90
(x_trn, y_trn), (x_tst, y_tst) = mnist.load_data()
x_trn = x_trn / 255
x_tst = x_tst / 255
len_tst = len(y_tst)
x_trn = x_trn.reshape(len(y_trn), 784)
x_tst = x_tst.reshape(len_tst, 784)
# Случайное изображение элемента обучающего множества
i = np.random.randint(len(y_trn))
img = x_trn[i].reshape(28, 28)
def one_plt(img):
plt.figure(figsize = (2, 2))
plt.imshow(img, cmap = 'gray')
plt.axis('off')
plt.show()
one_plt(img)
def one_part(units, x):
x = Dense(units)(x)
x = LeakyReLU()(x)
return Dropout(0.25)(x)
latent_size = 32 # Размер латентного пространста
inp = Input(shape = (784))
x = one_part(512, inp)
x = one_part(256, x)
x = one_part(128, x)
x = one_part(64, x)
x = Dense(latent_size)(x)
encoded = LeakyReLU()(x)
x = one_part(64, encoded)
x = one_part(128, x)
x = one_part(256, x)
x = one_part(512, x)
decoded = Dense(784, activation = 'sigmoid')(x)
model = Model(inputs = inp, outputs = decoded)
model.compile('adam', loss = 'binary_crossentropy') # nadam
# model.summary()
def some_plts(imgs):
fig, axs = plt.subplots(4, 4)
k = -1
for i in range(4):
for j in range(4):
k += 1
img = imgs[k].reshape(28, 28)
axs[i, j].imshow(img, cmap = 'gray')
axs[i, j].axis('off')
plt.subplots_adjust(wspace = 1, hspace = 0)
plt.show()
for epoch in range(epochs):
print('epoch:', epoch + 1)
model.fit(x = x_trn, y = x_trn)
# Выводим, если работаем в IPython, Jupyter или Colab
if plt_epoch and epoch > 0 and epoch % 5 == 0:
display.clear_output()
arr_idx = np.random.randint(0, len_tst, 16) # class 'numpy.ndarray'
imgs_for_test = x_tst[arr_idx].reshape(16, 784) # class 'numpy.ndarray'
some_plts(imgs_for_test)
imgs_pedicted = model.predict(imgs_for_test)
some_plts(imgs_pedicted) # imgs_pedicted.shape = (16, 784)
# Прогноз из шума
# img = np.random.uniform(0, 1, 16 * 784).reshape(16, 784)
# imgs_pedicted = model.predict(img)
# some_plts(imgs_pedicted)